From 769a46a49c4e01c49fa80e28c81e6e26539f996e Mon Sep 17 00:00:00 2001 From: Giona Martignani Date: Thu, 9 Jan 2025 12:32:34 +0100 Subject: [PATCH] Updated store, alarms and imports moved store and dependencies to core library, replaced alarm wrapper service with store, fixed imports --- package-lock.json | 5 +- .../hyt-input-template.component.ts | 2 - .../src/lib/hyt-input/hyt-input.component.ts | 1 - .../hyt-radio-button.component.ts | 1 - .../lib/constants/http-errors-dictionary.ts | 39 +++++++ projects/core/src/lib/constants/index.ts | 5 + .../hyperiot-alarm-wrapper.service.ts | 108 ------------------ .../core/src/lib}/models/branding.ts | 0 .../hyperiot-alarm.model.ts | 7 +- projects/core/src/lib/models/index.ts | 2 + .../branding/branding.service.spec.ts | 0 .../services/branding/branding.service.ts | 8 +- .../lib/store/branding/branding.actions.ts | 29 +++++ .../lib/store}/branding/branding.effects.ts | 42 +++---- .../lib/store/branding/branding.reducer.ts | 86 ++++++++++++++ .../lib/store/branding/branding.selectors.ts | 30 +++++ projects/core/src/lib/store/branding/index.ts | 4 + .../lib/store/hDevices/hDevices.actions.ts | 24 ++++ .../lib/store}/hDevices/hDevices.effects.ts | 14 +-- .../lib/store/hDevices/hDevices.reducer.ts | 99 ++++++++++++++++ .../lib/store/hDevices/hDevices.selectors.ts | 67 +++++++++++ projects/core/src/lib/store/hDevices/index.ts | 4 + .../lib/store/hPackets/hPackets.actions.ts | 24 ++++ .../lib/store}/hPackets/hPackets.effects.ts | 14 +-- .../lib/store/hPackets/hPackets.reducer.ts | 87 ++++++++++++++ .../lib/store/hPackets/hPackets.selectors.ts | 40 +++++++ projects/core/src/lib/store/hPackets/index.ts | 4 + .../lib/store/hProjects/hProjects.actions.ts | 26 +++++ .../lib/store}/hProjects/hProjects.effects.ts | 14 +-- .../lib/store/hProjects/hProjects.reducer.ts | 99 ++++++++++++++++ .../store/hProjects/hProjects.selectors.ts | 39 +++++++ .../core/src/lib/store/hProjects/index.ts | 4 + projects/core/src/lib/store/index.ts | 64 +++++++++++ .../core/src/lib/store/live-alarms/index.ts | 4 + .../store/live-alarms/live-alarms.actions.ts | 26 +++++ .../store}/live-alarms/live-alarms.effects.ts | 46 ++++---- .../store/live-alarms/live-alarms.reducer.ts | 106 +++++++++++++++++ .../live-alarms/live-alarms.selectors.ts | 48 ++++++++ .../core/src/lib/store/notification/index.ts | 4 + .../notification/notification.actions.ts | 9 ++ .../notification/notification.effects.ts | 27 ++--- .../notification/notification.reducer.ts | 62 ++++++++++ .../notification/notification.selectors.ts | 42 +++++++ projects/core/src/lib/store/rules/index.ts | 4 + .../core/src/lib/store/rules/rules.actions.ts | 26 +++++ .../src/lib/store}/rules/rules.effects.ts | 16 +-- .../core/src/lib/store/rules/rules.reducer.ts | 99 ++++++++++++++++ .../src/lib/store/rules/rules.selectors.ts | 40 +++++++ .../src/lib/store/user-site-setting/index.ts | 3 + .../user-site-setting.actions.ts | 25 ++++ .../user-site-setting.reducer.ts | 102 +++++++++++++++++ .../user-site-setting.selectors.ts | 14 +++ projects/core/src/public-api.ts | 12 +- .../packet-select/packet-select.component.ts | 1 - .../widgets-layout.component.ts | 11 +- .../alarms-widget.component.html | 12 +- .../alarms-widget/alarms-widget.component.ts | 47 +++++--- src/app/app.component.ts | 103 ++++------------- src/app/app.module.ts | 8 +- .../notification-dialog.component.html | 4 +- .../notification-dialog.component.ts | 19 +-- .../account-button.component.ts | 2 - .../notification-button.component.html | 6 +- .../notification-button.component.ts | 25 ++-- .../hyt-routing.module.ts | 1 - .../account/profile/profile.component.ts | 11 +- .../services/postLogin/post-login.service.ts | 11 +- src/app/state/branding/branding.actions.ts | 44 ------- src/app/state/branding/branding.model.ts | 17 --- src/app/state/branding/branding.reducer.ts | 81 ------------- src/app/state/branding/branding.selectors.ts | 36 ------ src/app/state/hDevices/hDevices.actions.ts | 42 ------- src/app/state/hDevices/hDevices.reducer.ts | 99 ---------------- src/app/state/hDevices/hDevices.selectors.ts | 74 ------------ src/app/state/hPackets/hPackets.actions.ts | 42 ------- src/app/state/hPackets/hPackets.reducer.ts | 100 ---------------- src/app/state/hPackets/hPackets.selectors.ts | 47 -------- src/app/state/hProjects/hProjects.actions.ts | 42 ------- src/app/state/hProjects/hProjects.reducer.ts | 100 ---------------- .../state/hProjects/hProjects.selectors.ts | 47 -------- src/app/state/index.ts | 53 --------- .../state/live-alarms/live-alarms.actions.ts | 42 ------- .../state/live-alarms/live-alarms.reducer.ts | 103 ----------------- .../live-alarms/live-alarms.selectors.ts | 50 -------- .../notification/notification.actions.ts | 10 -- .../state/notification/notification.model.ts | 8 -- .../notification/notification.reducer.ts | 50 -------- .../notification/notification.selectors.ts | 45 -------- .../state/permissions/permissions.actions.ts | 9 -- .../state/permissions/permissions.effects.ts | 0 .../state/permissions/permissions.reducers.ts | 0 src/app/state/rules/rules.actions.ts | 42 ------- src/app/state/rules/rules.reducer.ts | 100 ---------------- src/app/state/rules/rules.selectors.ts | 47 -------- 94 files changed, 1553 insertions(+), 1745 deletions(-) create mode 100644 projects/core/src/lib/constants/http-errors-dictionary.ts create mode 100644 projects/core/src/lib/constants/index.ts delete mode 100644 projects/core/src/lib/hyperiot-service/hyperiot-alarm-wrapper/hyperiot-alarm-wrapper.service.ts rename {src/app/services/branding => projects/core/src/lib}/models/branding.ts (100%) rename projects/core/src/lib/{hyperiot-service/hyperiot-alarm-wrapper => models}/hyperiot-alarm.model.ts (83%) create mode 100644 projects/core/src/lib/models/index.ts rename {src/app => projects/core/src/lib}/services/branding/branding.service.spec.ts (100%) rename {src/app => projects/core/src/lib}/services/branding/branding.service.ts (91%) create mode 100644 projects/core/src/lib/store/branding/branding.actions.ts rename {src/app/state => projects/core/src/lib/store}/branding/branding.effects.ts (55%) create mode 100644 projects/core/src/lib/store/branding/branding.reducer.ts create mode 100644 projects/core/src/lib/store/branding/branding.selectors.ts create mode 100644 projects/core/src/lib/store/branding/index.ts create mode 100644 projects/core/src/lib/store/hDevices/hDevices.actions.ts rename {src/app/state => projects/core/src/lib/store}/hDevices/hDevices.effects.ts (63%) create mode 100644 projects/core/src/lib/store/hDevices/hDevices.reducer.ts create mode 100644 projects/core/src/lib/store/hDevices/hDevices.selectors.ts create mode 100644 projects/core/src/lib/store/hDevices/index.ts create mode 100644 projects/core/src/lib/store/hPackets/hPackets.actions.ts rename {src/app/state => projects/core/src/lib/store}/hPackets/hPackets.effects.ts (66%) create mode 100644 projects/core/src/lib/store/hPackets/hPackets.reducer.ts create mode 100644 projects/core/src/lib/store/hPackets/hPackets.selectors.ts create mode 100644 projects/core/src/lib/store/hPackets/index.ts create mode 100644 projects/core/src/lib/store/hProjects/hProjects.actions.ts rename {src/app/state => projects/core/src/lib/store}/hProjects/hProjects.effects.ts (62%) create mode 100644 projects/core/src/lib/store/hProjects/hProjects.reducer.ts create mode 100644 projects/core/src/lib/store/hProjects/hProjects.selectors.ts create mode 100644 projects/core/src/lib/store/hProjects/index.ts create mode 100644 projects/core/src/lib/store/index.ts create mode 100644 projects/core/src/lib/store/live-alarms/index.ts create mode 100644 projects/core/src/lib/store/live-alarms/live-alarms.actions.ts rename {src/app/state => projects/core/src/lib/store}/live-alarms/live-alarms.effects.ts (78%) create mode 100644 projects/core/src/lib/store/live-alarms/live-alarms.reducer.ts create mode 100644 projects/core/src/lib/store/live-alarms/live-alarms.selectors.ts create mode 100644 projects/core/src/lib/store/notification/index.ts create mode 100644 projects/core/src/lib/store/notification/notification.actions.ts rename {src/app/state => projects/core/src/lib/store}/notification/notification.effects.ts (69%) create mode 100644 projects/core/src/lib/store/notification/notification.reducer.ts create mode 100644 projects/core/src/lib/store/notification/notification.selectors.ts create mode 100644 projects/core/src/lib/store/rules/index.ts create mode 100644 projects/core/src/lib/store/rules/rules.actions.ts rename {src/app/state => projects/core/src/lib/store}/rules/rules.effects.ts (61%) create mode 100644 projects/core/src/lib/store/rules/rules.reducer.ts create mode 100644 projects/core/src/lib/store/rules/rules.selectors.ts create mode 100644 projects/core/src/lib/store/user-site-setting/index.ts create mode 100644 projects/core/src/lib/store/user-site-setting/user-site-setting.actions.ts create mode 100644 projects/core/src/lib/store/user-site-setting/user-site-setting.reducer.ts create mode 100644 projects/core/src/lib/store/user-site-setting/user-site-setting.selectors.ts delete mode 100644 src/app/state/branding/branding.actions.ts delete mode 100644 src/app/state/branding/branding.model.ts delete mode 100644 src/app/state/branding/branding.reducer.ts delete mode 100644 src/app/state/branding/branding.selectors.ts delete mode 100644 src/app/state/hDevices/hDevices.actions.ts delete mode 100644 src/app/state/hDevices/hDevices.reducer.ts delete mode 100644 src/app/state/hDevices/hDevices.selectors.ts delete mode 100644 src/app/state/hPackets/hPackets.actions.ts delete mode 100644 src/app/state/hPackets/hPackets.reducer.ts delete mode 100644 src/app/state/hPackets/hPackets.selectors.ts delete mode 100644 src/app/state/hProjects/hProjects.actions.ts delete mode 100644 src/app/state/hProjects/hProjects.reducer.ts delete mode 100644 src/app/state/hProjects/hProjects.selectors.ts delete mode 100644 src/app/state/index.ts delete mode 100644 src/app/state/live-alarms/live-alarms.actions.ts delete mode 100644 src/app/state/live-alarms/live-alarms.reducer.ts delete mode 100644 src/app/state/live-alarms/live-alarms.selectors.ts delete mode 100644 src/app/state/notification/notification.actions.ts delete mode 100644 src/app/state/notification/notification.model.ts delete mode 100644 src/app/state/notification/notification.reducer.ts delete mode 100644 src/app/state/notification/notification.selectors.ts delete mode 100644 src/app/state/permissions/permissions.actions.ts delete mode 100644 src/app/state/permissions/permissions.effects.ts delete mode 100644 src/app/state/permissions/permissions.reducers.ts delete mode 100644 src/app/state/rules/rules.actions.ts delete mode 100644 src/app/state/rules/rules.reducer.ts delete mode 100644 src/app/state/rules/rules.selectors.ts diff --git a/package-lock.json b/package-lock.json index 09e67e1b..cc3d5056 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5107,9 +5107,8 @@ }, "node_modules/@ngrx/entity": { "version": "12.5.1", - "resolved": "https://nexus.acsoftware.it/nexus/repository/npm/@ngrx/entity/-/entity-12.5.1.tgz", + "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-12.5.1.tgz", "integrity": "sha512-bjRMMe83onhrhxu5rJo+FhaS0gFY4HbMulSjUpuh0/LJckd0Z3QUDs+UcqYW/tjG/2o2rbNDxkws6w1D0c5ksA==", - "license": "MIT", "dependencies": { "tslib": "^2.0.0" }, @@ -30829,7 +30828,7 @@ }, "@ngrx/entity": { "version": "12.5.1", - "resolved": "https://nexus.acsoftware.it/nexus/repository/npm/@ngrx/entity/-/entity-12.5.1.tgz", + "resolved": "https://registry.npmjs.org/@ngrx/entity/-/entity-12.5.1.tgz", "integrity": "sha512-bjRMMe83onhrhxu5rJo+FhaS0gFY4HbMulSjUpuh0/LJckd0Z3QUDs+UcqYW/tjG/2o2rbNDxkws6w1D0c5ksA==", "requires": { "tslib": "^2.0.0" diff --git a/projects/components/src/lib/hyt-input-template/hyt-input-template.component.ts b/projects/components/src/lib/hyt-input-template/hyt-input-template.component.ts index a76d7563..6b191c72 100644 --- a/projects/components/src/lib/hyt-input-template/hyt-input-template.component.ts +++ b/projects/components/src/lib/hyt-input-template/hyt-input-template.component.ts @@ -17,9 +17,7 @@ import { FormGroup } from '@angular/forms'; import { ErrorStateMatcher } from '@angular/material/core'; -import { Observable } from 'rxjs'; import { LoggerService, Logger } from 'core'; -import '@angular/localize/init'; /** * Custom provider for NG_VALUE_ACCESSOR diff --git a/projects/components/src/lib/hyt-input/hyt-input.component.ts b/projects/components/src/lib/hyt-input/hyt-input.component.ts index a0f2013f..ea8c7ffa 100644 --- a/projects/components/src/lib/hyt-input/hyt-input.component.ts +++ b/projects/components/src/lib/hyt-input/hyt-input.component.ts @@ -21,7 +21,6 @@ import { import { ErrorStateMatcher } from "@angular/material/core"; import { Logger, LoggerService } from "core"; -import "@angular/localize/init"; /** * Custom provider for NG_VALUE_ACCESSOR diff --git a/projects/components/src/lib/hyt-radio-button/hyt-radio-button.component.ts b/projects/components/src/lib/hyt-radio-button/hyt-radio-button.component.ts index 0ca9b809..ccb60f86 100644 --- a/projects/components/src/lib/hyt-radio-button/hyt-radio-button.component.ts +++ b/projects/components/src/lib/hyt-radio-button/hyt-radio-button.component.ts @@ -16,7 +16,6 @@ import { FormGroupDirective, NgForm, } from "@angular/forms"; -import "@angular/localize/init"; /** * Class used to represent a select option. diff --git a/projects/core/src/lib/constants/http-errors-dictionary.ts b/projects/core/src/lib/constants/http-errors-dictionary.ts new file mode 100644 index 00000000..ff157d17 --- /dev/null +++ b/projects/core/src/lib/constants/http-errors-dictionary.ts @@ -0,0 +1,39 @@ +/* + * + * * Copyright 2019-2023 HyperIoT + * * + * * Licensed under the Apache License, Version 2.0 (the "License") + * * you may not use this file except in compliance with the License. + * * You may obtain a copy of the License at + * * + * * http://www.apache.org/licenses/LICENSE-2.0 + * * + * * Unless required by applicable law or agreed to in writing, software + * * distributed under the License is distributed on an "AS IS" BASIS, + * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * * See the License for the specific language governing permissions and + * * limitations under the License. + * * + * + */ + +export const ErrorMessageDefault = { + title: $localize`:@@HYT_error:Error`, + body: $localize`:@@HYT_something_wrong:Something's wrong` +} + +export const HttpErrorsDictionary: { + [index: number]: { + title: string, + body: string + } +} = { + 401: { + title: $localize`:@@HYT_authorization_error:Athorization error`, + body: $localize`:@@HYT_you_do_not_have_sufficient_permissions_to_perform_this_operation:You do not have sufficient permissions to perform this operation` + }, + 403: { + title: $localize`:@@HYT_authentication_error:Authentication error`, + body: $localize`:@@HYT_you_do_not_have_sufficient_permissions_to_perform_this_operation:You do not have sufficient permissions to perform this operation` + } +}; diff --git a/projects/core/src/lib/constants/index.ts b/projects/core/src/lib/constants/index.ts new file mode 100644 index 00000000..7f4ac7f2 --- /dev/null +++ b/projects/core/src/lib/constants/index.ts @@ -0,0 +1,5 @@ +export * from './http-context-tokens'; +export * from './http-errors-dictionary'; + +export const HyperiotLogoPath = 'assets/images/logo/Hyperiot-Ex_S.png'; +export const HyperiotLogoMobilePath = 'assets/images/hyperiot_logo_single_char_animated.svg'; diff --git a/projects/core/src/lib/hyperiot-service/hyperiot-alarm-wrapper/hyperiot-alarm-wrapper.service.ts b/projects/core/src/lib/hyperiot-service/hyperiot-alarm-wrapper/hyperiot-alarm-wrapper.service.ts deleted file mode 100644 index 0a8df07e..00000000 --- a/projects/core/src/lib/hyperiot-service/hyperiot-alarm-wrapper/hyperiot-alarm-wrapper.service.ts +++ /dev/null @@ -1,108 +0,0 @@ -import { Injectable } from "@angular/core"; -import { RealtimeDataService } from "../../hyperiot-base/realtime-data-service/realtime-data.service"; -import { HytAlarm } from "./hyperiot-alarm.model"; -import { BehaviorSubject, Subject, mergeMap } from "rxjs"; -import { HprojectsService } from "../../hyperiot-client/h-project-client/api-module"; -import { AlarmsService } from "../../hyperiot-client/alarms-client/api-module"; -import { Store } from "@ngrx/store"; - -@Injectable({ - providedIn: "root", -}) -export class AlarmWrapperService { - /** - * Flag if the notification is active, saved in localStorage the preference - */ - public eventNotificationState: BehaviorSubject = new BehaviorSubject(JSON.parse(localStorage.getItem(HytAlarm.NotificationActiveKey)) ?? true); - /** - * Map contain all the active alarm - */ - private alarmsList: Map = new Map(); - private DEFAULT_BACKGROUND_COLOUR = '#1f58a5'; - private severityColors = new Map([ - [0, '#46A0F3'], - [1, '#F9BE26'], - [2, '#F35746'], - [3, '#8E20BC'], - ]); - private _alarmSubject: Subject = new Subject() - - constructor( - private realtimeDataService: RealtimeDataService, - private hprojectsService: HprojectsService, - private alarmsService: AlarmsService, - private store: Store - ) { } - - loadAndCollectAlarms() { - const SUFFIX = HytAlarm.AlarmSuffixsEnum; - - this.realtimeDataService.eventStream.subscribe((p) => { - const packet = p.data; - const isEvent = packet.name.endsWith(SUFFIX[SUFFIX._event]); - const isAlarm = packet.name.endsWith(SUFFIX[SUFFIX._event_alarm]); - if (packet.id === 0 && (isEvent || isAlarm)) { - const event = JSON.parse(packet.fields.event.value.string).data; - const tag = event.tags[0]; // retrieve only first tag - let backgroundColor = this.DEFAULT_BACKGROUND_COLOUR; - const textColor = "#fff" - if (isEvent) { - backgroundColor = tag ? tag.color : this.DEFAULT_BACKGROUND_COLOUR; - } else if (isAlarm) { - backgroundColor = this.severityColors.get(event.severity) || this.DEFAULT_BACKGROUND_COLOUR; - } - const alarm : HytAlarm.LiveAlarm = { - alarmId: event.alarmId, - alarmName: event.alarmName, - event: { - alarmEventId: event.ruleId, - alarmEventName: event.ruleName, - severity: event.severity, - alarmState: event.alarmState, - lastFiredTimestamp: event.fireTimestamp, - }, - deviceIds: [], - packetIds: event.packetIds, - color: { - background: backgroundColor, - text: textColor - }, - isEvent: isEvent, - isAlarm: isAlarm, - } - // MANAGE ALARM MAP USED IN ONLINE WIDGET AND NOTIFICATION BAR - if(isAlarm){ - //NOT FILTER FOR PROJECT, NEED TO CHANGE REALTIME DATA SERVICE - if(alarm.event.alarmState == "UP"){ - this.alarmsList.set(alarm.alarmId, alarm); - }else{ - this.alarmsList.delete(alarm.alarmId); - } - } - this._alarmSubject.next(alarm) - } - }) - - this.eventNotificationState.subscribe(res=> localStorage.setItem(HytAlarm.NotificationActiveKey, JSON.stringify(res))); - } - - get alarmSubject(){ - return this._alarmSubject; - } - - /** - * Return alarmList map as array sorted by event fire date - */ - get alarmListArray() : HytAlarm.LiveAlarm[]{ - return Array.from(this.alarmsList.values()).sort((alarm1, alarm2) => { - if (alarm1.event.lastFiredTimestamp < alarm2.event.lastFiredTimestamp ) { - return 1; - } - if (alarm1.event.lastFiredTimestamp > alarm2.event.lastFiredTimestamp) { - return -1; - } - return 0; - }); - } - -} diff --git a/src/app/services/branding/models/branding.ts b/projects/core/src/lib/models/branding.ts similarity index 100% rename from src/app/services/branding/models/branding.ts rename to projects/core/src/lib/models/branding.ts diff --git a/projects/core/src/lib/hyperiot-service/hyperiot-alarm-wrapper/hyperiot-alarm.model.ts b/projects/core/src/lib/models/hyperiot-alarm.model.ts similarity index 83% rename from projects/core/src/lib/hyperiot-service/hyperiot-alarm-wrapper/hyperiot-alarm.model.ts rename to projects/core/src/lib/models/hyperiot-alarm.model.ts index 50988e99..660b91dc 100644 --- a/projects/core/src/lib/hyperiot-service/hyperiot-alarm-wrapper/hyperiot-alarm.model.ts +++ b/projects/core/src/lib/models/hyperiot-alarm.model.ts @@ -9,14 +9,15 @@ export namespace HytAlarm{ alarmId: number; alarmName: string; event: { - alarmEventId: number; + alarmEventId?: number; alarmEventName: string; severity: number; alarmState: string; lastFiredTimestamp: number; - ruleDefinition?: string; + ruleDefinition: string; + ruleId: number; }; - projectId?: number; + projectId: number; deviceIds: number[]; packetIds?: number[]; color: { diff --git a/projects/core/src/lib/models/index.ts b/projects/core/src/lib/models/index.ts new file mode 100644 index 00000000..efa5a99a --- /dev/null +++ b/projects/core/src/lib/models/index.ts @@ -0,0 +1,2 @@ +export * from './branding'; +export * from './hyperiot-alarm.model'; diff --git a/src/app/services/branding/branding.service.spec.ts b/projects/core/src/lib/services/branding/branding.service.spec.ts similarity index 100% rename from src/app/services/branding/branding.service.spec.ts rename to projects/core/src/lib/services/branding/branding.service.spec.ts diff --git a/src/app/services/branding/branding.service.ts b/projects/core/src/lib/services/branding/branding.service.ts similarity index 91% rename from src/app/services/branding/branding.service.ts rename to projects/core/src/lib/services/branding/branding.service.ts index 9747e87c..f017c61f 100644 --- a/src/app/services/branding/branding.service.ts +++ b/projects/core/src/lib/services/branding/branding.service.ts @@ -1,12 +1,11 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; -import { UiBrandingService } from 'core'; import { lastValueFrom, Observable, tap } from 'rxjs'; -import { BrandingTheme } from './models/branding'; import { Store } from '@ngrx/store'; -import { BrandingActions } from 'src/app/state/branding/branding.actions'; -import { BrandingSelectors } from 'src/app/state/branding/branding.selectors'; +import { BrandingSelectors } from '../../store/branding/branding.selectors'; +import { BrandingActions } from '../../store/branding/branding.actions'; +import { BrandingTheme } from '../../models/branding'; @Injectable({ providedIn: 'root' @@ -25,7 +24,6 @@ export class BrandingService { }> = this.store.select(BrandingSelectors.selectThemeLogoPath); constructor( - private uiBrandingService: UiBrandingService, private _sanitizer: DomSanitizer, private httpClient: HttpClient, private store: Store diff --git a/projects/core/src/lib/store/branding/branding.actions.ts b/projects/core/src/lib/store/branding/branding.actions.ts new file mode 100644 index 00000000..5622d1c0 --- /dev/null +++ b/projects/core/src/lib/store/branding/branding.actions.ts @@ -0,0 +1,29 @@ +import { createAction, props } from "@ngrx/store"; +import { BrandingTheme } from "../../models/branding"; +import { BrandingStore } from "./branding.reducer"; + +export namespace BrandingActions { + export const load = createAction('[Branding] Load'); + export const updateAll = createAction( + '[Branding] Update', + props<{ brandingTheme: BrandingTheme }>() + ); + export const updateLogo = createAction( + '[Branding] Update Logo', + props<{ brandingTheme: BrandingTheme }>() + ); + export const updateColorSchema = createAction( + '[Branding] Update ColorScheme', + props<{ brandingTheme: BrandingTheme }>() + ); + export const reset = createAction('[Branding] Reset'); + export const unset = createAction('[Branding] Unset after logout'); + + export const loadSuccess = createAction('[Branding API] Branding Load Success', props<{ payload: BrandingStore.State }>()); + export const loadFailure = createAction('[Branding API] Branding Load Error', props<{ payload: any }>()); + export const updateSuccess = createAction('[Branding API] Branding Update Success', props<{ payload: BrandingStore.State }>()); + export const updateFailure = createAction('[Branding API] Branding Update Error', props<{ payload: any }>()); + export const resetSuccess = createAction('[Branding API] Branding Reset Success', props<{ payload: any }>()); + export const resetFailure = createAction('[Branding API] Branding Reset Error', props<{ payload: any }>()); + +} diff --git a/src/app/state/branding/branding.effects.ts b/projects/core/src/lib/store/branding/branding.effects.ts similarity index 55% rename from src/app/state/branding/branding.effects.ts rename to projects/core/src/lib/store/branding/branding.effects.ts index d47e8e09..0387b2b5 100644 --- a/src/app/state/branding/branding.effects.ts +++ b/projects/core/src/lib/store/branding/branding.effects.ts @@ -1,25 +1,22 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { Logger, LoggerService, UiBrandingService } from 'core'; +import { UiBrandingService } from '../../hyperiot-client/uibranding-client/api-module'; import { of } from 'rxjs'; import { map, mergeMap, catchError, exhaustMap } from 'rxjs/operators'; -import { BrandingService } from 'src/app/services/branding/branding.service'; -import { BrandingActions, BrandingApiActions } from './branding.actions'; -import { BrandingState } from './branding.model'; +import { BrandingStore } from './branding.reducer'; +import { BrandingActions } from './branding.actions'; +import { BrandingService } from '../../services/branding/branding.service'; @Injectable() export class BrandingEffects { - - private logger: Logger; load$ = createEffect(() => this.actions$.pipe( ofType(BrandingActions.load), mergeMap(() => this.uiBrandingService.getUIBranding() .pipe( map(branding => { - this.logger.debug('laod$ getUIBranding() response', branding); const colorSchema = JSON.parse(branding.colorScheme); - const newBranding: BrandingState = { + const newBranding: BrandingStore.State = { colorSchema, logo: { standard: this.brandingService.getSanitizedLogo(branding.logoBase64), @@ -27,12 +24,10 @@ export class BrandingEffects { }, isBrandedTheme: true }; - this.logger.debug('laod$ return payload', newBranding); - return BrandingApiActions.loadSuccess({ payload: newBranding }); + return BrandingActions.loadSuccess({ payload: newBranding }); }), catchError((err) => { - this.logger.debug('laod$ getUIBranding() catchError', err); - return of(BrandingApiActions.loadFailure({ payload: err })); + return of(BrandingActions.loadFailure({ payload: err })); }) )) ) @@ -44,9 +39,8 @@ export class BrandingEffects { exhaustMap(action => this.brandingService.updateBranding(action.brandingTheme).pipe( map(res => { - this.logger.debug('updateAll$ updateBranding() response', res); const colorSchema = JSON.parse(res.colorScheme) - const newBranding: BrandingState = { + const newBranding: BrandingStore.State = { colorSchema, logo: { standard: res.logoBase64 ? this.brandingService.getSanitizedLogo(res.logoBase64) : action.brandingTheme.fileBase64, @@ -54,12 +48,10 @@ export class BrandingEffects { }, isBrandedTheme: true }; - this.logger.debug('updateAll$ return payload', newBranding); - return BrandingApiActions.updateSuccess({ payload: newBranding }); + return BrandingActions.updateSuccess({ payload: newBranding }); }), catchError(error => { - this.logger.error('updateAll$ updateBranding() catchError', error); - return of(BrandingApiActions.updateFailure({ payload: error })); + return of(BrandingActions.updateFailure({ payload: error })); }) ) ) @@ -72,12 +64,10 @@ export class BrandingEffects { exhaustMap(action => this.brandingService.resetBranding().pipe( map(res => { - this.logger.debug('reset$ resetBranding() response', res); - return BrandingApiActions.resetSuccess({ payload: res }); + return BrandingActions.resetSuccess({ payload: res }); }), catchError(error => { - this.logger.error('reset$ resetBranding() catchError', error); - return of(BrandingApiActions.resetFailure({ payload: error })); + return of(BrandingActions.resetFailure({ payload: error })); }) ) ) @@ -87,10 +77,6 @@ export class BrandingEffects { constructor( private actions$: Actions, private brandingService: BrandingService, - private uiBrandingService: UiBrandingService, - loggerService: LoggerService - ) { - this.logger = new Logger(loggerService); - this.logger.registerClass("BrandingEffects"); - } + private uiBrandingService: UiBrandingService + ) { } } \ No newline at end of file diff --git a/projects/core/src/lib/store/branding/branding.reducer.ts b/projects/core/src/lib/store/branding/branding.reducer.ts new file mode 100644 index 00000000..55ec293b --- /dev/null +++ b/projects/core/src/lib/store/branding/branding.reducer.ts @@ -0,0 +1,86 @@ +import { createReducer, on } from "@ngrx/store"; +import { BrandingActions } from "./branding.actions"; +import { HyperiotLogoMobilePath, HyperiotLogoPath } from "../../constants"; +import { SafeResourceUrl } from "@angular/platform-browser"; + +export namespace BrandingStore { + + export const key = 'branding'; + + export interface State { + colorSchema: { + primaryColor: string; + secondaryColor: string; + }; + logo: { + standard: SafeResourceUrl | string; + mobile: SafeResourceUrl | string; + }, + isBrandedTheme: boolean; + error?: { + action: string, + payload: any + } + }; + + const initialState: State = { + colorSchema: { + primaryColor: '#0956B6', + secondaryColor: '#17a4fa' + }, + logo: { + standard: HyperiotLogoPath, + mobile: HyperiotLogoMobilePath, + }, + isBrandedTheme: false + }; + + const _reducer = createReducer( + initialState, + on(BrandingActions.load, (state) => { + return state; + }), + on(BrandingActions.updateAll, (state) => { + return state; + }), + on(BrandingActions.reset, (state) => { + return state; + }), + on(BrandingActions.unset, (state) => { + return initialState; + }), + on(BrandingActions.loadFailure, (state) => { + return state; + }), + on(BrandingActions.loadSuccess, (state, action) => { + const newState = {...state, ...action.payload}; + return newState; + }), + on(BrandingActions.updateFailure, (state, action) => { + const newState = {...state, error: { + action: action.type, + payload: action.payload + }}; + return newState; + }), + on(BrandingActions.updateSuccess, (state, action) => { + const newState = {...state, ...action.payload}; + return newState; + }), + on(BrandingActions.resetFailure, (state, action) => { + const newState = {...state, error: { + action: action.type, + payload: action.payload + }}; + return newState; + }), + on(BrandingActions.resetSuccess, (state) => { + return initialState; + }), + ); + + export function reducer(state, action) { + return _reducer(state, action); + } + +} diff --git a/projects/core/src/lib/store/branding/branding.selectors.ts b/projects/core/src/lib/store/branding/branding.selectors.ts new file mode 100644 index 00000000..ecd820df --- /dev/null +++ b/projects/core/src/lib/store/branding/branding.selectors.ts @@ -0,0 +1,30 @@ +import { createSelector } from '@ngrx/store'; +import { BrandingStore } from './branding.reducer'; +import { HyperiotStore } from '..'; + +export namespace BrandingSelectors { + + export const selectThemeBranding = (state: HyperiotStore.State) => state.branding; + + export const selectThemeColorSchema = createSelector( + selectThemeBranding, + (state: BrandingStore.State) => state.colorSchema + ); + + export const selectThemeLogoPath = createSelector( + selectThemeBranding, + (state: BrandingStore.State) => state.logo + ); + + export const selectError = createSelector( + selectThemeBranding, + (state: BrandingStore.State) => state.error + ); + + export const selectIsBrandedTheme = createSelector( + selectThemeBranding, + (state: BrandingStore.State) => state.isBrandedTheme + ); + +} + \ No newline at end of file diff --git a/projects/core/src/lib/store/branding/index.ts b/projects/core/src/lib/store/branding/index.ts new file mode 100644 index 00000000..8248c001 --- /dev/null +++ b/projects/core/src/lib/store/branding/index.ts @@ -0,0 +1,4 @@ +export * from './branding.actions'; +export * from './branding.effects'; +export * from './branding.reducer'; +export * from './branding.selectors'; diff --git a/projects/core/src/lib/store/hDevices/hDevices.actions.ts b/projects/core/src/lib/store/hDevices/hDevices.actions.ts new file mode 100644 index 00000000..93f8c056 --- /dev/null +++ b/projects/core/src/lib/store/hDevices/hDevices.actions.ts @@ -0,0 +1,24 @@ +import { EntityMap, EntityMapOne, Predicate, Update } from "@ngrx/entity"; +import { createAction, props } from "@ngrx/store"; +import { HDevice } from "../../hyperiot-client/models/hDevice"; + +export namespace HDeviceActions { + export const loadHDevices = createAction('[HDevice/API] Load HDevices'); + export const loadHDevicesSuccess = createAction('[HDevice/API] Load HDevices Success', props<{ hDevices: HDevice[] }>()); + export const loadHDevicesFailure = createAction('[HDevice/API] Load HDevices Failure', props<{ error: any }>()); + + export const setHDevices = createAction('[HDevice/API] Set HDevices', props<{ hDevices: HDevice[] }>()); + export const addHDevice = createAction('[HDevice/API] Add HDevice', props<{ hDevice: HDevice }>()); + export const setHDevice = createAction('[HDevice/API] Set HDevice', props<{ hDevice: HDevice }>()); + export const upsertHDevice = createAction('[HDevice/API] Upsert HDevice', props<{ hDevice: HDevice }>()); + export const addHDevices = createAction('[HDevice/API] Add HDevices', props<{ hDevices: HDevice[] }>()); + export const upsertHDevices = createAction('[HDevice/API] Upsert HDevices', props<{ hDevices: HDevice[] }>()); + export const updateHDevice = createAction('[HDevice/API] Update HDevice', props<{ update: Update }>()); + export const updateHDevices = createAction('[HDevice/API] Update HDevices', props<{ updates: Update[] }>()); + export const mapHDevice = createAction('[HDevice/API] Map HDevice', props<{ entityMap: EntityMapOne }>()); + export const mapHDevices = createAction('[HDevice/API] Map HDevices', props<{ entityMap: EntityMap }>()); + export const deleteHDevice = createAction('[HDevice/API] Delete HDevice', props<{ id: number }>()); + export const deleteHDevices = createAction('[HDevice/API] Delete HDevices', props<{ ids: number[] }>()); + export const deleteHDevicesByPredicate = createAction('[HDevice/API] Delete HDevices By Predicate', props<{ predicate: Predicate }>()); + export const clearHDevices = createAction('[HDevice/API] Clear HDevices'); +} diff --git a/src/app/state/hDevices/hDevices.effects.ts b/projects/core/src/lib/store/hDevices/hDevices.effects.ts similarity index 63% rename from src/app/state/hDevices/hDevices.effects.ts rename to projects/core/src/lib/store/hDevices/hDevices.effects.ts index ae7c18e0..c85f2e90 100644 --- a/src/app/state/hDevices/hDevices.effects.ts +++ b/projects/core/src/lib/store/hDevices/hDevices.effects.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { HdevicesService, Logger, LoggerService } from 'core'; +import { HdevicesService } from '../../hyperiot-client/h-device-client/api-module/api/hdevices.service'; import { of } from 'rxjs'; import { map, mergeMap, catchError } from 'rxjs/operators'; import { HDeviceActions } from './hDevices.actions'; @@ -8,18 +8,14 @@ import { HDeviceActions } from './hDevices.actions'; @Injectable() export class HDevicesEffects { - private logger: Logger; - load$ = createEffect(() => this.actions$.pipe( ofType(HDeviceActions.loadHDevices), mergeMap(() => this.hDevicesService.findAllHDevice() .pipe( map(hDevices => { - this.logger.debug('laod$ findAllHDevice() response', hDevices); return HDeviceActions.loadHDevicesSuccess({ hDevices }); }), catchError((err) => { - this.logger.debug('laod$ findAllHDevice() catchError', err); return of(HDeviceActions.loadHDevicesFailure({ error: err })); }), )) @@ -28,10 +24,6 @@ export class HDevicesEffects { constructor( private actions$: Actions, - private hDevicesService: HdevicesService, - loggerService: LoggerService, - ) { - this.logger = new Logger(loggerService); - this.logger.registerClass("HDevicesEffects"); - } + private hDevicesService: HdevicesService + ) { } } \ No newline at end of file diff --git a/projects/core/src/lib/store/hDevices/hDevices.reducer.ts b/projects/core/src/lib/store/hDevices/hDevices.reducer.ts new file mode 100644 index 00000000..597e2936 --- /dev/null +++ b/projects/core/src/lib/store/hDevices/hDevices.reducer.ts @@ -0,0 +1,99 @@ +import { createReducer, on } from "@ngrx/store"; +import { HDevice } from "../../hyperiot-client/models/hDevice"; +import { createEntityAdapter, EntityAdapter, EntityState } from "@ngrx/entity"; +import { HDeviceActions } from "./hDevices.actions"; + +export namespace HDeviceStore { + + export const key = 'hDevices'; + + export interface State extends EntityState { + // additional entities state properties + selectedHDeviceId: string | null; + } + + export const adapter: EntityAdapter = createEntityAdapter(); + + export const initialState: State = adapter.getInitialState({ + // additional entity state properties + selectedHDeviceId: null, + }); + + export const reducer = createReducer( + initialState, + on(HDeviceActions.loadHDevices, (state) => { + return { ...state }; + }), + on(HDeviceActions.loadHDevicesSuccess, (state, { hDevices }) => { + return adapter.setAll(hDevices, state); + }), + on(HDeviceActions.loadHDevicesFailure, (state, { error }) => { + return { ...state }; + }), + on(HDeviceActions.addHDevice, (state, { hDevice }) => { + return adapter.addOne(hDevice, state) + }), + on(HDeviceActions.setHDevice, (state, { hDevice }) => { + return adapter.setOne(hDevice, state) + }), + on(HDeviceActions.upsertHDevice, (state, { hDevice }) => { + return adapter.upsertOne(hDevice, state); + }), + on(HDeviceActions.addHDevices, (state, { hDevices }) => { + return adapter.addMany(hDevices, state); + }), + on(HDeviceActions.upsertHDevices, (state, { hDevices }) => { + return adapter.upsertMany(hDevices, state); + }), + on(HDeviceActions.updateHDevice, (state, { update }) => { + return adapter.updateOne(update, state); + }), + on(HDeviceActions.updateHDevices, (state, { updates }) => { + return adapter.updateMany(updates, state); + }), + on(HDeviceActions.mapHDevice, (state, { entityMap }) => { + return adapter.mapOne(entityMap, state); + }), + on(HDeviceActions.mapHDevices, (state, { entityMap }) => { + return adapter.map(entityMap, state); + }), + on(HDeviceActions.deleteHDevice, (state, { id }) => { + return adapter.removeOne(id, state); + }), + on(HDeviceActions.deleteHDevices, (state, { ids }) => { + return adapter.removeMany(ids, state); + }), + on(HDeviceActions.deleteHDevicesByPredicate, (state, { predicate }) => { + return adapter.removeMany(predicate, state); + }), + on(HDeviceActions.setHDevices, (state, { hDevices }) => { + return adapter.setMany(hDevices, state); + }), + on(HDeviceActions.clearHDevices, state => { + return adapter.removeAll({ ...state, selectedHDeviceId: null }); + }) + ); + + export const getSelectedHDeviceId = (state: HDeviceStore.State) => state.selectedHDeviceId; + + // get the selectors + const { + selectIds, + selectEntities, + selectAll, + selectTotal, + } = adapter.getSelectors(); + + // select the array of liveAlarm ids + export const selectHDeviceIds = selectIds; + + // select the dictionary of liveAlarm entities + export const selectHDeviceEntities = selectEntities; + + // select the array of liveAlarms + export const selectAllHDevices = selectAll; + + // select the total liveAlarm count + export const selectHDeviceTotal = selectTotal; + +} diff --git a/projects/core/src/lib/store/hDevices/hDevices.selectors.ts b/projects/core/src/lib/store/hDevices/hDevices.selectors.ts new file mode 100644 index 00000000..a5d2e7dd --- /dev/null +++ b/projects/core/src/lib/store/hDevices/hDevices.selectors.ts @@ -0,0 +1,67 @@ +import { createFeatureSelector, createSelector } from '@ngrx/store'; + +import { HDeviceStore } from './hDevices.reducer' +import { HDevice } from '../../hyperiot-client/models/hDevice'; +import { RuleSelectors } from '../rules/rules.selectors'; +import { HPacketSelectors } from '../hPackets/hPackets.selectors'; + +export namespace HDeviceSelectors { + + export const selectHDeviceState = createFeatureSelector(HDeviceStore.key); + + export const selectHDeviceIds = createSelector( + selectHDeviceState, + HDeviceStore.selectHDeviceIds // shorthand for usersState => HDeviceStore.selectHDeviceIds(usersState) + ); + export const selectHDeviceEntities = createSelector( + selectHDeviceState, + HDeviceStore.selectHDeviceEntities + ); + export const selectAllHDevices = createSelector( + selectHDeviceState, + HDeviceStore.selectAllHDevices + ); + export const selectHDeviceTotal = createSelector( + selectHDeviceState, + HDeviceStore.selectHDeviceTotal + ); + export const selectCurrentHDeviceId = createSelector( + selectHDeviceState, + HDeviceStore.getSelectedHDeviceId + ); + + export const selectCurrentHDevice = createSelector( + selectHDeviceEntities, + selectCurrentHDeviceId, + (alarmEnetities, userId) => userId && alarmEnetities[userId] + ); + + export const selectHDeviceById = (props: { id: number }) => createSelector( + selectHDeviceEntities, + (hDeviceEnetities) => props.id && hDeviceEnetities[props.id] + ); + + export const selectHDevcicesByRuleId = (props: { ruleId: number }) => createSelector( + RuleSelectors.selectRuleEntities, + HPacketSelectors.selectHPacketEntities, + selectHDeviceEntities, + (rules, packets, devicesEntities) => { + const ruleDefinition = rules[props.ruleId].ruleDefinition.replace(/"/g, '').trim(); + const ruleArray: string[] = ruleDefinition.match(/[^AND|OR]+(AND|OR)?/g).map(x => x.trim()); + + const devices: HDevice[] = []; + ruleArray.forEach(rule => { + const tempSplitted: string[] = rule.split(' ').filter(i => i); + const packetFieldPart = tempSplitted.shift(); + const splitted: string[] = packetFieldPart.split('.').concat(tempSplitted); + const packetId = +splitted[0]; + + const deviceByPacketId = devicesEntities[packets[packetId].device.id]; + + devices.push(deviceByPacketId); + }); + return devices; + } + ); + +} diff --git a/projects/core/src/lib/store/hDevices/index.ts b/projects/core/src/lib/store/hDevices/index.ts new file mode 100644 index 00000000..59cb51cd --- /dev/null +++ b/projects/core/src/lib/store/hDevices/index.ts @@ -0,0 +1,4 @@ +export * from './hDevices.actions'; +export * from './hDevices.effects'; +export * from './hDevices.reducer'; +export * from './hDevices.selectors'; diff --git a/projects/core/src/lib/store/hPackets/hPackets.actions.ts b/projects/core/src/lib/store/hPackets/hPackets.actions.ts new file mode 100644 index 00000000..2a62ff52 --- /dev/null +++ b/projects/core/src/lib/store/hPackets/hPackets.actions.ts @@ -0,0 +1,24 @@ +import { EntityMap, EntityMapOne, Predicate, Update } from "@ngrx/entity"; +import { createAction, props } from "@ngrx/store"; +import { HPacket } from "../../hyperiot-client/models/hPacket"; + +export namespace HPacketActions { + export const loadHPackets = createAction('[HPacket/API] Load HPackets'); + export const loadHPacketsSuccess = createAction('[HPacket/API] Load HPackets Success', props<{ hPackets: HPacket[] }>()); + export const loadHPacketsFailure = createAction('[HPacket/API] Load HPackets Failure', props<{ error: any }>()); + + export const setHPackets = createAction('[HPacket/API] Set HPackets', props<{ hPackets: HPacket[] }>()); + export const addHPacket = createAction('[HPacket/API] Add HPacket', props<{ hPacket: HPacket }>()); + export const setHPacket = createAction('[HPacket/API] Set HPacket', props<{ hPacket: HPacket }>()); + export const upsertHPacket = createAction('[HPacket/API] Upsert HPacket', props<{ hPacket: HPacket }>()); + export const addHPackets = createAction('[HPacket/API] Add HPackets', props<{ hPackets: HPacket[] }>()); + export const upsertHPackets = createAction('[HPacket/API] Upsert HPackets', props<{ hPackets: HPacket[] }>()); + export const updateHPacket = createAction('[HPacket/API] Update HPacket', props<{ update: Update }>()); + export const updateHPackets = createAction('[HPacket/API] Update HPackets', props<{ updates: Update[] }>()); + export const mapHPacket = createAction('[HPacket/API] Map HPacket', props<{ entityMap: EntityMapOne }>()); + export const mapHPackets = createAction('[HPacket/API] Map HPackets', props<{ entityMap: EntityMap }>()); + export const deleteHPacket = createAction('[HPacket/API] Delete HPacket', props<{ id: number }>()); + export const deleteHPackets = createAction('[HPacket/API] Delete HPackets', props<{ ids: number[] }>()); + export const deleteHPacketsByPredicate = createAction('[HPacket/API] Delete HPackets By Predicate', props<{ predicate: Predicate }>()); + export const clearHPackets = createAction('[HPacket/API] Clear HPackets'); +} diff --git a/src/app/state/hPackets/hPackets.effects.ts b/projects/core/src/lib/store/hPackets/hPackets.effects.ts similarity index 66% rename from src/app/state/hPackets/hPackets.effects.ts rename to projects/core/src/lib/store/hPackets/hPackets.effects.ts index dbab409d..124357e2 100644 --- a/src/app/state/hPackets/hPackets.effects.ts +++ b/projects/core/src/lib/store/hPackets/hPackets.effects.ts @@ -1,24 +1,20 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { HpacketsService, Logger, LoggerService } from 'core'; -import { HPacketActions } from './hPackets.actions'; +import { HpacketsService } from '../../hyperiot-client/h-packet-client/api-module'; import { catchError, map, mergeMap, of } from 'rxjs'; +import { HPacketActions } from './hPackets.actions'; @Injectable() export class HPacketsEffects { - private logger: Logger; - load$ = createEffect(() => this.actions$.pipe( ofType(HPacketActions.loadHPackets), mergeMap(() => this.hPacketsService.findAllHPacket() .pipe( map(hPackets => { - this.logger.debug('laod$ findAllHPacket() response', hPackets); return HPacketActions.loadHPacketsSuccess({ hPackets }); }), catchError((err) => { - this.logger.debug('laod$ findAllHPacket() catchError', err); return of(HPacketActions.loadHPacketsFailure({ error: err })); }), )) @@ -28,9 +24,5 @@ export class HPacketsEffects { constructor( private actions$: Actions, private hPacketsService: HpacketsService, - loggerService: LoggerService, - ) { - this.logger = new Logger(loggerService); - this.logger.registerClass("HPacketsEffects"); - } + ) { } } \ No newline at end of file diff --git a/projects/core/src/lib/store/hPackets/hPackets.reducer.ts b/projects/core/src/lib/store/hPackets/hPackets.reducer.ts new file mode 100644 index 00000000..2f2623b9 --- /dev/null +++ b/projects/core/src/lib/store/hPackets/hPackets.reducer.ts @@ -0,0 +1,87 @@ +import { createReducer, on } from "@ngrx/store"; +import { HPacket } from "../../hyperiot-client/models/hPacket"; +import { createEntityAdapter, EntityAdapter, EntityState } from "@ngrx/entity"; +import { HPacketActions } from "./hPackets.actions"; + +export namespace HPacketStore { + + export interface State extends EntityState { + // additional entities state properties + selectedHPacketId: string | null; + } + + export const key = 'hPackets'; + + export const adapter: EntityAdapter = createEntityAdapter(); + + export const initialState: State = adapter.getInitialState({ + // additional entity state properties + selectedHPacketId: null, + }); + + export const reducer = createReducer( + initialState, + on(HPacketActions.loadHPackets, (state) => { + return { ...state }; + }), + on(HPacketActions.loadHPacketsSuccess, (state, { hPackets }) => { + return adapter.setAll(hPackets, state); + }), + on(HPacketActions.loadHPacketsFailure, (state, { error }) => { + return { ...state }; + }), + on(HPacketActions.addHPacket, (state, { hPacket }) => { + return adapter.addOne(hPacket, state) + }), + on(HPacketActions.setHPacket, (state, { hPacket }) => { + return adapter.setOne(hPacket, state) + }), + on(HPacketActions.upsertHPacket, (state, { hPacket }) => { + return adapter.upsertOne(hPacket, state); + }), + on(HPacketActions.addHPackets, (state, { hPackets }) => { + return adapter.addMany(hPackets, state); + }), + on(HPacketActions.upsertHPackets, (state, { hPackets }) => { + return adapter.upsertMany(hPackets, state); + }), + on(HPacketActions.updateHPacket, (state, { update }) => { + return adapter.updateOne(update, state); + }), + on(HPacketActions.updateHPackets, (state, { updates }) => { + return adapter.updateMany(updates, state); + }), + on(HPacketActions.mapHPacket, (state, { entityMap }) => { + return adapter.mapOne(entityMap, state); + }), + on(HPacketActions.mapHPackets, (state, { entityMap }) => { + return adapter.map(entityMap, state); + }), + on(HPacketActions.deleteHPacket, (state, { id }) => { + return adapter.removeOne(id, state); + }), + on(HPacketActions.deleteHPackets, (state, { ids }) => { + return adapter.removeMany(ids, state); + }), + on(HPacketActions.deleteHPacketsByPredicate, (state, { predicate }) => { + return adapter.removeMany(predicate, state); + }), + on(HPacketActions.setHPackets, (state, { hPackets }) => { + return adapter.setMany(hPackets, state); + }), + on(HPacketActions.clearHPackets, state => { + return adapter.removeAll({ ...state, selectedHPacketId: null }); + }) + ); + + export const getSelectedHPacketId = (state: HPacketStore.State) => state.selectedHPacketId; + + // get the selectors + export const { + selectIds: selectHPacketIds, // select the array of liveAlarm ids + selectEntities: selectHPacketEntities, // select the dictionary of liveAlarm entities + selectAll: selectAllHPackets, // select the array of liveAlarms + selectTotal: selectHPacketTotal, // select the total liveAlarm count + } = adapter.getSelectors(); + +} diff --git a/projects/core/src/lib/store/hPackets/hPackets.selectors.ts b/projects/core/src/lib/store/hPackets/hPackets.selectors.ts new file mode 100644 index 00000000..ed0142ee --- /dev/null +++ b/projects/core/src/lib/store/hPackets/hPackets.selectors.ts @@ -0,0 +1,40 @@ +import { createFeatureSelector, createSelector } from '@ngrx/store'; +import { HPacketStore } from './hPackets.reducer'; + +export namespace HPacketSelectors { + + export const selectHPacketState = createFeatureSelector(HPacketStore.key); + + export const selectHPacketIds = createSelector( + selectHPacketState, + HPacketStore.selectHPacketIds // shorthand for usersState => HPacketStore.selectHPacketIds(usersState) + ); + export const selectHPacketEntities = createSelector( + selectHPacketState, + HPacketStore.selectHPacketEntities + ); + export const selectAllHPackets = createSelector( + selectHPacketState, + HPacketStore.selectAllHPackets + ); + export const selectHPacketTotal = createSelector( + selectHPacketState, + HPacketStore.selectHPacketTotal + ); + export const selectCurrentHPacketId = createSelector( + selectHPacketState, + HPacketStore.getSelectedHPacketId + ); + + export const selectCurrentHPacket = createSelector( + selectHPacketEntities, + selectCurrentHPacketId, + (alarmEnetities, userId) => userId && alarmEnetities[userId] + ); + + export const selectHPacketById = (props: {id: number}) => createSelector( + selectHPacketEntities, + (hPacketEnetities) => props.id && hPacketEnetities[props.id] + ); + +} diff --git a/projects/core/src/lib/store/hPackets/index.ts b/projects/core/src/lib/store/hPackets/index.ts new file mode 100644 index 00000000..e36463bb --- /dev/null +++ b/projects/core/src/lib/store/hPackets/index.ts @@ -0,0 +1,4 @@ +export * from './hPackets.actions'; +export * from './hPackets.effects'; +export * from './hPackets.reducer'; +export * from './hPackets.selectors'; diff --git a/projects/core/src/lib/store/hProjects/hProjects.actions.ts b/projects/core/src/lib/store/hProjects/hProjects.actions.ts new file mode 100644 index 00000000..a9ec4629 --- /dev/null +++ b/projects/core/src/lib/store/hProjects/hProjects.actions.ts @@ -0,0 +1,26 @@ +import { EntityMap, EntityMapOne, Predicate, Update } from "@ngrx/entity"; +import { createAction, props } from "@ngrx/store"; +import { HProject } from "../../hyperiot-client/models/hProject"; + +export namespace HProjectActions { + + export const loadHProjects = createAction('[HProject/API] Load HProjects'); + export const loadHProjectsSuccess = createAction('[HProject/API] Load HProjects Success', props<{ hProjects: HProject[] }>()); + export const loadHProjectsFailure = createAction('[HProject/API] Load HProjects Failure', props<{ error: any }>()); + + export const setHProjects = createAction('[HProject/API] Set HProjects', props<{ hProjects: HProject[] }>()); + export const addHProject = createAction('[HProject/API] Add HProject', props<{ hProject: HProject }>()); + export const setHProject = createAction('[HProject/API] Set HProject', props<{ hProject: HProject }>()); + export const upsertHProject = createAction('[HProject/API] Upsert HProject', props<{ hProject: HProject }>()); + export const addHProjects = createAction('[HProject/API] Add HProjects', props<{ hProjects: HProject[] }>()); + export const upsertHProjects = createAction('[HProject/API] Upsert HProjects', props<{ hProjects: HProject[] }>()); + export const updateHProject = createAction('[HProject/API] Update HProject', props<{ update: Update }>()); + export const updateHProjects = createAction('[HProject/API] Update HProjects', props<{ updates: Update[] }>()); + export const mapHProject = createAction('[HProject/API] Map HProject', props<{ entityMap: EntityMapOne }>()); + export const mapHProjects = createAction('[HProject/API] Map HProjects', props<{ entityMap: EntityMap }>()); + export const deleteHProject = createAction('[HProject/API] Delete HProject', props<{ id: number }>()); + export const deleteHProjects = createAction('[HProject/API] Delete HProjects', props<{ ids: number[] }>()); + export const deleteHProjectsByPredicate = createAction('[HProject/API] Delete HProjects By Predicate', props<{ predicate: Predicate }>()); + export const clearHProjects = createAction('[HProject/API] Clear HProjects'); + +} diff --git a/src/app/state/hProjects/hProjects.effects.ts b/projects/core/src/lib/store/hProjects/hProjects.effects.ts similarity index 62% rename from src/app/state/hProjects/hProjects.effects.ts rename to projects/core/src/lib/store/hProjects/hProjects.effects.ts index c6164aaf..7c66f26a 100644 --- a/src/app/state/hProjects/hProjects.effects.ts +++ b/projects/core/src/lib/store/hProjects/hProjects.effects.ts @@ -1,25 +1,21 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { HprojectsService, Logger, LoggerService } from 'core'; +import { HprojectsService } from '../../hyperiot-client/h-project-client/api-module'; import { of } from 'rxjs'; -import { map, mergeMap, catchError, exhaustMap } from 'rxjs/operators'; +import { map, mergeMap, catchError } from 'rxjs/operators'; import { HProjectActions } from './hProjects.actions'; @Injectable() export class HProjectsEffects { - private logger: Logger; - load$ = createEffect(() => this.actions$.pipe( ofType(HProjectActions.loadHProjects), mergeMap(() => this.hProjectsService.cardsView() .pipe( map(hProjects => { - this.logger.debug('laod$ cardsView() response', hProjects); return HProjectActions.loadHProjectsSuccess({ hProjects }); }), catchError((err) => { - this.logger.debug('laod$ cardsView() catchError', err); return of(HProjectActions.loadHProjectsFailure({ error: err })); }), )) @@ -29,9 +25,5 @@ export class HProjectsEffects { constructor( private actions$: Actions, private hProjectsService: HprojectsService, - loggerService: LoggerService, - ) { - this.logger = new Logger(loggerService); - this.logger.registerClass("HProjectsEffects"); - } + ) { } } \ No newline at end of file diff --git a/projects/core/src/lib/store/hProjects/hProjects.reducer.ts b/projects/core/src/lib/store/hProjects/hProjects.reducer.ts new file mode 100644 index 00000000..bca72f6f --- /dev/null +++ b/projects/core/src/lib/store/hProjects/hProjects.reducer.ts @@ -0,0 +1,99 @@ +import { createReducer, on } from "@ngrx/store"; +import { HProject } from "../../hyperiot-client/models/hProject"; +import { createEntityAdapter, EntityAdapter, EntityState } from "@ngrx/entity"; +import { HProjectActions } from "./hProjects.actions"; + +export namespace HProjectStore { + + export const key = 'hProjects'; + + export interface State extends EntityState { + // additional entities state properties + selectedHProjectId: string | null; + } + + export const adapter: EntityAdapter = createEntityAdapter(); + + export const initialState: State = adapter.getInitialState({ + // additional entity state properties + selectedHProjectId: null, + }); + + export const reducer = createReducer( + initialState, + on(HProjectActions.loadHProjects, (state) => { + return { ...state }; + }), + on(HProjectActions.loadHProjectsSuccess, (state, { hProjects }) => { + return adapter.setAll(hProjects, state); + }), + on(HProjectActions.loadHProjectsFailure, (state, { error }) => { + return { ...state }; + }), + on(HProjectActions.addHProject, (state, { hProject }) => { + return adapter.addOne(hProject, state) + }), + on(HProjectActions.setHProject, (state, { hProject }) => { + return adapter.setOne(hProject, state) + }), + on(HProjectActions.upsertHProject, (state, { hProject }) => { + return adapter.upsertOne(hProject, state); + }), + on(HProjectActions.addHProjects, (state, { hProjects }) => { + return adapter.addMany(hProjects, state); + }), + on(HProjectActions.upsertHProjects, (state, { hProjects }) => { + return adapter.upsertMany(hProjects, state); + }), + on(HProjectActions.updateHProject, (state, { update }) => { + return adapter.updateOne(update, state); + }), + on(HProjectActions.updateHProjects, (state, { updates }) => { + return adapter.updateMany(updates, state); + }), + on(HProjectActions.mapHProject, (state, { entityMap }) => { + return adapter.mapOne(entityMap, state); + }), + on(HProjectActions.mapHProjects, (state, { entityMap }) => { + return adapter.map(entityMap, state); + }), + on(HProjectActions.deleteHProject, (state, { id }) => { + return adapter.removeOne(id, state); + }), + on(HProjectActions.deleteHProjects, (state, { ids }) => { + return adapter.removeMany(ids, state); + }), + on(HProjectActions.deleteHProjectsByPredicate, (state, { predicate }) => { + return adapter.removeMany(predicate, state); + }), + on(HProjectActions.setHProjects, (state, { hProjects }) => { + return adapter.setMany(hProjects, state); + }), + on(HProjectActions.clearHProjects, state => { + return adapter.removeAll({ ...state, selectedHProjectId: null }); + }) + ); + + export const getSelectedHProjectId = (state: State) => state.selectedHProjectId; + + // get the selectors + const { + selectIds, + selectEntities, + selectAll, + selectTotal, + } = adapter.getSelectors(); + + // select the array of liveAlarm ids + export const selectHProjectIds = selectIds; + + // select the dictionary of liveAlarm entities + export const selectHProjectEntities = selectEntities; + + // select the array of liveAlarms + export const selectAllHProjects = selectAll; + + // select the total liveAlarm count + export const selectHProjectTotal = selectTotal; + +} diff --git a/projects/core/src/lib/store/hProjects/hProjects.selectors.ts b/projects/core/src/lib/store/hProjects/hProjects.selectors.ts new file mode 100644 index 00000000..25325a77 --- /dev/null +++ b/projects/core/src/lib/store/hProjects/hProjects.selectors.ts @@ -0,0 +1,39 @@ +import { createFeatureSelector, createSelector } from '@ngrx/store'; + +import { HProjectStore } from './hProjects.reducer'; + +export namespace HProjectSelectors { + export const selectHProjectState = createFeatureSelector(HProjectStore.key); + + export const selectHProjectIds = createSelector( + selectHProjectState, + HProjectStore.selectHProjectIds // shorthand for usersState => HProjectStore.selectHProjectIds(usersState) + ); + export const selectHProjectEntities = createSelector( + selectHProjectState, + HProjectStore.selectHProjectEntities + ); + export const selectAllHProjects = createSelector( + selectHProjectState, + HProjectStore.selectAllHProjects + ); + export const selectHProjectTotal = createSelector( + selectHProjectState, + HProjectStore.selectHProjectTotal + ); + export const selectCurrentHProjectId = createSelector( + selectHProjectState, + HProjectStore.getSelectedHProjectId + ); + + export const selectCurrentHProject = createSelector( + selectHProjectEntities, + selectCurrentHProjectId, + (alarmEnetities, userId) => userId && alarmEnetities[userId] + ); + + export const selectHProjectById = (props: {id: number}) => createSelector( + selectHProjectEntities, + (hProjectEnetities) => props.id && hProjectEnetities[props.id] + ); +} diff --git a/projects/core/src/lib/store/hProjects/index.ts b/projects/core/src/lib/store/hProjects/index.ts new file mode 100644 index 00000000..303e702d --- /dev/null +++ b/projects/core/src/lib/store/hProjects/index.ts @@ -0,0 +1,4 @@ +export * from './hProjects.actions'; +export * from './hProjects.effects'; +export * from './hProjects.reducer'; +export * from './hProjects.selectors'; diff --git a/projects/core/src/lib/store/index.ts b/projects/core/src/lib/store/index.ts new file mode 100644 index 00000000..bef3ff8a --- /dev/null +++ b/projects/core/src/lib/store/index.ts @@ -0,0 +1,64 @@ + +import { + ActionReducerMap, +} from '@ngrx/store'; + +import { BrandingStore } from "./branding/branding.reducer"; +import { LiveAlarmStore } from './live-alarms/live-alarms.reducer'; +import { NotificationStore } from './notification/notification.reducer'; +import { HProjectStore } from './hProjects/hProjects.reducer'; +import { HDeviceStore } from './hDevices/hDevices.reducer'; +import { HPacketStore } from './hPackets/hPackets.reducer'; +import { RuleStore } from './rules/rules.reducer'; +import { UserSiteSettingStore } from './user-site-setting/user-site-setting.reducer'; + +import { BrandingEffects } from './branding'; +import { RulesEffects } from './rules'; +import { HProjectsEffects } from './hProjects'; +import { HDevicesEffects } from './hDevices'; +import { HPacketsEffects } from './hPackets'; +import { LiveAlarmsEffects } from './live-alarms'; +import { NotificationEffects } from './notification'; + +export * from './branding'; +export * from './hDevices'; +export * from './hPackets'; +export * from './hProjects'; +export * from './live-alarms'; +export * from './notification'; +export * from './rules'; +export * from './user-site-setting'; + +export namespace HyperiotStore { + export interface State { + branding: BrandingStore.State, + liveAlarms: LiveAlarmStore.State; + rules: RuleStore.State, + hProjects: HProjectStore.State, + hDevices: HDeviceStore.State, + hPackets: HPacketStore.State, + notifications: NotificationStore.State, + userSiteSetting: UserSiteSettingStore.State, + }; + + export const Reducers: ActionReducerMap = { + branding: BrandingStore.reducer, + liveAlarms: LiveAlarmStore.reducer, + rules: RuleStore.reducer, + hProjects: HProjectStore.reducer, + hDevices: HDeviceStore.reducer, + hPackets: HPacketStore.reducer, + notifications: NotificationStore.reducer, + userSiteSetting: UserSiteSettingStore.reducer, + }; + + export const Effects = [ + BrandingEffects, + RulesEffects, + HProjectsEffects, + HDevicesEffects, + HPacketsEffects, + LiveAlarmsEffects, + NotificationEffects + ]; +} diff --git a/projects/core/src/lib/store/live-alarms/index.ts b/projects/core/src/lib/store/live-alarms/index.ts new file mode 100644 index 00000000..039fa081 --- /dev/null +++ b/projects/core/src/lib/store/live-alarms/index.ts @@ -0,0 +1,4 @@ +export * from './live-alarms.actions'; +export * from './live-alarms.effects'; +export * from './live-alarms.reducer'; +export * from './live-alarms.selectors'; diff --git a/projects/core/src/lib/store/live-alarms/live-alarms.actions.ts b/projects/core/src/lib/store/live-alarms/live-alarms.actions.ts new file mode 100644 index 00000000..e18baa86 --- /dev/null +++ b/projects/core/src/lib/store/live-alarms/live-alarms.actions.ts @@ -0,0 +1,26 @@ +import { createAction, props } from '@ngrx/store'; +import { Update, EntityMap, EntityMapOne, Predicate } from '@ngrx/entity'; +import { HytAlarm } from '../../models/hyperiot-alarm.model'; + +export namespace LiveAlarmActions { + + export const loadLiveAlarms = createAction('[LiveAlarm/API] Load LiveAlarms'); + export const loadLiveAlarmsSuccess = createAction('[LiveAlarm/API] Load LiveAlarms Success', props<{ liveAlarms: HytAlarm.LiveAlarm[] }>()); + export const loadLiveAlarmsFailure = createAction('[LiveAlarm/API] Load LiveAlarms Failure', props<{ error: any }>()); + + export const setLiveAlarms = createAction('[LiveAlarm/API] Set LiveAlarms', props<{ liveAlarms: HytAlarm.LiveAlarm[] }>()); + export const addLiveAlarm = createAction('[LiveAlarm/API] Add LiveAlarm', props<{ liveAlarm: HytAlarm.LiveAlarm }>()); + export const setLiveAlarm = createAction('[LiveAlarm/API] Set LiveAlarm', props<{ liveAlarm: HytAlarm.LiveAlarm }>()); + export const upsertLiveAlarm = createAction('[LiveAlarm/API] Upsert LiveAlarm', props<{ liveAlarm: HytAlarm.LiveAlarm }>()); + export const addLiveAlarms = createAction('[LiveAlarm/API] Add LiveAlarms', props<{ liveAlarms: HytAlarm.LiveAlarm[] }>()); + export const upsertLiveAlarms = createAction('[LiveAlarm/API] Upsert LiveAlarms', props<{ liveAlarms: HytAlarm.LiveAlarm[] }>()); + export const updateLiveAlarm = createAction('[LiveAlarm/API] Update LiveAlarm', props<{ update: Update }>()); + export const updateLiveAlarms = createAction('[LiveAlarm/API] Update LiveAlarms', props<{ updates: Update[] }>()); + export const mapLiveAlarm = createAction('[LiveAlarm/API] Map LiveAlarm', props<{ entityMap: EntityMapOne }>()); + export const mapLiveAlarms = createAction('[LiveAlarm/API] Map LiveAlarms', props<{ entityMap: EntityMap }>()); + export const deleteLiveAlarm = createAction('[LiveAlarm/API] Delete LiveAlarm', props<{ liveAlarm: HytAlarm.LiveAlarm }>()); + export const deleteLiveAlarms = createAction('[LiveAlarm/API] Delete LiveAlarms', props<{ ids: number[] }>()); + export const deleteLiveAlarmsByPredicate = createAction('[LiveAlarm/API] Delete LiveAlarms By Predicate', props<{ predicate: Predicate }>()); + export const clearLiveAlarms = createAction('[LiveAlarm/API] Clear LiveAlarms'); + +} diff --git a/src/app/state/live-alarms/live-alarms.effects.ts b/projects/core/src/lib/store/live-alarms/live-alarms.effects.ts similarity index 78% rename from src/app/state/live-alarms/live-alarms.effects.ts rename to projects/core/src/lib/store/live-alarms/live-alarms.effects.ts index 33f89c54..aee54dbb 100644 --- a/src/app/state/live-alarms/live-alarms.effects.ts +++ b/projects/core/src/lib/store/live-alarms/live-alarms.effects.ts @@ -1,18 +1,19 @@ import { Injectable } from '@angular/core'; import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; -import { AlarmsService, HytAlarm, Logger, LoggerService, RealtimeDataService } from 'core'; +import { AlarmsService } from '../../hyperiot-client/alarms-client/api-module'; +import { HytAlarm } from '../../models/hyperiot-alarm.model'; +import { RealtimeDataService } from '../../hyperiot-base/realtime-data-service/realtime-data.service'; import { from, of } from 'rxjs'; import { map, mergeMap, catchError, tap, switchMap, filter, toArray } from 'rxjs/operators'; -import * as LiveAlarmsActions from './live-alarms.actions'; +import { LiveAlarmActions } from './live-alarms.actions'; import { Store } from '@ngrx/store'; import { HProjectSelectors } from '../hProjects/hProjects.selectors'; import { HDeviceSelectors } from '../hDevices/hDevices.selectors'; +import { RuleSelectors } from '../rules/rules.selectors'; @Injectable() export class LiveAlarmsEffects { - private logger: Logger; - private severityColors = new Map([ [0, '#46A0F3'], [1, '#F9BE26'], @@ -23,12 +24,12 @@ export class LiveAlarmsEffects { private DEFAULT_BACKGROUND_COLOUR = '#1f58a5'; load$ = createEffect(() => this.actions$.pipe( - ofType(LiveAlarmsActions.loadLiveAlarms), + ofType(LiveAlarmActions.loadLiveAlarms), concatLatestFrom( () => this.store.select(HProjectSelectors.selectHProjectEntities) ), switchMap( - ([actions, projects]) => this.alarmsService.findAlarmStatusByProjectId(Object.keys(projects).map(id => +id)) + ([action, projects]) => this.alarmsService.findAlarmStatusByProjectId(Object.keys(projects).map(id => +id)) ), map(res => { let allAlarms = []; @@ -46,14 +47,14 @@ export class LiveAlarmsEffects { concatLatestFrom( (alarm: any) => { const maxSeverityEvent = alarm.alarmEvents.reduce((maxSeverityEvt, evt) => { - return evt.severity > evt.severity ? evt : maxSeverityEvt; + return evt.severity > maxSeverityEvt.severity ? evt : maxSeverityEvt; }, alarm.alarmEvents[0]); return this.store.select(HDeviceSelectors.selectHDevcicesByRuleId({ ruleId: maxSeverityEvent.ruleId })); } ), map(([alarm, devices]) => { const maxSeverityEvent = alarm.alarmEvents.reduce((maxSeverityEvt, evt) => { - return evt.severity > evt.severity ? evt : maxSeverityEvt; + return evt.severity > maxSeverityEvt.severity ? evt : maxSeverityEvt; }, alarm.alarmEvents[0]); const liveAlarm: HytAlarm.LiveAlarm = { alarmId: alarm.alarmId, @@ -65,6 +66,7 @@ export class LiveAlarmsEffects { ruleDefinition: maxSeverityEvent.ruleDefinition, lastFiredTimestamp: maxSeverityEvent.lastFiredTimestamp, alarmState: 'UP', + ruleId: maxSeverityEvent.ruleId }, projectId: alarm.projectId, color: { @@ -81,17 +83,16 @@ export class LiveAlarmsEffects { ), ), map(res => { - return LiveAlarmsActions.loadLiveAlarmsSuccess({ liveAlarms: res }); + return LiveAlarmActions.loadLiveAlarmsSuccess({ liveAlarms: res }); }), catchError((error) => { - this.logger.debug('laod$ findAlarmStatusByProjectId() catchError', error); - return of(LiveAlarmsActions.loadLiveAlarmsFailure({ error })); + return of(LiveAlarmActions.loadLiveAlarmsFailure({ error })); }), )); subscribeWs$ = createEffect(() => this.actions$.pipe( - ofType(LiveAlarmsActions.loadLiveAlarmsSuccess, LiveAlarmsActions.loadLiveAlarmsFailure), + ofType(LiveAlarmActions.loadLiveAlarmsSuccess, LiveAlarmActions.loadLiveAlarmsFailure), tap(() => this.collectAlarms()) ), { dispatch: false } @@ -102,11 +103,7 @@ export class LiveAlarmsEffects { private alarmsService: AlarmsService, private realtimeDataService: RealtimeDataService, private store: Store, - loggerService: LoggerService, - ) { - this.logger = new Logger(loggerService); - this.logger.registerClass("LiveAlarmsEffects"); - } + ) { } collectAlarms() { const SUFFIX = HytAlarm.AlarmSuffixsEnum; @@ -122,10 +119,13 @@ export class LiveAlarmsEffects { concatLatestFrom( (p) => { const event = JSON.parse(p.data.fields.event.value.string).data; - return this.store.select(HDeviceSelectors.selectHDevcicesByRuleId({ ruleId: event.ruleId })) + return [ + this.store.select(HDeviceSelectors.selectHDevcicesByRuleId({ ruleId: event.ruleId })), + this.store.select(RuleSelectors.selectRuleById({ id: event.ruleId })) + ] } ), - ).subscribe(([p, devices]) => { + ).subscribe(([p, devices, rule]) => { const packet = p.data; const isEvent = packet.name.endsWith(SUFFIX[SUFFIX._event]); const isAlarm = packet.name.endsWith(SUFFIX[SUFFIX._event_alarm]); @@ -145,12 +145,14 @@ export class LiveAlarmsEffects { alarmId: event.alarmId, alarmName: event.alarmName, event: { - alarmEventId: event.ruleId, alarmEventName: event.ruleName, severity: event.severity, alarmState: event.alarmState, lastFiredTimestamp: event.fireTimestamp, + ruleId: event.ruleId, + ruleDefinition: rule.ruleDefinition }, + projectId: rule.project.id, deviceIds, packetIds: event.packetIds, color: { @@ -164,9 +166,9 @@ export class LiveAlarmsEffects { if (isAlarm) { //NOT FILTER FOR PROJECT, NEED TO CHANGE REALTIME DATA SERVICE if (liveAlarm.event.alarmState == "UP") { - this.store.dispatch(LiveAlarmsActions.setLiveAlarm({ liveAlarm })); + this.store.dispatch(LiveAlarmActions.setLiveAlarm({ liveAlarm })); } else { - this.store.dispatch(LiveAlarmsActions.deleteLiveAlarm({ liveAlarm })); + this.store.dispatch(LiveAlarmActions.deleteLiveAlarm({ liveAlarm })); } } }) diff --git a/projects/core/src/lib/store/live-alarms/live-alarms.reducer.ts b/projects/core/src/lib/store/live-alarms/live-alarms.reducer.ts new file mode 100644 index 00000000..f4deca7b --- /dev/null +++ b/projects/core/src/lib/store/live-alarms/live-alarms.reducer.ts @@ -0,0 +1,106 @@ +import { createReducer, on } from '@ngrx/store'; +import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity'; +import { HytAlarm } from '../../models/hyperiot-alarm.model'; +import { LiveAlarmActions } from './live-alarms.actions'; + +export namespace LiveAlarmStore { + + export const key = 'liveAlarms'; + + export interface State extends EntityState { + // additional entities state properties + selectedLiveAlarmId: string | null; + } + + export function selectLiveAlarmId(a: HytAlarm.LiveAlarm): number { + //In this case this would be optional since primary key is id + return a.alarmId; + } + + export const adapter: EntityAdapter = createEntityAdapter({ + selectId: selectLiveAlarmId + }); + + export const initialState: State = adapter.getInitialState({ + // additional entity state properties + selectedLiveAlarmId: null, + }); + + export const reducer = createReducer( + initialState, + on(LiveAlarmActions.loadLiveAlarms, (state) => { + return { ...state }; + }), + on(LiveAlarmActions.loadLiveAlarmsSuccess, (state, { liveAlarms }) => { + return adapter.setAll(liveAlarms, state); + }), + on(LiveAlarmActions.loadLiveAlarmsFailure, (state, { error }) => { + return { ...state }; + }), + on(LiveAlarmActions.addLiveAlarm, (state, { liveAlarm }) => { + return adapter.addOne(liveAlarm, state) + }), + on(LiveAlarmActions.setLiveAlarm, (state, { liveAlarm }) => { + return adapter.setOne(liveAlarm, state) + }), + on(LiveAlarmActions.upsertLiveAlarm, (state, { liveAlarm }) => { + return adapter.upsertOne(liveAlarm, state); + }), + on(LiveAlarmActions.addLiveAlarms, (state, { liveAlarms }) => { + return adapter.addMany(liveAlarms, state); + }), + on(LiveAlarmActions.upsertLiveAlarms, (state, { liveAlarms }) => { + return adapter.upsertMany(liveAlarms, state); + }), + on(LiveAlarmActions.updateLiveAlarm, (state, { update }) => { + return adapter.updateOne(update, state); + }), + on(LiveAlarmActions.updateLiveAlarms, (state, { updates }) => { + return adapter.updateMany(updates, state); + }), + on(LiveAlarmActions.mapLiveAlarm, (state, { entityMap }) => { + return adapter.mapOne(entityMap, state); + }), + on(LiveAlarmActions.mapLiveAlarms, (state, { entityMap }) => { + return adapter.map(entityMap, state); + }), + on(LiveAlarmActions.deleteLiveAlarm, (state, { liveAlarm }) => { + return adapter.removeOne(liveAlarm.alarmId, state); + }), + on(LiveAlarmActions.deleteLiveAlarms, (state, { ids }) => { + return adapter.removeMany(ids, state); + }), + on(LiveAlarmActions.deleteLiveAlarmsByPredicate, (state, { predicate }) => { + return adapter.removeMany(predicate, state); + }), + on(LiveAlarmActions.setLiveAlarms, (state, { liveAlarms }) => { + return adapter.setMany(liveAlarms, state); + }), + on(LiveAlarmActions.clearLiveAlarms, state => { + return adapter.removeAll({ ...state, selectedLiveAlarmId: null }); + }) + ); + + export const getSelectedLiveAlarmId = (state: State) => state.selectedLiveAlarmId; + + // get the selectors + const { + selectIds, + selectEntities, + selectAll, + selectTotal, + } = adapter.getSelectors(); + + // select the array of liveAlarm ids + export const selectLiveAlarmIds = selectIds; + + // select the dictionary of liveAlarm entities + export const selectLiveAlarmEntities = selectEntities; + + // select the array of liveAlarms + export const selectAllLiveAlarms = selectAll; + + // select the total liveAlarm count + export const selectLiveAlarmTotal = selectTotal; + +} diff --git a/projects/core/src/lib/store/live-alarms/live-alarms.selectors.ts b/projects/core/src/lib/store/live-alarms/live-alarms.selectors.ts new file mode 100644 index 00000000..dc7946c3 --- /dev/null +++ b/projects/core/src/lib/store/live-alarms/live-alarms.selectors.ts @@ -0,0 +1,48 @@ +import { + createSelector, + createFeatureSelector, +} from '@ngrx/store'; +import { LiveAlarmStore } from './live-alarms.reducer'; + +export namespace LiveAlarmSelectors { + + export const selectLiveAlarmState = createFeatureSelector(LiveAlarmStore.key); + + export const selectLiveAlarmIds = createSelector( + selectLiveAlarmState, + LiveAlarmStore.selectLiveAlarmIds // shorthand for usersState => LiveAlarmStore.selectLiveAlarmIds(usersState) + ); + export const selectLiveAlarmEntities = createSelector( + selectLiveAlarmState, + LiveAlarmStore.selectLiveAlarmEntities + ); + export const selectAllLiveAlarms = createSelector( + selectLiveAlarmState, + LiveAlarmStore.selectAllLiveAlarms + ); + export const selectLiveAlarmTotal = createSelector( + selectLiveAlarmState, + LiveAlarmStore.selectLiveAlarmTotal + ); + export const selectCurrentLiveAlarmId = createSelector( + selectLiveAlarmState, + LiveAlarmStore.getSelectedLiveAlarmId + ); + + export const selectCurrentLiveAlarm = createSelector( + selectLiveAlarmEntities, + selectCurrentLiveAlarmId, + (alarmEnetities, userId) => userId && alarmEnetities[userId] + ); + + export const selectLiveAlarmById = (props: {id: number}) => createSelector( + selectLiveAlarmEntities, + (liveAlarmEnetities) => props.id && liveAlarmEnetities[props.id] + ); + + export const selectLiveAlarmsByProjectId = (props: {projectId: number}) => createSelector( + selectAllLiveAlarms, + (allLiveAlarms) => allLiveAlarms.filter(alarm => alarm.projectId === props.projectId) + ) + +} diff --git a/projects/core/src/lib/store/notification/index.ts b/projects/core/src/lib/store/notification/index.ts new file mode 100644 index 00000000..317f9ac3 --- /dev/null +++ b/projects/core/src/lib/store/notification/index.ts @@ -0,0 +1,4 @@ +export * from './notification.actions'; +export * from './notification.effects'; +export * from './notification.reducer'; +export * from './notification.selectors'; \ No newline at end of file diff --git a/projects/core/src/lib/store/notification/notification.actions.ts b/projects/core/src/lib/store/notification/notification.actions.ts new file mode 100644 index 00000000..db26c311 --- /dev/null +++ b/projects/core/src/lib/store/notification/notification.actions.ts @@ -0,0 +1,9 @@ +import { createAction, props } from "@ngrx/store"; +import { NotificationStore } from "./notification.reducer"; + +export namespace NotificationActions { + + export const setNotification = createAction('[Notification/API] Set Notification', props<{ notification: NotificationStore.Notification }>()); + export const deleteNotification = createAction('[Notification/API] Delete Notification', props<{ id: string }>()); + +} diff --git a/src/app/state/notification/notification.effects.ts b/projects/core/src/lib/store/notification/notification.effects.ts similarity index 69% rename from src/app/state/notification/notification.effects.ts rename to projects/core/src/lib/store/notification/notification.effects.ts index 713abddb..f79b0c8c 100644 --- a/src/app/state/notification/notification.effects.ts +++ b/projects/core/src/lib/store/notification/notification.effects.ts @@ -1,19 +1,15 @@ import { Injectable } from "@angular/core"; -import { Actions, concatLatestFrom, createEffect, ofType } from "@ngrx/effects"; -import { HytAlarm, Logger, LoggerService } from "core"; -import * as LiveAlarmsActions from '../live-alarms/live-alarms.actions'; -import * as LiveAlarmSelectors from '../live-alarms/live-alarms.selectors'; -import { Store } from "@ngrx/store"; -import { exhaustMap, mergeMap, of, switchMap } from "rxjs"; -import { NotificationActions } from "./notification.actions"; -import { Notification } from "./notification.model"; +import { Actions, createEffect, ofType } from "@ngrx/effects"; +import { HytAlarm } from "../../models/hyperiot-alarm.model"; +import { of, switchMap } from "rxjs"; import { ToastrService } from "ngx-toastr"; +import { NotificationActions } from "./notification.actions"; +import { LiveAlarmActions } from '../live-alarms/live-alarms.actions'; +import { NotificationStore } from "./notification.reducer"; @Injectable() export class NotificationEffects { - private logger: Logger; - private toastMessage = $localize`:@@HYT_dashboard_event_fired:The event has been fired`; private toastEventMessage = $localize`:@@HYT_dashboard_event_fired:The event has been fired`; private toastMessageAlarmUp = $localize`:@@HYT_dashboard_alarm_fired:The alarm has been fired`; @@ -21,7 +17,7 @@ export class NotificationEffects { convertAlarm$ = createEffect( () => this.actions$.pipe( - ofType(LiveAlarmsActions.setLiveAlarm, LiveAlarmsActions.deleteLiveAlarm), + ofType(LiveAlarmActions.setLiveAlarm, LiveAlarmActions.deleteLiveAlarm), switchMap( ({liveAlarm}) => { return this.converAlarm(liveAlarm) @@ -32,13 +28,8 @@ export class NotificationEffects { constructor( private actions$: Actions, - private store: Store, private toastr: ToastrService, - loggerService: LoggerService, - ) { - this.logger = new Logger(loggerService); - this.logger.registerClass("NotificationEffects"); - } + ) { } converAlarm(alarm: HytAlarm.LiveAlarm) { let toastImage = "info"; @@ -52,7 +43,7 @@ export class NotificationEffects { alarm.event.alarmState === "UP" ? this.toastMessageAlarmUp : this.toastMessageAlarmDown; } const toastId = this.toastr["index"]; - const notification: Notification = { + const notification: NotificationStore.Notification = { id: toastId, title: alarm.event.alarmEventName, message: this.toastMessage, diff --git a/projects/core/src/lib/store/notification/notification.reducer.ts b/projects/core/src/lib/store/notification/notification.reducer.ts new file mode 100644 index 00000000..fe358e4e --- /dev/null +++ b/projects/core/src/lib/store/notification/notification.reducer.ts @@ -0,0 +1,62 @@ +import { createReducer, on } from "@ngrx/store"; +import { createEntityAdapter, EntityAdapter, EntityState } from "@ngrx/entity"; +import { NotificationActions } from "./notification.actions"; + +export namespace NotificationStore { + + export const key = 'notifications'; + + export interface Notification { + id: string; + title: string; + message: string; + color: string; + bgColor: string; + image: string; + } + + const adapter: EntityAdapter = createEntityAdapter(); + + export interface State extends EntityState { + // additional entities state properties + selectedNotificationId: string | null; + } + + const initialState: State = adapter.getInitialState({ + // additional entity state properties + selectedNotificationId: null, + }); + + export const reducer = createReducer( + initialState, + on(NotificationActions.setNotification, (state, { notification }) => { + return adapter.setOne(notification, state) + }), + on(NotificationActions.deleteNotification, (state, { id }) => { + return adapter.removeOne(id, state) + }), + ) + + export const getSelectedNotificationId = (state: State) => state.selectedNotificationId; + + // get the selectors + const { + selectIds, + selectEntities, + selectAll, + selectTotal, + } = adapter.getSelectors(); + + // select the array of notification ids + export const selectNotificationIds = selectIds; + + // select the dictionary of notification entities + export const selectNotificationEntities = selectEntities; + + // select the array of notifications + export const selectAllNotifications = selectAll; + + // select the total notification count + export const selectNotificationTotal = selectTotal; + +} diff --git a/projects/core/src/lib/store/notification/notification.selectors.ts b/projects/core/src/lib/store/notification/notification.selectors.ts new file mode 100644 index 00000000..148e441b --- /dev/null +++ b/projects/core/src/lib/store/notification/notification.selectors.ts @@ -0,0 +1,42 @@ +import { createFeatureSelector, createSelector } from "@ngrx/store"; +import { NotificationStore } from './notification.reducer' + +export namespace NotificationSelectors { + + export interface NotificationState { + notifications: Notification[] + } + + export const selectNotificationState = createFeatureSelector(NotificationStore.key); + + export const selectNotificationIds = createSelector( + selectNotificationState, + NotificationStore.selectNotificationIds // shorthand for usersState => NotificationStore.selectNotificationIds(usersState) + ); + export const selectNotificationEntities = createSelector( + selectNotificationState, + NotificationStore.selectNotificationEntities + ); + export const selectAllNotifications = createSelector( + selectNotificationState, + NotificationStore.selectAllNotifications + ); + export const selectNotificationTotal = createSelector( + selectNotificationState, + NotificationStore.selectNotificationTotal + ); + export const selectCurrentNotificationId = createSelector( + selectNotificationState, + NotificationStore.getSelectedNotificationId + ); + + export const selectLastNotification = createSelector( + selectAllNotifications, + (state) => { + if (state.length) { + return state[state.length - 1]; + } + }, + ); + +} diff --git a/projects/core/src/lib/store/rules/index.ts b/projects/core/src/lib/store/rules/index.ts new file mode 100644 index 00000000..e764d48b --- /dev/null +++ b/projects/core/src/lib/store/rules/index.ts @@ -0,0 +1,4 @@ +export * from './rules.actions'; +export * from './rules.effects'; +export * from './rules.reducer'; +export * from './rules.selectors'; \ No newline at end of file diff --git a/projects/core/src/lib/store/rules/rules.actions.ts b/projects/core/src/lib/store/rules/rules.actions.ts new file mode 100644 index 00000000..bf7e2c50 --- /dev/null +++ b/projects/core/src/lib/store/rules/rules.actions.ts @@ -0,0 +1,26 @@ +import { EntityMap, EntityMapOne, Predicate, Update } from "@ngrx/entity"; +import { createAction, props } from "@ngrx/store"; +import { Rule } from "../../hyperiot-client/models/rule"; + +export namespace RuleActions { + + export const loadRules = createAction('[Rule/API] Load Rules'); + export const loadRulesSuccess = createAction('[Rule/API] Load Rules Success', props<{ rules: Rule[] }>()); + export const loadRulesFailure = createAction('[Rule/API] Load Rules Failure', props<{ error: any }>()); + + export const setRules = createAction('[Rule/API] Set Rules', props<{ rules: Rule[] }>()); + export const addRule = createAction('[Rule/API] Add Rule', props<{ rule: Rule }>()); + export const setRule = createAction('[Rule/API] Set Rule', props<{ rule: Rule }>()); + export const upsertRule = createAction('[Rule/API] Upsert Rule', props<{ rule: Rule }>()); + export const addRules = createAction('[Rule/API] Add Rules', props<{ rules: Rule[] }>()); + export const upsertRules = createAction('[Rule/API] Upsert Rules', props<{ rules: Rule[] }>()); + export const updateRule = createAction('[Rule/API] Update Rule', props<{ update: Update }>()); + export const updateRules = createAction('[Rule/API] Update Rules', props<{ updates: Update[] }>()); + export const mapRule = createAction('[Rule/API] Map Rule', props<{ entityMap: EntityMapOne }>()); + export const mapRules = createAction('[Rule/API] Map Rules', props<{ entityMap: EntityMap }>()); + export const deleteRule = createAction('[Rule/API] Delete Rule', props<{ id: number }>()); + export const deleteRules = createAction('[Rule/API] Delete Rules', props<{ ids: number[] }>()); + export const deleteRulesByPredicate = createAction('[Rule/API] Delete Rules By Predicate', props<{ predicate: Predicate }>()); + export const clearRules = createAction('[Rule/API] Clear Rules'); + +} diff --git a/src/app/state/rules/rules.effects.ts b/projects/core/src/lib/store/rules/rules.effects.ts similarity index 61% rename from src/app/state/rules/rules.effects.ts rename to projects/core/src/lib/store/rules/rules.effects.ts index ed5568e9..f63602de 100644 --- a/src/app/state/rules/rules.effects.ts +++ b/projects/core/src/lib/store/rules/rules.effects.ts @@ -1,25 +1,21 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; -import { Logger, LoggerService, RulesService } from 'core'; +import { RulesService } from '../../hyperiot-client/rule-client/api-module'; import { of } from 'rxjs'; -import { map, mergeMap, catchError, exhaustMap } from 'rxjs/operators'; +import { map, mergeMap, catchError } from 'rxjs/operators'; import { RuleActions } from './rules.actions'; @Injectable() export class RulesEffects { - - private logger: Logger; load$ = createEffect(() => this.actions$.pipe( ofType(RuleActions.loadRules), mergeMap(() => this.rulesService.findAllRule() .pipe( map(rules => { - this.logger.debug('laod$ findAllRule() response', rules); return RuleActions.loadRulesSuccess({ rules }); }), catchError((err) => { - this.logger.debug('laod$ findAllRule() catchError', err); return of(RuleActions.loadRulesFailure({ error: err })); }), )) @@ -29,9 +25,5 @@ export class RulesEffects { constructor( private actions$: Actions, private rulesService: RulesService, - loggerService: LoggerService, - ) { - this.logger = new Logger(loggerService); - this.logger.registerClass("RulesEffects"); - } -} \ No newline at end of file + ) { } +} diff --git a/projects/core/src/lib/store/rules/rules.reducer.ts b/projects/core/src/lib/store/rules/rules.reducer.ts new file mode 100644 index 00000000..2bd1ab24 --- /dev/null +++ b/projects/core/src/lib/store/rules/rules.reducer.ts @@ -0,0 +1,99 @@ +import { createReducer, on, Store } from "@ngrx/store"; +import { Rule } from "../../hyperiot-client/models/rule"; +import { createEntityAdapter, EntityAdapter, EntityState } from "@ngrx/entity"; +import { RuleActions } from "./rules.actions"; + +export namespace RuleStore { + + export const key = 'rules'; + + export const adapter: EntityAdapter = createEntityAdapter(); + + export interface State extends EntityState { + // additional entities state properties + selectedRuleId: string | null; + } + + export const initialState: State = adapter.getInitialState({ + // additional entity state properties + selectedRuleId: null, + }); + + export const reducer = createReducer( + initialState, + on(RuleActions.loadRules, (state) => { + return { ...state }; + }), + on(RuleActions.loadRulesSuccess, (state, { rules }) => { + return adapter.setAll(rules, state); + }), + on(RuleActions.loadRulesFailure, (state, { error }) => { + return { ...state }; + }), + on(RuleActions.addRule, (state, { rule }) => { + return adapter.addOne(rule, state) + }), + on(RuleActions.setRule, (state, { rule }) => { + return adapter.setOne(rule, state) + }), + on(RuleActions.upsertRule, (state, { rule }) => { + return adapter.upsertOne(rule, state); + }), + on(RuleActions.addRules, (state, { rules }) => { + return adapter.addMany(rules, state); + }), + on(RuleActions.upsertRules, (state, { rules }) => { + return adapter.upsertMany(rules, state); + }), + on(RuleActions.updateRule, (state, { update }) => { + return adapter.updateOne(update, state); + }), + on(RuleActions.updateRules, (state, { updates }) => { + return adapter.updateMany(updates, state); + }), + on(RuleActions.mapRule, (state, { entityMap }) => { + return adapter.mapOne(entityMap, state); + }), + on(RuleActions.mapRules, (state, { entityMap }) => { + return adapter.map(entityMap, state); + }), + on(RuleActions.deleteRule, (state, { id }) => { + return adapter.removeOne(id, state); + }), + on(RuleActions.deleteRules, (state, { ids }) => { + return adapter.removeMany(ids, state); + }), + on(RuleActions.deleteRulesByPredicate, (state, { predicate }) => { + return adapter.removeMany(predicate, state); + }), + on(RuleActions.setRules, (state, { rules }) => { + return adapter.setMany(rules, state); + }), + on(RuleActions.clearRules, state => { + return adapter.removeAll({ ...state, selectedRuleId: null }); + }) + ); + + export const getSelectedRuleId = (state: State) => state.selectedRuleId; + + // get the selectors + const { + selectIds, + selectEntities, + selectAll, + selectTotal, + } = adapter.getSelectors(); + + // select the array of liveAlarm ids + export const selectRuleIds = selectIds; + + // select the dictionary of liveAlarm entities + export const selectRuleEntities = selectEntities; + + // select the array of liveAlarms + export const selectAllRules = selectAll; + + // select the total liveAlarm count + export const selectRuleTotal = selectTotal; + +} diff --git a/projects/core/src/lib/store/rules/rules.selectors.ts b/projects/core/src/lib/store/rules/rules.selectors.ts new file mode 100644 index 00000000..22d1fe7e --- /dev/null +++ b/projects/core/src/lib/store/rules/rules.selectors.ts @@ -0,0 +1,40 @@ +import { createFeatureSelector, createSelector } from '@ngrx/store'; + +import { RuleStore } from './rules.reducer' + +export namespace RuleSelectors { + export const selectRuleState = createFeatureSelector(RuleStore.key); + + export const selectRuleIds = createSelector( + selectRuleState, + RuleStore.selectRuleIds // shorthand for usersState => RuleStore.selectRuleIds(usersState) + ); + export const selectRuleEntities = createSelector( + selectRuleState, + RuleStore.selectRuleEntities + ); + export const selectAllRules = createSelector( + selectRuleState, + RuleStore.selectAllRules + ); + export const selectRuleTotal = createSelector( + selectRuleState, + RuleStore.selectRuleTotal + ); + export const selectCurrentRuleId = createSelector( + selectRuleState, + RuleStore.getSelectedRuleId + ); + + export const selectCurrentRule = createSelector( + selectRuleEntities, + selectCurrentRuleId, + (alarmEnetities, userId) => userId && alarmEnetities[userId] + ); + + export const selectRuleById = (props: {id: number}) => createSelector( + selectRuleEntities, + (ruleEnetities) => props.id && ruleEnetities[props.id] + ); + +} diff --git a/projects/core/src/lib/store/user-site-setting/index.ts b/projects/core/src/lib/store/user-site-setting/index.ts new file mode 100644 index 00000000..1ea43025 --- /dev/null +++ b/projects/core/src/lib/store/user-site-setting/index.ts @@ -0,0 +1,3 @@ +export * from './user-site-setting.actions'; +export * from './user-site-setting.reducer'; +export * from './user-site-setting.selectors'; diff --git a/projects/core/src/lib/store/user-site-setting/user-site-setting.actions.ts b/projects/core/src/lib/store/user-site-setting/user-site-setting.actions.ts new file mode 100644 index 00000000..4193f5bf --- /dev/null +++ b/projects/core/src/lib/store/user-site-setting/user-site-setting.actions.ts @@ -0,0 +1,25 @@ +import { createAction, props } from "@ngrx/store"; +import { UserSiteSettingStore } from "./user-site-setting.reducer"; + +export namespace UserSiteSettingActions { + + export const load = createAction('[UserSiteSetting] Load'); + export const clear = createAction( + '[UserSiteSetting] Clear' + ); + export const setAllSettings = createAction( + '[UserSiteSetting] Update All Settings', + props<{ userSiteSetting: UserSiteSettingStore.State }>() + ); + export const updatePartialSettings = createAction( + '[UserSiteSetting] Update All Settings', + props<{ userSiteSetting: UserSiteSettingStore.State }>() + ); + export const updateSetting = createAction( + '[UserSiteSetting] Update Setting', + props<{ key: keyof UserSiteSettingStore.State, value: any }>() + ); + export const toggleNotification = createAction( + '[UserSiteSetting] Toggle Notification Status' + ); +} diff --git a/projects/core/src/lib/store/user-site-setting/user-site-setting.reducer.ts b/projects/core/src/lib/store/user-site-setting/user-site-setting.reducer.ts new file mode 100644 index 00000000..c53352a1 --- /dev/null +++ b/projects/core/src/lib/store/user-site-setting/user-site-setting.reducer.ts @@ -0,0 +1,102 @@ +import { createReducer, on } from "@ngrx/store"; +import { UserSiteSettingActions } from "./user-site-setting.actions"; + +export namespace UserSiteSettingStore { + + export const key = 'userSiteSetting'; + + const getUserKey = () => { + try { + const user = JSON.parse(localStorage.getItem('user')); + return `${user.username}_settings`; + } catch (error) { + return ''; + } + } + + const getUserSiteSettingLocalStorage = (): State | null => { + try { + return JSON.parse(localStorage.getItem(getUserKey())) as State; + } catch (error) { + return null; + } + } + + const setUserSiteSettingLocalStorage = (value: State) => { + localStorage.setItem(getUserKey(), JSON.stringify(value)); + } + + export interface State { + notificationActive?: boolean; + defaultDashboardProjectId?: number; + confirmDeleteWidgetIdsDismissed?: number[]; + } + + export const initialState: State = { + notificationActive: true, + }; + + const _reducer = createReducer( + initialState, + on(UserSiteSettingActions.load, () => { + const localStorageValue = getUserSiteSettingLocalStorage(); + if (localStorageValue) { + return localStorageValue; + } + return initialState; + }), + on(UserSiteSettingActions.clear, () => { + return initialState; + }), + on(UserSiteSettingActions.setAllSettings, (state, { userSiteSetting }) => { + let newValue = userSiteSetting; + try { + setUserSiteSettingLocalStorage(newValue); + } catch (error) { + newValue = state; + } + return newValue; + }), + on(UserSiteSettingActions.updatePartialSettings, (state, { userSiteSetting }) => { + let newValue = { + ...state, + ...userSiteSetting + }; + try { + setUserSiteSettingLocalStorage(newValue); + } catch (error) { + newValue = state; + } + return newValue; + }), + on(UserSiteSettingActions.updateSetting, (state, { key, value }) => { + let newValue = { + ...state, + [key]: value + }; + try { + setUserSiteSettingLocalStorage(newValue); + } catch (error) { + newValue = state; + } + return newValue; + }), + on(UserSiteSettingActions.toggleNotification, (state) => { + let newValue: State = { + ...state, + notificationActive: !state.notificationActive + }; + try { + setUserSiteSettingLocalStorage(newValue); + } catch (error) { + newValue = state; + } + return newValue; + }), + ); + + export function reducer(state, action) { + return _reducer(state, action); + } + +} diff --git a/projects/core/src/lib/store/user-site-setting/user-site-setting.selectors.ts b/projects/core/src/lib/store/user-site-setting/user-site-setting.selectors.ts new file mode 100644 index 00000000..322ff8f8 --- /dev/null +++ b/projects/core/src/lib/store/user-site-setting/user-site-setting.selectors.ts @@ -0,0 +1,14 @@ +import { createSelector } from "@ngrx/store"; +import { HyperiotStore, UserSiteSettingStore } from ".."; + +const selectUserSiteSetting = (state: HyperiotStore.State) => state.userSiteSetting; + +const selectNotificationActive = createSelector( + selectUserSiteSetting, + (state: UserSiteSettingStore.State) => state.notificationActive +); + +export const UserSiteSettingSelectors = { + selectUserSiteSetting, + selectNotificationActive, +} \ No newline at end of file diff --git a/projects/core/src/public-api.ts b/projects/core/src/public-api.ts index 028b6ced..027e48b0 100644 --- a/projects/core/src/public-api.ts +++ b/projects/core/src/public-api.ts @@ -2,6 +2,8 @@ * Public API Surface of core */ +import '@angular/localize/init'; + export * from './lib/core.service'; export * from './lib/core.component'; export * from './lib/core.module'; @@ -70,7 +72,6 @@ export * from './lib/hyperiot-service/hyperiot-logger/logger.service'; export { FileHandlerService } from './lib/hyperiot-service/hyperiot-file-handler/file-handler.service'; export { HPacketFieldsHandlerService } from './lib/hyperiot-service/hyperiot-h-packet-fields-handler/hpacket-fields-handler.service'; -export { AlarmWrapperService } from './lib/hyperiot-service/hyperiot-alarm-wrapper/hyperiot-alarm-wrapper.service' export { DateFormatterService } from './lib/hyperiot-service/date-formatter/date-formatter.service'; export * from './lib/hyperiot-service/hyperiot-algorithm-offline-data/algorithm-offline-data.service'; @@ -85,7 +86,7 @@ export { RealtimeDataService } from './lib/hyperiot-base/realtime-data-service/r export { OfflineDataService } from './lib/hyperiot-base/offline-data-service/offline-data.service'; export { DevDataService, DevDataSettings } from './lib/hyperiot-base/dev-data-service/dev-data.service'; export { RealtimeDataChannelController } from './lib/hyperiot-base/realtime-data-service/realtimeDataChannelController'; -export { HytAlarm } from './lib/hyperiot-service/hyperiot-alarm-wrapper/hyperiot-alarm.model' +export { HytAlarm } from './lib/models/hyperiot-alarm.model' export { CoreConfig } from './lib/config.service'; export { NotificationManagerService } from './lib/hyperiot-service/notification-manager/notification-manager.service'; @@ -94,4 +95,9 @@ export * from './lib/hyperiot-service/notification-manager/models/notification.m export { GlobalErrorHandlerService } from './lib/hyperiot-service/error-handler/global-error-handler.service'; export * from './lib/hyperiot-service/error-handler/models/error.model'; -export * from './lib/constants/http-context-tokens'; \ No newline at end of file +export * from './lib/constants'; +export * from './lib/models'; + +export * from './lib/store'; + +export * from './lib/services/branding/branding.service' \ No newline at end of file diff --git a/projects/widgets/src/lib/dashboard/widget-settings-dialog/packet-select/packet-select.component.ts b/projects/widgets/src/lib/dashboard/widget-settings-dialog/packet-select/packet-select.component.ts index 0c2f8c47..c6207223 100644 --- a/projects/widgets/src/lib/dashboard/widget-settings-dialog/packet-select/packet-select.component.ts +++ b/projects/widgets/src/lib/dashboard/widget-settings-dialog/packet-select/packet-select.component.ts @@ -15,7 +15,6 @@ import { HPacket, HPacketField, HpacketsService, AreasService, AreaDevice, HDevi import { mimeTypeList } from './MIMETypes'; import { FieldAliases, FieldFileMimeTypes, FieldTypes, FieldUnitConversion, FieldValuesMapList } from '../../../base/base-widget/model/widget.model'; import { DataSimulatorSettings } from "../data-simulator-settings/data-simulator.models"; -import { $localize } from "@angular/localize/init"; import { PageStatus } from '../models/page-status'; @Component({ diff --git a/projects/widgets/src/lib/dashboard/widgets-layout/widgets-layout.component.ts b/projects/widgets/src/lib/dashboard/widgets-layout/widgets-layout.component.ts index f2909535..f12ab3bd 100644 --- a/projects/widgets/src/lib/dashboard/widgets-layout/widgets-layout.component.ts +++ b/projects/widgets/src/lib/dashboard/widgets-layout/widgets-layout.component.ts @@ -11,7 +11,6 @@ import { } from 'angular-gridster2'; import { - AlarmWrapperService, Dashboard, DashboardWidget, HPacket, @@ -111,8 +110,6 @@ export class WidgetsDashboardLayoutComponent implements OnInit, OnDestroy { lastWindowSize; - eventNotificationIsOn: boolean; - /** * This is a demo dashboard for testing widgets * @@ -125,16 +122,10 @@ export class WidgetsDashboardLayoutComponent implements OnInit, OnDestroy { constructor( private realtimeDataService: RealtimeDataService, private configService: DashboardConfigService, - private alarmWrapper: AlarmWrapperService, private activatedRoute: ActivatedRoute, private dialogService: DialogService, private confirmDialogService: ConfirmDialogService, - ) { - this.eventNotificationIsOn = true; - this.alarmWrapper.eventNotificationState.subscribe(res => { - this.eventNotificationIsOn = res; - }); - } + ) { } ngOnInit() { this.loadDashboard(); diff --git a/projects/widgets/src/lib/widget/alarms-widget/alarms-widget.component.html b/projects/widgets/src/lib/widget/alarms-widget/alarms-widget.component.html index d5caea0c..ae1e425a 100644 --- a/projects/widgets/src/lib/widget/alarms-widget/alarms-widget.component.html +++ b/projects/widgets/src/lib/widget/alarms-widget/alarms-widget.component.html @@ -17,7 +17,7 @@ -
+
NO FILTER SELECTED. @@ -34,15 +34,15 @@
Severity - + {{sev.label}}
Showing - {{filteredList.length}} + {{(filteredList$ | async).length}} of - {{alarmListArray.length}} + {{(alarmListArray$ | async).length}}
-
+
There are alarms, but they're being hidden by the filter!
diff --git a/projects/widgets/src/lib/widget/alarms-widget/alarms-widget.component.ts b/projects/widgets/src/lib/widget/alarms-widget/alarms-widget.component.ts index 9b6efd58..d664b2bf 100644 --- a/projects/widgets/src/lib/widget/alarms-widget/alarms-widget.component.ts +++ b/projects/widgets/src/lib/widget/alarms-widget/alarms-widget.component.ts @@ -1,8 +1,10 @@ import { Component, Injector } from '@angular/core'; -import { Logger, LoggerService, HytAlarm, AlarmWrapperService, HpacketsService } from 'core'; +import { Logger, LoggerService, HytAlarm, HpacketsService, LiveAlarmSelectors } from 'core'; import { BaseWidgetComponent } from '../../base/base-widget/base-widget.component'; import { Option } from 'components'; import { animate, group, query, style, transition, trigger } from '@angular/animations'; +import { Store } from '@ngrx/store'; +import { BehaviorSubject, combineLatest, map, Observable } from 'rxjs'; @Component({ selector: 'hyperiot-alarms-widget', @@ -53,16 +55,37 @@ export class AlarmsWidgetComponent extends BaseWidgetComponent { * Selected severity to filter, linked to template with ngModel */ filteringSev : string[] = []; + + alarmListArray$: Observable = new Observable(); + filteredList$: Observable = new Observable(); + filterChanges$: BehaviorSubject = new BehaviorSubject(this.filteringSev); + constructor( injector: Injector, - protected loggerService: LoggerService, - private alarmWrapper: AlarmWrapperService, + protected loggerService: LoggerService, private hPacketsService: HpacketsService, + private store: Store ) { super(injector, loggerService); this.logger = new Logger(this.loggerService); this.logger.registerClass(AlarmsWidgetComponent.name); } + + ngOnInit(): void { + this.alarmListArray$ = this.store.select(LiveAlarmSelectors.selectLiveAlarmsByProjectId({ projectId: this.widget.projectId })); + this.filteredList$ = combineLatest([ + this.store.select(LiveAlarmSelectors.selectLiveAlarmsByProjectId({ projectId: this.widget.projectId })), + this.filterChanges$ + ]).pipe( + map(([value, filter]) => { + if (filter.length){ + return value.filter((alarm)=> filter.includes(alarm.event.severity.toString())) + } else { + return value; + } + }) + ) + } ngAfterViewInit() { this.configure(); @@ -75,24 +98,10 @@ export class AlarmsWidgetComponent extends BaseWidgetComponent { this.isConfigured = true; } - get alarmListArray() : HytAlarm.LiveAlarm[] { - return this.alarmWrapper.alarmListArray.filter( - alarm => alarm.projectId === this.widget.projectId || - (alarm.packetIds?.some(packetId => this.hPacketIdList.includes(packetId))) - ); + updateFilters() { + this.filterChanges$.next(this.filteringSev); } - /** - * If the user is filtering return the alarmList map as array filter, - * if not call the get alarmListArray - */ - get filteredList() : HytAlarm.LiveAlarm[]{ - if(this.filteringSev.length){ - return this.alarmListArray.filter((alarm)=> this.filteringSev.includes(alarm.event.severity.toString())) - }else{ - return this.alarmListArray; - } - } /** * Used for display all the severity that we are filtering as a list(ES: low, medium) */ diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 8cfcd060..31dba9fb 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -7,22 +7,22 @@ import { } from "@angular/core"; import { ActivatedRoute, NavigationEnd, Router } from "@angular/router"; import { - AlarmWrapperService, HProject, HprojectsService, IGNORE_ERROR_NOTIFY, Logger, LoggerService, RealtimeDataService, + UserSiteSettingSelectors, + BrandingService, + NotificationSelectors, } from "core"; import { ToastrService } from "ngx-toastr"; -import {Subject, Subscription, filter, takeUntil, distinctUntilChanged, tap} from "rxjs"; +import {Subject, Subscription, filter, takeUntil, map} from "rxjs"; import { environment } from "../environments/environment"; -import { BrandingService } from "./services/branding/branding.service"; import {HttpContext} from "@angular/common/http"; import {CookieService} from "ngx-cookie-service"; import { Store } from "@ngrx/store"; -import { NotificationSelectors } from "./state/notification/notification.selectors"; -import { NotificationActions } from "./state/notification/notification.actions"; +import { concatLatestFrom } from "@ngrx/effects"; @Component({ selector: "hyt-root", @@ -32,12 +32,7 @@ import { NotificationActions } from "./state/notification/notification.actions"; }) export class AppComponent implements OnInit, OnDestroy { public environment = environment; - eventNotificationIsOn: boolean; - private toastMessage = $localize`:@@HYT_dashboard_event_fired:The event has been fired`; - private toastEventMessage = $localize`:@@HYT_dashboard_event_fired:The event has been fired`; - private toastMessageAlarmUp = $localize`:@@HYT_dashboard_alarm_fired:The alarm has been fired`; - private toastMessageAlarmDown = $localize`:@@HYT_dashboard_alarm_cleared:Alarm cleared`; projectIds: number[]; /** Subject for manage the open subscriptions */ @@ -62,7 +57,6 @@ export class AppComponent implements OnInit, OnDestroy { private toastr: ToastrService, private loggerService: LoggerService, private router: Router, - private alarmWrapper: AlarmWrapperService, private brandingService: BrandingService, private cookieService: CookieService, private store: Store, @@ -70,7 +64,6 @@ export class AppComponent implements OnInit, OnDestroy { // Init Logger this.logger = new Logger(this.loggerService); this.logger.registerClass("AppComponent"); - this.eventNotificationIsOn = alarmWrapper.eventNotificationState.getValue(); } ngOnInit() { @@ -89,6 +82,8 @@ export class AppComponent implements OnInit, OnDestroy { } } }); + + this.subscribeToNotification(); } isLogged(): boolean { @@ -108,25 +103,6 @@ export class AppComponent implements OnInit, OnDestroy { this.projectIds = projectsList.map((project) => project.id); this.realtimeDataService.connect(this.projectIds); }); - - this.alarmWrapper.eventNotificationState - .pipe(takeUntil(this.ngUnsubscribe)) - .subscribe((res) => { - this.eventNotificationIsOn = res; - this.manageNotificationSubscription(); - }); - - //this.manageNotificationSubscription(); - } - - manageNotificationSubscription(){ - if (this.eventNotificationIsOn) { - this.logger.info("Subscribe to notifications ON"); - this.subscribeToNotification(); - } else { - this.logger.info("Subscribe to notifications OFF"); - if(this.alarmSubscription) this.alarmSubscription.unsubscribe(); - } } @HostListener("wheel", ["$event"]) @@ -148,12 +124,22 @@ export class AppComponent implements OnInit, OnDestroy { if(this.alarmSubscription) this.alarmSubscription.unsubscribe(); - this.alarmSubscription = this.store.select(NotificationSelectors.selectLastNotification).subscribe({ - next: (notification) => { - console.log('----', notification) - if (!notification) { - return; + this.alarmSubscription = this.store.select(NotificationSelectors.selectLastNotification) + .pipe( + concatLatestFrom( + () => this.store.select(UserSiteSettingSelectors.selectNotificationActive) + ), + filter( + ([value, isNotificationEnabled]) => { + return !!(isNotificationEnabled && value); } + ), + map( + ([value, isNotificationEnabled]) => value + ) + ) + .subscribe({ + next: (notification) => { this.toastr .show( notification.message, @@ -175,50 +161,7 @@ export class AppComponent implements OnInit, OnDestroy { }, }); } - }) - - /* if(this.alarmSubscription) this.alarmSubscription.unsubscribe(); - this.alarmSubscription = this.alarmWrapper.alarmSubject - .pipe( - tap((alarm) => { this.logger.debug("Alarm received", alarm); }), - takeUntil(this.ngUnsubscribe), - distinctUntilChanged() - ) - .subscribe((alarm) => { - let toastImage = "info"; - if (alarm.isEvent) { - toastImage = "toastEvent"; - this.toastMessage = this.toastEventMessage; - } else if (alarm.isAlarm) { - toastImage = - alarm.event.alarmState === "UP" ? "toastAlarmUp" : "toastAlarmDown"; - this.toastMessage = - alarm.event.alarmState === "UP" ? this.toastMessageAlarmUp : this.toastMessageAlarmDown; - if (alarm.event.alarmState === 'DOWN') - alarm.color.background = '#51a351'; // Green of resolved alarm BG (OFF state) - } - const toastId = this.toastr["index"]; - this.toastr - .show( - this.toastMessage, - alarm.event.alarmEventName, - { toastClass: "ngx-toastr toast-" + toastId }, - toastImage - ) - .onShown.subscribe({ - complete: () => { - document - .querySelector( - ".overlay-container #toast-container .ngx-toastr.toast-" + - toastId - ) - .setAttribute( - "style", - `background-color: ${alarm.color.background}; color: ${alarm.color.text}; transform: translateY(64px);` - ); - }, - }); - }); */ + }); } showToolBars(): boolean { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 724a51c5..5505359f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -25,7 +25,7 @@ import { AccountButtonComponent } from './components/topbar/account-button/accou import { MatIconModule } from '@angular/material/icon'; // hyperiot -import { Configuration, ConfigurationParameters, CoreModule, HyperiotClientModule, LoggerService } from 'core'; +import { Configuration, ConfigurationParameters, CoreModule, HyperiotClientModule, LoggerService, BrandingService, HyperiotStore} from 'core'; import { ComponentsModule } from 'components'; import { AddWidgetDialogComponent, DashboardModule, WidgetSettingsDialogComponent, WidgetsModule } from 'widgets'; import { RouterModule, DefaultUrlSerializer, UrlSerializer, UrlTree } from '@angular/router'; @@ -69,8 +69,6 @@ import { StoreModule } from '@ngrx/store'; import { StoreDevtoolsModule } from '@ngrx/store-devtools'; import { EffectsModule } from '@ngrx/effects'; import { GlobalErrorHandlerService } from '../../projects/core/src/lib/hyperiot-service/error-handler/global-error-handler.service'; -import {BrandingService} from "./services/branding/branding.service"; -import { effects, reducers } from './state'; PlotlyModule.plotlyjs = PlotlyJS; @@ -154,13 +152,13 @@ export function apiConfigFactory(): Configuration { BrowserModule, BrowserAnimationsModule, MatInputModule, - StoreModule.forRoot(reducers), + StoreModule.forRoot(HyperiotStore.Reducers), StoreDevtoolsModule.instrument({ maxAge: 25, // Retains last 25 states logOnly: environment.production, // Restrict extension to log-only mode autoPause: true, // Pauses recording actions and state changes when the extension window is not open }), - EffectsModule.forRoot(effects), + EffectsModule.forRoot(HyperiotStore.Effects), ], providers: [ // ActivatedRouteSnapshot, diff --git a/src/app/components/dialogs/notification-dialog/notification-dialog.component.html b/src/app/components/dialogs/notification-dialog/notification-dialog.component.html index 0029d88c..9a6e235d 100644 --- a/src/app/components/dialogs/notification-dialog/notification-dialog.component.html +++ b/src/app/components/dialogs/notification-dialog/notification-dialog.component.html @@ -32,14 +32,14 @@

No notifications