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}}

+ + +
{{element.name}} @@ -31,6 +32,7 @@

{{title}}

{{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; } }