From bbcbd3de427d9d747d672e52cd17e023945495cc Mon Sep 17 00:00:00 2001 From: Lauest Date: Wed, 5 Feb 2025 16:09:05 +0100 Subject: [PATCH 01/16] updates application sort list --- src/app/applications/application.service.ts | 4 +- .../application-map.component.html | 3 + .../application-map.component.scss | 5 + .../application-map.component.ts | 45 ++++++ ...sualization-failed-requests.component.html | 5 + ...sualization-failed-requests.component.scss | 0 ...visualization-failed-requests.component.ts | 74 ++++++++++ ...ion-visualization-top-codes.component.html | 5 + ...ion-visualization-top-codes.component.scss | 0 ...ation-visualization-top-codes.component.ts | 74 ++++++++++ .../application-visualization.component.html | 5 + .../application-visualization.component.scss | 5 + .../application-visualization.component.ts | 12 ++ .../applications-list.component.html | 23 ++- .../applications-list.component.scss | 2 + .../applications-list.component.ts | 28 +++- .../applications-table.component.html | 137 +++++++++++------- .../applications-table.component.scss | 67 +++++++++ .../applications-table.component.ts | 111 +++++--------- src/app/applications/applications.module.ts | 44 ++++-- src/app/shared/types/table.type.ts | 1 + src/assets/i18n/da.json | 6 +- src/assets/images/arrow_back.png | Bin 0 -> 910 bytes src/assets/images/arrow_forward.png | Bin 0 -> 626 bytes src/assets/scss/components/_tables.scss | 10 +- .../basic-information-box.component.html | 8 + .../basic-information-box.component.scss | 7 + .../basic-information-box.component.ts | 10 ++ .../basic-tap-switch.component.html | 21 +++ .../basic-tap-switch.component.scss | 53 +++++++ .../basic-tap-switch.component.ts | 48 ++++++ .../option-field/option-field.component.html | 3 + .../option-field/option-field.component.scss | 13 ++ .../option-field/option-fieldcomponent.ts | 34 +++++ .../status-icon/status-icon.component.html | 5 + .../status-icon/status-icon.component.scss | 7 + .../status-icon/status-icon.component.ts | 13 ++ .../table-paginator.component.html | 26 ++++ .../table-paginator.component.scss | 106 ++++++++++++++ .../table-paginator.component.ts | 64 ++++++++ .../table-sort-icon.component.html | 7 + .../table-sort-icon.component.scss | 3 + .../table-sort-icon.component.ts | 13 ++ src/styles.scss | 1 - 44 files changed, 949 insertions(+), 159 deletions(-) create mode 100644 src/app/applications/applications-list/application-map/application-map.component.html create mode 100644 src/app/applications/applications-list/application-map/application-map.component.scss create mode 100644 src/app/applications/applications-list/application-map/application-map.component.ts create mode 100644 src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.html create mode 100644 src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.scss create mode 100644 src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.ts create mode 100644 src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.html create mode 100644 src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.scss create mode 100644 src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.ts create mode 100644 src/app/applications/applications-list/application-visualization/application-visualization.component.html create mode 100644 src/app/applications/applications-list/application-visualization/application-visualization.component.scss create mode 100644 src/app/applications/applications-list/application-visualization/application-visualization.component.ts create mode 100644 src/assets/images/arrow_back.png create mode 100644 src/assets/images/arrow_forward.png create mode 100644 src/componenets/basic-information-box/basic-information-box.component.html create mode 100644 src/componenets/basic-information-box/basic-information-box.component.scss create mode 100644 src/componenets/basic-information-box/basic-information-box.component.ts create mode 100644 src/componenets/basic-tap-switch/basic-tap-switch.component.html create mode 100644 src/componenets/basic-tap-switch/basic-tap-switch.component.scss create mode 100644 src/componenets/basic-tap-switch/basic-tap-switch.component.ts create mode 100644 src/componenets/option-field/option-field.component.html create mode 100644 src/componenets/option-field/option-field.component.scss create mode 100644 src/componenets/option-field/option-fieldcomponent.ts create mode 100644 src/componenets/status-icon/status-icon.component.html create mode 100644 src/componenets/status-icon/status-icon.component.scss create mode 100644 src/componenets/status-icon/status-icon.component.ts create mode 100644 src/componenets/table-pagiantor.ts/table-paginator.component.html create mode 100644 src/componenets/table-pagiantor.ts/table-paginator.component.scss create mode 100644 src/componenets/table-pagiantor.ts/table-paginator.component.ts create mode 100644 src/componenets/table-sort-icon/table-sort-icon.component.html create mode 100644 src/componenets/table-sort-icon/table-sort-icon.component.scss create mode 100644 src/componenets/table-sort-icon/table-sort-icon.component.ts diff --git a/src/app/applications/application.service.ts b/src/app/applications/application.service.ts index 80936717c..6c3f9cf3e 100644 --- a/src/app/applications/application.service.ts +++ b/src/app/applications/application.service.ts @@ -1,9 +1,9 @@ import { Injectable } from "@angular/core"; +import { UserMinimalService } from "@app/admin/users/user-minimal.service"; import { Application, ApplicationData, UpdateApplicationOrganization } from "@applications/application.model"; -import { RestService } from "../shared/services/rest.service"; import { Observable } from "rxjs"; import { map } from "rxjs/operators"; -import { UserMinimalService } from "@app/admin/users/user-minimal.service"; +import { RestService } from "../shared/services/rest.service"; interface GetApplicationParameters { limit: number; diff --git a/src/app/applications/applications-list/application-map/application-map.component.html b/src/app/applications/applications-list/application-map/application-map.component.html new file mode 100644 index 000000000..e3fadbfa2 --- /dev/null +++ b/src/app/applications/applications-list/application-map/application-map.component.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/app/applications/applications-list/application-map/application-map.component.scss b/src/app/applications/applications-list/application-map/application-map.component.scss new file mode 100644 index 000000000..750352a28 --- /dev/null +++ b/src/app/applications/applications-list/application-map/application-map.component.scss @@ -0,0 +1,5 @@ +.map-page { + background-color: #ffff; + padding: 20px; + height: 500px; +} diff --git a/src/app/applications/applications-list/application-map/application-map.component.ts b/src/app/applications/applications-list/application-map/application-map.component.ts new file mode 100644 index 000000000..c471b89ca --- /dev/null +++ b/src/app/applications/applications-list/application-map/application-map.component.ts @@ -0,0 +1,45 @@ +import { Component } from "@angular/core"; +import { ApplicationService } from "@applications/application.service"; +import { MapCoordinates } from "@shared/components/map/map-coordinates.model"; +import { SharedModule } from "../../../shared/shared.module"; + +@Component({ + selector: "app-application-map", + standalone: true, + imports: [SharedModule], + templateUrl: "./application-map.component.html", + styleUrl: "./application-map.component.scss", +}) +export class ApplicationMapComponent { + constructor(private applicationService: ApplicationService) {} + + + + coordinateList: MapCoordinates[] = [ + { + latitude: 120, + longitude: 120, + draggable: false, + editEnabled: false, + useGeolocation: true, + markerInfo: { + active: true, + id: 22, + internalOrganizationId: 22, + internalOrganizationName: "22", + isDevice: false, + lastActive: new Date(), + name: "test", + networkTechnology: "lora", + }, + }, + ]; + + getApplications(): void { + const applicationsSubscription = this.applicationService + .getApplications(100000, 0, "asc", "id") + .subscribe(applicationData => { applicationData.data.forEach( + data => this.coordinateList.push() data. + )}); + } +} diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.html b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.html new file mode 100644 index 000000000..d1f1b310d --- /dev/null +++ b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.html @@ -0,0 +1,5 @@ +
+

Top 3 rest codes

+ + {{ chart }} +
diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.scss b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.ts b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.ts new file mode 100644 index 000000000..ad5d646b4 --- /dev/null +++ b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.ts @@ -0,0 +1,74 @@ +import { Component, OnInit } from "@angular/core"; +import { Chart } from "chart.js"; +interface RESTCode { + status: string; + color: string; +} + +const codes: RESTCode[] = [ + { + status: "200 OK", + color: "green", + }, + { + status: "201 Created", + color: "blue", + }, + { + status: "400 Bad Request", + color: "yellow", + }, + { + status: "401 Unauthorized", + color: "red", + }, + { + status: "403 Forbidden", + color: "red", + }, + { + status: "404 Not Found", + color: "orange", + }, + { + status: "500 Internal Server Error", + color: "dark red", + }, +]; + +@Component({ + selector: "app-application-visualization-failed-requests", + standalone: true, + imports: [], + templateUrl: "./application-visualization-failed-requests.component.html", + styleUrl: "./application-visualization-failed-requests.component.scss", +}) +export class ApplicationVisualizationFailedRequestsComponent implements OnInit { + public chart: any; + + ngOnInit(): void { + this.createChart(); + } + + createChart() { + this.chart = new Chart("requestChart", { + type: "doughnut", //this denotes tha type of chart + data: { + // values on X-Axis + labels: ["Red", "Pink", "Green", "Yellow", "Orange", "Blue"], + datasets: [ + { + label: "My First Dataset", + + data: [300, 240, 100, 432, 253, 34], + backgroundColor: ["200 OK", "201 Created", "400 Bad Request", "yellow", "orange", "blue"], + hoverOffset: 4, + }, + ], + }, + options: { + aspectRatio: 2.5, + }, + }); + } +} diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.html b/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.html new file mode 100644 index 000000000..a610c7fc8 --- /dev/null +++ b/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.html @@ -0,0 +1,5 @@ +
+

Top 3 rest codes

+ + {{ chart }} +
diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.scss b/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.ts b/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.ts new file mode 100644 index 000000000..04e827965 --- /dev/null +++ b/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.ts @@ -0,0 +1,74 @@ +import { Component, OnInit } from "@angular/core"; +import { Chart } from "chart.js"; +interface RESTCode { + status: string; + color: string; +} + +const codes: RESTCode[] = [ + { + status: "200 OK", + color: "green", + }, + { + status: "201 Created", + color: "blue", + }, + { + status: "400 Bad Request", + color: "yellow", + }, + { + status: "401 Unauthorized", + color: "red", + }, + { + status: "403 Forbidden", + color: "red", + }, + { + status: "404 Not Found", + color: "orange", + }, + { + status: "500 Internal Server Error", + color: "dark red", + }, +]; + +@Component({ + selector: "app-application-visualization-top-codes", + standalone: true, + imports: [], + templateUrl: "./application-visualization-top-codes.component.html", + styleUrl: "./application-visualization-top-codes.component.scss", +}) +export class ApplicationVisualizationTopCodesComponent implements OnInit { + public chart: any; + + ngOnInit(): void { + this.createChart(); + } + + createChart() { + this.chart = new Chart("MyChart", { + type: "doughnut", //this denotes tha type of chart + data: { + // values on X-Axis + labels: ["Red", "Pink", "Green", "Yellow", "Orange", "Blue"], + datasets: [ + { + label: "My First Dataset", + + data: [300, 240, 100, 432, 253, 34], + backgroundColor: ["200 OK", "201 Created", "400 Bad Request", "yellow", "orange", "blue"], + hoverOffset: 4, + }, + ], + }, + options: { + aspectRatio: 2.5, + }, + }); + } +} diff --git a/src/app/applications/applications-list/application-visualization/application-visualization.component.html b/src/app/applications/applications-list/application-visualization/application-visualization.component.html new file mode 100644 index 000000000..948ee4ff7 --- /dev/null +++ b/src/app/applications/applications-list/application-visualization/application-visualization.component.html @@ -0,0 +1,5 @@ +
+

application-visualization works!

+ + +
diff --git a/src/app/applications/applications-list/application-visualization/application-visualization.component.scss b/src/app/applications/applications-list/application-visualization/application-visualization.component.scss new file mode 100644 index 000000000..3203bd56a --- /dev/null +++ b/src/app/applications/applications-list/application-visualization/application-visualization.component.scss @@ -0,0 +1,5 @@ +.visualization-page { + display: flex; + flex: 1; + background-color: #fff; +} diff --git a/src/app/applications/applications-list/application-visualization/application-visualization.component.ts b/src/app/applications/applications-list/application-visualization/application-visualization.component.ts new file mode 100644 index 000000000..20517b5ef --- /dev/null +++ b/src/app/applications/applications-list/application-visualization/application-visualization.component.ts @@ -0,0 +1,12 @@ +import { Component } from "@angular/core"; +import { ApplicationVisualizationFailedRequestsComponent } from "./application-visualization-failed-requests/application-visualization-failed-requests.component"; +import { ApplicationVisualizationTopCodesComponent } from "./application-visualization-top-codes/application-visualization-top-codes.component"; + +@Component({ + selector: "app-application-visualization", + standalone: true, + imports: [ApplicationVisualizationTopCodesComponent, ApplicationVisualizationFailedRequestsComponent], + templateUrl: "./application-visualization.component.html", + styleUrl: "./application-visualization.component.scss", +}) +export class ApplicationVisualizationComponent {} diff --git a/src/app/applications/applications-list/applications-list.component.html b/src/app/applications/applications-list/applications-list.component.html index 4fc5997cd..58b81e18c 100644 --- a/src/app/applications/applications-list/applications-list.component.html +++ b/src/app/applications/applications-list/applications-list.component.html @@ -20,14 +20,25 @@

{{ "WELCOME-DIALOG.NO-ACCESS" | translate }}

>
+
+ +
-
-
-
- -
-
+
+ + @switch (index) { @case (1) { + + + } @case (2) { + + + + } @default { + + + + } }
diff --git a/src/app/applications/applications-list/applications-list.component.scss b/src/app/applications/applications-list/applications-list.component.scss index e69de29bb..72fb27dbf 100644 --- a/src/app/applications/applications-list/applications-list.component.scss +++ b/src/app/applications/applications-list/applications-list.component.scss @@ -0,0 +1,2 @@ +.info-box-containers { +} diff --git a/src/app/applications/applications-list/applications-list.component.ts b/src/app/applications/applications-list/applications-list.component.ts index b569758a3..097315308 100644 --- a/src/app/applications/applications-list/applications-list.component.ts +++ b/src/app/applications/applications-list/applications-list.component.ts @@ -4,15 +4,15 @@ import { Title } from "@angular/platform-browser"; import { ActivatedRoute, Router } from "@angular/router"; import { UserMinimalService } from "@app/admin/users/user-minimal.service"; import { NavbarComponent } from "@app/navbar/navbar.component"; -import { Application } from "@applications/application.model"; import { AuthService } from "@auth/auth.service"; import { environment } from "@environments/environment"; import { TranslateService } from "@ngx-translate/core"; import { WelcomeDialogComponent } from "@shared/components/welcome-dialog/welcome-dialog.component"; -import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; import { OrganizationAccessScope } from "@shared/enums/access-scopes"; -import { MeService } from "@shared/services/me.service"; import { WelcomeDialogModel } from "@shared/models/dialog.model"; +import { MeService } from "@shared/services/me.service"; +import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; +import { Tap } from "src/componenets/basic-tap-switch/basic-tap-switch.component"; const welcomeDialogId = "welcome-dialog"; @@ -23,12 +23,28 @@ const welcomeDialogId = "welcome-dialog"; styleUrls: ["./applications-list.component.scss"], }) export class ApplicationsListComponent implements OnInit { + taps: Tap[] = [ + { + Title: "Applikationer", + icon: { iconSrc: "../../assets/images/arrow_back.png", height: 10, width: 20 }, + counters: [ + { + color: "default", + value: "22", + }, + ], + }, + { Title: "Kort", icon: { iconSrc: "../../assets/images/arrow_back.png", height: 10, width: 20 } }, + { Title: "Visualisering", icon: { iconSrc: "../../assets/images/arrow_back.png", height: 10, width: 20 } }, + ]; + + index = 0; isLoadingResults = true; public pageLimit = environment.tablePageSize; public resultsLength: number; public pageOffset = 0; - public applications: Application[]; + @Input() organizationId: number; canEdit: boolean; private unauthorizedMessage: string; @@ -156,4 +172,8 @@ export class ApplicationsListComponent implements OnInit { this.isLoadingResults = false; }); } + + onNewSwitchIndex(index: number) { + this.index = index; + } } diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.html b/src/app/applications/applications-list/applications-table/applications-table.component.html index 4e641b6b6..64b58c887 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.html +++ b/src/app/applications/applications-list/applications-table/applications-table.component.html @@ -1,47 +1,101 @@ - - -
-
- -
-
-
- {{ errorMessage | translate }} -
- +
+ +
+
+ {{ errorMessage | translate }} +
+
+
+
+ + + + + + + + + + - + + + + + + + + + + - + + + + + @@ -177,15 +213,18 @@ - +
+ {{ "APPLICATION-TABLE.STATUS" | translate }} + + + + + {{ "APPLICATION-TABLE.STATE" | translate }} + + + + + {{ "APPLICATION-TABLE.NAME" | translate }} + + +
+
+ {{ element.name }} +
+
+ {{ element.description }} +
+
+
+ {{ "APPLICATION-TABLE.DATA" | translate }} + + + +
+ + + + +
+
+ {{ "APPLICATION-TABLE.IOT-DEVICES" | translate }} + - {{ - element.name - }} + {{ element?.iotDevices?.length ?? 0 }} + {{ "APPLICATION-TABLE.OWNER" | translate }} + {{ application.owner ?? "-" }}
+
- - - +
+ +
+
+
+
diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.scss b/src/app/applications/applications-list/applications-table/applications-table.component.scss index 29eef3e50..43179d1d9 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.scss +++ b/src/app/applications/applications-list/applications-table/applications-table.component.scss @@ -1,3 +1,70 @@ .flag-icon { color: red; } + +.name-and-description { + max-width: 300px; +} + +.application-name { + font-weight: bold; + font-size: 14px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; +} + +.application-description { + font-size: 12px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + max-width: 100%; +} + +.options-container { + display: flex; + width: fit-content; + gap: 5px; + align-items: center; + flex-wrap: wrap; +} + +.mat-paginator { + display: flex; + justify-content: center; +} + +.status-container { + width: 10px; +} + +.mat-sort-header-arrow { + display: none !important; +} + +.mat-paginator { + overflow: hidden; + display: none !important; +} + +.mat-mdc-paginator { + display: none !important; +} + +.main-container-table { + background-color: #ffff; + display: flex; + flex-direction: column; +} + +.tool-container { + width: 35px; + background-color: #ffff; +} + +.table-container { + display: flex; + flex: 1; +} 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 3b469b6b6..a2f409388 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 @@ -7,111 +7,62 @@ import { ViewChild, ViewEncapsulation, } from "@angular/core"; +import { MatDialog } from "@angular/material/dialog"; import { MatPaginator } from "@angular/material/paginator"; import { MatSort } from "@angular/material/sort"; import { Router } from "@angular/router"; +import { ApplicationChangeOrganizationDialogComponent } from "@applications/application-change-organization-dialog/application-change-organization-dialog.component"; import { Application, ApplicationData } from "@applications/application.model"; import { ApplicationService } from "@applications/application.service"; -import { environment } from "@environments/environment"; +import { Datatarget } from "@applications/datatarget/datatarget.model"; +import { ApplicationDeviceType } from "@applications/models/application-device-type.model"; +import { faFlag } from "@fortawesome/free-solid-svg-icons"; import { TranslateService } from "@ngx-translate/core"; import { DeleteDialogService } from "@shared/components/delete-dialog/delete-dialog.service"; -import { merge, Observable, of as observableOf } from "rxjs"; -import { catchError, map, startWith, switchMap } from "rxjs/operators"; import { DefaultPageSizeOptions } from "@shared/constants/page.constants"; -import { ControlledProperty } from "@shared/models/controlled-property.model"; import { ApplicationDeviceTypeEntries } from "@shared/enums/device-type"; -import { ApplicationDeviceType } from "@applications/models/application-device-type.model"; -import { Datatarget } from "@applications/datatarget/datatarget.model"; -import { faFlag } from "@fortawesome/free-solid-svg-icons"; -import { TableColumn } from "@shared/types/table.type"; -import { MatDialog } from "@angular/material/dialog"; +import { ControlledProperty } from "@shared/models/controlled-property.model"; import { ApplicationDialogModel } from "@shared/models/dialog.model"; -import { ApplicationChangeOrganizationDialogComponent } from "@applications/application-change-organization-dialog/application-change-organization-dialog.component"; +import { TableColumn } from "@shared/types/table.type"; +import { merge, Observable, of as observableOf } from "rxjs"; +import { catchError, map, startWith, switchMap } from "rxjs/operators"; const columnDefinitions: TableColumn[] = [ { - id: "name", - display: "APPLICATION-TABLE.NAME", - default: true, - toggleable: false, - }, - { - id: "owner", - display: "APPLICATION-TABLE.OWNER", + id: "status", + display: "APPLICATION-TABLE.STATUS", default: true, toggleable: true, }, { - id: "contactPerson", - display: "APPLICATION-TABLE.CONTACT-PERSON", - default: false, - toggleable: true, - }, - { - id: "devices", - display: "APPLICATION-TABLE.IOT-DEVICES", + id: "state", + display: "APPLICATION-TABLE.STATE", default: true, toggleable: true, }, { - id: "dataTargets", - display: "APPLICATION-TABLE.DATA-TARGETS", + id: "name", + display: "APPLICATION-TABLE.NAME", default: true, - toggleable: true, - }, - { - id: "openDataDkEnabled", - display: "APPLICATION-TABLE.OPEN-DATA-DK", - default: false, - toggleable: true, + toggleable: false, }, { - id: "status", - display: "APPLICATION-TABLE.STATUS", + id: "data", + display: "APPLICATION-TABLE.DATA", default: true, - toggleable: true, + toggleable: false, }, { - id: "personalData", - display: "APPLICATION-TABLE.PERSONAL-DATA", + id: "devices", + display: "APPLICATION-TABLE.IOT-DEVICES", default: true, toggleable: true, }, { - id: "startDate", - display: "APPLICATION-TABLE.START-DATE", - default: false, - toggleable: true, - }, - { - id: "endDate", - display: "APPLICATION-TABLE.END-DATE", - default: false, - toggleable: true, - }, - { - id: "category", - display: "APPLICATION-TABLE.CATEGORY", - default: false, - toggleable: true, - }, - { - id: "controlledProperties", - display: "APPLICATION-TABLE.CONTROLLED-PROPERTIES", - default: false, - toggleable: true, - }, - { - id: "deviceTypes", - display: "APPLICATION-TABLE.DEVICE-TYPES", - default: false, - toggleable: true, - }, - { - id: "menu", - display: "", + id: "owner", + display: "APPLICATION-TABLE.OWNER", default: true, - toggleable: false, + toggleable: true, }, ]; @@ -131,14 +82,12 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { data: Application[] = []; - public pageSize = environment.tablePageSize; pageSizeOptions = DefaultPageSizeOptions; resultsLength = 0; isLoadingResults = true; public errorMessage: string; applicationSavedColumns = "applicationSavedColumns"; - @ViewChild(MatPaginator) paginator: MatPaginator; @ViewChild(MatSort) sort: MatSort; @@ -157,6 +106,9 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { this.translate.use("da"); } + announceSortChange(event: { active: string; direction: string }) { + this.columnDefinitions.find(column => column.id === event.active).sort = event.direction as "acs" | "desc"; + } ngAfterViewInit() { // If the user changes the sort order, reset back to the first page. this.sort.sortChange.subscribe(() => (this.paginator.pageIndex = 0)); @@ -180,7 +132,9 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { return observableOf([]); }) ) - .subscribe(data => (this.data = data)); + .subscribe(data => { + this.data = data; + }); } getApplications(orderByColumn: string, orderByDirection: string): Observable { @@ -279,6 +233,9 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { } as ApplicationDialogModel, }); } + getSortDirection(id: string) { + return columnDefinitions.find(c => c.id === id).sort; + } - protected readonly columnDefinitions = columnDefinitions; + protected columnDefinitions = columnDefinitions; } diff --git a/src/app/applications/applications.module.ts b/src/app/applications/applications.module.ts index 1450e7ea5..6b543dd86 100644 --- a/src/app/applications/applications.module.ts +++ b/src/app/applications/applications.module.ts @@ -1,25 +1,35 @@ -import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { ReactiveFormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; +import { FontAwesomeModule } from "@fortawesome/angular-fontawesome"; import { TranslateModule } from "@ngx-translate/core"; -import { ApplicationsComponent } from "./applications.component"; import { FormModule } from "@shared/components/forms/form.module"; +import { DirectivesModule } from "@shared/directives/directives.module"; +import { NGMaterialModule } from "@shared/Modules/materiale.module"; +import { PipesModule } from "@shared/pipes/pipes.module"; +import { SharedModule } from "@shared/shared.module"; +import { BasicInformationBoxComponent } from "src/componenets/basic-information-box/basic-information-box.component"; +import { BasicTapSwitchComponent } from "src/componenets/basic-tap-switch/basic-tap-switch.component"; +import { OptionFieldComponent } from "src/componenets/option-field/option-fieldcomponent"; +import { StatusIconComponent } from "src/componenets/status-icon/status-icon.component"; +import { TablePaginatorComponent } from "src/componenets/table-pagiantor.ts/table-paginator.component"; +import { TableSortIconComponent } from "src/componenets/table-sort-icon/table-sort-icon.component"; +import { ApplicationChangeOrganizationDialogComponent } from "./application-change-organization-dialog/application-change-organization-dialog.component"; import { ApplicationDetailComponent } from "./application-detail/application-detail.component"; import { ApplicationEditComponent } from "./application-edit/application-edit.component"; +import { ApplicationMapComponent } from "./applications-list/application-map/application-map.component"; +import { ApplicationVisualizationFailedRequestsComponent } from "./applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component"; +import { ApplicationVisualizationTopCodesComponent } from "./applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component"; +import { ApplicationVisualizationComponent } from "./applications-list/application-visualization/application-visualization.component"; import { ApplicationsListComponent } from "./applications-list/applications-list.component"; +import { ApplicationsTableComponent } from "./applications-list/applications-table/applications-table.component"; import { ApplicaitonsRoutingModule } from "./applications-routing.module"; +import { ApplicationsComponent } from "./applications.component"; +import { BulkImportComponent } from "./bulk-import/bulk-import.component"; import { DatatargetModule } from "./datatarget/datatarget.module"; import { IotDevicesModule } from "./iot-devices/iot-devices.module"; -import { SharedModule } from "@shared/shared.module"; -import { FontAwesomeModule } from "@fortawesome/angular-fontawesome"; -import { DirectivesModule } from "@shared/directives/directives.module"; -import { NGMaterialModule } from "@shared/Modules/materiale.module"; -import { BulkImportComponent } from "./bulk-import/bulk-import.component"; -import { PipesModule } from "@shared/pipes/pipes.module"; -import { ApplicationsTableComponent } from "./applications-list/applications-table/applications-table.component"; import { MulticastModule } from "./multicast/multicast.module"; -import { ReactiveFormsModule } from "@angular/forms"; -import { ApplicationChangeOrganizationDialogComponent } from "./application-change-organization-dialog/application-change-organization-dialog.component"; @NgModule({ declarations: [ @@ -27,8 +37,8 @@ import { ApplicationChangeOrganizationDialogComponent } from "./application-chan ApplicationDetailComponent, ApplicationEditComponent, ApplicationsListComponent, - ApplicationsTableComponent, BulkImportComponent, + ApplicationsTableComponent, ApplicationChangeOrganizationDialogComponent, ], exports: [ApplicaitonsRoutingModule, ApplicationsComponent, ApplicationsTableComponent], @@ -46,6 +56,16 @@ import { ApplicationChangeOrganizationDialogComponent } from "./application-chan PipesModule, MulticastModule, ReactiveFormsModule, + OptionFieldComponent, + StatusIconComponent, + TableSortIconComponent, + TablePaginatorComponent, + BasicTapSwitchComponent, + ApplicationMapComponent, + ApplicationVisualizationComponent, + BasicInformationBoxComponent, + ApplicationVisualizationTopCodesComponent, + ApplicationVisualizationFailedRequestsComponent, ], }) export class ApplicationsModule {} diff --git a/src/app/shared/types/table.type.ts b/src/app/shared/types/table.type.ts index 1159c9dd3..6b3760e48 100644 --- a/src/app/shared/types/table.type.ts +++ b/src/app/shared/types/table.type.ts @@ -3,4 +3,5 @@ display: string; default: boolean; toggleable: boolean; + sort?: "acs" | "desc"; } diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 7e417d56c..a0f8a61ac 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -379,7 +379,7 @@ }, "APPLICATION-TABLE": { "NAME": "Navn", - "IOT-DEVICES": "IoT enheder", + "IOT-DEVICES": "Enheder", "UPDATED": "Senest opdateret", "DATA-TARGETS": "Datatargets", "STATUS": "Status", @@ -391,7 +391,9 @@ "PERSONAL-DATA": "Persondata", "CONTROLLED-PROPERTIES": "Data", "DEVICE-TYPES": "Forbindelsesteknologi", - "OPEN-DATA-DK": "Open Data DK" + "OPEN-DATA-DK": "Open Data DK", + "DATA": "Data", + "STATE": "State" }, "IOT-TABLE": { "APPLICATION": "Applikation", diff --git a/src/assets/images/arrow_back.png b/src/assets/images/arrow_back.png new file mode 100644 index 0000000000000000000000000000000000000000..d5eb274c231a96d4832b51d400bb773b272ac807 GIT binary patch literal 910 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>VD|8IaSW-5 zdpkEhJ0wuVb#vX)E>=-)EwK=t6%hd&7bH0zZR%qE>hC5bn_ zf$E=iDpR;;2>$D8(c?R{l!@g>dBfM>E3Nx%G=von?B~7{k?~4;lD;62%^vff_1~+| ze;1B&e0a}%z3p82y^n073J2;LV&;e2dfHv{88;|G5xFsw>86$cv0 zH)l1QQOTcWK;`-ko1Mkq3#^|BRO0=hhqm^{Cac z`4J5a|CI}lY^-RXqb8(q;6IB@nZ^~<_KiR#^BbMlweEhhburKs@dpdMC!VY95dkXU zk}1%;rMW#9XwiPg-*dT2&Oen0dg%QDyYEeRKivkoh55$ouscdmK8FKMSKp8>*j0L_ zFcioZ-*9{52G^6EjQ{czt}haKH7lJ(WcEq_3C#>2EhaQ?P%vD+kZF(D>}O7ESX~q4 zcZw<=$ljQlcWmndjW^2M7qeFAnw@R&;qE$QcZ^HGKhRj!((RlJlMCm}Dfb-@9RV^T zrx`gN3IQ=@Z0&7X$=V^b$)vEmWhM)dVNu@PG7}_XQ|sHL;xJ_byGc~3w_w`UPaTsA z1h;1fJ37f-GM+HucnGh`6USU;&dksR1;w*gJSt0KdmCF!a*QTSn3l>WbZN_Z2d7(M zQXU?U!+?rnbAXC=^QtVV-P_pmr_p(13rB`(Lfg!(dJooL(e?Kf^LW9wZ*Bvpn^X7) zUDh`W3$1@_W7;7To$U_g#7B5`Y|1<2SbFNioG ZFRa&BaHv(}Brt<9c)I$ztaD0e0svj5fkyxU literal 0 HcmV?d00001 diff --git a/src/assets/images/arrow_forward.png b/src/assets/images/arrow_forward.png new file mode 100644 index 0000000000000000000000000000000000000000..dc450f13ff65ec911695ca59423b0969b0520e92 GIT binary patch literal 626 zcmV-&0*(ENP)Px%EJ;K`RCr$P-R(|;P!L7Y^5p81UxO{FwX{-5=gj%&A59FQ?!{ENfjFJ=f)<#d zd(X~K0RSHa0SExN0C@MAfB=9CfOnq>a0VD-e9piBG)+HW9bd2sxWxasME`O{fB^i7 zza03M2;~3|;@cvW0{j!-5}^!WV|+V=5`Y)uTOo7?m?7lL}&-#hR_ng z385{33qorE2ZZ(j>If77$_O+7st8m7iU@Q7Y6z47N(i(7DhSj73JCN7>TC;1ItpfJ^+A08a7S0l39) z1>hLJ4S;L>768ui;Q;ROp#X`0z8Z#H2`4^qDI)Q2SC2|3Ao1^)?#ciXe|_Dw1R(Jr zFIsm7D7!`c=$ihK?MndWH~8WdSi~TVqXux$VW04@ODeI_6P-~!;?X9B +
+

basic-infomation-box works!

+ +

basic-infomation-box works!

+
+

basic-infomation-box works!

+
diff --git a/src/componenets/basic-information-box/basic-information-box.component.scss b/src/componenets/basic-information-box/basic-information-box.component.scss new file mode 100644 index 000000000..d3444a7e2 --- /dev/null +++ b/src/componenets/basic-information-box/basic-information-box.component.scss @@ -0,0 +1,7 @@ +.basic-infomation-box { + height: 250px; + background-color: #ffff; + display: flex; + flex: 1; + padding: 10px; +} diff --git a/src/componenets/basic-information-box/basic-information-box.component.ts b/src/componenets/basic-information-box/basic-information-box.component.ts new file mode 100644 index 000000000..e170c3bba --- /dev/null +++ b/src/componenets/basic-information-box/basic-information-box.component.ts @@ -0,0 +1,10 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "app-basic-information-box", + standalone: true, + imports: [], + templateUrl: "./basic-information-box.component.html", + styleUrl: "./basic-information-box.component.scss", +}) +export class BasicInformationBoxComponent {} diff --git a/src/componenets/basic-tap-switch/basic-tap-switch.component.html b/src/componenets/basic-tap-switch/basic-tap-switch.component.html new file mode 100644 index 000000000..c72e95c66 --- /dev/null +++ b/src/componenets/basic-tap-switch/basic-tap-switch.component.html @@ -0,0 +1,21 @@ +
+ @for (tap of taps; track tap.Title; let idx = $index) { +
+ @if(tap.icon){ + + } + {{ tap.Title }} + @for (counter of tap.counters; track counter; let idx = $index) { +
+ {{ counter.value }} +
+ } +
+ } +
diff --git a/src/componenets/basic-tap-switch/basic-tap-switch.component.scss b/src/componenets/basic-tap-switch/basic-tap-switch.component.scss new file mode 100644 index 000000000..eabc33f19 --- /dev/null +++ b/src/componenets/basic-tap-switch/basic-tap-switch.component.scss @@ -0,0 +1,53 @@ +.main-container { + display: flex; + flex: 1; + flex-direction: row; + margin-bottom: 1px; +} + +.active-tap { + height: 40px !important; + background-color: #ffff !important; + display: flex; + align-items: center; + padding: 0 20px; + font-size: 14px; + border-radius: 0 !important; + justify-content: center; +} + +.inactive-tap { + font-size: 14px; + padding: 0 20px; + height: 40px !important; + background-color: transparent !important; + display: flex; + align-items: center; + justify-content: center; +} + +.counter-default { + background-color: red; +} + +.counter-warning { + background-color: blue($color: #000000); +} + +.counter-stable { + background-color: green; +} + +.counter-alert { + background-color: yellow; +} + +.counter-base { + font-size: 14px; + padding: 0 5px; + border-radius: 10px; + height: 16px; + margin-left: 5px; + line-height: 16px; + color: #ffff; +} diff --git a/src/componenets/basic-tap-switch/basic-tap-switch.component.ts b/src/componenets/basic-tap-switch/basic-tap-switch.component.ts new file mode 100644 index 000000000..6fa943006 --- /dev/null +++ b/src/componenets/basic-tap-switch/basic-tap-switch.component.ts @@ -0,0 +1,48 @@ +import { NgClass, NgOptimizedImage } from "@angular/common"; +import { Component, EventEmitter, Input, Output, ViewEncapsulation } from "@angular/core"; +import { MatButtonModule } from "@angular/material/button"; + +export interface Counter { + value: string; + color: "default" | "warning" | "stable" | "alert"; +} + +export interface Icon { + iconSrc?: string; + width: number; + height: number; +} + +export interface Tap { + Title: string; + counters?: Counter[]; + icon?: Icon; +} + +export interface isActive { + isActive: boolean; +} + +@Component({ + selector: "app-basic-tap-switch", + standalone: true, + imports: [MatButtonModule, NgClass, NgOptimizedImage], + templateUrl: "./basic-tap-switch.component.html", + styleUrl: "./basic-tap-switch.component.scss", + encapsulation: ViewEncapsulation.ShadowDom, +}) +export class BasicTapSwitchComponent { + index: number = 0; + @Input() taps!: Tap[]; + + boxStyles: Record = {}; + + @Output() newItemEvent = new EventEmitter(); + + onClick(index: number) { + this.index = index; + this.newItemEvent.emit(index); + } + + onTap; +} diff --git a/src/componenets/option-field/option-field.component.html b/src/componenets/option-field/option-field.component.html new file mode 100644 index 000000000..3ef9629ba --- /dev/null +++ b/src/componenets/option-field/option-field.component.html @@ -0,0 +1,3 @@ +
+

{{ title }}

+
diff --git a/src/componenets/option-field/option-field.component.scss b/src/componenets/option-field/option-field.component.scss new file mode 100644 index 000000000..6d7f808c6 --- /dev/null +++ b/src/componenets/option-field/option-field.component.scss @@ -0,0 +1,13 @@ +.application-name { + border-radius: 5px; + padding-left: 10px; + padding-right: 10px; + width: fit-content; +} + +.title { + text-align: center; + font-weight: bold; + font-size: 12px; + line-height: 8px; +} diff --git a/src/componenets/option-field/option-fieldcomponent.ts b/src/componenets/option-field/option-fieldcomponent.ts new file mode 100644 index 000000000..efcb35c85 --- /dev/null +++ b/src/componenets/option-field/option-fieldcomponent.ts @@ -0,0 +1,34 @@ +import { NgStyle } from "@angular/common"; +import { Component, Input, OnInit } from "@angular/core"; + +@Component({ + selector: "app-option-field", + templateUrl: "./option-field.component.html", + styleUrls: ["./option-field.component.scss"], + standalone: true, + imports: [NgStyle], +}) +export class OptionFieldComponent implements OnInit { + ngOnInit(): void { + let color; + + switch (this.type) { + case "alert": + color = "red"; + break; + case "warring": + color = "yellow"; + break; + default: + color = "#aebabe"; + break; + } + + this.boxStyles = { + "background-color": color, + }; + } + @Input() title = ""; + @Input() type: "default" | "warring" | "alert" = "default"; + boxStyles: Record = {}; +} diff --git a/src/componenets/status-icon/status-icon.component.html b/src/componenets/status-icon/status-icon.component.html new file mode 100644 index 000000000..afa6f2a9f --- /dev/null +++ b/src/componenets/status-icon/status-icon.component.html @@ -0,0 +1,5 @@ +@switch (iconType) { @case ("default") { + +} @case ("warring") { + +} } diff --git a/src/componenets/status-icon/status-icon.component.scss b/src/componenets/status-icon/status-icon.component.scss new file mode 100644 index 000000000..5733b819d --- /dev/null +++ b/src/componenets/status-icon/status-icon.component.scss @@ -0,0 +1,7 @@ +.application-name { + border-radius: 5px; + padding-left: 5px; + padding-right: 5px; + height: 50px; + width: fit-content; +} diff --git a/src/componenets/status-icon/status-icon.component.ts b/src/componenets/status-icon/status-icon.component.ts new file mode 100644 index 000000000..c308e84f2 --- /dev/null +++ b/src/componenets/status-icon/status-icon.component.ts @@ -0,0 +1,13 @@ +import { Component, Input } from "@angular/core"; +import { MatIcon } from "@angular/material/icon"; + +@Component({ + selector: "app-status-icon", + templateUrl: "./status-icon.component.html", + styleUrls: ["./status-icon.component.scss"], + standalone: true, + imports: [MatIcon], +}) +export class StatusIconComponent { + @Input() iconType: "default" | "warring" = "default"; +} diff --git a/src/componenets/table-pagiantor.ts/table-paginator.component.html b/src/componenets/table-pagiantor.ts/table-paginator.component.html new file mode 100644 index 000000000..9917cdbff --- /dev/null +++ b/src/componenets/table-pagiantor.ts/table-paginator.component.html @@ -0,0 +1,26 @@ +
+
+ + + + + {{ option.label }} + + + +
+
+ +
+ {{ currentPage + "/" + numberOfPages }} +
+
+ +
+
+
+
diff --git a/src/componenets/table-pagiantor.ts/table-paginator.component.scss b/src/componenets/table-pagiantor.ts/table-paginator.component.scss new file mode 100644 index 000000000..09f90b441 --- /dev/null +++ b/src/componenets/table-pagiantor.ts/table-paginator.component.scss @@ -0,0 +1,106 @@ +.main-container { + display: flex; + flex: 1; + justify-content: space-between; + align-items: space; + height: 50px; + gap: 10px; + background-color: white; + padding-top: 30px; + padding-left: 20px; + padding-right: 20px; + overflow: hidden; +} + +.mat-mdc-select { + height: 15px; + line-height: 15px; + display: flex; + align-items: center; + font-size: 10px !important; + color: rgb(227, 224, 224) !important; +} + +.pages-of { + height: 23px; + min-width: 100; + border: 2px solid rgb(227, 224, 224); + border-radius: 3px; + padding: 0 15px; + margin-top: 1px; + font-size: 14px; +} + +.arrow-button { + height: 25px !important; + width: 35px !important; + margin: 5px; + margin-top: 2px; + background-color: rgb(227, 224, 224) !important; + display: flex; + align-items: center; + justify-content: center; + min-width: 35px !important; +} + +.mat-mdc-form-field { + height: 5px !important; + display: flex; + align-items: center; +} + +.mat-mdc-text-field-wrapper { + height: 25px !important; + display: flex; + align-items: center; + font-size: 8; + color: red; +} + +.select-container { + margin-top: 2px; + justify-self: left; + width: 150px; +} + +.spacer { + width: 150px; +} + +.button-container { + display: flex; + flex-direction: row; +} + +.mat-success { + background-color: green; + color: #fff; +} + +.left-arrow { + margin-top: 8px; + margin-left: 5px; +} +.right-arrow { + margin-top: 10px; + margin-left: 1px; +} + +.mat-mdc-select { + height: 15px; + line-height: 15px; + display: flex; + align-items: center; + font-size: 8px !important; + color: rgb(227, 224, 224) !important; +} + +.mat-mdc-option { + font-size: 10px !important; + color: rgb(227, 224, 224) !important; +} + +.mat-mdc-select-value { + font-size: 10px !important; + color: rgb(227, 224, 224) !important; +} diff --git a/src/componenets/table-pagiantor.ts/table-paginator.component.ts b/src/componenets/table-pagiantor.ts/table-paginator.component.ts new file mode 100644 index 000000000..9ca2083f2 --- /dev/null +++ b/src/componenets/table-pagiantor.ts/table-paginator.component.ts @@ -0,0 +1,64 @@ +import { NgFor, NgOptimizedImage } from "@angular/common"; +import { Component, Input, OnInit, ViewEncapsulation } from "@angular/core"; +import { MatButtonModule } from "@angular/material/button"; +import { MatOptionModule } from "@angular/material/core"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatIconModule } from "@angular/material/icon"; +import { MatPaginator } from "@angular/material/paginator"; +import { MatSelectModule } from "@angular/material/select"; + +export interface Option { + value: number; + label: string; +} + +@Component({ + selector: "app-table-paginator", + templateUrl: "./table-paginator.component.html", + styleUrls: ["./table-paginator.component.scss"], + standalone: true, + imports: [ + NgOptimizedImage, + NgFor, + MatIconModule, + MatFormFieldModule, + MatSelectModule, + MatOptionModule, + MatButtonModule, + ], + encapsulation: ViewEncapsulation.ShadowDom, +}) +export class TablePaginatorComponent implements OnInit { + ngOnInit(): void {} + @Input() paginator: MatPaginator; + + options: Option[] = [ + { value: 25, label: "25 pr. side" }, + { value: 50, label: "50 pr. side" }, + { value: 100, label: "100 pr. side" }, + ]; + selected: number = 25; + currentPage: number = 1; + numberOfPages: number = 0; + ngAfterViewChecked() { + if (this.paginator) this.numberOfPages = this.paginator.getNumberOfPages(); + } + + onRight(): void { + if (!this.paginator.hasNextPage()) return; + this.currentPage++; + this.paginator.nextPage(); + } + + onSelected(event: any): void { + console.log(event.value); + this.selected = event.value; + this.paginator._changePageSize(event.value); + } + + onLeft(): void { + if (this.currentPage === 1) return; + this.currentPage--; + this.paginator.previousPage(); + } +} diff --git a/src/componenets/table-sort-icon/table-sort-icon.component.html b/src/componenets/table-sort-icon/table-sort-icon.component.html new file mode 100644 index 000000000..f24ba8888 --- /dev/null +++ b/src/componenets/table-sort-icon/table-sort-icon.component.html @@ -0,0 +1,7 @@ +
+ @if (sortDirection === 'asc') { + + } @else { + + } +
diff --git a/src/componenets/table-sort-icon/table-sort-icon.component.scss b/src/componenets/table-sort-icon/table-sort-icon.component.scss new file mode 100644 index 000000000..ad18ec84a --- /dev/null +++ b/src/componenets/table-sort-icon/table-sort-icon.component.scss @@ -0,0 +1,3 @@ +.icon-container { + margin-top: 8px; +} diff --git a/src/componenets/table-sort-icon/table-sort-icon.component.ts b/src/componenets/table-sort-icon/table-sort-icon.component.ts new file mode 100644 index 000000000..d10df10e3 --- /dev/null +++ b/src/componenets/table-sort-icon/table-sort-icon.component.ts @@ -0,0 +1,13 @@ +import { Component, Input } from "@angular/core"; +import { MatIcon } from "@angular/material/icon"; + +@Component({ + selector: "app-table-sort-icon", + templateUrl: "./table-sort-icon.component.html", + styleUrls: ["./table-sort-icon.component.scss"], + standalone: true, + imports: [MatIcon], +}) +export class TableSortIconComponent { + @Input() sortDirection: "asc" | "desc" = "asc"; +} diff --git a/src/styles.scss b/src/styles.scss index 202924abd..4804c7714 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -31,7 +31,6 @@ //Setup @import "assets/scss/setup/base"; @import "assets/scss/setup/breakpoints"; - @import "assets/scss/setup/typography"; @import "assets/scss/setup/utilities"; @import "assets/scss/setup/variables"; From 1e268bba34d6f5780b1ffedda7ca0a3e09b58417 Mon Sep 17 00:00:00 2001 From: Lauest Date: Fri, 7 Feb 2025 09:20:56 +0100 Subject: [PATCH 02/16] style matching --- src/app/app-routing.module.ts | 8 +- .../application-detail.component.ts | 21 ++-- src/app/applications/application.model.ts | 10 +- src/app/applications/application.service.ts | 18 ++- .../application-filter.component.html | 42 +++++++ .../application-filter.component.scss | 70 ++++++++++++ .../application-filter.component.ts | 84 ++++++++++++++ .../application-map.component.html | 6 +- .../application-map.component.ts | 108 +++++++++++++----- ...sualization-failed-requests.component.html | 4 +- ...sualization-failed-requests.component.scss | 5 + ...visualization-failed-requests.component.ts | 84 +++++++++----- ...ion-visualization-top-codes.component.html | 15 ++- ...ation-visualization-top-codes.component.ts | 68 ++++------- .../application-visualization.component.html | 1 - .../applications-filter.service.ts | 87 ++++++++++++++ .../applications-list.component.html | 33 +++++- .../applications-list.component.scss | 5 + .../applications-list.component.ts | 15 ++- .../applications-table.component.ts | 8 +- src/app/applications/applications.module.ts | 14 ++- src/app/applications/enums/status.enum.ts | 10 +- src/app/navbar/navbar.component.html | 7 +- .../basic-information-box.component.html | 12 ++ .../basic-information-box.component.scss | 58 ++++++++++ .../basic-information-box.component.ts | 45 ++++++++ .../basic-tap-switch.component.html | 16 +-- .../basic-tap-switch.component.scss | 31 +++-- .../basic-tap-switch.component.ts | 21 ++-- .../form-body-application.component.ts | 32 +++--- .../metadata-details.component.ts | 8 +- .../option-field/option-field.component.html | 0 .../option-field/option-field.component.scss | 0 .../option-field/option-fieldcomponent.ts | 0 .../status-icon/status-icon.component.html | 5 + .../status-icon/status-icon.component.scss | 19 +++ .../status-icon/status-icon.component.ts | 0 .../table-paginator.component.html | 0 .../table-paginator.component.scss | 59 +++++----- .../table-paginator.component.ts | 5 +- .../table-sort-icon.component.html | 0 .../table-sort-icon.component.scss | 0 .../table-sort-icon.component.ts | 0 src/assets/images/filter.png | Bin 0 -> 8449 bytes src/assets/images/warning.png | Bin 0 -> 2882 bytes src/assets/scss/elements/_img.scss | 3 +- .../basic-information-box.component.html | 8 -- .../basic-information-box.component.scss | 7 -- .../basic-information-box.component.ts | 10 -- .../status-icon/status-icon.component.html | 5 - .../status-icon/status-icon.component.scss | 7 -- 51 files changed, 795 insertions(+), 279 deletions(-) create mode 100644 src/app/applications/applications-list/application-filter/application-filter.component.html create mode 100644 src/app/applications/applications-list/application-filter/application-filter.component.scss create mode 100644 src/app/applications/applications-list/application-filter/application-filter.component.ts create mode 100644 src/app/applications/applications-list/applications-filter.service.ts create mode 100644 src/app/shared/components/basic-information-box/basic-information-box.component.html create mode 100644 src/app/shared/components/basic-information-box/basic-information-box.component.scss create mode 100644 src/app/shared/components/basic-information-box/basic-information-box.component.ts rename src/{componenets => app/shared/components}/basic-tap-switch/basic-tap-switch.component.html (50%) rename src/{componenets => app/shared/components}/basic-tap-switch/basic-tap-switch.component.scss (61%) rename src/{componenets => app/shared/components}/basic-tap-switch/basic-tap-switch.component.ts (62%) rename src/{componenets => app/shared/components}/option-field/option-field.component.html (100%) rename src/{componenets => app/shared/components}/option-field/option-field.component.scss (100%) rename src/{componenets => app/shared/components}/option-field/option-fieldcomponent.ts (100%) create mode 100644 src/app/shared/components/status-icon/status-icon.component.html create mode 100644 src/app/shared/components/status-icon/status-icon.component.scss rename src/{componenets => app/shared/components}/status-icon/status-icon.component.ts (100%) rename src/{componenets => app/shared/components}/table-pagiantor.ts/table-paginator.component.html (100%) rename src/{componenets => app/shared/components}/table-pagiantor.ts/table-paginator.component.scss (85%) rename src/{componenets => app/shared/components}/table-pagiantor.ts/table-paginator.component.ts (91%) rename src/{componenets => app/shared/components}/table-sort-icon/table-sort-icon.component.html (100%) rename src/{componenets => app/shared/components}/table-sort-icon/table-sort-icon.component.scss (100%) rename src/{componenets => app/shared/components}/table-sort-icon/table-sort-icon.component.ts (100%) create mode 100644 src/assets/images/filter.png create mode 100644 src/assets/images/warning.png delete mode 100644 src/componenets/basic-information-box/basic-information-box.component.html delete mode 100644 src/componenets/basic-information-box/basic-information-box.component.scss delete mode 100644 src/componenets/basic-information-box/basic-information-box.component.ts delete mode 100644 src/componenets/status-icon/status-icon.component.html delete mode 100644 src/componenets/status-icon/status-icon.component.scss diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 78c19f686..eef9cab40 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -1,11 +1,11 @@ import { NgModule } from "@angular/core"; -import { Routes, RouterModule, PreloadAllModules } from "@angular/router"; +import { PreloadAllModules, RouterModule, Routes } from "@angular/router"; +import { NewUserComponent } from "./admin/users/new-kombit-user-page/new-user.component"; +import { UserPageComponent } from "./admin/users/user-page/user-page.component"; +import { AuthGuardService as AuthGuard } from "./auth/auth-guard.service"; import { AuthComponent } from "./auth/auth.component"; import { ErrorPageComponent } from "./error-page/error-page.component"; import { SearchComponent } from "./search/search.component"; -import { AuthGuardService as AuthGuard } from "./auth/auth-guard.service"; -import { NewUserComponent } from "./admin/users/new-kombit-user-page/new-user.component"; -import { UserPageComponent } from "./admin/users/user-page/user-page.component"; const routes: Routes = [ { diff --git a/src/app/applications/application-detail/application-detail.component.ts b/src/app/applications/application-detail/application-detail.component.ts index cbc27fbac..f86ccabdd 100644 --- a/src/app/applications/application-detail/application-detail.component.ts +++ b/src/app/applications/application-detail/application-detail.component.ts @@ -1,25 +1,24 @@ import { AfterViewInit, Component, EventEmitter, OnDestroy, OnInit, Output } from "@angular/core"; +import { MatDialog } from "@angular/material/dialog"; import { Title } from "@angular/platform-browser"; import { ActivatedRoute, Router } from "@angular/router"; +import { Gateway, GatewayResponseMany } from "@app/gateway/gateway.model"; import { Application } from "@applications/application.model"; import { ApplicationService } from "@applications/application.service"; +import { IotDevicesApplicationMapResponse } from "@applications/iot-devices/iot-device.model"; import { TranslateService } from "@ngx-translate/core"; import { DeleteDialogService } from "@shared/components/delete-dialog/delete-dialog.service"; +import { OrganizationAccessScope } from "@shared/enums/access-scopes"; import { BackButton } from "@shared/models/back-button.model"; +import { ApplicationDialogModel } from "@shared/models/dialog.model"; import { DropdownButton } from "@shared/models/dropdown-button.model"; +import { ChirpstackGatewayService } from "@shared/services/chirpstack-gateway.service"; import { MeService } from "@shared/services/me.service"; -import { Subscription } from "rxjs"; -import { OrganizationAccessScope } from "@shared/enums/access-scopes"; -import { IotDevicesApplicationMapResponse } from "@applications/iot-devices/iot-device.model"; import { RestService } from "@shared/services/rest.service"; -import { Observable } from "rxjs"; -import { map } from "rxjs/operators"; import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; -import { ChirpstackGatewayService } from "@shared/services/chirpstack-gateway.service"; -import { Gateway, GatewayResponseMany } from "@app/gateway/gateway.model"; -import { MatDialog } from "@angular/material/dialog"; +import { Observable, Subscription } from "rxjs"; +import { map } from "rxjs/operators"; import { ApplicationChangeOrganizationDialogComponent } from "../application-change-organization-dialog/application-change-organization-dialog.component"; -import { ApplicationDialogModel } from "@shared/models/dialog.model"; @Component({ selector: "app-application", @@ -147,9 +146,9 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI useGeolocation: false, markerInfo: { name: dev.name, - active: false, + active: dev.type, id: dev.id, - isDevice: true, + isDevice: false, internalOrganizationId: this.sharedVariableService.getSelectedOrganisationId(), networkTechnology: dev.type, lastActive: dev.latestSentMessage, diff --git a/src/app/applications/application.model.ts b/src/app/applications/application.model.ts index 15863e908..7733a12c5 100644 --- a/src/app/applications/application.model.ts +++ b/src/app/applications/application.model.ts @@ -1,12 +1,12 @@ +import { PermissionResponse } from "@app/admin/permission/permission.model"; import { ControlledPropertyTypes } from "@app/device-model/Enums/controlled-propperty.enum"; +import { Datatarget } from "@applications/datatarget/datatarget.model"; import { ApplicationDeviceTypeUnion } from "@shared/enums/device-type"; import { ControlledProperty } from "@shared/models/controlled-property.model"; import { Organisation } from "../admin/organisation/organisation.model"; -import { ApplicationStatus } from "./enums/status.enum"; +import { ApplicationState } from "./enums/status.enum"; import { IotDevice } from "./iot-devices/iot-device.model"; import { ApplicationDeviceType } from "./models/application-device-type.model"; -import { PermissionResponse } from "@app/admin/permission/permission.model"; -import { Datatarget } from "@applications/datatarget/datatarget.model"; export class Application { public id: number; @@ -20,7 +20,7 @@ export class Application { public updatedBy: number; public createdByName: string; public updatedByName: string; - public status?: ApplicationStatus; + public status?: ApplicationState; public startDate?: Date; public endDate?: Date; public category?: string; @@ -41,7 +41,7 @@ export class ApplicationRequest { public name: string; public description: string; public organizationId: number; - public status?: ApplicationStatus; + public status?: ApplicationState; public startDate?: Date; public endDate?: Date; public category?: string; diff --git a/src/app/applications/application.service.ts b/src/app/applications/application.service.ts index 6c3f9cf3e..f087c1ed9 100644 --- a/src/app/applications/application.service.ts +++ b/src/app/applications/application.service.ts @@ -1,9 +1,10 @@ import { Injectable } from "@angular/core"; import { UserMinimalService } from "@app/admin/users/user-minimal.service"; import { Application, ApplicationData, UpdateApplicationOrganization } from "@applications/application.model"; -import { Observable } from "rxjs"; +import { forkJoin, Observable } from "rxjs"; import { map } from "rxjs/operators"; import { RestService } from "../shared/services/rest.service"; +import { IotDevicesApplicationMapResponse } from "./iot-devices/iot-device.model"; interface GetApplicationParameters { limit: number; @@ -41,6 +42,21 @@ export class ApplicationService { }) ); } + getApplicationDevicesForMap(applicationIds: number[]): Observable { + const requests = applicationIds.map(applicationId => + this.restService.get(`application/${applicationId}/iot-devices-map`).pipe( + map((data: IotDevicesApplicationMapResponse[]) => { + return data; + }) + ) + ); + + return forkJoin(requests).pipe( + map((responses: IotDevicesApplicationMapResponse[][]) => { + return responses.reduce((acc, val) => acc.concat(val), []); + }) + ); + } getApplications( limit: number, diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.html b/src/app/applications/applications-list/application-filter/application-filter.component.html new file mode 100644 index 000000000..22951f452 --- /dev/null +++ b/src/app/applications/applications-list/application-filter/application-filter.component.html @@ -0,0 +1,42 @@ +
+
+
Status
+ + + + {{ option.label }} + + + +
+ +
+
Tilstand
+ + + + {{ option.label }} + + + +
+ +
+
Ejer
+ + + + {{ option.label }} + + + +
+ +
+ +
diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.scss b/src/app/applications/applications-list/application-filter/application-filter.component.scss new file mode 100644 index 000000000..bdeb20402 --- /dev/null +++ b/src/app/applications/applications-list/application-filter/application-filter.component.scss @@ -0,0 +1,70 @@ +.filter-container { + display: flex; + flex-direction: row; + flex: 1; + height: 65px; + margin-bottom: 25px; +} + +.filter-selector-container { + width: 200; + margin-right: 30px; + display: flex; + flex-direction: column; +} + +.filter-title { + font-size: 14px; +} + +.spacer { + display: flex; + flex: 1; +} + +.filter-button { + align-self: flex-end; + height: 35px !important; + width: 170px !important; + min-width: 170px !important; + display: flex !important; + align-items: center; + justify-content: center; + margin-bottom: 3px; + border: 1px solid black !important; +} + +.filter-icon-container { + display: flex !important; + align-items: center; + justify-content: center; + gap: 10px; + width: 150px; + font-size: 16px; +} + +.mat-mdc-select { + height: 20px; + line-height: 35px; + display: flex; + align-items: center; + font-size: 16px !important; + color: rgb(186, 183, 183) !important; +} + +.mat-mdc-form-field { + height: 20px !important; + display: flex; + align-items: center; +} + +.mat-mdc-text-field-wrapper { + background-color: #ffff !important; + height: 35px !important; + display: flex !important; + align-items: center !important; +} + +.mat-mdc-select-arrow { + display: none; +} diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.ts b/src/app/applications/applications-list/application-filter/application-filter.component.ts new file mode 100644 index 000000000..1d845bede --- /dev/null +++ b/src/app/applications/applications-list/application-filter/application-filter.component.ts @@ -0,0 +1,84 @@ +import { NgFor, NgOptimizedImage } from "@angular/common"; +import { Component, OnInit, ViewEncapsulation } from "@angular/core"; +import { MatButtonModule } from "@angular/material/button"; +import { MatOptionModule } from "@angular/material/core"; +import { MatFormFieldModule } from "@angular/material/form-field"; +import { MatIconModule } from "@angular/material/icon"; +import { MatSelectModule } from "@angular/material/select"; +import { ApplicationService } from "@applications/application.service"; +import { ApplicationState, ApplicationStatus } from "@applications/enums/status.enum"; +import { ApplicationsFilterService } from "../applications-filter.service"; + +@Component({ + selector: "app-application-filter", + standalone: true, + imports: [ + NgFor, + NgOptimizedImage, + MatIconModule, + MatFormFieldModule, + MatSelectModule, + MatOptionModule, + MatButtonModule, + ], + templateUrl: "./application-filter.component.html", + styleUrl: "./application-filter.component.scss", + encapsulation: ViewEncapsulation.ShadowDom, +}) +export class ApplicationFilterComponent implements OnInit { + constructor(private applicationService: ApplicationService, private filterService: ApplicationsFilterService) {} + ngOnInit(): void { + this.loadOwnerOptions(); + } + + statusOptions: { label: string; value: ApplicationState | "All" }[] = [ + { label: "Alle", value: "All" }, + { label: "Ingen", value: ApplicationState["NONE"] }, + { label: "In operation", value: ApplicationState["IN-OPERATION"] }, + { label: "Project", value: ApplicationState["PROJECT"] }, + { label: "Prototype", value: ApplicationState["PROTOTYPE"] }, + { label: "other", value: ApplicationState["OTHER"] }, + ]; + + stateOptions: { label: string; value: ApplicationStatus | "All" }[] = [ + { label: "Alle", value: "All" }, + { label: "Warning", value: ApplicationStatus.WARNING }, + { label: "Alert", value: ApplicationStatus.WARNING }, + { label: "Stable", value: ApplicationStatus.STABLE }, + ]; + + ownerOptions: { label: string; value: string | "All" }[] = []; + + loadOwnerOptions(): void { + this.filterService.getOwnerOptions().subscribe(options => { + options.push({ label: "Alle", value: "All" }); + this.ownerOptions = options; + }); + } + + state: string = "All"; + status: string = "All"; + owner: string = "All"; + + onState(event: any): void { + console.log("Tilstand changed:", event.value); + this.filterService.updateState(event.value); + } + + onStatus(event: any): void { + console.log("Status changed:", event.value); + this.filterService.updateStatus(event.value); + } + + onOwner(event: any): void { + console.log("Ejer changed:", event.value); + this.filterService.updateOwner(event.value); + } + + onButtonClick() { + this.state = "All"; + this.status = "All"; + this.owner = "All"; + this.filterService.resetFilter(); + } +} diff --git a/src/app/applications/applications-list/application-map/application-map.component.html b/src/app/applications/applications-list/application-map/application-map.component.html index e3fadbfa2..1736e2753 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.html +++ b/src/app/applications/applications-list/application-map/application-map.component.html @@ -1,3 +1,7 @@
- + @if(coordinateList){ + + + + }
diff --git a/src/app/applications/applications-list/application-map/application-map.component.ts b/src/app/applications/applications-list/application-map/application-map.component.ts index c471b89ca..b6d27505c 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.ts +++ b/src/app/applications/applications-list/application-map/application-map.component.ts @@ -1,45 +1,93 @@ -import { Component } from "@angular/core"; +import { Component, OnDestroy, OnInit } from "@angular/core"; +import { Application } from "@applications/application.model"; import { ApplicationService } from "@applications/application.service"; +import { ApplicationState, ApplicationStatus } from "@applications/enums/status.enum"; +import { IotDevicesApplicationMapResponse } from "@applications/iot-devices/iot-device.model"; import { MapCoordinates } from "@shared/components/map/map-coordinates.model"; +import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; +import { Subscription } from "rxjs"; +import { map } from "rxjs/operators"; import { SharedModule } from "../../../shared/shared.module"; +import { ApplicationsFilterService } from "../applications-filter.service"; @Component({ selector: "app-application-map", standalone: true, imports: [SharedModule], templateUrl: "./application-map.component.html", - styleUrl: "./application-map.component.scss", + styleUrls: ["./application-map.component.scss"], }) -export class ApplicationMapComponent { - constructor(private applicationService: ApplicationService) {} - - - - coordinateList: MapCoordinates[] = [ - { - latitude: 120, - longitude: 120, - draggable: false, - editEnabled: false, - useGeolocation: true, - markerInfo: { - active: true, - id: 22, - internalOrganizationId: 22, - internalOrganizationName: "22", - isDevice: false, - lastActive: new Date(), - name: "test", - networkTechnology: "lora", - }, - }, - ]; +export class ApplicationMapComponent implements OnInit, OnDestroy { + public devices: IotDevicesApplicationMapResponse[] = []; + filterValues: { status: ApplicationStatus | "All"; state: ApplicationState | "All"; owner: string | "All" }; + private valueSubscription!: Subscription; + + constructor( + private filterService: ApplicationsFilterService, + private applicationService: ApplicationService, + private sharedVariableService: SharedVariableService + ) {} + + ngOnInit() { + this.getApplications(); + this.valueSubscription = this.filterService.filterChanges$.subscribe(updatedValues => { + this.filterValues = updatedValues; + }); + } + + ngOnDestroy() { + if (this.valueSubscription) { + this.valueSubscription.unsubscribe(); + } + } + + coordinateList: MapCoordinates[] = null; + + private mapDevicesToCoordinateList() { + const tempCoordinateList: MapCoordinates[] = []; + + if (Array.isArray(this.devices)) { + this.devices.forEach(dev => { + const [longitude, latitude] = dev.location.coordinates; + + tempCoordinateList.push({ + longitude: longitude, + latitude: latitude, + draggable: false, + editEnabled: false, + useGeolocation: false, + markerInfo: { + internalOrganizationName: "s", + name: dev.name, + active: true, + id: dev.id, + isDevice: true, + internalOrganizationId: this.sharedVariableService.getSelectedOrganisationId(), + networkTechnology: dev.type, + lastActive: dev.latestSentMessage, + }, + }); + }); + } + + this.coordinateList = tempCoordinateList; + console.log("Mapped Coordinates:", this.coordinateList); + } getApplications(): void { - const applicationsSubscription = this.applicationService + this.applicationService .getApplications(100000, 0, "asc", "id") - .subscribe(applicationData => { applicationData.data.forEach( - data => this.coordinateList.push() data. - )}); + .pipe( + map(applicationData => { + const filteredApplications = this.filterService.SortApplications(applicationData.data as Application[]); + return filteredApplications.map(app => app.id); + }) + ) + .subscribe(mappedCoordinates => { + this.applicationService.getApplicationDevicesForMap(mappedCoordinates).subscribe(data => { + this.devices = data; + this.mapDevicesToCoordinateList(); + }); + }); } } diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.html b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.html index d1f1b310d..ee1c4a82c 100644 --- a/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.html +++ b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.html @@ -1,5 +1,3 @@
-

Top 3 rest codes

- - {{ chart }} +
diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.scss b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.scss index e69de29bb..60d332c85 100644 --- a/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.scss +++ b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.scss @@ -0,0 +1,5 @@ +.chart-container { + position: relative; + height: 400px; + width: 100%; +} diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.ts b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.ts index ad5d646b4..8ce24674a 100644 --- a/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.ts +++ b/src/app/applications/applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component.ts @@ -1,5 +1,5 @@ -import { Component, OnInit } from "@angular/core"; -import { Chart } from "chart.js"; +import { Component } from "@angular/core"; +import { ChartOptions } from "chart.js"; interface RESTCode { status: string; color: string; @@ -43,32 +43,62 @@ const codes: RESTCode[] = [ templateUrl: "./application-visualization-failed-requests.component.html", styleUrl: "./application-visualization-failed-requests.component.scss", }) -export class ApplicationVisualizationFailedRequestsComponent implements OnInit { - public chart: any; - - ngOnInit(): void { - this.createChart(); - } - - createChart() { - this.chart = new Chart("requestChart", { - type: "doughnut", //this denotes tha type of chart - data: { - // values on X-Axis - labels: ["Red", "Pink", "Green", "Yellow", "Orange", "Blue"], - datasets: [ - { - label: "My First Dataset", - - data: [300, 240, 100, 432, 253, 34], - backgroundColor: ["200 OK", "201 Created", "400 Bad Request", "yellow", "orange", "blue"], - hoverOffset: 4, - }, - ], +export class ApplicationVisualizationFailedRequestsComponent { + public chartData: any; + public chartOptions: ChartOptions = { + responsive: true, + maintainAspectRatio: false, + scales: { + x: { + title: { + display: true, + text: "Tidsrum", + }, + }, + y: { + title: { + display: true, + text: "Antal forespørgsler", + }, + beginAtZero: true, }, - options: { - aspectRatio: 2.5, + }, + plugins: { + legend: { + position: "top", }, - }); + }, + }; + + constructor() { + this.chartData = { + labels: ["08:00", "08:15", "08:30", "08:45", "09:00", "09:15", "09:30"], + datasets: [ + { + label: "Antal forespørgsler", + data: [40, 35, 38, 36, 34, 33, 37], // Example data + borderColor: "green", + borderWidth: 2, + borderDash: [5, 5], // Dashed line + fill: false, + type: "line", + pointRadius: 4, + }, + { + label: "Fejlede forespørgsler", + data: [20, 18, 2, 3, 10, 2, 1], // Example failed requests + backgroundColor: "red", + stack: "requests", + type: "bar", + }, + { + label: "Succesfulde forespørgsler", + data: [20, 17, 36, 33, 24, 31, 36], // Derived from total - failed + backgroundColor: "green", + stack: "requests", + type: "bar", + }, + ], + }; } } diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.html b/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.html index a610c7fc8..b18cb1846 100644 --- a/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.html +++ b/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.html @@ -1,5 +1,14 @@ -
-

Top 3 rest codes

+
+ - {{ chart }} + +
+
+
+ {{ item.status }} +
+
diff --git a/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.ts b/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.ts index 04e827965..c2654547d 100644 --- a/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.ts +++ b/src/app/applications/applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component.ts @@ -1,73 +1,55 @@ -import { Component, OnInit } from "@angular/core"; -import { Chart } from "chart.js"; +import { Component, ElementRef, OnInit, ViewChild } from "@angular/core"; +import { Chart, registerables } from "chart.js"; + interface RESTCode { status: string; color: string; } +Chart.register(...registerables); + const codes: RESTCode[] = [ - { - status: "200 OK", - color: "green", - }, - { - status: "201 Created", - color: "blue", - }, - { - status: "400 Bad Request", - color: "yellow", - }, - { - status: "401 Unauthorized", - color: "red", - }, - { - status: "403 Forbidden", - color: "red", - }, - { - status: "404 Not Found", - color: "orange", - }, - { - status: "500 Internal Server Error", - color: "dark red", - }, + { status: "200 OK", color: "green" }, + { status: "201 Created", color: "blue" }, + { status: "400 Bad Request", color: "yellow" }, + { status: "401 Unauthorized", color: "red" }, + { status: "403 Forbidden", color: "red" }, + { status: "404 Not Found", color: "orange" }, + { status: "500 Internal Server Error", color: "darkred" }, ]; @Component({ selector: "app-application-visualization-top-codes", standalone: true, - imports: [], templateUrl: "./application-visualization-top-codes.component.html", - styleUrl: "./application-visualization-top-codes.component.scss", + styleUrls: ["./application-visualization-top-codes.component.scss"], }) export class ApplicationVisualizationTopCodesComponent implements OnInit { - public chart: any; + @ViewChild("chartCanvas", { static: true }) chartCanvas!: ElementRef; + public chart!: any; + public legendData = codes; // Store legend data for use in template ngOnInit(): void { this.createChart(); } createChart() { - this.chart = new Chart("MyChart", { - type: "doughnut", //this denotes tha type of chart + this.chart = new Chart(this.chartCanvas.nativeElement, { + type: "doughnut", data: { - // values on X-Axis - labels: ["Red", "Pink", "Green", "Yellow", "Orange", "Blue"], + labels: codes.map(c => c.status), // Use status as labels datasets: [ { - label: "My First Dataset", - - data: [300, 240, 100, 432, 253, 34], - backgroundColor: ["200 OK", "201 Created", "400 Bad Request", "yellow", "orange", "blue"], - hoverOffset: 4, + data: [300, 240, 100, 432, 253, 34, 150], // Sample values + backgroundColor: codes.map(c => c.color), // Use colors from the array + borderWidth: 0, // Remove line separation }, ], }, options: { - aspectRatio: 2.5, + plugins: { + legend: { display: false }, // Hide default legend + }, }, }); } diff --git a/src/app/applications/applications-list/application-visualization/application-visualization.component.html b/src/app/applications/applications-list/application-visualization/application-visualization.component.html index 948ee4ff7..ac7f20d9c 100644 --- a/src/app/applications/applications-list/application-visualization/application-visualization.component.html +++ b/src/app/applications/applications-list/application-visualization/application-visualization.component.html @@ -1,5 +1,4 @@

application-visualization works!

-
diff --git a/src/app/applications/applications-list/applications-filter.service.ts b/src/app/applications/applications-list/applications-filter.service.ts new file mode 100644 index 000000000..a4eaf58d9 --- /dev/null +++ b/src/app/applications/applications-list/applications-filter.service.ts @@ -0,0 +1,87 @@ +import { Injectable } from "@angular/core"; +import { Application } from "@applications/application.model"; +import { ApplicationService } from "@applications/application.service"; +import { ApplicationState, ApplicationStatus } from "@applications/enums/status.enum"; +import { BehaviorSubject, Observable } from "rxjs"; +import { map } from "rxjs/operators"; + +@Injectable({ + providedIn: "root", +}) +export class ApplicationsFilterService { + private status: ApplicationStatus | "All" = "All"; + + private state: ApplicationState | "All" = "All"; + private owner: string | "All" = "All"; + + private valueChanges = new BehaviorSubject<{ + status: ApplicationStatus | "All"; + state: ApplicationState | "All"; + owner: string; + }>({ + status: this.status, + state: this.state, + owner: this.owner, + }); + + filterChanges$ = this.valueChanges.asObservable(); + + updateStatus(newValue: ApplicationStatus | null) { + this.status = newValue; + this.emitChange(); + } + + updateState(newValue: ApplicationState | null) { + this.state = newValue; + this.emitChange(); + } + + updateOwner(newValue: string) { + this.owner = newValue; + this.emitChange(); + } + + public resetFilter() { + this.state = "All"; + this.status = "All"; + this.owner = "All"; + this.emitChange(); + } + + private emitChange() { + this.valueChanges.next({ state: this.state, status: this.status, owner: this.owner }); + } + + public SortApplications(applications: Application[]) { + return applications.filter( + application => + (this.owner == "All" || application.owner === this.owner) && + (this.state == "All" || application.status === this.state) && + (this.state == "All" || application.status === this.state) + ); + } + + constructor(private applicationService: ApplicationService) {} + + getAppLicationIds(): Observable<{ label: string; value: string }[]> { + return this.applicationService.getApplications(100000, 0, "asc", "id").pipe( + map(applicationData => + applicationData.data.map(data => ({ + label: data.owner, + value: data.owner, + })) + ) + ); + } + + getOwnerOptions(): Observable<{ label: string; value: string }[]> { + return this.applicationService.getApplications(100000, 0, "asc", "id").pipe( + map(applicationData => + applicationData.data.map(data => ({ + label: data.owner, + value: data.owner, + })) + ) + ); + } +} diff --git a/src/app/applications/applications-list/applications-list.component.html b/src/app/applications/applications-list/applications-list.component.html index 58b81e18c..11870d674 100644 --- a/src/app/applications/applications-list/applications-list.component.html +++ b/src/app/applications/applications-list/applications-list.component.html @@ -20,11 +20,38 @@

{{ "WELCOME-DIALOG.NO-ACCESS" | translate }}

>
-
- -
+
+ +
+ + + + +
@switch (index) { @case (1) { diff --git a/src/app/applications/applications-list/applications-list.component.scss b/src/app/applications/applications-list/applications-list.component.scss index 72fb27dbf..e22fc819c 100644 --- a/src/app/applications/applications-list/applications-list.component.scss +++ b/src/app/applications/applications-list/applications-list.component.scss @@ -1,2 +1,7 @@ .info-box-containers { + display: flex; + flex-direction: row; + gap: 30px; + margin-bottom: 30px; + height: fit-content; } diff --git a/src/app/applications/applications-list/applications-list.component.ts b/src/app/applications/applications-list/applications-list.component.ts index 097315308..f7dbd64fd 100644 --- a/src/app/applications/applications-list/applications-list.component.ts +++ b/src/app/applications/applications-list/applications-list.component.ts @@ -7,12 +7,12 @@ import { NavbarComponent } from "@app/navbar/navbar.component"; import { AuthService } from "@auth/auth.service"; import { environment } from "@environments/environment"; import { TranslateService } from "@ngx-translate/core"; +import { Tap } from "@shared/components/basic-tap-switch/basic-tap-switch.component"; import { WelcomeDialogComponent } from "@shared/components/welcome-dialog/welcome-dialog.component"; import { OrganizationAccessScope } from "@shared/enums/access-scopes"; import { WelcomeDialogModel } from "@shared/models/dialog.model"; import { MeService } from "@shared/services/me.service"; import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; -import { Tap } from "src/componenets/basic-tap-switch/basic-tap-switch.component"; const welcomeDialogId = "welcome-dialog"; @@ -23,10 +23,11 @@ const welcomeDialogId = "welcome-dialog"; styleUrls: ["./applications-list.component.scss"], }) export class ApplicationsListComponent implements OnInit { + currentSubPath: string = ""; taps: Tap[] = [ { - Title: "Applikationer", - icon: { iconSrc: "../../assets/images/arrow_back.png", height: 10, width: 20 }, + title: "Applikationer", + matIconName: "layers", counters: [ { color: "default", @@ -34,8 +35,8 @@ export class ApplicationsListComponent implements OnInit { }, ], }, - { Title: "Kort", icon: { iconSrc: "../../assets/images/arrow_back.png", height: 10, width: 20 } }, - { Title: "Visualisering", icon: { iconSrc: "../../assets/images/arrow_back.png", height: 10, width: 20 } }, + { title: "Kort", matIconName: "location_on" }, + { title: "Visualisering", matIconName: "show_chart" }, ]; index = 0; @@ -69,6 +70,10 @@ export class ApplicationsListComponent implements OnInit { } ngOnInit(): void { + this.route.url.subscribe(urlSegments => { + this.currentSubPath = urlSegments.map(segment => segment.path).join("/"); + }); + this.translate.get(["TITLE.APPLICATION"]).subscribe(translations => { this.titleService.setTitle(translations["TITLE.APPLICATION"]); }); 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 a2f409388..db93dbc05 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 @@ -26,6 +26,7 @@ import { ApplicationDialogModel } from "@shared/models/dialog.model"; import { TableColumn } from "@shared/types/table.type"; import { merge, Observable, of as observableOf } from "rxjs"; import { catchError, map, startWith, switchMap } from "rxjs/operators"; +import { ApplicationsFilterService } from "../applications-filter.service"; const columnDefinitions: TableColumn[] = [ { @@ -97,7 +98,8 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { private router: Router, private deleteDialogService: DeleteDialogService, private cdRef: ChangeDetectorRef, - private changeOrganizationDialog: MatDialog + private changeOrganizationDialog: MatDialog, + private filterService: ApplicationsFilterService ) {} ngOnInit() { @@ -113,7 +115,7 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { // If the user changes the sort order, reset back to the first page. this.sort.sortChange.subscribe(() => (this.paginator.pageIndex = 0)); - merge(this.sort.sortChange, this.paginator.page) + merge(this.sort.sortChange, this.paginator.page, this.filterService.filterChanges$) .pipe( startWith({}), switchMap(() => { @@ -125,7 +127,7 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { this.isLoadingResults = false; this.resultsLength = data.count; - return data.data; + return this.filterService.SortApplications(data.data); }), catchError(() => { this.isLoadingResults = false; diff --git a/src/app/applications/applications.module.ts b/src/app/applications/applications.module.ts index 6b543dd86..2d9cd7aa4 100644 --- a/src/app/applications/applications.module.ts +++ b/src/app/applications/applications.module.ts @@ -4,20 +4,21 @@ import { ReactiveFormsModule } from "@angular/forms"; import { RouterModule } from "@angular/router"; import { FontAwesomeModule } from "@fortawesome/angular-fontawesome"; import { TranslateModule } from "@ngx-translate/core"; +import { BasicInformationBoxComponent } from "@shared/components/basic-information-box/basic-information-box.component"; +import { BasicTapSwitchComponent } from "@shared/components/basic-tap-switch/basic-tap-switch.component"; import { FormModule } from "@shared/components/forms/form.module"; +import { OptionFieldComponent } from "@shared/components/option-field/option-fieldcomponent"; +import { StatusIconComponent } from "@shared/components/status-icon/status-icon.component"; +import { TablePaginatorComponent } from "@shared/components/table-pagiantor.ts/table-paginator.component"; +import { TableSortIconComponent } from "@shared/components/table-sort-icon/table-sort-icon.component"; import { DirectivesModule } from "@shared/directives/directives.module"; import { NGMaterialModule } from "@shared/Modules/materiale.module"; import { PipesModule } from "@shared/pipes/pipes.module"; import { SharedModule } from "@shared/shared.module"; -import { BasicInformationBoxComponent } from "src/componenets/basic-information-box/basic-information-box.component"; -import { BasicTapSwitchComponent } from "src/componenets/basic-tap-switch/basic-tap-switch.component"; -import { OptionFieldComponent } from "src/componenets/option-field/option-fieldcomponent"; -import { StatusIconComponent } from "src/componenets/status-icon/status-icon.component"; -import { TablePaginatorComponent } from "src/componenets/table-pagiantor.ts/table-paginator.component"; -import { TableSortIconComponent } from "src/componenets/table-sort-icon/table-sort-icon.component"; import { ApplicationChangeOrganizationDialogComponent } from "./application-change-organization-dialog/application-change-organization-dialog.component"; import { ApplicationDetailComponent } from "./application-detail/application-detail.component"; import { ApplicationEditComponent } from "./application-edit/application-edit.component"; +import { ApplicationFilterComponent } from "./applications-list/application-filter/application-filter.component"; import { ApplicationMapComponent } from "./applications-list/application-map/application-map.component"; import { ApplicationVisualizationFailedRequestsComponent } from "./applications-list/application-visualization/application-visualization-failed-requests/application-visualization-failed-requests.component"; import { ApplicationVisualizationTopCodesComponent } from "./applications-list/application-visualization/application-visualization-top-codes/application-visualization-top-codes.component"; @@ -66,6 +67,7 @@ import { MulticastModule } from "./multicast/multicast.module"; BasicInformationBoxComponent, ApplicationVisualizationTopCodesComponent, ApplicationVisualizationFailedRequestsComponent, + ApplicationFilterComponent, ], }) export class ApplicationsModule {} diff --git a/src/app/applications/enums/status.enum.ts b/src/app/applications/enums/status.enum.ts index 9c888c2ec..9dba36b0f 100644 --- a/src/app/applications/enums/status.enum.ts +++ b/src/app/applications/enums/status.enum.ts @@ -1,6 +1,6 @@ import { recordToEntries } from "@shared/helpers/record.helper"; -export enum ApplicationStatus { +export enum ApplicationState { "NONE" = "NONE", "IN-OPERATION" = "IN-OPERATION", "PROJECT" = "PROJECT", @@ -8,4 +8,10 @@ export enum ApplicationStatus { "OTHER" = "OTHER", } -export const ApplicationStatusEntries = recordToEntries(ApplicationStatus); +export enum ApplicationStatus { + WARNING = "WARNING", + ALERT = "ALERT", + STABLE = "STABLE", +} + +export const ApplicationStateEntries = recordToEntries(ApplicationState); diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html index 227b92d9c..4578b5fef 100644 --- a/src/app/navbar/navbar.component.html +++ b/src/app/navbar/navbar.component.html @@ -1,10 +1,9 @@ -
+ +@if(searchText){ +
+
+
+
+
+ +
+
+
+
+
+} diff --git a/src/app/shared/components/top-bar/top-bar.component.scss b/src/app/shared/components/top-bar/top-bar.component.scss index 122977719..cb5795f7f 100644 --- a/src/app/shared/components/top-bar/top-bar.component.scss +++ b/src/app/shared/components/top-bar/top-bar.component.scss @@ -1,8 +1,11 @@ .top-main-container { background-color: #ffff; display: flex; + flex: 1; flex-direction: row; + height: 72px; justify-content: space-between; + align-items: center; } .bottom-main-container { @@ -11,5 +14,117 @@ justify-content: space-between; margin: 30px; margin-top: 40px; + overflow: none; margin-bottom: 40px; } + +:host .search-view { + position: absolute; + top: 70px; + left: 268px; + right: 0; + height: 65%; + z-index: 1000; + background-color: #ffff; +} + +@media only screen and (max-width: 768px) { + :host .search-view { + position: absolute; + top: 70px; + left: 0; + right: 0; + height: 65%; + z-index: 1000; + background-color: #ffff; + } +} + +:host .angle-down-icon { + height: 25px; + width: 12px; + color: #525252; + margin-right: 30px; + margin-left: 20px; +} + +:host .plus-circle-icon { + height: 20px; + width: 16px; + color: #ffff; +} + +:host .top-bar-profile-icon { + display: flex; + flex: 1; + justify-content: end; + background-color: #ffff; +} + +:host .top-bar-search { + display: flex; + flex: 3; + justify-content: start; +} + +:host .search-input { + border-radius: 0px; + border-width: 0px; + display: flex; + flex-direction: row; + width: 100%; + border: transparent; + margin-left: 30px; +} + +:host input:focus { + outline: none !important; + outline-style: none !important; + box-shadow: none !important; + border-color: transparent !important; +} + +:host .user-information-container { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +} + +:host .name-container { + display: flex; + flex-direction: row; + justify-content: end; + align-items: center; + font-size: 14; + font-weight: 500; + line-height: 20px; +} + +:host .title-container { + display: flex; + flex-direction: row; + justify-content: end; + align-items: center; + font-size: 12; + font-weight: 500; + line-height: 16px; + color: #525252; +} + +:host .profile-button { + background-color: #ffff; + border-width: 0px; +} + +:host .profile-button:focus { + outline: none !important; + outline-style: none !important; + box-shadow: none !important; + border-color: transparent !important; +} + +:host .create-application-button { + display: flex; + justify-content: start; +} diff --git a/src/app/shared/components/top-bar/top-bar.component.ts b/src/app/shared/components/top-bar/top-bar.component.ts index 94c96cbd7..fabcfd959 100644 --- a/src/app/shared/components/top-bar/top-bar.component.ts +++ b/src/app/shared/components/top-bar/top-bar.component.ts @@ -1,5 +1,7 @@ import { Location } from "@angular/common"; import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core"; +import { MatIconRegistry } from "@angular/material/icon"; +import { DomSanitizer } from "@angular/platform-browser"; import { Router } from "@angular/router"; import { OrganisationResponse } from "@app/admin/organisation/organisation.model"; import { PermissionResponse } from "@app/admin/permission/permission.model"; @@ -11,7 +13,7 @@ import { Datatarget } from "@applications/datatarget/datatarget.model"; import { IotDevice } from "@applications/iot-devices/iot-device.model"; import { AuthService } from "@auth/auth.service"; import { environment } from "@environments/environment"; -import { faChevronLeft, faQuestionCircle, faSearch, faUser } from "@fortawesome/free-solid-svg-icons"; +import { faChevronLeft, faQuestionCircle, faUser } from "@fortawesome/free-solid-svg-icons"; import { TranslateService } from "@ngx-translate/core"; import { PayloadDecoder } from "@payload-decoder/payload-decoder.model"; import { BackButton } from "@shared/models/back-button.model"; @@ -45,6 +47,7 @@ export class TopBarComponent implements OnInit { faChevronLeft = faChevronLeft; faQuestionCircle = faQuestionCircle; faUser = faUser; + searchText: string = ""; @Input() staticTitle: string; @Input() title: string; @@ -68,17 +71,29 @@ export class TopBarComponent implements OnInit { @Input() dropDownButton: DropdownButton; @Input() canEdit = false; - faSearch = faSearch; - constructor( public translate: TranslateService, private location: Location, private router: Router, private sharedVariableService: SharedVariableService, private authService: AuthService, - private loggedInService: LoggedInService + private loggedInService: LoggedInService, + private matIconRegistry: MatIconRegistry, + private domSanitizer: DomSanitizer ) { translate.use("da"); + + this.matIconRegistry.addSvgIcon( + "plus-circle", + this.domSanitizer.bypassSecurityTrustResourceUrl("../../../../assets/images/plus-circle.svg"), + {} + ); + + this.matIconRegistry.addSvgIcon( + "angle-down", + this.domSanitizer.bypassSecurityTrustResourceUrl("../../../../assets/images/angle-down.svg"), + {} + ); } ngOnInit(): void { @@ -102,14 +117,7 @@ export class TopBarComponent implements OnInit { } search(value: string): void { - // Redirect to search results page and do search - const urlEncoded = encodeURIComponent(value); - - if (value) { - this.router.navigate(["/search"], { queryParams: { q: urlEncoded } }); - } else { - this.decode(""); - } + this.searchText = value; } decode(val: string): string { diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index 303a03fbb..769dfebc9 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -1,25 +1,27 @@ -import { NgModule } from "@angular/core"; import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { MatIconModule } from "@angular/material/icon"; // Components +import { FormsModule } from "@angular/forms"; +import { RouterModule } from "@angular/router"; +import { SearchModule } from "@app/search/search.module"; +import { FontAwesomeModule } from "@fortawesome/angular-fontawesome"; import { TranslateModule } from "@ngx-translate/core"; -import { DirectivesModule } from "./directives/directives.module"; -import { LoadingSpinnerComponent } from "./components/loading-spinner/loading-spinner.component"; import { AlertComponent } from "./components/alert/alert.component"; import { BatteriStatusComponent } from "./components/batteri-status/batteri-status.component"; -import { MapComponent } from "./components/map/map.component"; -import { NGMaterialModule } from "./Modules/materiale.module"; +import { ColumnSelectorComponent } from "./components/column-selector/column-selector.component"; import { DeleteDialogComponent } from "./components/delete-dialog/delete-dialog.component"; -import { FormsModule } from "@angular/forms"; -import { RouterModule } from "@angular/router"; -import { FontAwesomeModule } from "@fortawesome/angular-fontawesome"; -import { TopBarComponent } from "./components/top-bar/top-bar.component"; -import { TopBarTableComponent } from "./components/top-bar-table/top-bar-table.component"; -import { GeneralDetailsComponent } from "./components/general-details/general-details.component"; -import { PipesModule } from "./pipes/pipes.module"; import { DynamicImgComponent } from "./components/dynamic-img/dynamic-img.component"; +import { GeneralDetailsComponent } from "./components/general-details/general-details.component"; +import { LoadingSpinnerComponent } from "./components/loading-spinner/loading-spinner.component"; +import { MapComponent } from "./components/map/map.component"; import { MetadataDetailsComponent } from "./components/metadata-details/metadata-details.component"; -import { ColumnSelectorComponent } from "./components/column-selector/column-selector.component"; +import { TopBarTableComponent } from "./components/top-bar-table/top-bar-table.component"; +import { TopBarComponent } from "./components/top-bar/top-bar.component"; +import { DirectivesModule } from "./directives/directives.module"; +import { NGMaterialModule } from "./Modules/materiale.module"; +import { PipesModule } from "./pipes/pipes.module"; @NgModule({ declarations: [ @@ -44,6 +46,8 @@ import { ColumnSelectorComponent } from "./components/column-selector/column-sel NGMaterialModule, FontAwesomeModule, PipesModule, + SearchModule, + MatIconModule, ], exports: [ AlertComponent, diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 1b1f19e68..89f1f89af 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -80,7 +80,7 @@ "NAME": "Navn", "ID": "Id", "ORGANISATION": "Organisation", - "PLACEHOLDER": "Der kan søges efter IoT enheder, applikationer og gateways", + "PLACEHOLDER": "Skriv her for at søge ..", "QUERY": "resultater for", "NO-RESULTS": "Du kun kan søge efter IoT enheder, applikationer og gateways", "FETCHING": "Henter søgeresultater" diff --git a/src/assets/images/angle-down.svg b/src/assets/images/angle-down.svg index b5532917f..3ab996d94 100644 --- a/src/assets/images/angle-down.svg +++ b/src/assets/images/angle-down.svg @@ -1,3 +1,5 @@ - - + + \ No newline at end of file diff --git a/src/assets/images/plus-circle.svg b/src/assets/images/plus-circle.svg new file mode 100644 index 000000000..62ee8b9a6 --- /dev/null +++ b/src/assets/images/plus-circle.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/src/assets/images/warning.png b/src/assets/images/warning.png deleted file mode 100644 index a9cabff323f5b5b28647a338ca8681ee1c6a179f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2882 zcmV-I3%&G-P)Px<{7FPXRCr$PU3-umMH&BnvzLUFJS=iEdq_ZTX8|ip@U|CI?iExJ1fh&T@hT`l z1VIo=EM9_8P*5PR0*nO(f*=TjBFIw^1PLOCknKH)CK}n9L2uZXTK z-5x!c0Y3Pi#`iGr=}n;{V7cbeVZBB|&k^8=!s7(mr`fn=@Dq7y@0;$Jj%K~52xyed z6PR$5Dnw$OsMoBUqrs4#bk7j*+UMtPJ?ouWBLH>|fNSN3nHwtGJ-_CS^k5Bdxn~G) zOXejYoEIuI#-&EhIzNq3~BwKO&uNU-n9gb?Yh&p6MYjS1Z>|<^bEY38_!kxU;gXs z?da)L->xN~AqrPB=yYY^gkLg)2slXja0b3cm-ZQ*0yPHVpstjNu zW;E!{5irW?+D~6Ms`Xnom2pJjBm&(KFlSVC{&%)Y!Ji~`B>@^O)R)$uX(r>82fs+HJrMwI1B{AM zv;2~kdh41DaD;gS0VkURv{`0O1Pr6#zx`s)&y_ zs`jl>^d>EvDgl-#Y_%omxv4iCnh+3qTiGcUk0Rnb0#;PZ{{dN`)^o(Zd1t`JeskXARJb74O6i&hN(yci61)@0<%@3#C2g zMS9JCq#avv`ldpFE6k@S?{&8JnfW-QX8*XAfGf;<0PI1)gvY4nYt{j+WE-M*I)kqc z0BDIJtv%y_*iN5mCt$2pJjElvF2HH!S*|NgZr0zBR?B!?Q5Xg2vnsn9)2aQn`t|Jq z8ny4V65#H(!vH*O1fW5sqwMWr)K)#)OvWjh4-(-kE&Bh$kk(<%eruG9i{z|K(t>XkRppA*b2!j@=BJqe0 z7^v0*Cdq^dC>M_h^N-YX5x>wc?Fs>2CmHBC0Zz$0iwIY$gP=zYSzi<;&?GWoG7AE) zJaU9B@G!nNlj$e{lZPYz#H+lmps_ZuzxK+X!vv8O0ga(TnKfD(U~{dP>#GdBxN=n( z-{Q!0lmMq(xQ>`kQ9H($8`3^Etn*0`FqsAZleTgXh>5SySM5{7`WIEMV+1tH#f8l5 zZ#k&ixW2`9vuVka@vx33Nx<@X^JeO^H~besPB|YC?WtGmOTzjXMXrMc6dq!xpt^pn zAuaz9J#s7ne(|2g!r)>^!h3RiI``gWm#xEJt9*XLH(gaMF zqLl!43h*WJUFYksnxQ z`G+KtTRWR^Dr0LF6z9$y=hu{T0q~aQQ6`x{m3v9LM=vMLERfKxV~B*tFK(!;!HAfa>DC`Xb}A{;B3$9ja8N1?thCOnm| zT6;&)+e$W(3}}eLNgQ-HpYe=Qv;6P-bbWJ$DFKw!BbQIsrF~<&!L&`lKZc5WPGf(+ zM|lm9$orIDUFEO0yS_Ce~>-pECGJwQjoHkoC~}Sj}{`MZn~aqCfg)s2tU$mFx7rdeS8Dp~y9CGiZ-$BY9lW zN9}4{`)v{62=guij!=$%@X7fEYUNZLotlIlf(-7us49pEEv4`ZV_I)uziT|3aTQZ*mp`td*yBpH> zUz|&$d0D?EYP^vNn7mu#PrTczjBS>i(ZA)3e_0pRp&b;~X zz(pd!Ee-At()`;5EgJ*xVv{~UZT1JDJ&-)2bbYpwiH5)kTx7hMoxm%Fg~ z-RqYvUp&bO=sbJz3CK!NBJ9L3L9PBUClR+k0!qUCu~6VLbjn{w?eG!6Er}58VgFhy zkboq-$#k?vAR{2<(UB355s)$hDVxtSAR{1U1X4DiWk5zi$_S)vKFffNfRqtP*?g7( g838FHkh1yz1FQV=j_*Mtt^fc407*qoM6N<$f@Hd44FCWD diff --git a/src/assets/scss/components/_tables.scss b/src/assets/scss/components/_tables.scss index 5b24cdd60..2d2556b08 100644 --- a/src/assets/scss/components/_tables.scss +++ b/src/assets/scss/components/_tables.scss @@ -35,6 +35,10 @@ table { } } +.mat-mdc-paginator { + display: none !important; +} + .mat-sort-header-arrow { display: none; } diff --git a/src/assets/scss/elements/_links.scss b/src/assets/scss/elements/_links.scss index 5ce76542f..18a2e6d2a 100644 --- a/src/assets/scss/elements/_links.scss +++ b/src/assets/scss/elements/_links.scss @@ -1,5 +1,7 @@ @import "../setup//variables"; +// Links + a:focus, button:focus, .focus { @@ -9,44 +11,41 @@ button:focus, a { color: $color-link; - border-bottom: none; + border-bottom: 5px solid transparent; cursor: pointer; text-decoration: none; - display: block; - padding: 10px 15px; - font-weight: 500; - font-family: inter; - border-radius: 3px; - margin-left: 10px; - margin-right: 10px; - height: 33px; - line-height: 14px; - margin-top: 2px; - margin-bottom: 2px; &:hover, &.link-hover, &:visited:hover { - color: white; - background-color: $color-link-active-bg; + color: $color-link-hover; + border-bottom: 5px solid $color-link-hover-bg; + + &:disabled, + .disabled { + background-color: transparent !important; + } } &:active, &.link-active { - background-color: $color-link-active-bg; - color: black; + background-color: inherit; + color: $color-active; + border-bottom: 5px solid $color-link-active-bg; } &:focus, &.link-focus { - color: white; - background-color: $color-link-active-bg; + color: $color-link-focus; + background-color: transparent; + border-bottom: calculateRem(5) solid $color-link-focus-bg; } &:disabled, &.disabled { box-shadow: none !important; cursor: not-allowed !important; + //color: #000 !important; // FIXME: Hvad skal der der være her? outline-offset: inherit !important; &:focus { diff --git a/src/assets/scss/setup/_variables.scss b/src/assets/scss/setup/_variables.scss index 3a8c90524..a30d51a65 100644 --- a/src/assets/scss/setup/_variables.scss +++ b/src/assets/scss/setup/_variables.scss @@ -384,3 +384,10 @@ $red: #dc3545; overflow-y: hidden; } } + +$alert-color: #991b1b; +$stable-color: #047857; +$default-color: #525252; +$default-icon-color: #404040; + +$selector-font-color: #737373; From c9953a54118e70a45c09d05064f2d3881a1b8f37 Mon Sep 17 00:00:00 2001 From: Lauest Date: Wed, 12 Feb 2025 08:21:38 +0100 Subject: [PATCH 05/16] updates to use the new endpoints --- src/app/applications/application.model.ts | 8 ++- src/app/applications/application.service.ts | 22 +++++-- .../application-filter.component.html | 2 +- .../application-filter.component.ts | 30 ++++----- .../applications-filter.service.ts | 51 +++++++++++++++ .../application-map.component.ts | 40 ++++++------ .../applications-filter.service.ts | 64 ------------------- .../applications-table.component.html | 2 +- .../applications-table.component.ts | 4 +- src/app/applications/enums/status.enum.ts | 11 +--- .../form-body-application.component.ts | 10 +-- .../metadata-details.component.ts | 6 +- .../status-icon/status-icon.component.html | 4 +- .../status-icon/status-icon.component.ts | 2 +- 14 files changed, 127 insertions(+), 129 deletions(-) create mode 100644 src/app/applications/applications-list/application-filter/applications-filter.service.ts delete mode 100644 src/app/applications/applications-list/applications-filter.service.ts diff --git a/src/app/applications/application.model.ts b/src/app/applications/application.model.ts index 7733a12c5..63fd9a979 100644 --- a/src/app/applications/application.model.ts +++ b/src/app/applications/application.model.ts @@ -4,10 +4,12 @@ import { Datatarget } from "@applications/datatarget/datatarget.model"; import { ApplicationDeviceTypeUnion } from "@shared/enums/device-type"; import { ControlledProperty } from "@shared/models/controlled-property.model"; import { Organisation } from "../admin/organisation/organisation.model"; -import { ApplicationState } from "./enums/status.enum"; +import { ApplicationStatus } from "./enums/status.enum"; import { IotDevice } from "./iot-devices/iot-device.model"; import { ApplicationDeviceType } from "./models/application-device-type.model"; +export type ApplicationWithStatus = Application & { statusCheck: "stable" | "alert" }; + export class Application { public id: number; public createdAt: string; @@ -20,7 +22,7 @@ export class Application { public updatedBy: number; public createdByName: string; public updatedByName: string; - public status?: ApplicationState; + public status?: ApplicationStatus; public startDate?: Date; public endDate?: Date; public category?: string; @@ -41,7 +43,7 @@ export class ApplicationRequest { public name: string; public description: string; public organizationId: number; - public status?: ApplicationState; + public status?: ApplicationStatus; public startDate?: Date; public endDate?: Date; public category?: string; diff --git a/src/app/applications/application.service.ts b/src/app/applications/application.service.ts index 7f3f48324..25cce696e 100644 --- a/src/app/applications/application.service.ts +++ b/src/app/applications/application.service.ts @@ -4,6 +4,8 @@ import { Application, ApplicationData, UpdateApplicationOrganization } from "@ap import { forkJoin, Observable } from "rxjs"; import { map } from "rxjs/operators"; import { RestService } from "../shared/services/rest.service"; +import { ApplicationsFilterService } from "./applications-list/application-filter/applications-filter.service"; +import { ApplicationStatus, ApplicationStatusCheck } from "./enums/status.enum"; import { IotDevicesApplicationMapResponse } from "./iot-devices/iot-device.model"; interface GetApplicationParameters { @@ -13,6 +15,9 @@ interface GetApplicationParameters { orderOn: string; organizationId?: number; permissionId?: number; + status?: ApplicationStatus; + statusCheck?: ApplicationStatusCheck; + owner?: string; } @Injectable({ @@ -21,7 +26,11 @@ interface GetApplicationParameters { export class ApplicationService { public id: number; public canEdit = false; - constructor(private restService: RestService, private userMinimalService: UserMinimalService) {} + constructor( + private restService: RestService, + private userMinimalService: UserMinimalService, + private filterService: ApplicationsFilterService + ) {} createApplication(body: any): Observable { return this.restService.post("application", body, { observe: "response" }); @@ -58,6 +67,10 @@ export class ApplicationService { ); } + getApplicationFilterOptions(id: number): Observable { + return this.restService.get(`application/${id}/filter-information`); + } + getApplications( limit: number, offset: number, @@ -71,6 +84,9 @@ export class ApplicationService { offset, sort, orderOn, + statusCheck: this.filterService.statusCheck === "All" ? null : this.filterService.statusCheck, + status: this.filterService.status === "All" ? null : this.filterService.status, + owner: this.filterService.owner === "All" ? null : this.filterService.owner, }; if (permissionId) { body.permissionId = permissionId; @@ -89,10 +105,6 @@ export class ApplicationService { return this.restService.get("application", body); } - getApplicationFilterOptions(id: number): Observable { - return this.restService.get(`application/${id}/filter-information`, {}, id); - } - deleteApplication(id: number) { return this.restService.delete("application", id); } diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.html b/src/app/applications/applications-list/application-filter/application-filter.component.html index 22951f452..321ae0414 100644 --- a/src/app/applications/applications-list/application-filter/application-filter.component.html +++ b/src/app/applications/applications-list/application-filter/application-filter.component.html @@ -13,7 +13,7 @@
Tilstand
- + {{ option.label }} diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.ts b/src/app/applications/applications-list/application-filter/application-filter.component.ts index 27f4fc69d..19057b99c 100644 --- a/src/app/applications/applications-list/application-filter/application-filter.component.ts +++ b/src/app/applications/applications-list/application-filter/application-filter.component.ts @@ -6,9 +6,9 @@ import { MatFormFieldModule } from "@angular/material/form-field"; import { MatIconModule } from "@angular/material/icon"; import { MatSelectModule } from "@angular/material/select"; import { ApplicationService } from "@applications/application.service"; -import { ApplicationState, ApplicationStatus } from "@applications/enums/status.enum"; +import { ApplicationStatus, ApplicationStatusCheck } from "@applications/enums/status.enum"; import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; -import { ApplicationsFilterService } from "../applications-filter.service"; +import { ApplicationsFilterService } from "./applications-filter.service"; @Component({ selector: "app-application-filter", @@ -38,26 +38,26 @@ export class ApplicationFilterComponent implements OnInit { }); } - stateOptions: { label: string; value: ApplicationState | "All" }[] = [ + stateOptions: { label: string; value: ApplicationStatus | "All" }[] = [ { label: "Alle", value: "All" }, - { label: "Ingen", value: ApplicationState["NONE"] }, - { label: "In operation", value: ApplicationState["IN-OPERATION"] }, - { label: "Project", value: ApplicationState["PROJECT"] }, - { label: "Prototype", value: ApplicationState["PROTOTYPE"] }, - { label: "other", value: ApplicationState["OTHER"] }, + { label: "Ingen", value: ApplicationStatus["NONE"] }, + { label: "In operation", value: ApplicationStatus["IN-OPERATION"] }, + { label: "Project", value: ApplicationStatus["PROJECT"] }, + { label: "Prototype", value: ApplicationStatus["PROTOTYPE"] }, + { label: "other", value: ApplicationStatus["OTHER"] }, ]; - statusOptions: { label: string; value: ApplicationStatus | "All" }[] = [ + statusOptions: { label: string; value: ApplicationStatusCheck | "All" }[] = [ { label: "Alle", value: "All" }, - { label: "Alert", value: ApplicationStatus.WARNING }, - { label: "Stable", value: ApplicationStatus.STABLE }, + { label: "Alert", value: "alert" }, + { label: "Stable", value: "stable" }, ]; ownerOptions: { label: string; value: string | "All" }[] = []; loadOwnerOptions(orgId: number): void { - this.applicationService.getApplicationFilterOptions(orgId).subscribe(options => { - console.log(options); + this.applicationService.getApplicationFilterOptions(1).subscribe(options => { + console.log(options[0]); const optionsArray: { label: string; value: string }[] = [{ label: "Alle", value: "All" }]; options.forEach(option => optionsArray.push({ label: option, value: option })); this.ownerOptions = optionsArray; @@ -68,9 +68,9 @@ export class ApplicationFilterComponent implements OnInit { status: string = "All"; owner: string = "All"; - onState(event: any): void { + onStatusCheck(event: any): void { console.log("Tilstand changed:", event.value); - this.filterService.updateState(event.value); + this.filterService.updateStatusCheck(event.value); } onStatus(event: any): void { diff --git a/src/app/applications/applications-list/application-filter/applications-filter.service.ts b/src/app/applications/applications-list/application-filter/applications-filter.service.ts new file mode 100644 index 000000000..2150cfd7c --- /dev/null +++ b/src/app/applications/applications-list/application-filter/applications-filter.service.ts @@ -0,0 +1,51 @@ +import { Injectable } from "@angular/core"; +import { ApplicationStatus, ApplicationStatusCheck } from "@applications/enums/status.enum"; +import { BehaviorSubject } from "rxjs"; + +@Injectable({ + providedIn: "root", +}) +export class ApplicationsFilterService { + public status: ApplicationStatus | "All" = "All"; + + public statusCheck: ApplicationStatusCheck | "All" = "All"; + public owner: string | "All" = "All"; + + private valueChanges = new BehaviorSubject<{ + status: ApplicationStatus | "All"; + statusCheck: ApplicationStatusCheck | "All"; + owner: string; + }>({ + status: this.status, + statusCheck: this.statusCheck, + owner: this.owner, + }); + + filterChanges$ = this.valueChanges.asObservable(); + + updateStatus(newValue: ApplicationStatus | null) { + this.status = newValue; + this.emitChange(); + } + + updateStatusCheck(newValue: ApplicationStatusCheck | null) { + this.statusCheck = newValue; + this.emitChange(); + } + + updateOwner(newValue: string) { + this.owner = newValue; + this.emitChange(); + } + + public resetFilter() { + this.statusCheck = "All"; + this.status = "All"; + this.owner = "All"; + this.emitChange(); + } + + private emitChange() { + this.valueChanges.next({ statusCheck: this.statusCheck, status: this.status, owner: this.owner }); + } +} diff --git a/src/app/applications/applications-list/application-map/application-map.component.ts b/src/app/applications/applications-list/application-map/application-map.component.ts index 39e451876..b5b55d50c 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.ts +++ b/src/app/applications/applications-list/application-map/application-map.component.ts @@ -1,15 +1,13 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { MatCheckboxModule } from "@angular/material/checkbox"; -import { Application } from "@applications/application.model"; import { ApplicationService } from "@applications/application.service"; -import { ApplicationState, ApplicationStatus } from "@applications/enums/status.enum"; +import { ApplicationStatus, ApplicationStatusCheck } from "@applications/enums/status.enum"; import { IotDevicesApplicationMapResponse } from "@applications/iot-devices/iot-device.model"; import { MapCoordinates } from "@shared/components/map/map-coordinates.model"; import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; import { Subscription } from "rxjs"; -import { map } from "rxjs/operators"; import { SharedModule } from "../../../shared/shared.module"; -import { ApplicationsFilterService } from "../applications-filter.service"; +import { ApplicationsFilterService } from "../application-filter/applications-filter.service"; @Component({ selector: "app-application-map", @@ -20,7 +18,11 @@ import { ApplicationsFilterService } from "../applications-filter.service"; }) export class ApplicationMapComponent implements OnInit, OnDestroy { public devices: IotDevicesApplicationMapResponse[] = []; - filterValues: { status: ApplicationStatus | "All"; state: ApplicationState | "All"; owner: string | "All" }; + filterValues: { + status: ApplicationStatus | "All"; + statusCheck: ApplicationStatusCheck | "All"; + owner: string | "All"; + }; private valueSubscription!: Subscription; constructor( @@ -75,19 +77,19 @@ export class ApplicationMapComponent implements OnInit, OnDestroy { } getApplications(): void { - this.applicationService - .getApplications(100000, 0, "asc", "id") - .pipe( - map(applicationData => { - const filteredApplications = this.filterService.SortApplications(applicationData.data as Application[]); - return filteredApplications.map(app => app.id); - }) - ) - .subscribe(mappedCoordinates => { - this.applicationService.getApplicationDevicesForMap(mappedCoordinates).subscribe(data => { - this.devices = data; - this.mapDevicesToCoordinateList(); - }); - }); + // this.applicationService + // .getApplications(100000, 0, "asc", "id") + // .pipe( + // map(applicationData => { + // const filteredApplications = this.filterService.SortApplications(applicationData.data as Application[]); + // return filteredApplications.map(app => app.id); + // }) + // ) + // .subscribe(mappedCoordinates => { + // this.applicationService.getApplicationDevicesForMap(mappedCoordinates).subscribe(data => { + // this.devices = data; + // this.mapDevicesToCoordinateList(); + // }); + // }); } } diff --git a/src/app/applications/applications-list/applications-filter.service.ts b/src/app/applications/applications-list/applications-filter.service.ts deleted file mode 100644 index b9d1a6806..000000000 --- a/src/app/applications/applications-list/applications-filter.service.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { Injectable } from "@angular/core"; -import { Application } from "@applications/application.model"; -import { ApplicationService } from "@applications/application.service"; -import { ApplicationState, ApplicationStatus } from "@applications/enums/status.enum"; -import { BehaviorSubject } from "rxjs"; - -@Injectable({ - providedIn: "root", -}) -export class ApplicationsFilterService { - private status: ApplicationStatus | "All" = "All"; - - private state: ApplicationState | "All" = "All"; - private owner: string | "All" = "All"; - - private valueChanges = new BehaviorSubject<{ - status: ApplicationStatus | "All"; - state: ApplicationState | "All"; - owner: string; - }>({ - status: this.status, - state: this.state, - owner: this.owner, - }); - - filterChanges$ = this.valueChanges.asObservable(); - - updateStatus(newValue: ApplicationStatus | null) { - this.status = newValue; - this.emitChange(); - } - - updateState(newValue: ApplicationState | null) { - this.state = newValue; - this.emitChange(); - } - - updateOwner(newValue: string) { - this.owner = newValue; - this.emitChange(); - } - - public resetFilter() { - this.state = "All"; - this.status = "All"; - this.owner = "All"; - this.emitChange(); - } - - private emitChange() { - this.valueChanges.next({ state: this.state, status: this.status, owner: this.owner }); - } - - public SortApplications(applications: Application[]) { - return applications.filter( - application => - (this.owner == "All" || application.owner === this.owner) && - (this.state == "All" || application.status === this.state) && - (this.state == "All" || application.status === this.state) - ); - } - - constructor(private applicationService: ApplicationService) {} -} diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.html b/src/app/applications/applications-list/applications-table/applications-table.component.html index 32224d2c7..ee4a6f58b 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.html +++ b/src/app/applications/applications-list/applications-table/applications-table.component.html @@ -23,7 +23,7 @@ - + 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 db93dbc05..9f0da17f2 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 @@ -26,7 +26,7 @@ import { ApplicationDialogModel } from "@shared/models/dialog.model"; import { TableColumn } from "@shared/types/table.type"; import { merge, Observable, of as observableOf } from "rxjs"; import { catchError, map, startWith, switchMap } from "rxjs/operators"; -import { ApplicationsFilterService } from "../applications-filter.service"; +import { ApplicationsFilterService } from "../application-filter/applications-filter.service"; const columnDefinitions: TableColumn[] = [ { @@ -127,7 +127,7 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { this.isLoadingResults = false; this.resultsLength = data.count; - return this.filterService.SortApplications(data.data); + return data.data; }), catchError(() => { this.isLoadingResults = false; diff --git a/src/app/applications/enums/status.enum.ts b/src/app/applications/enums/status.enum.ts index 9dba36b0f..82c6010e1 100644 --- a/src/app/applications/enums/status.enum.ts +++ b/src/app/applications/enums/status.enum.ts @@ -1,17 +1,12 @@ import { recordToEntries } from "@shared/helpers/record.helper"; -export enum ApplicationState { +export enum ApplicationStatus { "NONE" = "NONE", "IN-OPERATION" = "IN-OPERATION", "PROJECT" = "PROJECT", "PROTOTYPE" = "PROTOTYPE", "OTHER" = "OTHER", } +export type ApplicationStatusCheck = "stable" | "alert"; -export enum ApplicationStatus { - WARNING = "WARNING", - ALERT = "ALERT", - STABLE = "STABLE", -} - -export const ApplicationStateEntries = recordToEntries(ApplicationState); +export const ApplicationStatusEntries = recordToEntries(ApplicationStatus); diff --git a/src/app/shared/components/forms/form-body-application/form-body-application.component.ts b/src/app/shared/components/forms/form-body-application/form-body-application.component.ts index 599603141..5c01d26bb 100644 --- a/src/app/shared/components/forms/form-body-application/form-body-application.component.ts +++ b/src/app/shared/components/forms/form-body-application/form-body-application.component.ts @@ -7,7 +7,7 @@ import { PermissionService } from "@app/admin/permission/permission.service"; import { ControlledPropertyTypes } from "@app/device-model/Enums/controlled-propperty.enum"; import { Application, ApplicationRequest } from "@applications/application.model"; import { ApplicationService } from "@applications/application.service"; -import { ApplicationState, ApplicationStateEntries } from "@applications/enums/status.enum"; +import { ApplicationStatus, ApplicationStatusEntries } from "@applications/enums/status.enum"; import { TranslateService } from "@ngx-translate/core"; import { ApplicationDeviceTypeEntries, ApplicationDeviceTypes } from "@shared/enums/device-type"; import { MeService } from "@shared/services/me.service"; @@ -84,16 +84,16 @@ export class FormBodyApplicationComponent implements OnInit, OnDestroy { this.getPermissions(this.sharedVariableService.getUserInfo().user.id); const statusTranslationPrefix = "APPLICATION.STATUS."; - const statusTranslationKeys = ApplicationStateEntries.map(x => `${statusTranslationPrefix}${x.key}`); + const statusTranslationKeys = ApplicationStatusEntries.map(x => `${statusTranslationPrefix}${x.key}`); const deviceTypeTranslationPrefix = "IOT-DEVICE-TYPES."; const deviceTypeTranslationKeys = ApplicationDeviceTypeEntries.map(x => `${deviceTypeTranslationPrefix}${x.key}`); this.translate .get([...statusTranslationKeys, ...deviceTypeTranslationKeys, deviceTypeTranslationPrefix + "OTHER"]) .subscribe(translations => { // Populate the dropdown options with a translated label and the enum value - const statusOptions: DropdownOption[] = ApplicationStateEntries.map(entry => ({ + const statusOptions: DropdownOption[] = ApplicationStatusEntries.map(entry => ({ label: translations[statusTranslationPrefix + entry.key], - value: ApplicationState[entry.key], + value: ApplicationStatus[entry.key], })); this.statuses.push(...statusOptions); @@ -126,7 +126,7 @@ export class FormBodyApplicationComponent implements OnInit, OnDestroy { } fillDefaultMetadata() { - this.application.status = this.application.status ?? ApplicationState["NONE"]; + this.application.status = this.application.status ?? ApplicationStatus["NONE"]; } getApplication(id: number): void { diff --git a/src/app/shared/components/metadata-details/metadata-details.component.ts b/src/app/shared/components/metadata-details/metadata-details.component.ts index 436732e01..47cb05539 100644 --- a/src/app/shared/components/metadata-details/metadata-details.component.ts +++ b/src/app/shared/components/metadata-details/metadata-details.component.ts @@ -1,6 +1,6 @@ import { Component, Input, OnInit } from "@angular/core"; import { PermissionResponse } from "@app/admin/permission/permission.model"; -import { ApplicationState } from "@applications/enums/status.enum"; +import { ApplicationStatus } from "@applications/enums/status.enum"; import { ApplicationDeviceType } from "@applications/models/application-device-type.model"; import { TranslateService } from "@ngx-translate/core"; import { toPascalKebabCase } from "@shared/helpers/string.helper"; @@ -13,7 +13,7 @@ import { ControlledProperty } from "@shared/models/controlled-property.model"; }) export class MetadataDetailsComponent implements OnInit { @Input() permissions?: PermissionResponse[]; - @Input() status?: ApplicationState; + @Input() status?: ApplicationStatus; @Input() startDate?: Date; @Input() endDate?: Date; @Input() category?: string; @@ -30,7 +30,7 @@ export class MetadataDetailsComponent implements OnInit { entries = Object.entries; toPascalKebabCase = toPascalKebabCase; - ApplicationStatus = ApplicationState; + ApplicationStatus = ApplicationStatus; constructor(private translate: TranslateService) {} diff --git a/src/app/shared/components/status-icon/status-icon.component.html b/src/app/shared/components/status-icon/status-icon.component.html index 8639a81de..4def8c7cb 100644 --- a/src/app/shared/components/status-icon/status-icon.component.html +++ b/src/app/shared/components/status-icon/status-icon.component.html @@ -1,5 +1,5 @@ -@switch (iconType) { @case ("default") { +@switch (iconType) { @case ("stable") { -} @case ("warring") { +} @case ("alert") { } } diff --git a/src/app/shared/components/status-icon/status-icon.component.ts b/src/app/shared/components/status-icon/status-icon.component.ts index 13f231390..f226a6bdf 100644 --- a/src/app/shared/components/status-icon/status-icon.component.ts +++ b/src/app/shared/components/status-icon/status-icon.component.ts @@ -9,5 +9,5 @@ import { Component, Input } from "@angular/core"; imports: [NgOptimizedImage], }) export class StatusIconComponent { - @Input() iconType: "default" | "warring" = "default"; + @Input() iconType: "alert" | "stable" = "stable"; } From 838896502201e20203a5d2fed6c37669cf1b482a Mon Sep 17 00:00:00 2001 From: Lauest Date: Wed, 12 Feb 2025 08:51:25 +0100 Subject: [PATCH 06/16] added name to top bar --- src/app/shared/components/top-bar/top-bar.component.html | 4 ++-- src/app/shared/components/top-bar/top-bar.component.ts | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/app/shared/components/top-bar/top-bar.component.html b/src/app/shared/components/top-bar/top-bar.component.html index 788da5201..6617bc7d8 100644 --- a/src/app/shared/components/top-bar/top-bar.component.html +++ b/src/app/shared/components/top-bar/top-bar.component.html @@ -27,8 +27,8 @@
diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.scss b/src/app/applications/applications-list/application-filter/application-filter.component.scss index ffcb34441..4c52a5c9a 100644 --- a/src/app/applications/applications-list/application-filter/application-filter.component.scss +++ b/src/app/applications/applications-list/application-filter/application-filter.component.scss @@ -9,7 +9,7 @@ } .filter-selector-container { - width: 200; + width: 200px; margin-right: 30px; display: flex; flex-direction: column; diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.ts b/src/app/applications/applications-list/application-filter/application-filter.component.ts index 19057b99c..1151eb383 100644 --- a/src/app/applications/applications-list/application-filter/application-filter.component.ts +++ b/src/app/applications/applications-list/application-filter/application-filter.component.ts @@ -7,6 +7,8 @@ import { MatIconModule } from "@angular/material/icon"; import { MatSelectModule } from "@angular/material/select"; import { ApplicationService } from "@applications/application.service"; import { ApplicationStatus, ApplicationStatusCheck } from "@applications/enums/status.enum"; + +import { TranslateModule, TranslateService } from "@ngx-translate/core"; import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; import { ApplicationsFilterService } from "./applications-filter.service"; @@ -21,6 +23,7 @@ import { ApplicationsFilterService } from "./applications-filter.service"; MatSelectModule, MatOptionModule, MatButtonModule, + TranslateModule, ], templateUrl: "./application-filter.component.html", styleUrl: "./application-filter.component.scss", @@ -30,38 +33,38 @@ export class ApplicationFilterComponent implements OnInit { constructor( private applicationService: ApplicationService, private filterService: ApplicationsFilterService, - private sharedVariableService: SharedVariableService + private sharedVariableService: SharedVariableService, + public translate: TranslateService ) {} ngOnInit(): void { - this.sharedVariableService.getValue().subscribe(organizationId => { - this.loadOwnerOptions(organizationId); - }); + this.loadOwnerOptions(); } stateOptions: { label: string; value: ApplicationStatus | "All" }[] = [ - { label: "Alle", value: "All" }, - { label: "Ingen", value: ApplicationStatus["NONE"] }, - { label: "In operation", value: ApplicationStatus["IN-OPERATION"] }, - { label: "Project", value: ApplicationStatus["PROJECT"] }, - { label: "Prototype", value: ApplicationStatus["PROTOTYPE"] }, - { label: "other", value: ApplicationStatus["OTHER"] }, + { label: "APPLICATION-FILTER.ALL", value: "All" }, + { label: "APPLICATION-FILTER.NONE", value: ApplicationStatus["NONE"] }, + { label: "APPLICATION-FILTER.IN-OPERATION", value: ApplicationStatus["IN-OPERATION"] }, + { label: "APPLICATION-FILTER.PROJECT", value: ApplicationStatus["PROJECT"] }, + { label: "APPLICATION-FILTER.PROTOTYPE", value: ApplicationStatus["PROTOTYPE"] }, + { label: "APPLICATION-FILTER.OTHER", value: ApplicationStatus["OTHER"] }, ]; statusOptions: { label: string; value: ApplicationStatusCheck | "All" }[] = [ - { label: "Alle", value: "All" }, - { label: "Alert", value: "alert" }, - { label: "Stable", value: "stable" }, + { label: "APPLICATION-FILTER.ALL", value: "All" }, + { label: "APPLICATION-FILTER.ALERT", value: "alert" }, + { label: "APPLICATION-FILTER.STABLE", value: "stable" }, ]; ownerOptions: { label: string; value: string | "All" }[] = []; - loadOwnerOptions(orgId: number): void { - this.applicationService.getApplicationFilterOptions(1).subscribe(options => { - console.log(options[0]); - const optionsArray: { label: string; value: string }[] = [{ label: "Alle", value: "All" }]; - options.forEach(option => optionsArray.push({ label: option, value: option })); - this.ownerOptions = optionsArray; - }); + loadOwnerOptions(): void { + this.applicationService + .getApplicationFilterOptions(this.sharedVariableService.getSelectedOrganisationId()) + .subscribe(options => { + const optionsArray: { label: string; value: string }[] = []; + options.forEach(option => optionsArray.push({ label: option, value: option })); + this.ownerOptions = optionsArray; + }); } state: string = "All"; @@ -69,17 +72,14 @@ export class ApplicationFilterComponent implements OnInit { owner: string = "All"; onStatusCheck(event: any): void { - console.log("Tilstand changed:", event.value); this.filterService.updateStatusCheck(event.value); } onStatus(event: any): void { - console.log("Status changed:", event.value); this.filterService.updateStatus(event.value); } onOwner(event: any): void { - console.log("Ejer changed:", event.value); this.filterService.updateOwner(event.value); } diff --git a/src/app/applications/applications-list/application-map/application-map.component.html b/src/app/applications/applications-list/application-map/application-map.component.html index d561eda1d..4ea8b80a8 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.html +++ b/src/app/applications/applications-list/application-map/application-map.component.html @@ -3,7 +3,13 @@ }
- - +
+ +
{{ "APPLICATION-INFORMATION-BOX.DEVICES" | translate }}
+
+
+ +
{{ "APPLICATION-INFORMATION-BOX.GATEWAYS" | translate }}
+
diff --git a/src/app/applications/applications-list/application-map/application-map.component.scss b/src/app/applications/applications-list/application-map/application-map.component.scss index bdb0214c0..1fa215065 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.scss +++ b/src/app/applications/applications-list/application-map/application-map.component.scss @@ -1,17 +1,25 @@ -.map-page { - background-color: #ffff; +:host .map-page { + background-color: #ffffff; padding: 20px; height: 600px; position: relative; } -.map-overlay { +:host .map-overlay { height: 89px; width: 132px; - background-color: #ffff; + background-color: #ffffff; position: absolute; bottom: 30px; left: 30px; z-index: 10000; border-radius: 4px; + display: flex; + flex-direction: column; +} + +.check-box-container { + display: flex; + flex-direction: row; + align-items: center; } diff --git a/src/app/applications/applications-list/application-map/application-map.component.ts b/src/app/applications/applications-list/application-map/application-map.component.ts index b5b55d50c..62fa393e7 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.ts +++ b/src/app/applications/applications-list/application-map/application-map.component.ts @@ -2,7 +2,8 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { MatCheckboxModule } from "@angular/material/checkbox"; import { ApplicationService } from "@applications/application.service"; import { ApplicationStatus, ApplicationStatusCheck } from "@applications/enums/status.enum"; -import { IotDevicesApplicationMapResponse } from "@applications/iot-devices/iot-device.model"; +import { IotDevice } from "@applications/iot-devices/iot-device.model"; +import { TranslateService } from "@ngx-translate/core"; import { MapCoordinates } from "@shared/components/map/map-coordinates.model"; import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; import { Subscription } from "rxjs"; @@ -17,7 +18,7 @@ import { ApplicationsFilterService } from "../application-filter/applications-fi styleUrls: ["./application-map.component.scss"], }) export class ApplicationMapComponent implements OnInit, OnDestroy { - public devices: IotDevicesApplicationMapResponse[] = []; + public devices: IotDevice[] = []; filterValues: { status: ApplicationStatus | "All"; statusCheck: ApplicationStatusCheck | "All"; @@ -28,6 +29,7 @@ export class ApplicationMapComponent implements OnInit, OnDestroy { constructor( private filterService: ApplicationsFilterService, private applicationService: ApplicationService, + public translate: TranslateService, private sharedVariableService: SharedVariableService ) {} @@ -67,7 +69,7 @@ export class ApplicationMapComponent implements OnInit, OnDestroy { isDevice: true, internalOrganizationId: this.sharedVariableService.getSelectedOrganisationId(), networkTechnology: dev.type, - lastActive: dev.latestSentMessage, + lastActive: dev?.latestReceivedMessage ? dev?.latestReceivedMessage.sentTime : null, }, }); }); @@ -77,19 +79,11 @@ export class ApplicationMapComponent implements OnInit, OnDestroy { } getApplications(): void { - // this.applicationService - // .getApplications(100000, 0, "asc", "id") - // .pipe( - // map(applicationData => { - // const filteredApplications = this.filterService.SortApplications(applicationData.data as Application[]); - // return filteredApplications.map(app => app.id); - // }) - // ) - // .subscribe(mappedCoordinates => { - // this.applicationService.getApplicationDevicesForMap(mappedCoordinates).subscribe(data => { - // this.devices = data; - // this.mapDevicesToCoordinateList(); - // }); - // }); + this.applicationService + .getApplicationDevices(this.sharedVariableService.getSelectedOrganisationId()) + .subscribe(data => { + this.devices = data; + this.mapDevicesToCoordinateList(); + }); } } diff --git a/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.html b/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.html index fac323744..91851716f 100644 --- a/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.html +++ b/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.html @@ -2,18 +2,18 @@ @@ -22,8 +22,8 @@ [width]="25" [matSVGSrc]="'micro-chip'" [type]="'default'" - [count]="133" - [description]="'Enheder'" + [count]="totalDevices" + [description]="'APPLICATION-INFORMATION-BOX.DEVICES' | translate" />
diff --git a/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.ts b/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.ts index 053ac0de2..8ebae0bf3 100644 --- a/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.ts +++ b/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.ts @@ -4,6 +4,7 @@ import { DomSanitizer } from "@angular/platform-browser"; import { ApplicationService } from "@applications/application.service"; import { TranslateModule, TranslateService } from "@ngx-translate/core"; import { ChirpstackGatewayService } from "@shared/services/chirpstack-gateway.service"; +import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; import { BasicInformationBoxComponent } from "../../../shared/components/basic-information-box/basic-information-box.component"; @Component({ @@ -15,13 +16,19 @@ import { BasicInformationBoxComponent } from "../../../shared/components/basic-i }) export class ApplicationsListDashboardComponent implements OnInit { gateways: number = 0; + total: number = 0; + withError: number = 0; + withoutError: number = 0; + totalDevices: number = 0; + totalGateways: number; constructor( private gatewayService: ChirpstackGatewayService, private applicationService: ApplicationService, private translate: TranslateService, private matIconRegistry: MatIconRegistry, - private domSanitizer: DomSanitizer + private domSanitizer: DomSanitizer, + private sharedVariableService: SharedVariableService ) { this.matIconRegistry.addSvgIcon( "micro-chip", @@ -49,9 +56,22 @@ export class ApplicationsListDashboardComponent implements OnInit { } ngOnInit(): void { this.gatewayService.getMultiple().subscribe(data => (this.gateways = data.totalCount)); + this.applicationService + .getApplicationsWithError(this.sharedVariableService.getSelectedOrganisationId()) + .subscribe(data => { + this.withError = data.withError; + this.totalDevices = data.withError; + this.withoutError = data.total - data.withError; + this.total = data.total; + }); - //TODO:: Number of devices - //TODO:: status stable of ..... - //TODO:: status error of ..... + this.gatewayService + .getMultiple() + .subscribe( + data => + (this.totalGateways = data.resultList.filter( + gw => gw.organizationId === this.sharedVariableService.getSelectedOrganisationId() + ).length) + ); } } diff --git a/src/app/applications/applications-list/applications-list.component.ts b/src/app/applications/applications-list/applications-list.component.ts index c1528dcbc..85924988c 100644 --- a/src/app/applications/applications-list/applications-list.component.ts +++ b/src/app/applications/applications-list/applications-list.component.ts @@ -5,10 +5,11 @@ import { DomSanitizer, Title } from "@angular/platform-browser"; import { ActivatedRoute, Router } from "@angular/router"; import { UserMinimalService } from "@app/admin/users/user-minimal.service"; import { NavbarComponent } from "@app/navbar/navbar.component"; +import { ApplicationService } from "@applications/application.service"; import { AuthService } from "@auth/auth.service"; import { environment } from "@environments/environment"; import { TranslateService } from "@ngx-translate/core"; -import { Tap } from "@shared/components/basic-tap-switch/basic-tap-switch.component"; +import { Counter, Tap } from "@shared/components/basic-tap-switch/basic-tap-switch.component"; import { WelcomeDialogComponent } from "@shared/components/welcome-dialog/welcome-dialog.component"; import { OrganizationAccessScope } from "@shared/enums/access-scopes"; import { WelcomeDialogModel } from "@shared/models/dialog.model"; @@ -25,19 +26,7 @@ const welcomeDialogId = "welcome-dialog"; }) export class ApplicationsListComponent implements OnInit { currentSubPath: string = ""; - taps: Tap[] = [ - { - title: "Applikationer", - icon: { matSVGSrc: "layers-tap", height: 16, width: 16 }, - counters: [ - { - color: "default", - value: "22", - }, - ], - }, - { title: "Kort", icon: { matSVGSrc: "map-tap", height: 17, width: 18 } }, - ]; + taps: Tap[]; index = 0; isLoadingResults = true; @@ -54,6 +43,9 @@ export class ApplicationsListComponent implements OnInit { hasSomePermission: boolean; isGlobalAdmin = false; + applicationWithError = 0; + totalApplication = 0; + constructor( public translate: TranslateService, private titleService: Title, @@ -66,7 +58,8 @@ export class ApplicationsListComponent implements OnInit { private dialog: MatDialog, private userMinimalService: UserMinimalService, private matIconRegistry: MatIconRegistry, - private domSanitizer: DomSanitizer + private domSanitizer: DomSanitizer, + private applicationService: ApplicationService ) { translate.use("da"); @@ -94,6 +87,30 @@ export class ApplicationsListComponent implements OnInit { this.organizationId = this.globalService.getSelectedOrganisationId(); this.canEdit = this.meService.hasAccessToTargetOrganization(OrganizationAccessScope.ApplicationWrite); + this.applicationService + .getApplicationsWithError(this.sharedVariableService.getSelectedOrganisationId()) + .subscribe(data => { + const counters: Counter[] = [ + { + color: "default", + value: data.total.toString(), + }, + ]; + + if (data.withError) { + counters.push({ color: "alert", value: data.withError.toString() }); + } + + this.taps = [ + { + title: "Applikationer", + icon: { matSVGSrc: "layers-tap", height: 16, width: 16 }, + counters: counters, + }, + { title: "Kort", icon: { matSVGSrc: "map-tap", height: 17, width: 18 } }, + ]; + }); + // Authenticate user this.verifyUserAndInit(); } diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.html b/src/app/applications/applications-list/applications-table/applications-table.component.html index ee4a6f58b..121d7dc43 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.html +++ b/src/app/applications/applications-list/applications-table/applications-table.component.html @@ -218,7 +218,7 @@ - +
{{ getUsername() }}
{{ "USER_PAGE.USER_PAGE" | translate }} + {{ "NAV.LOGOUT" | translate }} +
diff --git a/src/app/shared/components/top-bar/top-bar.component.scss b/src/app/shared/components/top-bar/top-bar.component.scss index cb5795f7f..0f5494fcd 100644 --- a/src/app/shared/components/top-bar/top-bar.component.scss +++ b/src/app/shared/components/top-bar/top-bar.component.scss @@ -14,7 +14,6 @@ justify-content: space-between; margin: 30px; margin-top: 40px; - overflow: none; margin-bottom: 40px; } @@ -96,7 +95,7 @@ flex-direction: row; justify-content: end; align-items: center; - font-size: 14; + font-size: 14px; font-weight: 500; line-height: 20px; } @@ -106,7 +105,7 @@ flex-direction: row; justify-content: end; align-items: center; - font-size: 12; + font-size: 12px; font-weight: 500; line-height: 16px; color: #525252; diff --git a/src/assets/i18n/da.json b/src/assets/i18n/da.json index 89f1f89af..0c4403898 100644 --- a/src/assets/i18n/da.json +++ b/src/assets/i18n/da.json @@ -407,6 +407,27 @@ "DATA": "Data", "STATE": "State" }, + "APPLICATION-FILTER": { + "OWNER": "Ejer", + "STATE": "Tilstand", + "STATUS": "Status", + "RESET-FILTER": "Nulstil filter", + "ALL": "Alle", + "ALERT": "Alert", + "STABLE": "Stable", + "NONE": "Ingen", + "IN-OPERATION": "I drift", + "PROJECT": "Projekt", + "PROTOTYPE": "Prototype", + "OTHER": "Andet" + }, + "APPLICATION-INFORMATION-BOX": { + "DEVICES": "Enheder", + "GATEWAYS": "Gateways", + "APPLICATIONS-WITH-ERROR": "Applikationer med fejl", + "APPLICATIONS-WITHOUT-ERROR": "Applikationer uden fejl" + }, + "IOT-TABLE": { "APPLICATION": "Applikation", "NETWORK-TECHNOLOGY": "Netværksteknologi", diff --git a/src/assets/scss/components/_tables.scss b/src/assets/scss/components/_tables.scss index 2d2556b08..dc39795aa 100644 --- a/src/assets/scss/components/_tables.scss +++ b/src/assets/scss/components/_tables.scss @@ -35,14 +35,6 @@ table { } } -.mat-mdc-paginator { - display: none !important; -} - -.mat-sort-header-arrow { - display: none; -} - .dropdown { .applicationRow__edit { width: 10px; From fcb392550d8a34d5c192c069f4b95f46e41dea90 Mon Sep 17 00:00:00 2001 From: Lauest Date: Wed, 12 Feb 2025 16:12:46 +0100 Subject: [PATCH 08/16] fixes from pr --- .../application-map.component.html | 4 +-- .../application-map.component.scss | 1 + .../application-map.component.ts | 2 ++ .../basic-tap-switch.component.html | 6 +++- .../basic-tap-switch.component.scss | 30 +++++++++++-------- src/assets/scss/setup/_variables.scss | 2 ++ 6 files changed, 30 insertions(+), 15 deletions(-) diff --git a/src/app/applications/applications-list/application-map/application-map.component.html b/src/app/applications/applications-list/application-map/application-map.component.html index 4ea8b80a8..7fd47dda1 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.html +++ b/src/app/applications/applications-list/application-map/application-map.component.html @@ -4,11 +4,11 @@ }
- +
{{ "APPLICATION-INFORMATION-BOX.DEVICES" | translate }}
- +
{{ "APPLICATION-INFORMATION-BOX.GATEWAYS" | translate }}
diff --git a/src/app/applications/applications-list/application-map/application-map.component.scss b/src/app/applications/applications-list/application-map/application-map.component.scss index 1fa215065..a566205c3 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.scss +++ b/src/app/applications/applications-list/application-map/application-map.component.scss @@ -16,6 +16,7 @@ border-radius: 4px; display: flex; flex-direction: column; + padding-top: 5px; } .check-box-container { diff --git a/src/app/applications/applications-list/application-map/application-map.component.ts b/src/app/applications/applications-list/application-map/application-map.component.ts index 62fa393e7..63271dbdd 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.ts +++ b/src/app/applications/applications-list/application-map/application-map.component.ts @@ -19,6 +19,8 @@ import { ApplicationsFilterService } from "../application-filter/applications-fi }) export class ApplicationMapComponent implements OnInit, OnDestroy { public devices: IotDevice[] = []; + public device: boolean = true; + public gateway: boolean = true; filterValues: { status: ApplicationStatus | "All"; statusCheck: ApplicationStatusCheck | "All"; diff --git a/src/app/shared/components/basic-tap-switch/basic-tap-switch.component.html b/src/app/shared/components/basic-tap-switch/basic-tap-switch.component.html index 73226bfa8..05aae8aac 100644 --- a/src/app/shared/components/basic-tap-switch/basic-tap-switch.component.html +++ b/src/app/shared/components/basic-tap-switch/basic-tap-switch.component.html @@ -6,7 +6,11 @@ } {{ tap.title }} @for (counter of tap.counters; track counter; let idx = $index) { -
+
{{ counter.value }}
} diff --git a/src/app/shared/components/basic-tap-switch/basic-tap-switch.component.scss b/src/app/shared/components/basic-tap-switch/basic-tap-switch.component.scss index 6c4c35d56..8fcbb5a68 100644 --- a/src/app/shared/components/basic-tap-switch/basic-tap-switch.component.scss +++ b/src/app/shared/components/basic-tap-switch/basic-tap-switch.component.scss @@ -1,3 +1,5 @@ +@import "../../../../assets/scss/setup/variables"; + .main-container { display: flex; height: 46px !important; @@ -13,17 +15,17 @@ padding: 0 20px; } .active-tap { - background-color: #ffff !important; - color: #404040; - fill: #404040; + background-color: $white !important; + color: $default-icon-color; + fill: $default-icon-color; } .inactive-tap { - fill: black !important; - color: black; + fill: $color-link !important; + color: $color-link; background-color: transparent !important; } .active-tap-icon { - color: #404040; + color: $default-icon-color; width: 16px; //height margin-bottom: 5px; } @@ -31,22 +33,26 @@ .inactive-tap-icon { margin-bottom: 5px; width: 16px; //height - color: black; + color: $color-link; } .counter-default { - background-color: #404040; + background-color: $default-icon-color; +} + +.counter-default-inactive { + background-color: $color-link; } .counter-warning { - background-color: #fde047; + background-color: $warning-color; } .counter-stable { - background-color: #047857; + background-color: $stable-color; } .counter-alert { - background-color: #991b1b; + background-color: $alert-color; } .counter-base { font-size: 14px; @@ -59,5 +65,5 @@ align-items: center; display: flex; margin-left: 3px; - color: #ffff; + color: $white; } diff --git a/src/assets/scss/setup/_variables.scss b/src/assets/scss/setup/_variables.scss index a30d51a65..f8d7a82ce 100644 --- a/src/assets/scss/setup/_variables.scss +++ b/src/assets/scss/setup/_variables.scss @@ -387,6 +387,8 @@ $red: #dc3545; $alert-color: #991b1b; $stable-color: #047857; +$warning-color: #fde047; + $default-color: #525252; $default-icon-color: #404040; From a84de0a6e809796d0523485c6db15b624630110e Mon Sep 17 00:00:00 2001 From: Lauest Date: Thu, 13 Feb 2025 13:18:54 +0100 Subject: [PATCH 09/16] pr fixes --- .../application-detail.component.ts | 7 +- .../application-filter.component.html | 6 +- .../application-filter.component.scss | 18 +++- .../application-filter.component.ts | 5 +- .../applications-table.component.html | 49 +++++----- .../applications-table.component.scss | 9 +- .../applications-table.component.ts | 87 ++++++++++++++++-- .../table-paginator.component.html | 35 +++++-- .../table-paginator.component.scss | 58 ++++++++---- .../table-paginator.component.ts | 3 +- .../components/top-bar/top-bar.component.html | 48 +++++++--- .../components/top-bar/top-bar.component.scss | 53 ++++++++--- src/assets/images/angle-left.svg | 3 + src/assets/images/angle-right.svg | 3 + src/assets/images/arrow_back.png | Bin 910 -> 0 bytes src/assets/images/arrow_forward.png | Bin 626 -> 0 bytes src/assets/images/filter.png | Bin 8449 -> 0 bytes src/assets/images/sliders.svg | 3 + src/assets/scss/setup/_variables.scss | 4 +- 19 files changed, 293 insertions(+), 98 deletions(-) create mode 100644 src/assets/images/angle-left.svg create mode 100644 src/assets/images/angle-right.svg delete mode 100644 src/assets/images/arrow_back.png delete mode 100644 src/assets/images/arrow_forward.png delete mode 100644 src/assets/images/filter.png create mode 100644 src/assets/images/sliders.svg diff --git a/src/app/applications/application-detail/application-detail.component.ts b/src/app/applications/application-detail/application-detail.component.ts index 5e8bafa41..6bee80ae9 100644 --- a/src/app/applications/application-detail/application-detail.component.ts +++ b/src/app/applications/application-detail/application-detail.component.ts @@ -1,4 +1,4 @@ -import { AfterViewInit, Component, EventEmitter, OnDestroy, OnInit, Output } from "@angular/core"; +import { AfterViewInit, ChangeDetectorRef, Component, EventEmitter, OnDestroy, OnInit, Output } from "@angular/core"; import { MatDialog } from "@angular/material/dialog"; import { Title } from "@angular/platform-browser"; import { ActivatedRoute, Router } from "@angular/router"; @@ -71,11 +71,13 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI private restService: RestService, private sharedVariableService: SharedVariableService, private chirpstackGatewayService: ChirpstackGatewayService, - private changeOrganizationDialog: MatDialog + private changeOrganizationDialog: MatDialog, + private cdr: ChangeDetectorRef ) {} ngOnInit(): void { this.id = +this.route.snapshot.paramMap.get("id"); + if (this.id) { this.bindApplication(this.id); this.dropdownButton = { @@ -213,6 +215,7 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI bindApplication(id: number): void { this.applicationsSubscription = this.applicationService.getApplication(id).subscribe(application => { this.application = application; + this.cdr.detectChanges(); }); } diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.html b/src/app/applications/applications-list/application-filter/application-filter.component.html index ce76a7a4e..931174f9d 100644 --- a/src/app/applications/applications-list/application-filter/application-filter.component.html +++ b/src/app/applications/applications-list/application-filter/application-filter.component.html @@ -38,8 +38,10 @@
diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.scss b/src/app/applications/applications-list/application-filter/application-filter.component.scss index 4c52a5c9a..fa699bdd0 100644 --- a/src/app/applications/applications-list/application-filter/application-filter.component.scss +++ b/src/app/applications/applications-list/application-filter/application-filter.component.scss @@ -4,8 +4,15 @@ display: flex; flex-direction: row; flex: 1; - height: 65px; + min-height: 65px; margin-bottom: 25px; + flex-wrap: wrap; +} + +@media (max-width: 768px) { + .filter-container { + flex-direction: column; + } } .filter-selector-container { @@ -13,6 +20,7 @@ margin-right: 30px; display: flex; flex-direction: column; + margin-bottom: 30px; } .filter-title { @@ -41,12 +49,15 @@ justify-content: center; gap: 10px; width: 150px; +} + +.filter-label { font-size: 16px; + font-weight: 500; } :host .mat-mdc-select { - height: 20px; - line-height: 35px; + height: 24px; display: flex; align-items: center; font-size: 16px !important; @@ -64,6 +75,7 @@ height: 40px !important; display: flex !important; align-items: center !important; + font-size: 16px !important; } :host .mat-mdc-select-arrow { diff --git a/src/app/applications/applications-list/application-filter/application-filter.component.ts b/src/app/applications/applications-list/application-filter/application-filter.component.ts index 1151eb383..3ba13cc74 100644 --- a/src/app/applications/applications-list/application-filter/application-filter.component.ts +++ b/src/app/applications/applications-list/application-filter/application-filter.component.ts @@ -7,6 +7,7 @@ import { MatIconModule } from "@angular/material/icon"; import { MatSelectModule } from "@angular/material/select"; import { ApplicationService } from "@applications/application.service"; import { ApplicationStatus, ApplicationStatusCheck } from "@applications/enums/status.enum"; +import { ChirpstackGatewayService } from "./../../../shared/services/chirpstack-gateway.service"; import { TranslateModule, TranslateService } from "@ngx-translate/core"; import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; @@ -34,10 +35,12 @@ export class ApplicationFilterComponent implements OnInit { private applicationService: ApplicationService, private filterService: ApplicationsFilterService, private sharedVariableService: SharedVariableService, - public translate: TranslateService + public translate: TranslateService, + public ChirpstackGatewayService: ChirpstackGatewayService ) {} ngOnInit(): void { this.loadOwnerOptions(); + this.ChirpstackGatewayService.getMultiple().subscribe(data => data); } stateOptions: { label: string; value: ApplicationStatus | "All" }[] = [ diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.html b/src/app/applications/applications-list/applications-table/applications-table.component.html index 121d7dc43..4c3253f30 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.html +++ b/src/app/applications/applications-list/applications-table/applications-table.component.html @@ -17,20 +17,20 @@ matSortDirection="asc" (matSortChange)="announceSortChange($event)" > - - + + {{ "APPLICATION-TABLE.STATUS" | translate }} - + - + - + {{ "APPLICATION-TABLE.STATE" | translate }} - + - +
{{ element.name }} @@ -59,16 +59,15 @@ - {{ "APPLICATION-TABLE.DATA" | translate }} + {{ "APPLICATION-TABLE.CONTROLLED-PROPERTIES" | translate }}
- - - - + @for (property of application.controlledProperties; track $index) { + + }
@@ -93,15 +92,12 @@ - - - - - {{ "APPLICATION-TABLE.CONTACT-PERSON" | translate }} + {{ application.contactPerson ?? "-" }} @@ -111,6 +107,7 @@ {{ "APPLICATION-TABLE.DATA-TARGETS" | translate }} + {{ application?.dataTargets?.length ?? 0 }} @@ -120,6 +117,7 @@ {{ "APPLICATION-TABLE.OPEN-DATA-DK" | translate }} + {{ isOpenDataDK(application.dataTargets) | yesNo }} @@ -129,6 +127,7 @@ {{ "APPLICATION-TABLE.PERSONAL-DATA" | translate }} + @@ -139,6 +138,7 @@ {{ "APPLICATION-TABLE.START-DATE" | translate }} + {{ (application.startDate | dateOnly) ?? "-" }} @@ -148,6 +148,7 @@ {{ "APPLICATION-TABLE.END-DATE" | translate }} + {{ (application.endDate | dateOnly) ?? "-" }} @@ -157,32 +158,26 @@ {{ "APPLICATION-TABLE.CATEGORY" | translate }} + {{ application.category ?? "-" }} - - - {{ "APPLICATION-TABLE.CONTROLLED-PROPERTIES" | translate }} - - - {{ mapControlledProperties(application.controlledProperties) ?? "-" }} - - - {{ "APPLICATION-TABLE.DEVICE-TYPES" | translate }} + {{ mapDeviceTypes(application.deviceTypes) ?? "-" }} - --> + + ½
-
- {{ currentPage + "/" + numberOfPages }} -
-
- + {{ currentPage + " / " + numberOfPages }}
+
diff --git a/src/app/shared/components/table-pagiantor.ts/table-paginator.component.scss b/src/app/shared/components/table-pagiantor.ts/table-paginator.component.scss index 290953e9d..cc9a51681 100644 --- a/src/app/shared/components/table-pagiantor.ts/table-paginator.component.scss +++ b/src/app/shared/components/table-pagiantor.ts/table-paginator.component.scss @@ -1,3 +1,5 @@ +@import "../../../../assets/scss/setup/variables"; + :host .main-container { display: flex; flex: 1; @@ -5,7 +7,7 @@ align-items: space; height: 50px; gap: 10px; - background-color: white; + background-color: $white; padding-top: 30px; padding-left: 20px; padding-right: 20px; @@ -13,13 +15,15 @@ } :host .pages-of { - height: 32px; - line-height: 10px; - border: 1px solid rgb(227, 224, 224); + height: 30px; + min-width: 64px; + line-height: 24px; + font-weight: 500; + border: 1px solid $default-neutral-color; border-radius: 3px; - padding: 0 15px; + font-size: 16px; - color: #404040; + color: $default-icon-color; display: flex; justify-content: center; align-items: center; @@ -29,7 +33,6 @@ height: 32px !important; min-width: 42px !important; width: 42px !important; - background-color: rgb(227, 224, 224) !important; display: flex; margin-left: 5px; margin-right: 5px; @@ -37,13 +40,10 @@ justify-content: center; } -:host .left-arrow { - margin-top: 8px; - margin-left: 5px; -} -:host .right-arrow { - margin-top: 10px; - margin-left: 1px; +:host .icon-arrow { + display: flex; + justify-content: center; + align-items: center; } :host .spacer { @@ -56,17 +56,17 @@ display: flex; align-items: center; font-size: 10px !important; - color: #737373 !important; + color: $selector-font-color !important; } :host .mat-mdc-option { font-size: 10px !important; - color: #737373 !important; + color: $selector-font-color !important; } :host .mat-mdc-select-value { font-size: 15px !important; - color: #737373 !important; + color: $selector-font-color !important; } :host .mat-mdc-text-field-wrapper { @@ -77,11 +77,33 @@ } :host .select-container { - min-width: 150px; + min-width: 250px; + flex-shrink: 0; } :host .button-container { display: flex; flex-direction: row; width: 100px; + flex-wrap: nowrap; + justify-content: center; +} + +:host .angle-down-selector-icon { + position: absolute; + z-index: 100 !important; + top: 20px; + right: 0px; +} + +:host .mat-mdc-select-arrow-wrapper { + display: none !important; +} + +:host .active-color { + background-color: $default-color !important; +} + +:host .inactive-color { + background-color: $default-neutral-color !important; } diff --git a/src/app/shared/components/table-pagiantor.ts/table-paginator.component.ts b/src/app/shared/components/table-pagiantor.ts/table-paginator.component.ts index 9e8fdf1ef..82a1892c3 100644 --- a/src/app/shared/components/table-pagiantor.ts/table-paginator.component.ts +++ b/src/app/shared/components/table-pagiantor.ts/table-paginator.component.ts @@ -1,4 +1,4 @@ -import { NgFor, NgOptimizedImage } from "@angular/common"; +import { NgClass, NgFor, NgOptimizedImage } from "@angular/common"; import { Component, Input, OnInit, ViewEncapsulation } from "@angular/core"; import { MatButtonModule } from "@angular/material/button"; import { MatOptionModule } from "@angular/material/core"; @@ -25,6 +25,7 @@ export interface Option { MatSelectModule, MatOptionModule, MatButtonModule, + NgClass, ], encapsulation: ViewEncapsulation.ShadowDom, }) diff --git a/src/app/shared/components/top-bar/top-bar.component.html b/src/app/shared/components/top-bar/top-bar.component.html index 9c56867a8..8483dd479 100644 --- a/src/app/shared/components/top-bar/top-bar.component.html +++ b/src/app/shared/components/top-bar/top-bar.component.html @@ -52,7 +52,7 @@
-
+ + @if(searchText){
diff --git a/src/app/shared/components/top-bar/top-bar.component.scss b/src/app/shared/components/top-bar/top-bar.component.scss index 0f5494fcd..d75d6ecac 100644 --- a/src/app/shared/components/top-bar/top-bar.component.scss +++ b/src/app/shared/components/top-bar/top-bar.component.scss @@ -1,3 +1,5 @@ +@import "../../../../assets/scss/setup/variables"; + .top-main-container { background-color: #ffff; display: flex; @@ -17,6 +19,12 @@ margin-bottom: 40px; } +@media (max-width: 768px) { + .bottom-main-container { + flex-direction: column; + } +} + :host .search-view { position: absolute; top: 70px; @@ -24,7 +32,7 @@ right: 0; height: 65%; z-index: 1000; - background-color: #ffff; + background-color: $white; } @media only screen and (max-width: 768px) { @@ -35,7 +43,7 @@ right: 0; height: 65%; z-index: 1000; - background-color: #ffff; + background-color: $white; } } @@ -43,21 +51,22 @@ height: 25px; width: 12px; color: #525252; - margin-right: 30px; - margin-left: 20px; + margin-right: 20px; + margin-left: 50px; } :host .plus-circle-icon { - height: 20px; - width: 16px; - color: #ffff; + height: 25px; + width: 20px; + color: $white; + margin-right: 20px; } :host .top-bar-profile-icon { display: flex; flex: 1; justify-content: end; - background-color: #ffff; + background-color: $white; } :host .top-bar-search { @@ -108,11 +117,11 @@ font-size: 12px; font-weight: 500; line-height: 16px; - color: #525252; + color: $default-color; } :host .profile-button { - background-color: #ffff; + background-color: $white; border-width: 0px; } @@ -123,7 +132,29 @@ border-color: transparent !important; } -:host .create-application-button { +:host .create-application-button-label { + font-size: 16px; + font-weight: 500; + color: $white; + line-height: 22px; + height: 20px; +} + +:host .create-application { + height: 40px; + border: none; + background-color: $color-primary; display: flex; + align-items: center; justify-content: start; + border-radius: 5px; + padding-right: 20px; + padding-left: 20px; +} + +:host .page-title { + font-size: 30px; + font-weight: 500; + line-height: 36px; + margin-bottom: 20px; } diff --git a/src/assets/images/angle-left.svg b/src/assets/images/angle-left.svg new file mode 100644 index 000000000..a0c8296ec --- /dev/null +++ b/src/assets/images/angle-left.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/angle-right.svg b/src/assets/images/angle-right.svg new file mode 100644 index 000000000..425fda302 --- /dev/null +++ b/src/assets/images/angle-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/images/arrow_back.png b/src/assets/images/arrow_back.png deleted file mode 100644 index d5eb274c231a96d4832b51d400bb773b272ac807..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 910 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGojKx9jP7LeL$-HD>VD|8IaSW-5 zdpkEhJ0wuVb#vX)E>=-)EwK=t6%hd&7bH0zZR%qE>hC5bn_ zf$E=iDpR;;2>$D8(c?R{l!@g>dBfM>E3Nx%G=von?B~7{k?~4;lD;62%^vff_1~+| ze;1B&e0a}%z3p82y^n073J2;LV&;e2dfHv{88;|G5xFsw>86$cv0 zH)l1QQOTcWK;`-ko1Mkq3#^|BRO0=hhqm^{Cac z`4J5a|CI}lY^-RXqb8(q;6IB@nZ^~<_KiR#^BbMlweEhhburKs@dpdMC!VY95dkXU zk}1%;rMW#9XwiPg-*dT2&Oen0dg%QDyYEeRKivkoh55$ouscdmK8FKMSKp8>*j0L_ zFcioZ-*9{52G^6EjQ{czt}haKH7lJ(WcEq_3C#>2EhaQ?P%vD+kZF(D>}O7ESX~q4 zcZw<=$ljQlcWmndjW^2M7qeFAnw@R&;qE$QcZ^HGKhRj!((RlJlMCm}Dfb-@9RV^T zrx`gN3IQ=@Z0&7X$=V^b$)vEmWhM)dVNu@PG7}_XQ|sHL;xJ_byGc~3w_w`UPaTsA z1h;1fJ37f-GM+HucnGh`6USU;&dksR1;w*gJSt0KdmCF!a*QTSn3l>WbZN_Z2d7(M zQXU?U!+?rnbAXC=^QtVV-P_pmr_p(13rB`(Lfg!(dJooL(e?Kf^LW9wZ*Bvpn^X7) zUDh`W3$1@_W7;7To$U_g#7B5`Y|1<2SbFNioG ZFRa&BaHv(}Brt<9c)I$ztaD0e0svj5fkyxU diff --git a/src/assets/images/arrow_forward.png b/src/assets/images/arrow_forward.png deleted file mode 100644 index dc450f13ff65ec911695ca59423b0969b0520e92..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 626 zcmV-&0*(ENP)Px%EJ;K`RCr$P-R(|;P!L7Y^5p81UxO{FwX{-5=gj%&A59FQ?!{ENfjFJ=f)<#d zd(X~K0RSHa0SExN0C@MAfB=9CfOnq>a0VD-e9piBG)+HW9bd2sxWxasME`O{fB^i7 zza03M2;~3|;@cvW0{j!-5}^!WV|+V=5`Y)uTOo7?m?7lL}&-#hR_ng z385{33qorE2ZZ(j>If77$_O+7st8m7iU@Q7Y6z47N(i(7DhSj73JCN7>TC;1ItpfJ^+A08a7S0l39) z1>hLJ4S;L>768ui;Q;ROp#X`0z8Z#H2`4^qDI)Q2SC2|3Ao1^)?#ciXe|_Dw1R(Jr zFIsm7D7!`c=$ihK?MndWH~8WdSi~TVqXux$VW04@ODeI_6P-~!;?X9B_)cBR+cGid|tZVx9{!t{R7^gA3k$4w=u8tI_JDz=RBXU$Nl*@lYG?CR)9~M z4}m}kKm;oy0)Ybmq7b~?;DbZ%Tmv6m;TDh!FL=fBo=pPZu_1&L;RuA_yX`kJTT>7R z8h2f?cE98teEw3@>9BK%sHi9%zo3iZKBq&@=>&)Q(!Uu?BM|Zk$m*~QxnOQEI;+U_ z7JDK1oRUJe0I$($euY2P*oZ54RFYCCFZlWdA2_BLKT4cKR0Ur2S>|LMuAP&=9yx;$ z@oNzIOO4LkJV8?Gd!~#$A}`EqZ*d&9D=*)wX_(r9FPUDh{kYDo`#xDPNeeNq{;$8Q`Doij+`>$}^H#b6LUl_eZ1I4uRc7m~pa4WJP(>Sa=+vx1+wrpvOuw7cD5hTSfq z0o&Dylez8!GTp@c;513cSh{M%E;BpZP|nx9gCMwkq)2V}$c%JdQ|lExbl{TAXWLbq zlan=<-n-`F%kHSt9D?i&KC8U@VEOP39`WjMxw*C(WyW6=M zcH_%jdisZhV0`5{?sL+k+-wWdI!Apk--_Y9MdOBk+EPcU8r1%IzF5w5BAed}_&q@AW~ala|i}qUETu>P{zNeBe;m*u~9t-{vw2AL^-$ z(w(|TQ%(5r&~AUxiX4tWut3P!l7hZH$d#x?E!2RdIqcHX^uA-(G*9y`?@#$Q-z#6v zH`~Gtw+{;g>u^BtyKt>3CyQBy*fbDn$DN_!F4S&qF+v|I?%I1Mu-7Xkkmbil_C*$$cAE+m-ISz;3 zVr_*>J-K8uv~iH#S*wzweLKlY75o+Gc&EXXK}s^Vsg9ehH?s1QgOWrH+pX+l5)3!p z;WHz0@_D`) zE6U!<99AT&-Yu1tzRd24LX?R8Jnyvn@Z`eo!#$)wp{wXNkt)X=#w!o3jLo~K$}>aA zf4JkXwAKZ6Bessmh+;XY>fAya-g>X#ipa?QHMKK3h)*g79gkyPUaM#b6dODdgM!8X zHl+!S6em?8@({5q?e5JpBkf{@3qey@0`csmaHL6~$3qM&l-4g+UKD*__2$vc@XXFz zjp*-bdyaw)Pcs^i#XDsenp^yBM$cgI8R|63Ki!E~x01G94OBCs(!7hKiwx}AJEaoe zokYw^`N@ob;p~?7LJ<7(Z~N>Jy@>pb+ir6MLt!W+hfV5tqu5h~QMI}Va5DGlB^|ta zb;BO+bl#+0ze|3D{XfD9K@oK3y`O2uu$jsSAJPul(P+W9a11zGB)k+WDWmA2yd z;TW*0#?g%hg0(|jN(xRsRXQE@P^QwI7QAH-^Yy2P{84yOk#RunT4ua6BX#tIu{!~F5#d3^ja|I*iSED)o`a#xAN9p^sY)x~g zi4E_x=l?FIt;I)tW>t-^)Cd~FD>$Ax%m%umoD{!|R#KW&hKS;$AC`A-$X#!uEKw5u zeuck$Lrq6V-Q4OGsQrvA>=GT(|IL;DQ-NLHp4s#MI_oyelJ=b=DJnR1!tuhx zQEE_qFZa4=;deQ~S#Q!~`aaz9uUvc=OQv}kbHPqa<@IHGh&b+`=;@amR2Y%&&7QN= z1cG#Kx82L?ak}U!sjw~}ZU;K`{3vWT}XLz53vv&YnNo6lF|6oBnCVyC?L= z2PsCBU-yoKsNpu^s!3fGc-^&v9!axto2@6nomfGh2}E30@N{Bw6D1v`L=?A#8IDUf z>~+@3W`k9ShCvq3{9HT)!+C_7%FTVv!xChapamW8I;xEam?yunJhXfdvFE#-Wekl1wOpQ~-~x zA~C82YntkAI=}n}YlG^Z5&fyT1w+Ai_4BexB$W^@z1?}J9T&p~8o-Q#*vHv!Ec?JT zfQWq+V)K6NQkLBvGt1Xp1KhE)dHJT+5X_|~ZHUc7KU8(<*zyV01$pGv%ut4=U22h% zqJDisU|z#;FZ=dZZSK zdfR}I@zA?6f8F8mW&s>jS`0S}emyGK>d3VyGAMk3_ox^fo2%-ivvG;TF3Z7I|! z1^}kv_4zlkQxhK9H8Ad>Q#@1nw*fByWo2`b{rR&J!(Tb`#aFDFs)X( zJ+7^|^_gwQxt(F=Vrr#hXz0arIry?ej$AS7+tfH&MGOGUNRlIAKw|B_ms{ZksIhXd zG(c6H-)$f4h>H~j`;U5L1>bQ<>gV-U1}jpuTygAZ05SITh4C*(YXt7$8}?xHc#i0p zWFR%E{nT~JOI9pNy+Y<6g;|z?h?Eext7vL9s$U}Sd&xuekolhv@KE+8_3E z-U((L{uuYeEO-6}li@`*dQV>tH;+mi!$WN1R&z`z2lwbPVkeRrM}G&%y3v!iIyI6rRfTke+&NL zoL)5fTOy<#dR%oQp4W;=-BK@=V%o3eb5PD<%6O=~(bRm+rdqtm#LXh(lGslbf)~AQ ze0!hNR)x6C%crUWz8(^Gck1gi&f3;8?i<|Rih+r>3Lg4?8)8$E1n1wnrah`3s1^UOMHy>b*BWP}cjy_ZjYs_l&3D+lu0f7rw;@KzIe(YgtL|Fo9+9no1 zug>-&!NuvS9manHpIp|g44|MUfKAAgBC0j+xjdYk-28o2A=KJ#!8{@Gd zx@?tzO?bacb^GfHp^@WNea~?r{1r|uhkbMqRostxs;(QB;3HD{0Xk)rOl0@#(`sjY z&Im|_BjG*8I>pOXADi_<7jOY-8qE> zMShBjol~)bH(uuIi)Vw>GlNL7fqnwy-zB!cdKKNGX+q_`MOb;k3J{cP8gEwb%dLZdEfe=++(ll+l>MaO~t@SV{k{(JPn{iicV| zvVN^SP_%1HtwfLy{k!kxtpds9Q0=rm1OTRQ|FbK1@4MZC_W3xUo9_ISga2vlAU5R| zn!nvJ1hA@)lIAxS48Z+oO4h9Wb}?uSTOa?^e|U-Y&1%IfIf93DV17BH5s1pZ8xukI zO$CLLu1|eWdU5o|>eL5iE7S6$@S*n^U`p>Z7zbmRV!yaoY##mvaJyS1lIzA|WHCM> zZx`51a9(N-#LjywGLP=Myp-I)>QCZa1siYfV*S&eNnq!JSyF7Vb#m9w2B7G4&sI48wng2`@h?xb) zV^A5lPsX4Q{MdgtN){1I3*id6^wPUUiu(vA5>?g4*{7`j#}efWUb#!px*C5V5&V^1945I7yY?h{{($UkQagS+WvB^q&-!Z>N{RmZudh9qQe@c6Ezq2E# zN4wiTd|7#XH^vupNkreK*)_2Vn|=xpY51$G=ASYH83D@Ks(>ByyB8;hU)x?^M+kHcXL9M)2A>Pz^Z`@J^K zD9#S#)+#V#4cOu&@}kzrAPaqK>GDBYCF3w4enf8`&e4*CKhf!k1nwKD1z*(IR%`=I z_>AhnxeR<6%(UoL>2>Ncndf60l02_R-{3xvkVLk*$(LUAXtDG-I{8)wUuO4;dX4I3 z?{t>M%^v1;`yNhRWf4ic=0!(x)@al`ePJGCaPgt){x66p3bC825b@k@9?r4N@|Wrh zQ+KmZ!Hlp?>SF41>>i%)M0?o(EIveX9CzXND7O6hNCv3)t8iUp>f^M((K4nS*dBHf z_^-zA@Q~||bIk@l8ckiS zikt_U5b=+=oW<0tlu*pbM=a3rnH}{|{C#?m>zSSLGrG{Uu&QuXjrL%yy^Y+6`)R<7 z%?d13v%y!<1>?eRs?aoP6sud89rXU-=oePuo)j>b!8mbuVBZw%UE^(Ax3w+@21Tl# zK+Ubi)I-)Sn6wl(4G7Mk#Itub8_Y>Pz-Qb!Ap?pW`YUQC^&{48?$@rbe!wKELuSIhYQSWavZ<-xQmKHA z9TLKy?#x3MSdj~WZL3J>{kBd_oxNNyEg4H7aFJg-!2w1e3X3# zq!h-PBB?ffbVlkTHSwx<7z8&695*+p*j-_ux0{R}DY#Nz z&{r+mBSbFeSb_Di;K{Mgl;{H?%JZ@(6Rw)>B&*KrvaUL7x#zog(Unnu(rT4hlrR6WYn>eJvt~yjLq5i3vXz)Smnh6Tk=`3+qnYs&8s!C zD|{on;vGGZ2?7uO04-kC<+6h{#=nf!O`9p&pQl≪zw7z0sUe0FZxCa8ds+4@%(k zvsLE?X~93jClYMZ-fdH4Kj6i9E3*0%yH}Ja@DuKI#M|d*RiO6sGIq?ysDpZ1_QxNs z?p^g?7&>wgf?q(nH%mua6@Gba&P^-M;%?rP1?C}ONw?k<Va@+p!lC$q{?)%T+f(W86=o4H?npICZ= zvYx?08)0r2yZD`%kImNwWovjQa)Os#N$XEEI(j?2wM%9aby-!qHg|sANcZoRgMs{7 z_`zt5E+QfOLO|JvZnQl`m3oaLuuY8^)?J!GVmd}edGiEO!%Rg+r&Bx^<(pGTW3-;+ z^Aw7`9r73wE!&CcM@x#Cek@a}mq(1vjc}$3pKD;~jw+ zNqdljvjfMvGlw0p8Cxy@Y}1G^L#o)yIBU#R0mqP077aO6YG*jfrM^UfYOCZ$Cq4?8 zY>L2wq%aivi;_HonqqiJGV@$|d)moF367{~u7^jAVzQRP>k7>>(;TET#dS_ld`6J9 zr)Q(fIK5+FLg>eE4`JFWlM>Y^r3TEt8p0^Swf!ew?brOmqE45lCMkS3>dv>z414X1Y@v^n{g|Ho{U^OGsF%ip{_xNSIso^=j@Nv|ty z_Y9uG;=4H;jFOc0a35_%eu!N@$Ic=6CcrNFGUa12L4Ya?wg<4c1e~h>6^9F7Io7mo zO^O^fIISd~zTukrkf%{_qu0s_RhtEFkirSO9^MNPwdjUd=nB4-Fve3xxfC?^)@IK(pCg!p#=@b-Wqd=PF{osj!}+5u<@-yQ*@GS)N(Dn&L%a(T1OHtZ&JU-a@mMhO#x^8pUM) z4$Qo;G0u9K+?WHH%^jtMk}X-qWk7#>n%8*cXq+Dhg;iTdmE-V-+!Q<%vcnJ8FI_)@ zi_jM#=e&qmBUA<8A;npnUdz6TpKk+t8KEM6GaW*+8JfEw*gH~e3ODey_gV5x9Rf%2 zps#OZXSfSr2(|^~KB`xw!Z)Zx^R7vr0Y^9;{zwr2G>|(4W9Aw)X`JW0l zBwQD)h_8!c`6==2T2`Lct-xO1`V#AdOIt4g7QH(4s(uIQY|AV&lCK+EaBEO^{FC&hBk;g)db5~o_L;?BSnhBY1lXWEFI}7 z)-)4t;B90nyW|B3qal;|vKh;P7MuR5OnZo8ltZ#|b42>}WPr1+1#TIFNQf-;TkR(n^z6~PDoMv`V z;;3leb=>Sx5|jQ+u&1a(7$E60(<7^z6Dkdp*Ny}4tofG1YGW_0MncN;T^|ss7Wew< zwfo!fxQkSJcc(YZX!quMSQ4xB$cKXpmW%lS#PF)K+PWXfYjpN_3h)=R$BdPqU_+1n z_E2J&7ORaXuhpdZ7e<0-JNBOsb7qIoELHFswQ-*be7Qj<5XcGB3t~*Gxf2YCj{Amx4Xfnq=0Igmv*e9zP0Emic zi$fOJ`WlM@3rXb!fDAHjUVfZ@DaD<)K={E?@Yu4Iz}DLKaUyU0gFKJ?*NSp>Kr(IL z$nkH8=gHRU!T5+PZ>Yhj8TH}MJYsPy8TP-vR>!QhJFm+R@<;?NZe!WW6#>YxSBj0V zca4SYx@pkP>@ zq#;&a?*Hnu@g3ev{on@!VcWk2_^(==|KGu5vbPYH8-;TAp>mbr>B|2A D_WC!G diff --git a/src/assets/images/sliders.svg b/src/assets/images/sliders.svg new file mode 100644 index 000000000..2b194a963 --- /dev/null +++ b/src/assets/images/sliders.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/scss/setup/_variables.scss b/src/assets/scss/setup/_variables.scss index f8d7a82ce..146d6ba12 100644 --- a/src/assets/scss/setup/_variables.scss +++ b/src/assets/scss/setup/_variables.scss @@ -187,7 +187,7 @@ $color-purple-002: rgba(81, 45, 109, 0.75) !default; $color-purple-003: rgba(81, 45, 109, 0.5) !default; $color-purple-004: rgba(81, 45, 109, 0.25) !default; -$color-orange-001: rgba(245, 122, 47, 1) !default; +$color-orange-001: #c2410c !default; $color-orange-002: rgba(245, 122, 47, 0.75) !default; $color-orange-003: rgba(245, 122, 47, 0.5) !default; $color-orange-004: rgba(245, 122, 47, 0.25) !default; @@ -384,12 +384,12 @@ $red: #dc3545; overflow-y: hidden; } } - $alert-color: #991b1b; $stable-color: #047857; $warning-color: #fde047; $default-color: #525252; +$default-neutral-color: #d4d4d4; $default-icon-color: #404040; $selector-font-color: #737373; From f4ca57b3c026b4ab3b49768d656da111878d171b Mon Sep 17 00:00:00 2001 From: Lauest Date: Thu, 13 Feb 2025 13:46:29 +0100 Subject: [PATCH 10/16] pr --- .../applications-table.component.html | 78 +++++++++++++------ .../applications-table.component.scss | 14 +++- 2 files changed, 67 insertions(+), 25 deletions(-) diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.html b/src/app/applications/applications-list/applications-table/applications-table.component.html index 4c3253f30..5ab09d7f2 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.html +++ b/src/app/applications/applications-list/applications-table/applications-table.component.html @@ -19,7 +19,9 @@ > - {{ "APPLICATION-TABLE.STATUS" | translate }} +
+ {{ "APPLICATION-TABLE.STATUS" | translate }} +
@@ -29,20 +31,26 @@ - {{ "APPLICATION-TABLE.STATE" | translate }} +
+ {{ "APPLICATION-TABLE.STATE" | translate }} +
- +
+ +
- {{ "APPLICATION-TABLE.NAME" | translate }} +
+ {{ "APPLICATION-TABLE.NAME" | translate }} +
@@ -59,7 +67,9 @@ - {{ "APPLICATION-TABLE.CONTROLLED-PROPERTIES" | translate }} +
+ {{ "APPLICATION-TABLE.CONTROLLED-PROPERTIES" | translate }} +
@@ -74,7 +84,9 @@ - {{ "APPLICATION-TABLE.IOT-DEVICES" | translate }} +
+ {{ "APPLICATION-TABLE.IOT-DEVICES" | translate }} +
@@ -84,7 +96,9 @@ - {{ "APPLICATION-TABLE.OWNER" | translate }} +
+ {{ "APPLICATION-TABLE.OWNER" | translate }} +
@@ -95,8 +109,10 @@ - - {{ "APPLICATION-TABLE.CONTACT-PERSON" | translate }} + +
+ {{ "APPLICATION-TABLE.CONTACT-PERSON" | translate }} +
@@ -105,8 +121,10 @@
- - {{ "APPLICATION-TABLE.DATA-TARGETS" | translate }} + +
+ {{ "APPLICATION-TABLE.DATA-TARGETS" | translate }} +
@@ -115,8 +133,12 @@
- - {{ "APPLICATION-TABLE.OPEN-DATA-DK" | translate }} + +
+ {{ "APPLICATION-TABLE.OPEN-DATA-DK" | translate }} +
@@ -125,8 +147,10 @@
- - {{ "APPLICATION-TABLE.PERSONAL-DATA" | translate }} + +
+ {{ "APPLICATION-TABLE.PERSONAL-DATA" | translate }} +
@@ -137,7 +161,9 @@ - {{ "APPLICATION-TABLE.START-DATE" | translate }} +
+ {{ "APPLICATION-TABLE.START-DATE" | translate }} +
@@ -147,7 +173,9 @@ - {{ "APPLICATION-TABLE.END-DATE" | translate }} +
+ {{ "APPLICATION-TABLE.END-DATE" | translate }} +
@@ -157,7 +185,9 @@ - {{ "APPLICATION-TABLE.CATEGORY" | translate }} +
+ {{ "APPLICATION-TABLE.CATEGORY" | translate }} +
@@ -167,7 +197,9 @@ - {{ "APPLICATION-TABLE.DEVICE-TYPES" | translate }} +
+ {{ "APPLICATION-TABLE.DEVICE-TYPES" | translate }} +
@@ -177,7 +209,7 @@ - ½ + + - test + {{ getOrgName(selected) }}
- {{ org.name + "www" }} + {{ org.name }} diff --git a/src/app/navbar/navbar.component.ts b/src/app/navbar/navbar.component.ts index 167d14a04..f53bc0d75 100644 --- a/src/app/navbar/navbar.component.ts +++ b/src/app/navbar/navbar.component.ts @@ -132,7 +132,9 @@ export class NavbarComponent implements OnInit { } this.setLocalPermissionCheck(userInfo.organizations[0]?.id); } - + getOrgName(id: number) { + return this.organisations.find(org => org.id === id).name ?? ""; + } private setLocalPermissionCheck(orgId: number) { this.isUserAdmin = this.meService.hasAccessToTargetOrganization( OrganizationAccessScope.UserAdministrationWrite, From f0ae23b3e499a3679dd9b342e027f279a27fc6f1 Mon Sep 17 00:00:00 2001 From: Lauest Date: Fri, 14 Feb 2025 11:33:59 +0100 Subject: [PATCH 12/16] changes from pr --- .../application-map.component.html | 12 +--- .../application-map.component.scss | 14 ++++- .../application-map.component.ts | 53 ++++++++++++++---- ...applications-list-dashboard.component.html | 2 +- .../applications-list-dashboard.component.ts | 4 +- .../applications-list.component.html | 11 ++-- .../applications-list.component.ts | 31 +++++----- .../applications-table.component.html | 3 +- .../applications-table.component.scss | 1 + .../applications-table.component.ts | 2 +- .../applications-routing.module.ts | 3 +- src/app/applications/applications.module.ts | 2 +- .../global-admin/global-admin.component.scss | 5 +- .../global-admin/global-admin.component.ts | 10 +--- src/app/navbar/navbar.component.html | 5 -- src/app/navbar/navbar.component.scss | 7 +-- src/app/navbar/navbar.component.ts | 37 +----------- src/app/search/search-table.component.ts | 20 ++++++- .../basic-information-box.component.html | 4 +- .../basic-information-box.component.scss | 2 +- .../basic-information-box.component.ts | 19 +++---- .../basic-tap-switch.component.html | 12 ++-- .../basic-tap-switch.component.ts | 32 +++++------ .../components/map/map-coordinates.model.ts | 3 +- .../shared/components/map/map.component.ts | 52 ++++++++++++----- ...component.ts => option-field.component.ts} | 8 ++- .../status-icon/status-icon.component.html | 4 +- .../status-icon/status-icon.component.scss | 4 ++ .../status-icon/status-icon.component.ts | 24 +++++++- .../table-paginator.component.scss | 3 +- .../table-paginator.component.ts | 18 ++---- src/app/shared/types/table.type.ts | 2 +- src/assets/i18n/da.json | 6 +- src/assets/images/alert-device-pin.svg | 13 +++++ src/assets/images/alert-gateway-pin.svg | 12 ++++ src/assets/images/stable-device-pin-r.png | Bin 0 -> 18794 bytes src/assets/images/stable-device-pin.png | Bin 0 -> 18784 bytes src/assets/images/stable-device-pin.svg | 13 +++++ src/assets/images/stable-gateway-pin.svg | 42 ++++++++++++++ 39 files changed, 302 insertions(+), 193 deletions(-) rename src/app/shared/components/option-field/{option-fieldcomponent.ts => option-field.component.ts} (89%) create mode 100644 src/assets/images/alert-device-pin.svg create mode 100644 src/assets/images/alert-gateway-pin.svg create mode 100644 src/assets/images/stable-device-pin-r.png create mode 100644 src/assets/images/stable-device-pin.png create mode 100644 src/assets/images/stable-device-pin.svg create mode 100644 src/assets/images/stable-gateway-pin.svg diff --git a/src/app/applications/applications-list/application-map/application-map.component.html b/src/app/applications/applications-list/application-map/application-map.component.html index 7fd47dda1..ac32fa940 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.html +++ b/src/app/applications/applications-list/application-map/application-map.component.html @@ -1,15 +1,5 @@
@if(coordinateList){ - + } -
-
- -
{{ "APPLICATION-INFORMATION-BOX.DEVICES" | translate }}
-
-
- -
{{ "APPLICATION-INFORMATION-BOX.GATEWAYS" | translate }}
-
-
diff --git a/src/app/applications/applications-list/application-map/application-map.component.scss b/src/app/applications/applications-list/application-map/application-map.component.scss index a566205c3..3ce8b2c05 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.scss +++ b/src/app/applications/applications-list/application-map/application-map.component.scss @@ -1,3 +1,5 @@ +@import "../../../../assets/scss/setup/variables"; + :host .map-page { background-color: #ffffff; padding: 20px; @@ -6,9 +8,9 @@ } :host .map-overlay { - height: 89px; + height: 50px; width: 132px; - background-color: #ffffff; + background-color: $white; position: absolute; bottom: 30px; left: 30px; @@ -24,3 +26,11 @@ flex-direction: row; align-items: center; } + +.mdc-checkbox__background { + background-color: $white !important; +} + +.mdc-checkbox { + background-color: $white !important; +} diff --git a/src/app/applications/applications-list/application-map/application-map.component.ts b/src/app/applications/applications-list/application-map/application-map.component.ts index 63271dbdd..cd8a9eb00 100644 --- a/src/app/applications/applications-list/application-map/application-map.component.ts +++ b/src/app/applications/applications-list/application-map/application-map.component.ts @@ -1,12 +1,14 @@ import { Component, OnDestroy, OnInit } from "@angular/core"; import { MatCheckboxModule } from "@angular/material/checkbox"; +import { Gateway } from "@app/gateway/gateway.model"; import { ApplicationService } from "@applications/application.service"; import { ApplicationStatus, ApplicationStatusCheck } from "@applications/enums/status.enum"; import { IotDevice } from "@applications/iot-devices/iot-device.model"; import { TranslateService } from "@ngx-translate/core"; import { MapCoordinates } from "@shared/components/map/map-coordinates.model"; +import { ChirpstackGatewayService } from "@shared/services/chirpstack-gateway.service"; import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; -import { Subscription } from "rxjs"; +import { forkJoin, Subscription } from "rxjs"; import { SharedModule } from "../../../shared/shared.module"; import { ApplicationsFilterService } from "../application-filter/applications-filter.service"; @@ -19,6 +21,7 @@ import { ApplicationsFilterService } from "../application-filter/applications-fi }) export class ApplicationMapComponent implements OnInit, OnDestroy { public devices: IotDevice[] = []; + public gateways: Gateway[] = []; public device: boolean = true; public gateway: boolean = true; filterValues: { @@ -32,11 +35,13 @@ export class ApplicationMapComponent implements OnInit, OnDestroy { private filterService: ApplicationsFilterService, private applicationService: ApplicationService, public translate: TranslateService, - private sharedVariableService: SharedVariableService + private sharedVariableService: SharedVariableService, + private gatewayService: ChirpstackGatewayService ) {} ngOnInit() { - this.getApplications(); + this.loadMapData(); + this.valueSubscription = this.filterService.filterChanges$.subscribe(updatedValues => { this.filterValues = updatedValues; }); @@ -50,7 +55,7 @@ export class ApplicationMapComponent implements OnInit, OnDestroy { coordinateList: MapCoordinates[] = null; - private mapDevicesToCoordinateList() { + private mapToCoordinateList() { const tempCoordinateList: MapCoordinates[] = []; if (Array.isArray(this.devices)) { @@ -77,15 +82,41 @@ export class ApplicationMapComponent implements OnInit, OnDestroy { }); } + if (Array.isArray(this.gateways)) { + this.gateways.forEach(gw => { + tempCoordinateList.push({ + longitude: gw.location.longitude, + latitude: gw.location.latitude, + draggable: false, + editEnabled: false, + useGeolocation: false, + markerInfo: { + internalOrganizationName: "s", + name: gw.name, + active: true, + id: gw.id, + isDevice: false, + isGateway: true, + internalOrganizationId: this.sharedVariableService.getSelectedOrganisationId(), + networkTechnology: "loRaWAN", + lastActive: undefined, + }, + }); + }); + } + this.coordinateList = tempCoordinateList; } - getApplications(): void { - this.applicationService - .getApplicationDevices(this.sharedVariableService.getSelectedOrganisationId()) - .subscribe(data => { - this.devices = data; - this.mapDevicesToCoordinateList(); - }); + loadMapData(): void { + forkJoin({ + devices: this.applicationService.getApplicationDevices(this.sharedVariableService.getSelectedOrganisationId()), + gateways: this.gatewayService.getForMaps(), + }).subscribe(({ devices, gateways }) => { + this.devices = devices; + this.gateways = gateways.resultList; + + this.mapToCoordinateList(); + }); } } diff --git a/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.html b/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.html index 91851716f..416b2f040 100644 --- a/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.html +++ b/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.html @@ -30,7 +30,7 @@ [width]="25" [matSVGSrc]="'satellite-dish'" [type]="'default'" - [count]="gateways" + [count]="totalGateways" [description]="'APPLICATION-INFORMATION-BOX.GATEWAYS' | translate" />
diff --git a/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.ts b/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.ts index 8ebae0bf3..6cb697862 100644 --- a/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.ts +++ b/src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.ts @@ -15,7 +15,6 @@ import { BasicInformationBoxComponent } from "../../../shared/components/basic-i styleUrl: "./applications-list-dashboard.component.scss", }) export class ApplicationsListDashboardComponent implements OnInit { - gateways: number = 0; total: number = 0; withError: number = 0; withoutError: number = 0; @@ -55,12 +54,11 @@ export class ApplicationsListDashboardComponent implements OnInit { ); } ngOnInit(): void { - this.gatewayService.getMultiple().subscribe(data => (this.gateways = data.totalCount)); this.applicationService .getApplicationsWithError(this.sharedVariableService.getSelectedOrganisationId()) .subscribe(data => { this.withError = data.withError; - this.totalDevices = data.withError; + this.totalDevices = data.totalDevices; this.withoutError = data.total - data.withError; this.total = data.total; }); diff --git a/src/app/applications/applications-list/applications-list.component.html b/src/app/applications/applications-list/applications-list.component.html index 7591b95cc..9c6521cb0 100644 --- a/src/app/applications/applications-list/applications-list.component.html +++ b/src/app/applications/applications-list/applications-list.component.html @@ -25,15 +25,12 @@

{{ "WELCOME-DIALOG.NO-ACCESS" | translate }}

- - @switch (index) { @case (1) { - + + @if(router.url === mapRoute){ - } @default { - + } @if(router.url === listRoute){ - - } } + }
diff --git a/src/app/applications/applications-list/applications-list.component.ts b/src/app/applications/applications-list/applications-list.component.ts index 85924988c..3f468357d 100644 --- a/src/app/applications/applications-list/applications-list.component.ts +++ b/src/app/applications/applications-list/applications-list.component.ts @@ -2,14 +2,14 @@ import { Component, Input, OnInit } from "@angular/core"; import { MatDialog } from "@angular/material/dialog"; import { MatIconRegistry } from "@angular/material/icon"; import { DomSanitizer, Title } from "@angular/platform-browser"; -import { ActivatedRoute, Router } from "@angular/router"; +import { ActivatedRoute, NavigationEnd, Router } from "@angular/router"; import { UserMinimalService } from "@app/admin/users/user-minimal.service"; import { NavbarComponent } from "@app/navbar/navbar.component"; import { ApplicationService } from "@applications/application.service"; import { AuthService } from "@auth/auth.service"; import { environment } from "@environments/environment"; import { TranslateService } from "@ngx-translate/core"; -import { Counter, Tap } from "@shared/components/basic-tap-switch/basic-tap-switch.component"; +import { Counter, Tab } from "@shared/components/basic-tap-switch/basic-tap-switch.component"; import { WelcomeDialogComponent } from "@shared/components/welcome-dialog/welcome-dialog.component"; import { OrganizationAccessScope } from "@shared/enums/access-scopes"; import { WelcomeDialogModel } from "@shared/models/dialog.model"; @@ -26,14 +26,15 @@ const welcomeDialogId = "welcome-dialog"; }) export class ApplicationsListComponent implements OnInit { currentSubPath: string = ""; - taps: Tap[]; + tabs: Tab[]; - index = 0; isLoadingResults = true; public pageLimit = environment.tablePageSize; public resultsLength: number; public pageOffset = 0; + mapRoute = "/applications/map"; + listRoute = "/applications"; @Input() organizationId: number; canEdit: boolean; @@ -43,8 +44,7 @@ export class ApplicationsListComponent implements OnInit { hasSomePermission: boolean; isGlobalAdmin = false; - applicationWithError = 0; - totalApplication = 0; + currentPath = ""; constructor( public translate: TranslateService, @@ -53,8 +53,8 @@ export class ApplicationsListComponent implements OnInit { private meService: MeService, private sharedVariableService: SharedVariableService, private authService: AuthService, - private route: ActivatedRoute, - private router: Router, + public route: ActivatedRoute, + public router: Router, private dialog: MatDialog, private userMinimalService: UserMinimalService, private matIconRegistry: MatIconRegistry, @@ -101,18 +101,25 @@ export class ApplicationsListComponent implements OnInit { counters.push({ color: "alert", value: data.withError.toString() }); } - this.taps = [ + this.tabs = [ { title: "Applikationer", icon: { matSVGSrc: "layers-tap", height: 16, width: 16 }, counters: counters, + uri: this.listRoute, }, - { title: "Kort", icon: { matSVGSrc: "map-tap", height: 17, width: 18 } }, + { title: "Kort", icon: { matSVGSrc: "map-tap", height: 17, width: 18 }, uri: this.mapRoute }, ]; }); // Authenticate user this.verifyUserAndInit(); + + this.router.events.subscribe(event => { + if (event instanceof NavigationEnd) { + this.currentPath = event.url; + } + }); } verifyUserAndInit() { @@ -208,8 +215,4 @@ export class ApplicationsListComponent implements OnInit { this.isLoadingResults = false; }); } - - onNewSwitchIndex(index: number) { - this.index = index; - } } diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.html b/src/app/applications/applications-list/applications-table/applications-table.component.html index 5ab09d7f2..8adf062c4 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.html +++ b/src/app/applications/applications-list/applications-table/applications-table.component.html @@ -40,7 +40,7 @@
@@ -73,7 +73,6 @@ -
@for (property of application.controlledProperties; track $index) { diff --git a/src/app/applications/applications-list/applications-table/applications-table.component.scss b/src/app/applications/applications-list/applications-table/applications-table.component.scss index 2136d7e6d..3c1d07ea9 100644 --- a/src/app/applications/applications-list/applications-table/applications-table.component.scss +++ b/src/app/applications/applications-list/applications-table/applications-table.component.scss @@ -60,6 +60,7 @@ .column-title-color { color: $color-link; + font-weight: bold; } .column-title-color-inactive { 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 8b8075ee8..4e0890f05 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 @@ -164,7 +164,7 @@ export class ApplicationsTableComponent implements AfterViewInit, OnInit { } announceSortChange(event: { active: string; direction: string }) { - this.columnDefinitions.find(column => column.id === event.active).sort = event.direction as "acs" | "desc"; + this.columnDefinitions.find(column => column.id === event.active).sort = event.direction as "asc" | "desc"; } ngAfterViewInit() { // If the user changes the sort order, reset back to the first page. diff --git a/src/app/applications/applications-routing.module.ts b/src/app/applications/applications-routing.module.ts index a9f0a0020..1e36fb9c8 100644 --- a/src/app/applications/applications-routing.module.ts +++ b/src/app/applications/applications-routing.module.ts @@ -16,6 +16,7 @@ import { DatatargetDetailComponent } from "./datatarget/datatarget-detail/datata import { DatatargetEditComponent } from "./datatarget/datatarget-edit/datatarget-edit.component"; import { DatatargetLogComponent } from "./datatarget/datatarget-log/datatarget-log.component"; import { DatatargetNewComponent } from "./datatarget/datatarget-new/datatarget-new.component"; +import { DatatargetTestConnectionComponent } from "./datatarget/datatarget-test-connection/datatarget-test-connection.component"; import { FiwareDetailComponent } from "./datatarget/fiware/fiware-detail/fiware-detail.component"; import { HttppushDetailComponent } from "./datatarget/httppush/httppush-detail/httppush-detail.component"; import { MqttDetailComponent } from "./datatarget/mqtt/mqtt-detail/mqtt-detail.component"; @@ -23,7 +24,6 @@ import { IoTDeviceDetailComponent } from "./iot-devices/iot-device-detail/iot-de import { IotDeviceEditComponent } from "./iot-devices/iot-device-edit/iot-device-edit.component"; import { MulticastDetailComponent } from "./multicast/multicast-detail/multicast-detail.component"; import { MulticastEditComponent } from "./multicast/multicast-edit/multicast-edit.component"; -import { DatatargetTestConnectionComponent } from "./datatarget/datatarget-test-connection/datatarget-test-connection.component"; const applicationRoutes: Routes = [ { @@ -31,6 +31,7 @@ const applicationRoutes: Routes = [ component: ApplicationsComponent, children: [ { path: "", component: ApplicationsListComponent }, + { path: "map", component: ApplicationsListComponent }, { path: "new-application", component: ApplicationEditComponent }, { path: "edit-application/:id", component: ApplicationEditComponent }, { diff --git a/src/app/applications/applications.module.ts b/src/app/applications/applications.module.ts index 71016f316..f1c420b43 100644 --- a/src/app/applications/applications.module.ts +++ b/src/app/applications/applications.module.ts @@ -7,7 +7,7 @@ import { TranslateModule } from "@ngx-translate/core"; import { BasicInformationBoxComponent } from "@shared/components/basic-information-box/basic-information-box.component"; import { BasicTapSwitchComponent } from "@shared/components/basic-tap-switch/basic-tap-switch.component"; import { FormModule } from "@shared/components/forms/form.module"; -import { OptionFieldComponent } from "@shared/components/option-field/option-fieldcomponent"; +import { OptionFieldComponent } from "@shared/components/option-field/option-field.component"; import { StatusIconComponent } from "@shared/components/status-icon/status-icon.component"; import { TablePaginatorComponent } from "@shared/components/table-pagiantor.ts/table-paginator.component"; import { TableSortIconComponent } from "@shared/components/table-sort-icon/table-sort-icon.component"; diff --git a/src/app/navbar/global-admin/global-admin.component.scss b/src/app/navbar/global-admin/global-admin.component.scss index 96a8e631f..545b7387c 100644 --- a/src/app/navbar/global-admin/global-admin.component.scss +++ b/src/app/navbar/global-admin/global-admin.component.scss @@ -20,12 +20,9 @@ button:focus, padding: 10px 15px; font-weight: 500; border-radius: 3px; - margin-left: 10px; - margin-right: 10px; height: 33px; line-height: 14px; - margin-top: 2px; - margin-bottom: 2px; + margin: 2px 10px; &:hover, &.link-hover, diff --git a/src/app/navbar/global-admin/global-admin.component.ts b/src/app/navbar/global-admin/global-admin.component.ts index dec1dbb46..90e64127f 100644 --- a/src/app/navbar/global-admin/global-admin.component.ts +++ b/src/app/navbar/global-admin/global-admin.component.ts @@ -1,9 +1,7 @@ import { Component, OnInit } from "@angular/core"; -import { PermissionType } from "@app/admin/permission/permission.model"; import { UserResponse } from "@app/admin/users/user.model"; -import { faGlobe, faUsers, faIdBadge, faSitemap, faUser } from "@fortawesome/free-solid-svg-icons"; -import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; import { MeService } from "@shared/services/me.service"; +import { SharedVariableService } from "@shared/shared-variable/shared-variable.service"; @Component({ selector: "app-global-admin", @@ -11,12 +9,6 @@ import { MeService } from "@shared/services/me.service"; styleUrls: ["./global-admin.component.scss"], }) export class GlobalAdminComponent implements OnInit { - faGlobe = faGlobe; - faUsers = faUsers; - faIdBadge = faIdBadge; - faSitemap = faSitemap; - faUser = faUser; - public user: UserResponse; public isGlobalAdmin = false; diff --git a/src/app/navbar/navbar.component.html b/src/app/navbar/navbar.component.html index 808f43c28..297ff5d60 100644 --- a/src/app/navbar/navbar.component.html +++ b/src/app/navbar/navbar.component.html @@ -35,11 +35,6 @@ [ngClass]="{ collapse: !isCollapsed }" >