Skip to content

Commit

Permalink
added anomaly widget
Browse files Browse the repository at this point in the history
  • Loading branch information
hahahannes committed Dec 22, 2023
1 parent 2b60d6b commit fde79cd
Show file tree
Hide file tree
Showing 16 changed files with 572 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ export class DashboardNewWidgetDialogComponent {
// {value: DashboardTypesEnum.DeviceStatus, viewValue: 'Device Status', disabled: false, tooltip: ''},
{ value: DashboardTypesEnum.DataTable, viewValue: 'Data Table', disabled: false, tooltip: '' },
{ value: DashboardTypesEnum.AcControl, viewValue: 'Air Condition Control', disabled: false, tooltip: '', requirementsService: undefined },
{ value: DashboardTypesEnum.AnomalyDetection, viewValue: 'Anomaly Detection', disabled: false, tooltip: '' },
];
switchCategories: SwitchCategories[] = [
{
Expand Down
1 change: 1 addition & 0 deletions src/app/modules/dashboard/shared/dashboard-types.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,5 @@ export enum DashboardTypesEnum {
DeviceStatus = 'device_status',
DataTable = 'data_table',
AcControl = 'ac_control',
AnomalyDetection = "anomaly_detection"
}
2 changes: 2 additions & 0 deletions src/app/modules/data/operator-repo/operator-repo.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ export class OperatorRepoComponent implements OnInit, OnDestroy {
.subscribe((resp: { operators: OperatorModel[]; totalCount: number }) => {
if (resp.operators.length > 0) {
this.operators = resp.operators;
console.log(this.userId)
console.log(resp.operators)
this.operators.forEach((operator) => (operator.editable = operator.userId === this.userId));
this.operatorsDataSource.data = this.operators;

Expand Down
32 changes: 32 additions & 0 deletions src/app/widgets/anomaly/anomaly.component.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
.mat-mdc-card {
width: 100%;
height: 100%;
box-sizing: border-box;
}

.mat-mdc-card-content {
height: calc(100% - 72px);
margin: 0;
overflow-y: auto;
}

.outer-container {
height: 100%
}

.anomaly-container {
display: flex;
flex-direction: column;
align-items: center;
}

mat-icon {
font-size: 40px;
}

.mat-icon {
height: 100%;
width: 100%;
}


85 changes: 85 additions & 0 deletions src/app/widgets/anomaly/anomaly.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<!--
~ Copyright 2022 InfAI (CC SES)
~
~ 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.
-->

<mat-card appearance="outlined">
<senergy-widget-header [widget]="widget" [refreshing]="refreshing"></senergy-widget-header>
<mat-card-content>
<senergy-widget-spinner [show]="!ready"></senergy-widget-spinner>
<div *ngIf="ready && widget.properties.measurement === undefined" fxFill fxLayout="column"
fxLayoutAlign="center center">
<div>Please configure widget!</div>
</div>
<div *ngIf="ready && widget.properties.measurement !== undefined" fxLayoutAlign="center center" class="outer-container">
<div *ngIf="anomaly.type == 'time'" class="anomaly-container">
<div>
<mat-icon>schedule</mat-icon>
</div>
<div>
<h2 *ngIf="anomaly.subType == 'high'">Time between inputs was too long!</h2>
<h2 *ngIf="anomaly.subType == 'low'">Time between inputs was too short!</h2>
</div>
<div>
<p>{{anomaly.value | number:'1.2-3'}} {{anomaly.unit}}</p>
</div>

</div>

<div *ngIf="anomaly.type == 'schema'" class="anomaly-container">
<div>
<mat-icon>schema</mat-icon>
</div>
<div>
<h2>Input data did not follow the schema!</h2>
</div>
<div>
<p>{{anomaly.value}}</p>
</div>
</div>

<div *ngIf="anomaly.type == 'extreme_value'" class="anomaly-container">
<div>
<mat-icon>error</mat-icon>
</div>
<div>
<h2 *ngIf="anomaly.subType == 'high'">Input is too high!</h2>
<h2 *ngIf="anomaly.subType == 'low'">Input is too low!</h2>
</div>
<div>
<p>{{anomaly.value}}</p>
</div>
</div>

<div *ngIf="anomaly.type == 'curve_anomaly'" class="anomaly-container">
<div>
<mat-icon>error</mat-icon>
</div>
<div>
<h2>Value is anomalous!</h2>
</div>
<div>
<p>{{anomaly.value}}</p>
</div>
</div>
</div>
</mat-card-content>
<div>
<senergy-widget-footer [widgetHasUpdateableProperties]="true"
[userHasUpdateNameAuthorization]="userHasUpdateNameAuthorization" [refreshing]="refreshing"
[userHasDeleteAuthorization]="userHasDeleteAuthorization"
[userHasUpdatePropertiesAuthorization]="userHasUpdatePropertiesAuthorization" [dashboardId]="dashboardId"
[widget]="widget" (editEvent)="edit()"></senergy-widget-footer>
</div>
</mat-card>
23 changes: 23 additions & 0 deletions src/app/widgets/anomaly/anomaly.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { AnomalyComponent } from './anomaly.component';

describe('AnomalyComponent', () => {
let component: AnomalyComponent;
let fixture: ComponentFixture<AnomalyComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ AnomalyComponent ]
})
.compileComponents();

fixture = TestBed.createComponent(AnomalyComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
68 changes: 68 additions & 0 deletions src/app/widgets/anomaly/anomaly.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Component, Input, OnInit } from '@angular/core';
import { Subscription, concatMap, Observable, map, of } from 'rxjs';
import { WidgetModel } from 'src/app/modules/dashboard/shared/dashboard-widget.model';
import { DashboardService } from 'src/app/modules/dashboard/shared/dashboard.service';
import { AnomalyResultModel } from './shared/anomaly.model';
import { AnomalyService } from './shared/anomaly.service';

@Component({
selector: 'senergy-anomaly-detection',
templateUrl: './anomaly.component.html',
styleUrls: ['./anomaly.component.css']
})
export class AnomalyComponent implements OnInit {
ready: boolean = false
refreshing: boolean = false;
destroy = new Subscription();
anomaly: AnomalyResultModel = {} as AnomalyResultModel;

@Input() dashboardId = '';
@Input() widget: WidgetModel = {} as WidgetModel;
@Input() zoom = false;
@Input() userHasDeleteAuthorization = false;
@Input() userHasUpdatePropertiesAuthorization = false;
@Input() userHasUpdateNameAuthorization = false;

constructor(
private dashboardService: DashboardService,
private anomalyService: AnomalyService
) {}

ngOnInit(): void {
this.update()
}

private update() {
this.destroy = this.dashboardService.initWidgetObservable.pipe(
concatMap((event: string) => {
if (event === 'reloadAll' || event === this.widget.id) {
this.refreshing = true;
return this.loadAnomaly()
}
return of()
})).subscribe({
next: (_) => {
this.ready = true
this.refreshing = false
},
error: (_) => {
this.ready = true
this.refreshing = false
}
})
}

edit() {
this.anomalyService.openEditDialog(this.dashboardId, this.widget.id, this.userHasUpdateNameAuthorization, this.userHasUpdatePropertiesAuthorization)
}

loadAnomaly(): Observable<any> {
return this.anomalyService.getAnomaly(this.widget).pipe(
map((anomaly) => {
if(anomaly != null) {
this.anomaly = anomaly
}
})
)
}
}
Empty file.
45 changes: 45 additions & 0 deletions src/app/widgets/anomaly/dialog/edit/edit.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<!--
~ Copyright 2020 InfAI (CC SES)
~
~ 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.
-->

<h2 mat-dialog-title>Edit Anomaly Detection</h2>

<mat-dialog-content>
<senergy-widget-spinner [show]="!ready"></senergy-widget-spinner>
<div *ngIf="ready">
<form fxLayout="column" [formGroup]="form">
<mat-form-field color="accent" fxFlex="47" *ngIf="userHasUpdateNameAuthorization">
<mat-label>Name</mat-label>
<input type="text" matInput placeholder="Name" formControlName="name">
</mat-form-field>

<mat-form-field color="accent" fxFlex="47" *ngIf="userHasUpdatePropertiesAuthorization">
<mat-label>Choose Export</mat-label>
<input type="text" matInput formControlName="export" [matAutocomplete]="auto" required>
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayFn">
<mat-option *ngFor="let option of exports" [value]="option">
{{option.name}}
</mat-option>
</mat-autocomplete>
</mat-form-field>
</form>
</div>

</mat-dialog-content>

<mat-dialog-actions fxLayoutAlign="end center">
<button mat-raised-button color="primary" (click)="close()">Cancel</button>
<button mat-raised-button color="accent" (click)="save()" [disabled]="form.invalid">Save</button>
</mat-dialog-actions>
23 changes: 23 additions & 0 deletions src/app/widgets/anomaly/dialog/edit/edit.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { EditComponent } from './edit.component';

describe('EditComponent', () => {
let component: EditComponent;
let fixture: ComponentFixture<EditComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ EditComponent ]
})
.compileComponents();

fixture = TestBed.createComponent(EditComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Loading

0 comments on commit fde79cd

Please sign in to comment.