added side panels

This commit is contained in:
2020-03-17 10:03:24 -05:00
parent eb19039ed7
commit d6f5187090
7 changed files with 285 additions and 103 deletions

View File

@@ -1,54 +1,93 @@
<div class="container">
<mat-sidenav-container
fullscreen
[hasBackdrop]="mobileQuery.matches">
<mat-sidenav #lnav
mode="over"
class="sidenav">
<div class="content">
<mat-accordion >
<mat-expansion-panel *ngFor="let location of this.dataservice.serverMessages">
<mat-sidenav-container fullscreen> <!--[hasBackdrop]="mobileQuery.matches">-->
<mat-sidenav #lnav mode="side" class="sidenav" closed >
<div class="content">
<mat-accordion>
<mat-expansion-panel *ngFor="let fields of this.sidebar | keyvalue">
<mat-expansion-panel-header>
<mat-panel-title>{{location.location}}</mat-panel-title>
<mat-panel-title>{{fields.key}}</mat-panel-title>
</mat-expansion-panel-header>
<p *ngFor="let keys of location | keyvalue">{{keys.key}} {{keys.value}}</p>
<mat-accordion>
<mat-expansion-panel *ngFor="let location of fields.value"
cdkDropList #locationList="cdkDropList" [cdkDropListConnectedTo]="[chartList]" (cdkDropListDropped)="drop($event)">
<mat-expansion-panel-header>
<mat-panel-title cdkDrag>{{location.location}}</mat-panel-title>
</mat-expansion-panel-header>
<div class="item-list">
<div class="item-box" *ngFor="let keys of location | keyvalue" cdkDrag>{{keys.key}}: {{keys.value}}</div>
</div>
</mat-expansion-panel>
</mat-accordion>
</mat-expansion-panel>
</mat-accordion>
</mat-accordion>
</div>
</mat-sidenav>
<mat-sidenav #rnav mode="side" class="sidenav" position="end" closed >
<div *ngFor="let route of nav">
<a mat-button routerLink="{{route.path}}" routerLinkActive="active" (click)="toggleMobileNav(rnav)" >{{route.title}}</a>
</div>
<mat-menu #appMenu="matMenu">
<ng-container *ngFor="let item of this.dataservice.groups; let i = index">
<button mat-menu-item (click)="roleChange(i)"> {{ item }}</button>
</ng-container>
</mat-menu>
<button mat-button [matMenuTriggerFor]="appMenu" >
Role Change
</button>
<div></div>
<button mat-flat-button (click)="this.signOut(rnav)" color="accent">Sign Out</button>
</mat-sidenav>
<mat-sidenav-content class="sidenav-content">
<mat-toolbar
class="toolbar"
[class.app-is-mobile]="mobileQuery.matches"
color="primary">
<button
mat-icon-button
(click)="lnav.toggle()"
*ngIf="mobileQuery.matches">
<mat-toolbar class="toolbar" [class.app-is-mobile]="mobileQuery.matches" color="primary">
<button mat-icon-button (click)="lnav.toggle()" *ngIf="this.authService.loggedIn">
<mat-icon>menu</mat-icon>
</button>
{{title}}
<div *ngFor="let route of nav">
<div class="flex-spacer"></div>
<button mat-icon-button (click)="rnav.toggle()" *ngIf="this.authService.loggedIn">
<mat-icon>menu</mat-icon>
</button>
<!-- <div *ngFor="let route of nav">
<a mat-button routerLink="{{route.path}}" routerLinkActive="active" (click)="toggleMobileNav(lnav)">{{route.title}}</a>
</div>
<div class="fill-space"></div>
<span whoami></span>
<div class="flex-spacer"></div>
<mat-menu #appMenu="matMenu">
<ng-container *ngFor="let item of this.dataservice.groups; let i = index">
<button mat-menu-item (click)="roleChange(i)"> {{ item }}</button>
</ng-container>
</mat-menu>
<button mat-icon-button [matMenuTriggerFor]="appMenu">
<mat-icon>more_vert</mat-icon>
</button>
<span whoami></span> -->
</mat-toolbar>
<mat-drawer-container class="sidenav-container">
<mat-drawer
mode="side"
[opened]="!mobileQuery.matches">
<!-- <mat-drawer mode="side" [opened]="!mobileQuery.matches">
<div class="content">
<mat-accordion >
<mat-expansion-panel *ngFor="let location of this.dataservice.serverMessages">
<mat-expansion-panel-header>
<mat-panel-title>{{location.location}}</mat-panel-title>
</mat-expansion-panel-header>
<p *ngFor="let keys of location | keyvalue">{{keys.key}}: {{keys.value}}</p>
</mat-expansion-panel>
<mat-accordion>
<mat-expansion-panel *ngFor="let fields of this.sidebar | keyvalue">
<mat-expansion-panel-header>
<mat-panel-title>{{fields.key}}</mat-panel-title>
</mat-expansion-panel-header>
<mat-accordion>
<mat-expansion-panel *ngFor="let location of fields.value">
<mat-expansion-panel-header>
<mat-panel-title>{{location.location}}</mat-panel-title>
</mat-expansion-panel-header>
<p *ngFor="let keys of location | keyvalue">{{keys.key}}: {{keys.value}}</p>
</mat-expansion-panel>
</mat-accordion>
</mat-expansion-panel>
</mat-accordion>
</div>
</mat-drawer>
</mat-drawer> -->
<mat-drawer-content>
<div class="content">
<router-outlet></router-outlet>

View File

@@ -77,4 +77,30 @@ a {
.active {
color: mat-color($app-active);
}
}
.flex-spacer {
flex-grow: 1;
}
.item-list {
border: solid 1px #ccc;
min-height: 60px;
background: white;
border-radius: 4px;
overflow: hidden;
display: block;
}
.item-box {
padding: 20px 10px;
border-bottom: solid 1px #ccc;
color: rgba(0, 0, 0, 0.87);
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
box-sizing: border-box;
cursor: move;
background: white;
font-size: 14px;
}

View File

@@ -1,7 +1,11 @@
import { Component, ChangeDetectorRef, EventEmitter, Output } from '@angular/core';
import { Component, ChangeDetectorRef, EventEmitter, Output, OnInit } from '@angular/core';
import { MediaMatcher } from '@angular/cdk/layout';
import { MatSidenav } from '@angular/material/sidenav';
import { DataService } from './services/data.service';
import { DataService, AWSData } from './services/data.service';
import { AuthService } from './auth/auth.service';
import { Router } from '@angular/router';
import { RangeValueAccessor } from '@angular/forms';
import { CdkDragDrop } from '@angular/cdk/drag-drop';
@Component({
@@ -9,8 +13,9 @@ import { DataService } from './services/data.service';
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'Henry Pump SCADA';
export class AppComponent implements OnInit {
title = 'HP SCADA';
sidebar: AWSData = [];
mobileQuery: MediaQueryList;
nav = [
{
@@ -27,19 +32,48 @@ export class AppComponent {
}
];
private mobileQueryListener: () => void;
@Output() toggleSideNav = new EventEmitter();
constructor( changeDetectorRef: ChangeDetectorRef, media: MediaMatcher , public dataservice: DataService) {
constructor( changeDetectorRef: ChangeDetectorRef, media: MediaMatcher , public dataservice: DataService,
public authService: AuthService, private router: Router) {
this.mobileQuery = media.matchMedia('(max-width: 600px)');
this.mobileQueryListener = () => changeDetectorRef.detectChanges();
this.mobileQuery.addListener(this.mobileQueryListener);
}
ngOnInit() {
this.dataservice.message.subscribe((data) => {
data.forEach( element => {
if (this.sidebar[element.field]) {
this.sidebar[element.field].push(element);
} else {
this.sidebar[element.field] = [];
this.sidebar[element.field].push(element);
}
});
});
}
roleChange(index: number) {
this.sidebar = [];
this.dataservice.setRole(index);
}
toggleMobileNav(nav: MatSidenav) {
if (this.mobileQuery.matches) {
nav.toggle();
}
}
signOut(nav: MatSidenav) {
nav.toggle();
this.sidebar = [];
this.dataservice.serverMessages = [];
this.authService.signOut()
.then(() => this.router.navigate(['auth/signin']));
}
drop(event: CdkDragDrop<string[]>) {
console.log(event);
}
}

View File

@@ -3,6 +3,7 @@ import Auth, { CognitoHostedUIIdentityProvider } from '@aws-amplify/auth';
import { Hub, ICredentials } from '@aws-amplify/core';
import { Subject, Observable } from 'rxjs';
import { CognitoUser } from 'amazon-cognito-identity-js';
import { DataService } from '../services/data.service';
export interface NewUser {
email: string;
@@ -26,13 +27,14 @@ export class AuthService {
authState: Observable<CognitoUser|any> = this.authStateSubject.asObservable();
constructor() {
constructor(private dataService: DataService) {
Hub.listen('auth', (data) => {
const { channel, payload } = data;
if (channel === 'auth') {
this.authStateSubject.next(payload.event);
}
});
Auth.currentAuthenticatedUser().then(() => this.loggedIn = true).catch(() => this.loggedIn = false);
}
signUp(user: NewUser): Promise<CognitoUser|any> {
@@ -53,6 +55,7 @@ export class AuthService {
Auth.signIn(username, password)
.then((user: CognitoUser|any) => {
this.loggedIn = true;
this.dataService.startUp();
resolve(user);
}).catch((error: any) => reject(error));
});

View File

@@ -1,19 +1,4 @@
<div class ="viewer">
<div class="container" fxLayout="row wrap" fxLayoutGap="30px">
Total Flow Rate {{ totalFlowRate }}
<div class="flex-spacer"></div>
<mat-menu #appMenu="matMenu">
<ng-container *ngFor="let item of groups; let i = index">
<button mat-menu-item (click)="setRole(i)"> {{ item }}</button>
</ng-container>
</mat-menu>
<button mat-icon-button [matMenuTriggerFor]="appMenu">
<mat-icon>more_vert</mat-icon>
</button>
</div>
<div id="charts"></div>
<div id="charts" cdkDropList #chartList="cdkDropList" [cdkDropListConnectedTo]="[locationList]" (cdkDropListDropped)="drop($event)"></div>
</div>

View File

@@ -1,6 +1,7 @@
import { Component, OnInit } from '@angular/core';
import { Chart } from 'chart.js';
import { DataService, MyJSON } from '../services/data.service';
import { DataService, AWSData } from '../services/data.service';
import { CdkDropList } from '@angular/cdk/drag-drop';
@Component({
selector: 'app-home',
templateUrl: './dashboard.component.html',
@@ -9,46 +10,111 @@ import { DataService, MyJSON } from '../services/data.service';
export class DashboardComponent implements OnInit {
constructor(private dataservice: DataService) { }
constructor(private dataservice: DataService) { }
title = 'Bar Chart';
charts = new Array<Chart>();
messages: Array<MyJSON>;
charttypes = ['bar', 'line', 'radar', 'doughnut', 'pie', 'polarArea', 'bubble', 'scatter'];
ngOnInit() {
for (let i = 0; i < 8; i++) {
const chart = document.createElement('canvas');
chart.id = 'chart-' + i.toString();
chart.style.width = '100%';
chart.style.height = '500px';
document.getElementById('charts').appendChild(chart);
this.charts.push(new Chart(document.getElementById('chart-' + i.toString()), {
type: this.charttypes[i],
charts: Array<Chart>;
messages: Array<AWSData> = [];
charttypes = ['bar', 'line'];
userCharts = {
'arn:aws:iam::860246592755:role/HPIoT_CrownQuest_User': {
'chart-0': {
type: 'bar',
data: {
labels: [],
labels: ['Horton 20 WS 9-8', 'Horton 20 WS 9-7', 'Horton 20 WS 10-20', 'Horton 20 WS 10-20'].sort((a, b) => a.localeCompare(b)),
datasets: [{
label: '',
label: 'Horton',
data: {
'Horton 20 WS 9-7': ['volumeflow'],
'Horton 20 WS 10-20': ['pressure', 'depth'],
'Horton 20 WS 9-8': ['volumeflow']
}
}]
}
},
'chart-1': {
type: 'line',
data: {
labels: ['LimeQuest 5 WS 1-1', 'Wilkinson 34 WS 2-2', 'Horton 20 WS 10-20'].sort((a, b) => a.localeCompare(b)),
datasets: [{
label: 'Horton',
data: {
'LimeQuest 5 WS 1-1': ['depth'],
'Horton 20 WS 10-20': ['pressure'],
'Wilkinson 34 WS 2-2': ['current']
}
}]
}
}
},
'arn:aws:iam::860246592755:role/HPIoT_QEP_User': {
'chart-0': {
type: 'radar',
data: {
labels: ['Frequency', 'Pressure', 'Current', 'Down Hole'],
datasets: [{
label: 'POE 1',
data: {
'POE 1': ['frequency', 'pressure', 'current', 'down_hole_level']
}}]
}
}
}
};
ngOnInit() {
this.dataservice.roleSubject.subscribe(() => {
this.initCharts();
});
this.initCharts();
this.dataservice.message.subscribe((data) => {
this.messages = data;
// console.log(this.messages);
this.populate();
});
}
getData(req) {
const x = [];
this.messages.forEach(location => {
if (Object.keys(req).indexOf(location.location) > -1) {
req[location.location].forEach((ele) => {
x.push(location[ele]);
});
}
});
return x;
}
initCharts() {
document.getElementById('charts').innerHTML = '';
this.charts = new Array<Chart>();
Object.keys(this.userCharts[this.dataservice.currentRole]).forEach( key => {
const chart = document.createElement('canvas');
chart.id = key;
chart.style.width = '100%';
chart.style.height = '25rem';
document.getElementById('charts').appendChild(chart);
this.charts.push(new Chart(document.getElementById(key), {
type: this.userCharts[this.dataservice.currentRole][key].type,
data: {
labels: this.userCharts[this.dataservice.currentRole][key].data.labels,
datasets: [{
label: this.userCharts[this.dataservice.currentRole][key].data.datasets.label,
data: []
}]
}
}));
}
this.dataservice.message.subscribe((data) => {
this.messages = data;
this.populate();
});
}
populate() {
this.charts.forEach(element => {
element.data.labels = this.messages.map((d) => d.location);
element.data.datasets.forEach( dataset => {
dataset.label = 'Volume Flow';
dataset.data = this.messages.map( d => d.volumeflow);
element.type = this.userCharts[this.dataservice.currentRole][element.canvas.id].type;
element.data.labels = this.userCharts[this.dataservice.currentRole][element.canvas.id].data.labels;
element.data.datasets.forEach( (dataset, ind) => {
dataset.label = this.userCharts[this.dataservice.currentRole][element.canvas.id].data.datasets[ind].label;
dataset.data = this.getData(this.userCharts[this.dataservice.currentRole][element.canvas.id].data.datasets[ind].data);
dataset.backgroundColor = dataset.data.map((item, index) => 'rgba(' +
index * (255 / this.messages.length) + ',' +
index * (255 / dataset.data.length) + ',' +
0 + ',' +
(this.messages.length - index) * (255 / this.messages.length) + ',' + '0.8)');
(dataset.data.length - index) * (255 / dataset.data.length) + ',' + '0.8)');
});
element.update();
});

View File

@@ -1,8 +1,9 @@
import { Injectable } from '@angular/core';
import Auth from '@aws-amplify/auth';
import { WebSocketSubject } from 'rxjs/webSocket';
import { Observable, Subject } from 'rxjs';
export interface MyJSON {
import { Observable, Subject, BehaviorSubject } from 'rxjs';
import { PassThrough } from 'stream';
export interface AWSData {
[key: string]: any;
}
@@ -12,30 +13,57 @@ export interface MyJSON {
export class DataService {
public serverMessages: Array<MyJSON> = [];
public message = new Subject<MyJSON[]>();
public serverMessages: Array<AWSData> = [];
public message = new BehaviorSubject<AWSData[]>(this.serverMessages);
private socket$: WebSocketSubject<any>;
totalFlowRate = 0;
private roles: string[];
private groups: string[];
private currentRole: string;
public currentRole: string;
public roleSubject = new Subject<string>();
private token: string;
constructor() {
Auth.currentAuthenticatedUser().then(data => {
// console.log(data);
this.roles = data.signInUserSession.idToken.payload['cognito:roles'];
this.groups = data.signInUserSession.idToken.payload['cognito:groups'];
this.groups.forEach( (element, index, array) => {
array[index] = element.replace(/_/g, ' ');
});
this.currentRole = data.signInUserSession.idToken.payload['cognito:roles'][0];
this.token = data.signInUserSession.accessToken.jwtToken;
this.message.subscribe({
next: d => d
});
this.connect();
}); }
// console.log(data);
this.roles = data.signInUserSession.idToken.payload['cognito:roles'];
this.groups = data.signInUserSession.idToken.payload['cognito:groups'];
this.groups.forEach( (element, index, array) => {
array[index] = element.replace(/_/g, ' ');
});
this.currentRole = data.signInUserSession.idToken.payload['cognito:roles'][0];
this.token = data.signInUserSession.accessToken.jwtToken;
this.message.subscribe({
next: d => d
});
this.roleSubject.subscribe({
next: r => r
});
this.connect();
}).catch((err) =>
err
);
}
startUp() {
Auth.currentAuthenticatedUser().then(data => {
// console.log(data);
this.roles = data.signInUserSession.idToken.payload['cognito:roles'];
this.groups = data.signInUserSession.idToken.payload['cognito:groups'];
this.groups.forEach( (element, index, array) => {
array[index] = element.replace(/_/g, ' ');
});
this.currentRole = data.signInUserSession.idToken.payload['cognito:roles'][0];
this.token = data.signInUserSession.accessToken.jwtToken;
this.message.subscribe({
next: d => d
});
this.roleSubject.subscribe({
next: r => r
});
this.connect();
}).catch((error) => console.log(error));
}
connect() {
this.connectWS(this.token, this.currentRole);
@@ -68,7 +96,7 @@ export class DataService {
);
}
updateList(obj: MyJSON) {
updateList(obj: AWSData) {
// console.log(this.serverMessages);
// console.log(obj);
const index = this.serverMessages.findIndex((e) => e.location === obj.location);
@@ -85,6 +113,7 @@ export class DataService {
setRole(index: number) {
this.currentRole = this.roles[index];
this.roleSubject.next(this.currentRole);
this.socket$.complete();
this.serverMessages = [];
this.connect();