Skip to content

Commit 32140cc

Browse files
Merge pull request #198 from OS2iot/feature/Application-overview-feedback-changes
Feature/application overview feedback changes
2 parents 2d6302f + a32a259 commit 32140cc

25 files changed

+432
-337
lines changed

src/app/applications/application-detail/application-detail.component.ts

Lines changed: 62 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { SharedVariableService } from "@shared/shared-variable/shared-variable.s
1919
import { Observable, Subscription } from "rxjs";
2020
import { map } from "rxjs/operators";
2121
import { ApplicationChangeOrganizationDialogComponent } from "../application-change-organization-dialog/application-change-organization-dialog.component";
22+
import moment from "moment/moment";
2223

2324
@Component({
2425
selector: "app-application",
@@ -53,12 +54,12 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI
5354
public canEdit = false;
5455
public devices: IotDevicesApplicationMapResponse[];
5556
public coordinateList = [];
56-
private deviceSubscription: Subscription;
57-
private gatewaysSubscription: Subscription;
5857
public gateways: Gateway[];
5958
public redMarker = "/assets/images/red-marker.png";
6059
public greenMarker = "/assets/images/green-marker.png";
6160
public greyMarker = "/assets/images/grey-marker.png";
61+
private deviceSubscription: Subscription;
62+
private gatewaysSubscription: Subscription;
6263

6364
constructor(
6465
private applicationService: ApplicationService,
@@ -125,6 +126,57 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI
125126
});
126127
}
127128

129+
onDeleteApplication() {
130+
this.deleteDialogService.showApplicationDialog(this.application).subscribe(response => {
131+
if (response) {
132+
this.applicationService.deleteApplication(this.application.id).subscribe(response => {
133+
if (response.ok && response.body.affected > 0) {
134+
console.log("delete application with id:" + this.application.id.toString());
135+
this.router.navigate(["applications"]);
136+
} else {
137+
this.errorMessage = response?.error?.message;
138+
}
139+
});
140+
} else {
141+
console.log(response);
142+
}
143+
});
144+
}
145+
146+
onOpenChangeOrganizationDialog() {
147+
this.changeOrganizationDialog.open(ApplicationChangeOrganizationDialogComponent, {
148+
data: {
149+
applicationId: this.id,
150+
organizationId: this.application.belongsTo.id,
151+
} as ApplicationDialogModel,
152+
});
153+
}
154+
155+
bindApplication(id: number): void {
156+
this.applicationsSubscription = this.applicationService.getApplication(id).subscribe(application => {
157+
this.application = application;
158+
this.cdr.detectChanges();
159+
});
160+
}
161+
162+
getDevices(): Observable<IotDevicesApplicationMapResponse[]> {
163+
return this.restService.get(`application/${this.id}/iot-devices-map`).pipe(
164+
map((data: IotDevicesApplicationMapResponse[]) => {
165+
// For some reason, the backend is not capable to sort MQTT_EXTERNAL_BROKER and MQTT_INTERNAL_BROKER.
166+
// Therefore we do it manually in the frontend.
167+
return data;
168+
})
169+
);
170+
}
171+
172+
ngOnDestroy() {
173+
this.gatewaysSubscription.unsubscribe();
174+
this.deviceSubscription?.unsubscribe();
175+
if (this.applicationsSubscription) {
176+
this.applicationsSubscription.unsubscribe();
177+
}
178+
}
179+
128180
private getGateways(): void {
129181
this.gatewaysSubscription = this.chirpstackGatewayService
130182
.getForMaps()
@@ -140,6 +192,10 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI
140192
if (!dev.location) {
141193
return;
142194
}
195+
const isActive = dev.latestSentMessage
196+
? moment(dev.latestSentMessage).unix() > moment(new Date()).subtract(1, "day").unix()
197+
: false;
198+
143199
tempCoordinateList.push({
144200
longitude: dev.location.coordinates[0],
145201
latitude: dev.location.coordinates[1],
@@ -148,9 +204,10 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI
148204
useGeolocation: false,
149205
markerInfo: {
150206
name: dev.name,
151-
active: dev.type,
207+
active: isActive,
152208
id: dev.id,
153209
isDevice: true,
210+
isGateway: false,
154211
internalOrganizationId: this.sharedVariableService.getSelectedOrganisationId(),
155212
networkTechnology: dev.type,
156213
lastActive: dev.latestSentMessage,
@@ -174,6 +231,8 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI
174231
name: gateway.name,
175232
active: this.getGatewayStatus(gateway),
176233
id: gateway.gatewayId,
234+
isDevice: false,
235+
isGateway: true,
177236
internalOrganizationId: gateway.organizationId,
178237
internalOrganizationName: gateway.organizationName,
179238
},
@@ -185,55 +244,4 @@ export class ApplicationDetailComponent implements OnInit, OnDestroy, AfterViewI
185244
private getGatewayStatus(gateway: Gateway): boolean {
186245
return this.chirpstackGatewayService.isGatewayActive(gateway);
187246
}
188-
189-
onDeleteApplication() {
190-
this.deleteDialogService.showApplicationDialog(this.application).subscribe(response => {
191-
if (response) {
192-
this.applicationService.deleteApplication(this.application.id).subscribe(response => {
193-
if (response.ok && response.body.affected > 0) {
194-
console.log("delete application with id:" + this.application.id.toString());
195-
this.router.navigate(["applications"]);
196-
} else {
197-
this.errorMessage = response?.error?.message;
198-
}
199-
});
200-
} else {
201-
console.log(response);
202-
}
203-
});
204-
}
205-
206-
onOpenChangeOrganizationDialog() {
207-
this.changeOrganizationDialog.open(ApplicationChangeOrganizationDialogComponent, {
208-
data: {
209-
applicationId: this.id,
210-
organizationId: this.application.belongsTo.id,
211-
} as ApplicationDialogModel,
212-
});
213-
}
214-
215-
bindApplication(id: number): void {
216-
this.applicationsSubscription = this.applicationService.getApplication(id).subscribe(application => {
217-
this.application = application;
218-
this.cdr.detectChanges();
219-
});
220-
}
221-
222-
getDevices(): Observable<IotDevicesApplicationMapResponse[]> {
223-
return this.restService.get(`application/${this.id}/iot-devices-map`).pipe(
224-
map((data: IotDevicesApplicationMapResponse[]) => {
225-
// For some reason, the backend is not capable to sort MQTT_EXTERNAL_BROKER and MQTT_INTERNAL_BROKER.
226-
// Therefore we do it manually in the frontend.
227-
return data;
228-
})
229-
);
230-
}
231-
232-
ngOnDestroy() {
233-
this.gatewaysSubscription.unsubscribe();
234-
this.deviceSubscription?.unsubscribe();
235-
if (this.applicationsSubscription) {
236-
this.applicationsSubscription.unsubscribe();
237-
}
238-
}
239247
}
Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
<div class="map-page">
2-
@if(coordinateList){
3-
<app-map [coordinateList]="coordinateList" [isFromApplication]="true"></app-map>
2+
@if (coordinateList) {
3+
<app-map [coordinateList]="coordinateList" [isFromApplication]="true"></app-map>
44
}
5+
<mat-checkbox (change)="mapToCoordinateList()" [(ngModel)]="displayDevices">
6+
Devices
7+
</mat-checkbox>
8+
<mat-checkbox (change)="mapToCoordinateList()" [(ngModel)]="displayGateways">
9+
Gateways
10+
</mat-checkbox>
511
</div>

src/app/applications/applications-list/application-map/application-map.component.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
:host .map-page {
44
background-color: #ffffff;
55
padding: 20px;
6+
padding-bottom: 40px;
67
height: 600px;
78
position: relative;
89
}

src/app/applications/applications-list/application-map/application-map.component.ts

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,24 @@ import { MapCoordinates } from "@shared/components/map/map-coordinates.model";
99
import { ChirpstackGatewayService } from "@shared/services/chirpstack-gateway.service";
1010
import { SharedVariableService } from "@shared/shared-variable/shared-variable.service";
1111
import { forkJoin, Subscription } from "rxjs";
12-
import { SharedModule } from "../../../shared/shared.module";
12+
import { SharedModule } from "@shared/shared.module";
1313
import { ApplicationsFilterService } from "../application-filter/applications-filter.service";
1414
import moment from "moment";
15+
import { FormsModule } from "@angular/forms";
1516

1617
@Component({
1718
selector: "app-application-map",
1819
standalone: true,
19-
imports: [MatCheckboxModule, SharedModule],
20+
imports: [MatCheckboxModule, SharedModule, FormsModule],
2021
templateUrl: "./application-map.component.html",
2122
styleUrls: ["./application-map.component.scss"],
2223
})
2324
export class ApplicationMapComponent implements OnInit, OnDestroy {
2425
public devices: IotDevice[] = [];
2526
public gateways: Gateway[] = [];
26-
public device: boolean = true;
27-
public gateway: boolean = true;
27+
public displayDevices: boolean = true;
28+
public displayGateways: boolean = true;
29+
2830
filterValues: {
2931
status: ApplicationStatus | "All";
3032
statusCheck: ApplicationStatusCheck | "All";
@@ -55,22 +57,10 @@ export class ApplicationMapComponent implements OnInit, OnDestroy {
5557
}
5658
}
5759

58-
private loadMapData(): void {
59-
forkJoin({
60-
devices: this.applicationService.getApplicationDevices(this.sharedVariableService.getSelectedOrganisationId()),
61-
gateways: this.gatewayService.getForMaps(),
62-
}).subscribe(({ devices, gateways }) => {
63-
this.devices = devices;
64-
this.gateways = gateways.resultList;
65-
66-
this.mapToCoordinateList();
67-
});
68-
}
69-
70-
private mapToCoordinateList() {
60+
public mapToCoordinateList() {
7161
const tempCoordinateList: MapCoordinates[] = [];
7262

73-
if (Array.isArray(this.devices)) {
63+
if (Array.isArray(this.devices) && this.displayDevices) {
7464
this.devices.forEach(dev => {
7565
const [longitude, latitude] = dev.location.coordinates;
7666

@@ -99,7 +89,7 @@ export class ApplicationMapComponent implements OnInit, OnDestroy {
9989
});
10090
}
10191

102-
if (Array.isArray(this.gateways)) {
92+
if (Array.isArray(this.gateways) && this.displayGateways) {
10393
this.gateways.forEach(gw => {
10494
tempCoordinateList.push({
10595
longitude: gw.location.longitude,
@@ -124,4 +114,16 @@ export class ApplicationMapComponent implements OnInit, OnDestroy {
124114

125115
this.coordinateList = tempCoordinateList;
126116
}
117+
118+
private loadMapData(): void {
119+
forkJoin({
120+
devices: this.applicationService.getApplicationDevices(this.sharedVariableService.getSelectedOrganisationId()),
121+
gateways: this.gatewayService.getForMaps(),
122+
}).subscribe(({ devices, gateways }) => {
123+
this.devices = devices;
124+
this.gateways = gateways.resultList;
125+
126+
this.mapToCoordinateList();
127+
});
128+
}
127129
}
Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,36 @@
11
<div class="info-box-containers">
22
<app-basic-information-box
3-
[matSVGSrc]="'exclamation-triangle'"
4-
[type]="'warning'"
5-
[count]="withError"
63
[countOf]="total"
4+
[count]="withError"
75
[description]="'APPLICATION-INFORMATION-BOX.APPLICATIONS-WITH-ERROR' | translate"
86
[height]="35"
7+
[matSVGSrc]="'exclamation-triangle'"
8+
[type]="'warning'"
99
[width]="25"
1010
/>
1111
<app-basic-information-box
12-
[matSVGSrc]="'check-circle'"
13-
[type]="'stable'"
14-
[count]="withoutError"
1512
[countOf]="total"
13+
[count]="withoutError"
1614
[description]="'APPLICATION-INFORMATION-BOX.APPLICATIONS-WITHOUT-ERROR' | translate"
1715
[height]="30"
16+
[matSVGSrc]="'check-circle'"
17+
[type]="'stable'"
1818
[width]="25"
1919
/>
2020
<app-basic-information-box
21+
[count]="totalDevices"
22+
[description]="'APPLICATION-INFORMATION-BOX.DEVICES' | translate"
2123
[height]="35"
22-
[width]="25"
2324
[matSVGSrc]="'micro-chip'"
2425
[type]="'default'"
25-
[count]="totalDevices"
26-
[description]="'APPLICATION-INFORMATION-BOX.DEVICES' | translate"
26+
[width]="25"
2727
/>
2828
<app-basic-information-box
29+
[count]="totalGateways"
30+
[description]="'APPLICATION-INFORMATION-BOX.GATEWAYS' | translate"
2931
[height]="35"
30-
[width]="25"
3132
[matSVGSrc]="'satellite-dish'"
3233
[type]="'default'"
33-
[count]="totalGateways"
34-
[description]="'APPLICATION-INFORMATION-BOX.GATEWAYS' | translate"
34+
[width]="25"
3535
/>
3636
</div>

src/app/applications/applications-list/applications-list-dashboard/applications-list-dashboard.component.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
gap: 30px;
55
margin-bottom: 30px;
66
height: fit-content;
7+
flex-wrap: wrap;
78
}

0 commit comments

Comments
 (0)