From d531172e73c8c8efdbb67b4854a18a6c14caca2c Mon Sep 17 00:00:00 2001
From: AramAlsabti <92869496+AramAlsabti@users.noreply.github.com>
Date: Thu, 2 Jun 2022 11:01:56 +0200
Subject: [PATCH] Show gateway status for whole time period (#101)
* Show gateway status for whole time period
* Comment gateway status
---
.../enums/gateway-status-interval.enum.ts | 17 ++++++++
.../gateway-status.component.html | 3 ++
.../gateway-status.component.ts | 40 ++++++++++++-------
.../gateway/gateway-status-class.pipe.ts | 36 ++++++++++++-----
4 files changed, 72 insertions(+), 24 deletions(-)
diff --git a/src/app/gateway/enums/gateway-status-interval.enum.ts b/src/app/gateway/enums/gateway-status-interval.enum.ts
index 2e20a3d9..ceb325c0 100644
--- a/src/app/gateway/enums/gateway-status-interval.enum.ts
+++ b/src/app/gateway/enums/gateway-status-interval.enum.ts
@@ -1,5 +1,22 @@
+import * as moment from 'moment';
+
export enum GatewayStatusInterval {
DAY = 'DAY',
WEEK = 'WEEK',
MONTH = 'MONTH',
}
+
+export const gatewayStatusIntervalToDate = (
+ interval: GatewayStatusInterval
+): Date => {
+ const now = new Date();
+
+ switch (interval) {
+ case GatewayStatusInterval.WEEK:
+ return moment(now).subtract(7, 'days').toDate();
+ case GatewayStatusInterval.MONTH:
+ return moment(now).subtract(30, 'days').toDate();
+ default:
+ return moment(now).subtract(1, 'days').toDate();
+ }
+};
diff --git a/src/app/gateway/gateway-status/gateway-status.component.html b/src/app/gateway/gateway-status/gateway-status.component.html
index 08c943a8..eddb95d1 100644
--- a/src/app/gateway/gateway-status/gateway-status.component.html
+++ b/src/app/gateway/gateway-status/gateway-status.component.html
@@ -19,6 +19,7 @@
{{title}}
diff --git a/src/app/gateway/gateway-status/gateway-status.component.ts b/src/app/gateway/gateway-status/gateway-status.component.ts
index 8b1479be..fa2c1674 100644
--- a/src/app/gateway/gateway-status/gateway-status.component.ts
+++ b/src/app/gateway/gateway-status/gateway-status.component.ts
@@ -14,7 +14,7 @@ import { recordToEntries } from '@shared/helpers/record.helper';
import { LoRaWANGatewayService } from '@shared/services/lorawan-gateway.service';
import * as moment from 'moment';
import { Observable, Subject, Subscription } from 'rxjs';
-import { GatewayStatusInterval } from '../enums/gateway-status-interval.enum';
+import { GatewayStatusInterval, gatewayStatusIntervalToDate } from '../enums/gateway-status-interval.enum';
import { GatewayStatus, AllGatewayStatusResponse } from '../gateway.model';
import { map } from 'rxjs/operators';
import { DefaultPageSizeOptions } from '@shared/constants/page.constants';
@@ -46,7 +46,10 @@ export class GatewayStatusComponent implements AfterContentInit, OnDestroy {
* List of pre-processed timestamps for performance
*/
timeColumns: TimeColumn[] = [];
- displayedColumns: (TimeColumn | string)[] = [];
+ /**
+ * Columns to display. Must not contain objects in order for the table to render.
+ */
+ displayedColumns: string[] = [];
nameText = '';
neverSeenText = '';
timestampText = '';
@@ -135,14 +138,16 @@ export class GatewayStatusComponent implements AfterContentInit, OnDestroy {
timeInterval
).subscribe((response) => {
this.isLoadingResults = false;
+ // Get the earliest date from the selected interval
+ const fromDate = gatewayStatusIntervalToDate(timeInterval);
- if (response) {
- this.handleStatusResponse(response);
+ if (Array.isArray(response?.data)) {
+ this.handleStatusResponse(response, fromDate);
}
});
}
- private handleStatusResponse(response: AllGatewayStatusResponse) {
+ private handleStatusResponse(response: AllGatewayStatusResponse, fromDate: Date) {
this.resultsLength = response.count;
const gatewaysWithLatestTimestampsPerHour = this.takeLatestTimestampInHour(
response.data
@@ -151,11 +156,18 @@ export class GatewayStatusComponent implements AfterContentInit, OnDestroy {
gatewaysWithLatestTimestampsPerHour
);
+ // Sort the gateways and their status timestamps
const sortedData = gatewaysWithWholeHourTimestamps
.slice()
- .sort((a, b) => a.name.localeCompare(b.name));
+ .sort((a, b) => a.name.localeCompare(b.name))
+ .map((gateway) => ({
+ ...gateway,
+ statusTimestamps: gateway.statusTimestamps.sort(
+ (a, b) => a.timestamp.getTime() - b.timestamp.getTime()
+ ),
+ }));
- this.buildColumns(sortedData);
+ this.buildColumns(sortedData, fromDate);
this.visibleFooterTimeInterval = Math.round(
this.clamp(this.timeColumns.length / 4, 1, 6)
);
@@ -164,28 +176,26 @@ export class GatewayStatusComponent implements AfterContentInit, OnDestroy {
this.dataSource.paginator = this.paginator;
}
- private buildColumns(response: GatewayStatus[]) {
- let minDate: Date | null | undefined;
+ private buildColumns(response: GatewayStatus[], fromDate: Date) {
+ // Ensure the first column is the (earliest) selected date
+ const minDate = fromDate;
let maxDate: Date | null | undefined;
this.timeColumns = [];
+ // Determine the date of the first and last column
response.forEach((gateway) => {
gateway.statusTimestamps.forEach(({ timestamp }) => {
- if (!minDate) {
- minDate = timestamp;
- }
if (!maxDate) {
maxDate = timestamp;
}
- if (timestamp < minDate) {
- minDate = timestamp;
- } else if (timestamp > maxDate) {
+ if (timestamp > maxDate) {
maxDate = timestamp;
}
});
});
+ // If there's a date range, build the columns from them
if (minDate && maxDate) {
const currDate = moment(minDate).startOf('hour');
const lastDate = moment(maxDate).startOf('hour');
diff --git a/src/app/shared/pipes/gateway/gateway-status-class.pipe.ts b/src/app/shared/pipes/gateway/gateway-status-class.pipe.ts
index 863e62fd..d0031a00 100644
--- a/src/app/shared/pipes/gateway/gateway-status-class.pipe.ts
+++ b/src/app/shared/pipes/gateway/gateway-status-class.pipe.ts
@@ -1,5 +1,10 @@
import { Pipe, PipeTransform } from '@angular/core';
import { StatusTimestamp } from '@app/gateway/gateway.model';
+import * as moment from 'moment';
+
+const neverSeenClass = 'never-seen';
+const offlineClass = 'offline';
+const onlineClass = 'online';
@Pipe({
name: 'gatewayStatusClass',
@@ -14,14 +19,27 @@ export class GatewayStatusClassPipe implements PipeTransform {
timestamp: string,
..._: unknown[]
): string {
- return !statusTimestamps.length
- ? 'never-seen'
- : statusTimestamps.some(
- (gatewayTimestamp) =>
- gatewayTimestamp.timestamp.toISOString() === timestamp &&
- gatewayTimestamp.wasOnline
- )
- ? 'online'
- : 'offline';
+ if (!statusTimestamps.length) {
+ return neverSeenClass;
+ }
+
+ let currentStatusClass = offlineClass;
+ const selectedDate = moment(timestamp).toDate();
+
+ for (const gatewayTimestamp of statusTimestamps) {
+ const isoGatewayTimestamp = gatewayTimestamp.timestamp.toISOString();
+
+ if (isoGatewayTimestamp === timestamp) {
+ return gatewayTimestamp.wasOnline ? onlineClass : offlineClass;
+ }
+
+ if (gatewayTimestamp.timestamp > selectedDate) {
+ return currentStatusClass;
+ }
+
+ currentStatusClass = gatewayTimestamp.wasOnline ? onlineClass : offlineClass;
+ }
+
+ return currentStatusClass;
}
}