From 3f696a9200dc1bbbfae05833aa3a91c9c65a3466 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 5 Aug 2019 07:07:47 -0700 Subject: [PATCH 01/14] Widget prepared --- package.json | 1 + src/app/app.module.ts | 4 +- .../log-console/log-console.component.html | 21 +++++ .../log-console/log-console.component.scss | 76 +++++++++++++++++++ .../log-console/log-console.component.spec.ts | 0 .../log-console/log-console.component.ts | 54 +++++++++++++ .../project-map/project-map.component.html | 1 + .../handlers/project-web-service-handler.ts | 7 +- yarn.lock | 5 ++ 9 files changed, 167 insertions(+), 2 deletions(-) create mode 100644 src/app/components/project-map/log-console/log-console.component.html create mode 100644 src/app/components/project-map/log-console/log-console.component.scss create mode 100644 src/app/components/project-map/log-console/log-console.component.spec.ts create mode 100644 src/app/components/project-map/log-console/log-console.component.ts diff --git a/package.json b/package.json index ff4897de..f26880a7 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "rxjs-compat": "^6.5.2", "tree-kill": "^1.2.1", "typeface-roboto": "^0.0.75", + "xterm": "^3.14.5", "yargs": "^13.3.0", "zone.js": "^0.9.1" }, diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4242bce2..a474e6e7 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -191,6 +191,7 @@ import { DuplicateActionComponent } from './components/project-map/context-menu/ import { MapSettingService } from './services/mapsettings.service'; import { ProjectMapMenuComponent } from './components/project-map/project-map-menu/project-map-menu.component'; import { HelpComponent } from './components/help/help.component'; +import { LogConsoleComponent } from './components/project-map/log-console/log-console.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -312,7 +313,8 @@ if (environment.production) { ConsoleComponent, NodesMenuComponent, ProjectMapMenuComponent, - HelpComponent + HelpComponent, + LogConsoleComponent ], imports: [ BrowserModule, diff --git a/src/app/components/project-map/log-console/log-console.component.html b/src/app/components/project-map/log-console/log-console.component.html new file mode 100644 index 00000000..aa51c3d1 --- /dev/null +++ b/src/app/components/project-map/log-console/log-console.component.html @@ -0,0 +1,21 @@ +
+
+ Console +
+ help_outline + close +
+
+
+
+
+
+ keyboard_arrow_right + +
+
diff --git a/src/app/components/project-map/log-console/log-console.component.scss b/src/app/components/project-map/log-console/log-console.component.scss new file mode 100644 index 00000000..58bca0e6 --- /dev/null +++ b/src/app/components/project-map/log-console/log-console.component.scss @@ -0,0 +1,76 @@ +.consoleWrapper { + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + position: fixed; + bottom: 20px; + left: 20px; + height: 120px; + width: 600px; + background: #263238; + color: white; + overflow: hidden; + font-size: 12px; +} + +.consoleHeader { + width: 100%; + height: 24px; + font-size: 12px; + overflow: hidden; + margin-right: 5px; + display: flex; + padding: 2px; + justify-content: space-between; +} + +.console { + width: 596px; + height: 64px; + overflow-y: scroll; + margin: 2px; + color: #dbd5d5; + scrollbar-color: darkgrey #263238; + scrollbar-width: thin; +} + +.consoleInput { + width: 100%; + height: 24px; + padding: 2px; + display: flex; +} + +.commandLine { + background-color: #263238; + color: white; + border: none; +} + +.divider { + width: 580px; + margin-left: 10px; + margin-right: 10px; + height: 2px; +} + +mat-icon { + font-size: 18px; + width: 20px; + height: 20px; +} + +input:focus{ + outline: none; +} + +::-webkit-scrollbar { + width: 0.5em; +} + +::-webkit-scrollbar-track { + -webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3); +} + +::-webkit-scrollbar-thumb { + background-color: darkgrey; + outline: 1px solid #263238; +} diff --git a/src/app/components/project-map/log-console/log-console.component.spec.ts b/src/app/components/project-map/log-console/log-console.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts new file mode 100644 index 00000000..8c4ac8f1 --- /dev/null +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -0,0 +1,54 @@ +import { Component, OnInit, AfterViewInit, OnDestroy, Input, ViewChild, ElementRef } from '@angular/core'; +import { Subscription } from 'rxjs'; +import { ProjectWebServiceHandler } from '../../../handlers/project-web-service-handler'; + + +@Component({ + selector: 'app-log-console', + templateUrl: './log-console.component.html', + styleUrls: ['./log-console.component.scss'] +}) +export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { + @ViewChild('console', {static: false}) console: ElementRef; + private subscription: Subscription; + command: string = ''; + + constructor( + private projectWebServiceHandler: ProjectWebServiceHandler + ) {} + + ngOnInit() { + this.subscription = this.projectWebServiceHandler.logEmitter.subscribe((event) => { + let message = `Event received: ${event.action}.` + this.showMessage(message); + }) + } + + ngAfterViewInit() { + this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; + } + + ngOnDestroy() { + this.subscription.unsubscribe(); + } + + onKeyDown(event) { + if (event.key === "Enter") { + this.handleCommand(); + } + } + + handleCommand() { + if (this.command === 'start all') { + this.showMessage("Starting all nodes..."); + } else { + this.showMessage(`Unknown syntax: ${this.command}`); + } + this.command = ''; + } + + showMessage(message: string) { + this.console.nativeElement.innerHTML += message += "
"; + this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; + } +} diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 42cbcd30..da2eb77f 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -120,3 +120,4 @@ + diff --git a/src/app/handlers/project-web-service-handler.ts b/src/app/handlers/project-web-service-handler.ts index 597553f6..d4f93c5c 100644 --- a/src/app/handlers/project-web-service-handler.ts +++ b/src/app/handlers/project-web-service-handler.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, EventEmitter } from '@angular/core'; import { Subject } from 'rxjs'; import { NodesDataSource } from '../cartography/datasources/nodes-datasource'; @@ -15,6 +15,8 @@ export class WebServiceMessage { @Injectable() export class ProjectWebServiceHandler { + public logEmitter = new EventEmitter(); + constructor( private nodesDataSource: NodesDataSource, private linksDataSource: LinksDataSource, @@ -22,6 +24,9 @@ export class ProjectWebServiceHandler { ) {} public handleMessage(message: WebServiceMessage) { + if( message.action !== 'ping' && message.action !== 'compute.updated') { + this.logEmitter.emit(message); + } if (message.action === 'node.updated') { this.nodesDataSource.update(message.event as Node); } diff --git a/yarn.lock b/yarn.lock index 0d799b27..71512706 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9006,6 +9006,11 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" +xterm@^3.14.5: + version "3.14.5" + resolved "https://registry.npmjs.org/xterm/-/xterm-3.14.5.tgz#c9d14e48be6873aa46fb429f22f2165557fd2dea" + integrity sha512-DVmQ8jlEtL+WbBKUZuMxHMBgK/yeIZwkXB81bH+MGaKKnJGYwA+770hzhXPfwEIokK9On9YIFPRleVp/5G7z9g== + y18n@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" From 34a31449f3ae69f733a6e8768ae053b7abfb613d Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 6 Aug 2019 04:44:29 -0700 Subject: [PATCH 02/14] start/stop/suspend/reload commands added --- .../log-console/log-console.component.ts | 81 ++++++++++++++++++- .../project-map/project-map.component.html | 2 +- src/app/services/node.service.ts | 8 ++ 3 files changed, 89 insertions(+), 2 deletions(-) diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index 8c4ac8f1..330bdffa 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -1,6 +1,10 @@ import { Component, OnInit, AfterViewInit, OnDestroy, Input, ViewChild, ElementRef } from '@angular/core'; import { Subscription } from 'rxjs'; import { ProjectWebServiceHandler } from '../../../handlers/project-web-service-handler'; +import { NodeService } from '../../../services/node.service'; +import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; +import { Project } from '../../../models/project'; +import { Server } from '../../../models/server'; @Component({ @@ -9,12 +13,21 @@ import { ProjectWebServiceHandler } from '../../../handlers/project-web-service- styleUrls: ['./log-console.component.scss'] }) export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { + @Input() project: Project; + @Input() server: Server; @ViewChild('console', {static: false}) console: ElementRef; private subscription: Subscription; command: string = ''; + private regexStart: RegExp = /^start (.*?)$/; + private regexStop: RegExp = /^stop (.*?)$/; + private regexSuspend: RegExp = /^suspend (.*?)$/; + private regexReload: RegExp = /^reload (.*?)$/; + constructor( - private projectWebServiceHandler: ProjectWebServiceHandler + private projectWebServiceHandler: ProjectWebServiceHandler, + private nodeService: NodeService, + private nodesDataSource: NodesDataSource ) {} ngOnInit() { @@ -41,6 +54,72 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { handleCommand() { if (this.command === 'start all') { this.showMessage("Starting all nodes..."); + this.nodeService.startAll(this.server, this.project).subscribe(() => { + this.showMessage("All nodes started.") + }); + } else if (this.command === 'stop all') { + this.showMessage("Stopping all nodes..."); + this.nodeService.stopAll(this.server, this.project).subscribe(() => { + this.showMessage("All nodes stopped.") + }); + } else if (this.command === 'suspend all') { + this.showMessage("Suspending all nodes..."); + this.nodeService.suspendAll(this.server, this.project).subscribe(() => { + this.showMessage("All nodes suspended.") + }); + } else if (this.command === 'reload all') { + this.showMessage("Reloading all nodes..."); + this.nodeService.reloadAll(this.server, this.project).subscribe(() => { + this.showMessage("All nodes reloaded.") + }); + } else if (this.regexStart.test(this.command)) { + let splittedCommand = this.command.split(/[ ,]+/); + let node = this.nodesDataSource.getItems().find(n => { + n.name.valueOf() === splittedCommand[1].valueOf(); + return n; + }); + if (node) { + this.showMessage(`Starting node ${splittedCommand[1]}...`); + this.nodeService.start(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} started.`)); + } else { + this.showMessage(`Node with ${splittedCommand[1]} name was not found.`); + } + } else if (this.regexStop.test(this.command)) { + let splittedCommand = this.command.split(/[ ,]+/); + let node = this.nodesDataSource.getItems().find(n => { + n.name.valueOf() === splittedCommand[1].valueOf(); + return n; + }); + if (node) { + this.showMessage(`Stopping node ${splittedCommand[1]}...`); + this.nodeService.stop(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} stopped.`)); + } else { + this.showMessage(`Node with ${splittedCommand[1]} name was not found.`); + } + } else if (this.regexSuspend.test(this.command)) { + let splittedCommand = this.command.split(/[ ,]+/); + let node = this.nodesDataSource.getItems().find(n => { + n.name.valueOf() === splittedCommand[1].valueOf(); + return n; + }); + if (node) { + this.showMessage(`Suspending node ${splittedCommand[1]}...`); + this.nodeService.suspend(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} stopped.`)); + } else { + this.showMessage(`Node with ${splittedCommand[1]} name was not found.`); + } + } else if (this.regexReload.test(this.command)) { + let splittedCommand = this.command.split(/[ ,]+/); + let node = this.nodesDataSource.getItems().find(n => { + n.name.valueOf() === splittedCommand[1].valueOf(); + return n; + }); + if (node) { + this.showMessage(`Reloading node ${splittedCommand[1]}...`); + this.nodeService.reload(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} reloaded.`)); + } else { + this.showMessage(`Node with ${splittedCommand[1]} name was not found.`); + } } else { this.showMessage(`Unknown syntax: ${this.command}`); } diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index da2eb77f..980d3ed2 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -120,4 +120,4 @@ - + diff --git a/src/app/services/node.service.ts b/src/app/services/node.service.ts index b0852956..4f894d09 100644 --- a/src/app/services/node.service.ts +++ b/src/app/services/node.service.ts @@ -29,10 +29,18 @@ export class NodeService { return this.httpServer.post(server, `/projects/${project.project_id}/nodes/stop`, {}); } + suspend(server: Server, node: Node) { + return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/suspend`, {}); + } + suspendAll(server: Server, project: Project) { return this.httpServer.post(server, `/projects/${project.project_id}/nodes/suspend`, {}); } + reload(server: Server, node: Node) { + return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/reload`, {}); + } + reloadAll(server: Server, project: Project) { return this.httpServer.post(server, `/projects/${project.project_id}/nodes/reload`, {}); } From 91545e50494be38789db884d2f424a799e28d4e1 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 6 Aug 2019 07:19:59 -0700 Subject: [PATCH 03/14] Extending commands --- .../log-console/log-console.component.ts | 114 ++++++++++-------- .../handlers/project-web-service-handler.ts | 16 ++- 2 files changed, 77 insertions(+), 53 deletions(-) diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index 330bdffa..ccab35ca 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -5,6 +5,9 @@ import { NodeService } from '../../../services/node.service'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; import { Project } from '../../../models/project'; import { Server } from '../../../models/server'; +import { Drawing } from '../../../cartography/models/drawing'; +import { Link } from '../../../models/link'; +import { Node } from '../../../cartography/models/node'; @Component({ @@ -16,13 +19,16 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { @Input() project: Project; @Input() server: Server; @ViewChild('console', {static: false}) console: ElementRef; - private subscription: Subscription; + private nodeSubscription: Subscription; + private linkSubscription: Subscription; + private drawingSubscription: Subscription; command: string = ''; private regexStart: RegExp = /^start (.*?)$/; private regexStop: RegExp = /^stop (.*?)$/; private regexSuspend: RegExp = /^suspend (.*?)$/; private regexReload: RegExp = /^reload (.*?)$/; + private regexShow: RegExp = /^show (.*?)$/; constructor( private projectWebServiceHandler: ProjectWebServiceHandler, @@ -31,10 +37,21 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { ) {} ngOnInit() { - this.subscription = this.projectWebServiceHandler.logEmitter.subscribe((event) => { - let message = `Event received: ${event.action}.` + this.nodeSubscription = this.projectWebServiceHandler.nodeNotificationEmitter.subscribe((event) => { + let node: Node = event.event as Node; + let message = `Event received: ${event.action} - ${this.printNode(node)}.` this.showMessage(message); - }) + }); + this.linkSubscription = this.projectWebServiceHandler.linkNotificationEmitter.subscribe((event) => { + let link: Link = event.event as Link; + let message = `Event received: ${event.action} - ${this.printLink(link)}.` + this.showMessage(message); + }); + this.drawingSubscription = this.projectWebServiceHandler.drawingNotificationEmitter.subscribe((event) => { + let drawing: Drawing = event.event as Drawing; + let message = `Event received: ${event.action} - ${this.printDrawing(drawing)}.` + this.showMessage(message); + }); } ngAfterViewInit() { @@ -42,7 +59,9 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { } ngOnDestroy() { - this.subscription.unsubscribe(); + this.nodeSubscription.unsubscribe(); + this.linkSubscription.unsubscribe(); + this.drawingSubscription.unsubscribe(); } onKeyDown(event) { @@ -52,7 +71,11 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { } handleCommand() { - if (this.command === 'start all') { + if (this.command === 'help') { + this.showMessage("Available commands: help, version, start all, start {node name}, stop all, stop {node name}, suspend all, suspend {node name}, reload all, reload {node name}, show {node name}.") + } else if (this.command === 'version') { + this.showMessage("Current version: 2019.2.0"); + } else if (this.command === 'start all') { this.showMessage("Starting all nodes..."); this.nodeService.startAll(this.server, this.project).subscribe(() => { this.showMessage("All nodes started.") @@ -72,51 +95,31 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.nodeService.reloadAll(this.server, this.project).subscribe(() => { this.showMessage("All nodes reloaded.") }); - } else if (this.regexStart.test(this.command)) { + } else if ( + this.regexStart.test(this.command) || this.regexStop.test(this.command) || this.regexSuspend.test(this.command) || this.regexReload.test(this.command)) { let splittedCommand = this.command.split(/[ ,]+/); - let node = this.nodesDataSource.getItems().find(n => { - n.name.valueOf() === splittedCommand[1].valueOf(); - return n; - }); + let node = this.nodesDataSource.getItems().find(n => n.name.valueOf() === splittedCommand[1].valueOf()); if (node) { - this.showMessage(`Starting node ${splittedCommand[1]}...`); - this.nodeService.start(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} started.`)); - } else { - this.showMessage(`Node with ${splittedCommand[1]} name was not found.`); - } - } else if (this.regexStop.test(this.command)) { - let splittedCommand = this.command.split(/[ ,]+/); - let node = this.nodesDataSource.getItems().find(n => { - n.name.valueOf() === splittedCommand[1].valueOf(); - return n; - }); - if (node) { - this.showMessage(`Stopping node ${splittedCommand[1]}...`); - this.nodeService.stop(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} stopped.`)); - } else { - this.showMessage(`Node with ${splittedCommand[1]} name was not found.`); - } - } else if (this.regexSuspend.test(this.command)) { - let splittedCommand = this.command.split(/[ ,]+/); - let node = this.nodesDataSource.getItems().find(n => { - n.name.valueOf() === splittedCommand[1].valueOf(); - return n; - }); - if (node) { - this.showMessage(`Suspending node ${splittedCommand[1]}...`); - this.nodeService.suspend(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} stopped.`)); - } else { - this.showMessage(`Node with ${splittedCommand[1]} name was not found.`); - } - } else if (this.regexReload.test(this.command)) { - let splittedCommand = this.command.split(/[ ,]+/); - let node = this.nodesDataSource.getItems().find(n => { - n.name.valueOf() === splittedCommand[1].valueOf(); - return n; - }); - if (node) { - this.showMessage(`Reloading node ${splittedCommand[1]}...`); - this.nodeService.reload(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} reloaded.`)); + if (this.regexStart.test(this.command)) { + this.showMessage(`Starting node ${splittedCommand[1]}...`); + this.nodeService.start(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} started.`)); + } + else if (this.regexStop.test(this.command)) { + this.showMessage(`Stopping node ${splittedCommand[1]}...`); + this.nodeService.stop(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} stopped.`)); + } + else if (this.regexSuspend.test(this.command)) { + this.showMessage(`Suspending node ${splittedCommand[1]}...`); + this.nodeService.suspend(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} suspended.`)); + } + else if (this.regexReload.test(this.command)) { + this.showMessage(`Reloading node ${splittedCommand[1]}...`); + this.nodeService.reload(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} reloaded.`)); + } + else if (this.regexShow.test(this.command)) { + this.showMessage(`Information about node ${node.name}:`); + this.showMessage(this.printNode(node)); + } } else { this.showMessage(`Node with ${splittedCommand[1]} name was not found.`); } @@ -130,4 +133,17 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.console.nativeElement.innerHTML += message += "
"; this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; } + + printNode(node: Node): string { + return 'command line: ' + node.command_line + ', ' + + 'name: ' + node.name + } + + printLink(link: Link): string { + return ''; + } + + printDrawing(drawing: Drawing): string { + return ''; + } } diff --git a/src/app/handlers/project-web-service-handler.ts b/src/app/handlers/project-web-service-handler.ts index d4f93c5c..c42379a9 100644 --- a/src/app/handlers/project-web-service-handler.ts +++ b/src/app/handlers/project-web-service-handler.ts @@ -15,7 +15,9 @@ export class WebServiceMessage { @Injectable() export class ProjectWebServiceHandler { - public logEmitter = new EventEmitter(); + public nodeNotificationEmitter = new EventEmitter(); + public linkNotificationEmitter = new EventEmitter(); + public drawingNotificationEmitter = new EventEmitter(); constructor( private nodesDataSource: NodesDataSource, @@ -24,35 +26,41 @@ export class ProjectWebServiceHandler { ) {} public handleMessage(message: WebServiceMessage) { - if( message.action !== 'ping' && message.action !== 'compute.updated') { - this.logEmitter.emit(message); - } if (message.action === 'node.updated') { this.nodesDataSource.update(message.event as Node); + this.nodeNotificationEmitter.emit(message); } if (message.action === 'node.created') { this.nodesDataSource.add(message.event as Node); + this.nodeNotificationEmitter.emit(message); } if (message.action === 'node.deleted') { this.nodesDataSource.remove(message.event as Node); + this.nodeNotificationEmitter.emit(message); } if (message.action === 'link.created') { this.linksDataSource.add(message.event as Link); + this.linkNotificationEmitter.emit(message); } if (message.action === 'link.updated') { this.linksDataSource.update(message.event as Link); + this.linkNotificationEmitter.emit(message); } if (message.action === 'link.deleted') { this.linksDataSource.remove(message.event as Link); + this.linkNotificationEmitter.emit(message); } if (message.action === 'drawing.created') { this.drawingsDataSource.add(message.event as Drawing); + this.drawingNotificationEmitter.emit(message); } if (message.action === 'drawing.updated') { this.drawingsDataSource.update(message.event as Drawing); + this.drawingNotificationEmitter.emit(message); } if (message.action === 'drawing.deleted') { this.drawingsDataSource.remove(message.event as Drawing); + this.drawingNotificationEmitter.emit(message); } } } From 668b640a9e1319aa44f36ecbafbba42cf54e0886 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 7 Aug 2019 01:55:19 -0700 Subject: [PATCH 04/14] Unit tests added --- .../log-console/log-console.component.spec.ts | 165 ++++++++++++++++++ .../project-map/project-map.component.spec.ts | 20 +++ src/app/services/node.service.spec.ts | 24 +++ 3 files changed, 209 insertions(+) diff --git a/src/app/components/project-map/log-console/log-console.component.spec.ts b/src/app/components/project-map/log-console/log-console.component.spec.ts index e69de29b..17febf72 100644 --- a/src/app/components/project-map/log-console/log-console.component.spec.ts +++ b/src/app/components/project-map/log-console/log-console.component.spec.ts @@ -0,0 +1,165 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { BrowserModule } from '@angular/platform-browser'; +import { NO_ERRORS_SCHEMA, EventEmitter } from '@angular/core'; +import { MatMenuModule } from '@angular/material'; +import { Server } from '../../../models/server'; +import { LogConsoleComponent } from './log-console.component'; +import { ProjectWebServiceHandler, WebServiceMessage } from '../../../handlers/project-web-service-handler'; +import { NodeService } from '../../../services/node.service'; +import { MockedNodeService, MockedNodesDataSource } from '../project-map.component.spec'; +import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; +import { of } from 'rxjs'; + +export class MockedProjectWebServiceHandler { + public nodeNotificationEmitter = new EventEmitter(); + public linkNotificationEmitter = new EventEmitter(); + public drawingNotificationEmitter = new EventEmitter(); +} + +describe('LogConsoleComponent', () => { + let component: LogConsoleComponent; + let fixture: ComponentFixture; + + let mockedNodeService: MockedNodeService = new MockedNodeService(); + let mockedNodesDataSource: MockedNodesDataSource = new MockedNodesDataSource(); + let mockedProjectWebServiceHandler: MockedProjectWebServiceHandler = new MockedProjectWebServiceHandler(); + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MatMenuModule, BrowserModule], + providers: [ + { provide: ProjectWebServiceHandler, useValue: mockedProjectWebServiceHandler }, + { provide: NodeService, useValue: mockedNodeService }, + { provide: NodesDataSource, useValue: mockedNodesDataSource } + ], + declarations: [LogConsoleComponent], + schemas: [NO_ERRORS_SCHEMA] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LogConsoleComponent); + component = fixture.componentInstance; + component.server = {location: 'local'} as Server; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should call show message when help command entered', () => { + spyOn(component, 'showMessage'); + component.command = 'help'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Available commands: help, version, start all, start {node name}, stop all, stop {node name}, suspend all, suspend {node name}, reload all, reload {node name}, show {node name}.'); + }); + + it('should call show message when version command entered', () => { + spyOn(component, 'showMessage'); + component.command = 'version'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Current version: 2019.2.0'); + }); + + it('should call show message when unknown command entered', () => { + spyOn(component, 'showMessage'); + component.command = 'xyz'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Unknown syntax: xyz'); + }); + + it('should call node service when start all entered', () => { + spyOn(component, 'showMessage'); + spyOn(mockedNodeService, 'startAll').and.returnValue(of({})); + component.command = 'start all'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Starting all nodes...'); + expect(mockedNodeService.startAll).toHaveBeenCalled(); + }); + + it('should call node service when stop all entered', () => { + spyOn(component, 'showMessage'); + spyOn(mockedNodeService, 'stopAll').and.returnValue(of({})); + component.command = 'stop all'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Stopping all nodes...'); + expect(mockedNodeService.stopAll).toHaveBeenCalled(); + }); + + it('should call node service when suspend all entered', () => { + spyOn(component, 'showMessage'); + spyOn(mockedNodeService, 'suspendAll').and.returnValue(of({})); + component.command = 'suspend all'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Suspending all nodes...'); + expect(mockedNodeService.suspendAll).toHaveBeenCalled(); + }); + + it('should call node service when reload all entered', () => { + spyOn(component, 'showMessage'); + spyOn(mockedNodeService, 'reloadAll').and.returnValue(of({})); + component.command = 'reload all'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Reloading all nodes...'); + expect(mockedNodeService.reloadAll).toHaveBeenCalled(); + }); + + it('should call node service when start node entered', () => { + spyOn(component, 'showMessage'); + spyOn(mockedNodeService, 'start').and.returnValue(of({})); + component.command = 'start testNode'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Starting node testNode...'); + expect(mockedNodeService.start).toHaveBeenCalled(); + }); + + it('should call node service when stop node entered', () => { + spyOn(component, 'showMessage'); + spyOn(mockedNodeService, 'stop').and.returnValue(of({})); + component.command = 'stop testNode'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Stopping node testNode...'); + expect(mockedNodeService.stop).toHaveBeenCalled(); + }); + + it('should call node service when suspend node entered', () => { + spyOn(component, 'showMessage'); + spyOn(mockedNodeService, 'suspend').and.returnValue(of({})); + component.command = 'suspend testNode'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Suspending node testNode...'); + expect(mockedNodeService.suspend).toHaveBeenCalled(); + }); + + it('should call node service when reload node entered', () => { + spyOn(component, 'showMessage'); + spyOn(mockedNodeService, 'reload').and.returnValue(of({})); + component.command = 'reload testNode'; + + component.handleCommand(); + + expect(component.showMessage).toHaveBeenCalledWith('Reloading node testNode...'); + expect(mockedNodeService.reload).toHaveBeenCalled(); + }); +}); diff --git a/src/app/components/project-map/project-map.component.spec.ts b/src/app/components/project-map/project-map.component.spec.ts index 8daeda92..cc4b2320 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -91,6 +91,22 @@ export class MockedNodeService { return of(); } + start(server: Server, node: Node) { + return of(); + } + + stop(server: Server, node: Node) { + return of(); + } + + suspend(server: Server, node: Node) { + return of(); + } + + reload(server: Server, node: Node) { + return of(); + } + duplicate(server: Server, node: Node) { return of(node); } @@ -184,6 +200,10 @@ export class MockedNodesDataSource { return {status: 'started'}; } + getItems() { + return [{name: 'testNode'}]; + } + update() { return of({}); } diff --git a/src/app/services/node.service.spec.ts b/src/app/services/node.service.spec.ts index 6559f9d2..1687c7ab 100644 --- a/src/app/services/node.service.spec.ts +++ b/src/app/services/node.service.spec.ts @@ -64,6 +64,30 @@ describe('NodeService', () => { expect(req.request.body).toEqual({}); })); + it('should suspend node', inject([NodeService], (service:NodeService) => { + const node = new Node(); + node.project_id = 'myproject'; + node.node_id = 'id'; + + service.suspend(server, node).subscribe(); + + const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/projects/myproject/nodes/id/suspend'); + expect(req.request.method).toEqual('POST'); + expect(req.request.body).toEqual({}); + })); + + it('should reload node', inject([NodeService], (service:NodeService) => { + const node = new Node(); + node.project_id = 'myproject'; + node.node_id = 'id'; + + service.reload(server, node).subscribe(); + + const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/projects/myproject/nodes/id/reload'); + expect(req.request.method).toEqual('POST'); + expect(req.request.body).toEqual({}); + })); + it('should start all nodes', inject([NodeService], (service: NodeService) => { let project = { project_id: '1' From 7f30d6ddf6078d051b9c1bdbe4474354e00662e7 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 7 Aug 2019 03:02:52 -0700 Subject: [PATCH 05/14] Update log-console.component.ts --- .../log-console/log-console.component.ts | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index ccab35ca..956b9579 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -8,6 +8,7 @@ import { Server } from '../../../models/server'; import { Drawing } from '../../../cartography/models/drawing'; import { Link } from '../../../models/link'; import { Node } from '../../../cartography/models/node'; +import { Port } from '../../../models/port'; @Component({ @@ -96,7 +97,7 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.showMessage("All nodes reloaded.") }); } else if ( - this.regexStart.test(this.command) || this.regexStop.test(this.command) || this.regexSuspend.test(this.command) || this.regexReload.test(this.command)) { + this.regexStart.test(this.command) || this.regexStop.test(this.command) || this.regexSuspend.test(this.command) || this.regexReload.test(this.command) || this.regexShow.test(this.command)) { let splittedCommand = this.command.split(/[ ,]+/); let node = this.nodesDataSource.getItems().find(n => n.name.valueOf() === splittedCommand[1].valueOf()); if (node) { @@ -135,15 +136,60 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { } printNode(node: Node): string { - return 'command line: ' + node.command_line + ', ' - + 'name: ' + node.name + return `command_line: ${node.command_line}, + compute_id: ${node.compute_id}, + console: ${node.console}, + console_host: ${node.console_host}, + console_type: ${node.console_type}, + first_port_name: ${node.first_port_name}, + height: ${node.height}, + label: ${node.label.text}, + name: ${node.name}, + node_directory: ${node.node_directory}, + node_id: ${node.node_id}, + node_type: ${node.node_type}, + port_name_format: ${node.port_name_format}, + port_segment_size: ${node.port_segment_size}, ` + + this.printPorts(node.ports) + + `project_id: ${node.project_id}, + status: ${node.status}, + symbol: ${node.symbol}, + symbol_url: ${node.symbol_url}, + width: ${node.width}, + x: ${node.x}, + y: ${node.y}, + z: ${node.z}`; + } + + printPorts(ports: Port[]): string { + let response: string = `ports: ` + ports.forEach(port => { + response = response + `adapter_number: ${port.adapter_number}, + link_type: ${port.link_type}, + name: ${port.name}, + port_number: ${port.port_number}, + short_name: ${port.short_name}, ` + }); + return response; } printLink(link: Link): string { - return ''; + return `capture_file_name: ${link.capture_file_name}, + capture_file_path: ${link.capture_file_path}, + capturing: ${link.capturing}, + link_id: ${link.link_id}, + link_type: ${link.link_type}, + project_id: ${link.project_id}, + suspend: ${link.suspend}, `; } printDrawing(drawing: Drawing): string { - return ''; + return `drawing_id: ${drawing.drawing_id}, + project_id: ${drawing.project_id}, + rotation: ${drawing.rotation}, + svg: ${drawing.svg}, + x: ${drawing.x}, + y: ${drawing.y}, + z: ${drawing.z}`; } } From 99df35282e88b6810b3dcbd7e64668ae325fef37 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 7 Aug 2019 05:19:54 -0700 Subject: [PATCH 06/14] Button on map to show/hide console --- src/app/app.module.ts | 2 ++ .../log-console/log-console.component.ts | 15 +++++++++++++-- .../log-console/log-events-datasource.ts | 9 +++++++++ .../project-map/project-map.component.html | 9 +++++++-- .../project-map/project-map.component.scss | 4 ++++ .../project-map/project-map.component.ts | 5 +++++ 6 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 src/app/components/project-map/log-console/log-events-datasource.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a474e6e7..8a247a42 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -192,6 +192,7 @@ import { MapSettingService } from './services/mapsettings.service'; import { ProjectMapMenuComponent } from './components/project-map/project-map-menu/project-map-menu.component'; import { HelpComponent } from './components/help/help.component'; import { LogConsoleComponent } from './components/project-map/log-console/log-console.component'; +import { LogEventsDataSource } from './components/project-map/log-console/log-events-datasource'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -354,6 +355,7 @@ if (environment.production) { LinksDataSource, NodesDataSource, SymbolsDataSource, + LogEventsDataSource, SelectionManager, InRectangleHelper, DrawingsDataSource, diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index 956b9579..7e8728ce 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -9,6 +9,7 @@ import { Drawing } from '../../../cartography/models/drawing'; import { Link } from '../../../models/link'; import { Node } from '../../../cartography/models/node'; import { Port } from '../../../models/port'; +import { LogEventsDataSource } from './log-events-datasource'; @Component({ @@ -34,7 +35,8 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { constructor( private projectWebServiceHandler: ProjectWebServiceHandler, private nodeService: NodeService, - private nodesDataSource: NodesDataSource + private nodesDataSource: NodesDataSource, + private logEventsDataSource: LogEventsDataSource ) {} ngOnInit() { @@ -56,6 +58,7 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { } ngAfterViewInit() { + this.console.nativeElement.innerHTML = this.logEventsDataSource.getItems()[0] ? this.logEventsDataSource.getItems()[0] : ''; this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; } @@ -130,8 +133,16 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.command = ''; } + clearConsole() { + this.console.nativeElement.innerHTML = ''; + this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; + } + showMessage(message: string) { - this.console.nativeElement.innerHTML += message += "
"; + this.logEventsDataSource.clear(); + this.logEventsDataSource.add(this.console.nativeElement.innerHTML + message + "
"); + + this.console.nativeElement.innerHTML += message += "
"; this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; } diff --git a/src/app/components/project-map/log-console/log-events-datasource.ts b/src/app/components/project-map/log-console/log-events-datasource.ts new file mode 100644 index 00000000..29fa4801 --- /dev/null +++ b/src/app/components/project-map/log-console/log-events-datasource.ts @@ -0,0 +1,9 @@ +import { Injectable } from '@angular/core'; +import { DataSource } from '../../../cartography/datasources/datasource'; + +@Injectable() +export class LogEventsDataSource extends DataSource { + protected getItemKey(log: string) { + return log; + } +} diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 980d3ed2..8272bc55 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -49,7 +49,7 @@ - + @@ -57,6 +57,9 @@ Show interface labels + + Show console + @@ -120,4 +123,6 @@ - +
+ +
diff --git a/src/app/components/project-map/project-map.component.scss b/src/app/components/project-map/project-map.component.scss index 49f1556a..553b5a13 100644 --- a/src/app/components/project-map/project-map.component.scss +++ b/src/app/components/project-map/project-map.component.scss @@ -230,3 +230,7 @@ g.node text, .context-menu-items .mat-menu-item:focus { background: none; } + +.visible { + display: none; +} diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 002d167b..df1c5cdd 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -68,6 +68,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { public server: Server; public ws: WebSocket; public isProjectMapMenuVisible: boolean = false; + public isConsoleVisible: boolean = false; tools = { selection: true, @@ -362,6 +363,10 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.project.show_interface_labels = enabled; } + public toggleShowConsole(visible: boolean) { + this.isConsoleVisible = visible; + } + public hideMenu() { this.projectMapMenuComponent.resetDrawToolChoice() this.isProjectMapMenuVisible = false; From 3da59f20e09e74a44f8cdba1fad148c2de922456 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 19 Aug 2019 01:34:29 -0700 Subject: [PATCH 07/14] Update log console component --- .../project-map/log-console/log-console.component.html | 3 +-- .../project-map/log-console/log-console.component.scss | 4 ++++ .../project-map/log-console/log-console.component.ts | 7 ++++++- src/app/components/project-map/project-map.component.html | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/app/components/project-map/log-console/log-console.component.html b/src/app/components/project-map/log-console/log-console.component.html index aa51c3d1..a2e78268 100644 --- a/src/app/components/project-map/log-console/log-console.component.html +++ b/src/app/components/project-map/log-console/log-console.component.html @@ -2,8 +2,7 @@
Console
- help_outline - close + close
diff --git a/src/app/components/project-map/log-console/log-console.component.scss b/src/app/components/project-map/log-console/log-console.component.scss index 58bca0e6..79e3abe4 100644 --- a/src/app/components/project-map/log-console/log-console.component.scss +++ b/src/app/components/project-map/log-console/log-console.component.scss @@ -74,3 +74,7 @@ input:focus{ background-color: darkgrey; outline: 1px solid #263238; } + +.closeButton { + cursor: pointer; +} diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index 7e8728ce..c6e4ff74 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, AfterViewInit, OnDestroy, Input, ViewChild, ElementRef } from '@angular/core'; +import { Component, OnInit, AfterViewInit, OnDestroy, Input, ViewChild, ElementRef, Output, EventEmitter } from '@angular/core'; import { Subscription } from 'rxjs'; import { ProjectWebServiceHandler } from '../../../handlers/project-web-service-handler'; import { NodeService } from '../../../services/node.service'; @@ -20,6 +20,7 @@ import { LogEventsDataSource } from './log-events-datasource'; export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { @Input() project: Project; @Input() server: Server; + @Output() closeConsole = new EventEmitter(); @ViewChild('console', {static: false}) console: ElementRef; private nodeSubscription: Subscription; private linkSubscription: Subscription; @@ -203,4 +204,8 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { y: ${drawing.y}, z: ${drawing.z}`; } + + close() { + this.closeConsole.emit(false); + } } diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 8272bc55..39411fe1 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -124,5 +124,5 @@
- +
From cfef46e25cf985482f01c4f5e961a6991372ba07 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 21 Aug 2019 00:13:44 -0700 Subject: [PATCH 08/14] Update log-console.component.spec.ts --- .../project-map/log-console/log-console.component.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/components/project-map/log-console/log-console.component.spec.ts b/src/app/components/project-map/log-console/log-console.component.spec.ts index 17febf72..342c7b48 100644 --- a/src/app/components/project-map/log-console/log-console.component.spec.ts +++ b/src/app/components/project-map/log-console/log-console.component.spec.ts @@ -9,6 +9,7 @@ import { NodeService } from '../../../services/node.service'; import { MockedNodeService, MockedNodesDataSource } from '../project-map.component.spec'; import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; import { of } from 'rxjs'; +import { LogEventsDataSource } from './log-events-datasource'; export class MockedProjectWebServiceHandler { public nodeNotificationEmitter = new EventEmitter(); @@ -30,7 +31,8 @@ describe('LogConsoleComponent', () => { providers: [ { provide: ProjectWebServiceHandler, useValue: mockedProjectWebServiceHandler }, { provide: NodeService, useValue: mockedNodeService }, - { provide: NodesDataSource, useValue: mockedNodesDataSource } + { provide: NodesDataSource, useValue: mockedNodesDataSource }, + { provide: LogEventsDataSource, useClass: LogEventsDataSource } ], declarations: [LogConsoleComponent], schemas: [NO_ERRORS_SCHEMA] From fee26eff87c6b0c322256b30f636f11c68e883df Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 22 Aug 2019 05:26:48 -0700 Subject: [PATCH 09/14] Requests to server visible in console --- .../log-console/log-console.component.ts | 9 +++++++-- src/app/services/http-server.service.ts | 14 +++++++++++++- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index c6e4ff74..52b6eec6 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -10,6 +10,7 @@ import { Link } from '../../../models/link'; import { Node } from '../../../cartography/models/node'; import { Port } from '../../../models/port'; import { LogEventsDataSource } from './log-events-datasource'; +import { HttpServer } from '../../../services/http-server.service'; @Component({ @@ -25,6 +26,7 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { private nodeSubscription: Subscription; private linkSubscription: Subscription; private drawingSubscription: Subscription; + private serverRequestsSubscription: Subscription; command: string = ''; private regexStart: RegExp = /^start (.*?)$/; @@ -37,7 +39,8 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { private projectWebServiceHandler: ProjectWebServiceHandler, private nodeService: NodeService, private nodesDataSource: NodesDataSource, - private logEventsDataSource: LogEventsDataSource + private logEventsDataSource: LogEventsDataSource, + private httpService: HttpServer ) {} ngOnInit() { @@ -56,6 +59,9 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { let message = `Event received: ${event.action} - ${this.printDrawing(drawing)}.` this.showMessage(message); }); + this.serverRequestsSubscription = this.httpService.requestsNotificationEmitter.subscribe((event) => { + this.showMessage(event); + }); } ngAfterViewInit() { @@ -199,7 +205,6 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { return `drawing_id: ${drawing.drawing_id}, project_id: ${drawing.project_id}, rotation: ${drawing.rotation}, - svg: ${drawing.svg}, x: ${drawing.x}, y: ${drawing.y}, z: ${drawing.z}`; diff --git a/src/app/services/http-server.service.ts b/src/app/services/http-server.service.ts index 5758ecc5..ca9b71ce 100644 --- a/src/app/services/http-server.service.ts +++ b/src/app/services/http-server.service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@angular/core'; +import { Injectable, EventEmitter } from '@angular/core'; import { HttpHeaders, HttpClient, HttpParams, HttpErrorResponse } from '@angular/common/http'; import { Observable, throwError } from 'rxjs'; @@ -79,11 +79,15 @@ export class ServerErrorHandler { @Injectable() export class HttpServer { + public requestsNotificationEmitter = new EventEmitter(); + constructor(private http: HttpClient, private errorHandler: ServerErrorHandler) {} get(server: Server, url: string, options?: JsonOptions): Observable { options = this.getJsonOptions(options); const intercepted = this.getOptionsForServer(server, url, options); + this.requestsNotificationEmitter.emit(`GET ${intercepted.url}`); + return this.http .get(intercepted.url, intercepted.options as JsonOptions) .pipe(catchError(this.errorHandler.handleError)) as Observable; @@ -92,6 +96,8 @@ export class HttpServer { getText(server: Server, url: string, options?: TextOptions): Observable { options = this.getTextOptions(options); const intercepted = this.getOptionsForServer(server, url, options); + this.requestsNotificationEmitter.emit(`GET ${intercepted.url}`); + return this.http .get(intercepted.url, intercepted.options as TextOptions) .pipe(catchError(this.errorHandler.handleError)); @@ -100,6 +106,8 @@ export class HttpServer { post(server: Server, url: string, body: any | null, options?: JsonOptions): Observable { options = this.getJsonOptions(options); const intercepted = this.getOptionsForServer(server, url, options); + this.requestsNotificationEmitter.emit(`POST ${intercepted.url}`); + return this.http .post(intercepted.url, body, intercepted.options) .pipe(catchError(this.errorHandler.handleError)) as Observable; @@ -108,6 +116,8 @@ export class HttpServer { put(server: Server, url: string, body: any, options?: JsonOptions): Observable { options = this.getJsonOptions(options); const intercepted = this.getOptionsForServer(server, url, options); + this.requestsNotificationEmitter.emit(`PUT ${intercepted.url}`); + return this.http .put(intercepted.url, body, intercepted.options) .pipe(catchError(this.errorHandler.handleError)) as Observable; @@ -116,6 +126,8 @@ export class HttpServer { delete(server: Server, url: string, options?: JsonOptions): Observable { options = this.getJsonOptions(options); const intercepted = this.getOptionsForServer(server, url, options); + this.requestsNotificationEmitter.emit(`DELETE ${intercepted.url}`); + return this.http .delete(intercepted.url, intercepted.options) .pipe(catchError(this.errorHandler.handleError)) as Observable; From 801b3ebfac5a68b8a3ff509b7055909a116d4d9c Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 26 Aug 2019 05:17:50 -0700 Subject: [PATCH 10/14] Introducing filters --- .../log-console/log-console.component.html | 23 +++- .../log-console/log-console.component.scss | 18 ++- .../log-console/log-console.component.ts | 106 ++++++++++++------ .../log-console/log-events-datasource.ts | 5 +- .../project-map/project-map.component.ts | 3 + src/app/models/logEvent.ts | 4 + src/app/services/mapsettings.service.ts | 5 + 7 files changed, 120 insertions(+), 44 deletions(-) create mode 100644 src/app/models/logEvent.ts diff --git a/src/app/components/project-map/log-console/log-console.component.html b/src/app/components/project-map/log-console/log-console.component.html index a2e78268..c7c2bea3 100644 --- a/src/app/components/project-map/log-console/log-console.component.html +++ b/src/app/components/project-map/log-console/log-console.component.html @@ -1,13 +1,29 @@
- Console +
+ Console + + Select filter + + + {{filter}} + + + +
+
close
+ +
+ + {{event.message}}
+
+
-
-
+
keyboard_arrow_right
+
diff --git a/src/app/components/project-map/log-console/log-console.component.scss b/src/app/components/project-map/log-console/log-console.component.scss index 79e3abe4..f3428e8b 100644 --- a/src/app/components/project-map/log-console/log-console.component.scss +++ b/src/app/components/project-map/log-console/log-console.component.scss @@ -3,7 +3,7 @@ position: fixed; bottom: 20px; left: 20px; - height: 120px; + height: 180px; width: 600px; background: #263238; color: white; @@ -13,18 +13,18 @@ .consoleHeader { width: 100%; - height: 24px; + height: 50px; font-size: 12px; overflow: hidden; margin-right: 5px; display: flex; - padding: 2px; + padding: 5px; justify-content: space-between; } .console { width: 596px; - height: 64px; + height: 100px; overflow-y: scroll; margin: 2px; color: #dbd5d5; @@ -34,7 +34,7 @@ .consoleInput { width: 100%; - height: 24px; + height: 30px; padding: 2px; display: flex; } @@ -53,11 +53,17 @@ } mat-icon { - font-size: 18px; + margin-top: 4px; + font-size: 20px; width: 20px; height: 20px; } +mat-checkbox { + margin-right: 5px; + margin-left: 5px; +} + input:focus{ outline: none; } diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index 52b6eec6..3febd6a9 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -11,6 +11,7 @@ import { Node } from '../../../cartography/models/node'; import { Port } from '../../../models/port'; import { LogEventsDataSource } from './log-events-datasource'; import { HttpServer } from '../../../services/http-server.service'; +import { LogEvent } from '../../../models/logEvent'; @Component({ @@ -29,6 +30,10 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { private serverRequestsSubscription: Subscription; command: string = ''; + filters: string[] = ['all', 'errors', 'warnings', 'map updates', 'server requests']; + selectedFilter: string = 'all'; + filteredEvents: LogEvent[] = []; + private regexStart: RegExp = /^start (.*?)$/; private regexStop: RegExp = /^stop (.*?)$/; private regexSuspend: RegExp = /^suspend (.*?)$/; @@ -47,25 +52,36 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.nodeSubscription = this.projectWebServiceHandler.nodeNotificationEmitter.subscribe((event) => { let node: Node = event.event as Node; let message = `Event received: ${event.action} - ${this.printNode(node)}.` - this.showMessage(message); + this.showMessage({ + type: 'map update', + message: message + }); }); this.linkSubscription = this.projectWebServiceHandler.linkNotificationEmitter.subscribe((event) => { let link: Link = event.event as Link; let message = `Event received: ${event.action} - ${this.printLink(link)}.` - this.showMessage(message); + this.showMessage({ + type: 'map update', + message: message + }); }); this.drawingSubscription = this.projectWebServiceHandler.drawingNotificationEmitter.subscribe((event) => { let drawing: Drawing = event.event as Drawing; let message = `Event received: ${event.action} - ${this.printDrawing(drawing)}.` - this.showMessage(message); + this.showMessage({ + type: 'map update', + message: message + }); }); - this.serverRequestsSubscription = this.httpService.requestsNotificationEmitter.subscribe((event) => { - this.showMessage(event); + this.serverRequestsSubscription = this.httpService.requestsNotificationEmitter.subscribe((message) => { + this.showMessage({ + type: 'server request', + message: message + }); }); } ngAfterViewInit() { - this.console.nativeElement.innerHTML = this.logEventsDataSource.getItems()[0] ? this.logEventsDataSource.getItems()[0] : ''; this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; } @@ -73,6 +89,11 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.nodeSubscription.unsubscribe(); this.linkSubscription.unsubscribe(); this.drawingSubscription.unsubscribe(); + this.serverRequestsSubscription.unsubscribe(); + } + + applyFilter() { + this.filteredEvents = this.getFilteredEvents(); } onKeyDown(event) { @@ -83,28 +104,28 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { handleCommand() { if (this.command === 'help') { - this.showMessage("Available commands: help, version, start all, start {node name}, stop all, stop {node name}, suspend all, suspend {node name}, reload all, reload {node name}, show {node name}.") + this.showCommand("Available commands: help, version, start all, start {node name}, stop all, stop {node name}, suspend all, suspend {node name}, reload all, reload {node name}, show {node name}.") } else if (this.command === 'version') { - this.showMessage("Current version: 2019.2.0"); + this.showCommand("Current version: 2019.2.0"); } else if (this.command === 'start all') { - this.showMessage("Starting all nodes..."); + this.showCommand("Starting all nodes..."); this.nodeService.startAll(this.server, this.project).subscribe(() => { - this.showMessage("All nodes started.") + this.showCommand("All nodes started.") }); } else if (this.command === 'stop all') { - this.showMessage("Stopping all nodes..."); + this.showCommand("Stopping all nodes..."); this.nodeService.stopAll(this.server, this.project).subscribe(() => { - this.showMessage("All nodes stopped.") + this.showCommand("All nodes stopped.") }); } else if (this.command === 'suspend all') { - this.showMessage("Suspending all nodes..."); + this.showCommand("Suspending all nodes..."); this.nodeService.suspendAll(this.server, this.project).subscribe(() => { - this.showMessage("All nodes suspended.") + this.showCommand("All nodes suspended.") }); } else if (this.command === 'reload all') { - this.showMessage("Reloading all nodes..."); + this.showCommand("Reloading all nodes..."); this.nodeService.reloadAll(this.server, this.project).subscribe(() => { - this.showMessage("All nodes reloaded.") + this.showCommand("All nodes reloaded.") }); } else if ( this.regexStart.test(this.command) || this.regexStop.test(this.command) || this.regexSuspend.test(this.command) || this.regexReload.test(this.command) || this.regexShow.test(this.command)) { @@ -112,47 +133,66 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { let node = this.nodesDataSource.getItems().find(n => n.name.valueOf() === splittedCommand[1].valueOf()); if (node) { if (this.regexStart.test(this.command)) { - this.showMessage(`Starting node ${splittedCommand[1]}...`); - this.nodeService.start(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} started.`)); + this.showCommand(`Starting node ${splittedCommand[1]}...`); + this.nodeService.start(this.server, node).subscribe(() => this.showCommand(`Node ${node.name} started.`)); } else if (this.regexStop.test(this.command)) { - this.showMessage(`Stopping node ${splittedCommand[1]}...`); - this.nodeService.stop(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} stopped.`)); + this.showCommand(`Stopping node ${splittedCommand[1]}...`); + this.nodeService.stop(this.server, node).subscribe(() => this.showCommand(`Node ${node.name} stopped.`)); } else if (this.regexSuspend.test(this.command)) { - this.showMessage(`Suspending node ${splittedCommand[1]}...`); - this.nodeService.suspend(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} suspended.`)); + this.showCommand(`Suspending node ${splittedCommand[1]}...`); + this.nodeService.suspend(this.server, node).subscribe(() => this.showCommand(`Node ${node.name} suspended.`)); } else if (this.regexReload.test(this.command)) { - this.showMessage(`Reloading node ${splittedCommand[1]}...`); - this.nodeService.reload(this.server, node).subscribe(() => this.showMessage(`Node ${node.name} reloaded.`)); + this.showCommand(`Reloading node ${splittedCommand[1]}...`); + this.nodeService.reload(this.server, node).subscribe(() => this.showCommand(`Node ${node.name} reloaded.`)); } else if (this.regexShow.test(this.command)) { - this.showMessage(`Information about node ${node.name}:`); - this.showMessage(this.printNode(node)); + this.showCommand(`Information about node ${node.name}:`); + this.showCommand(this.printNode(node)); } } else { - this.showMessage(`Node with ${splittedCommand[1]} name was not found.`); + this.showCommand(`Node with ${splittedCommand[1]} name was not found.`); } } else { - this.showMessage(`Unknown syntax: ${this.command}`); + this.showCommand(`Unknown syntax: ${this.command}`); } this.command = ''; } clearConsole() { - this.console.nativeElement.innerHTML = ''; + this.filteredEvents = []; this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; } - showMessage(message: string) { - this.logEventsDataSource.clear(); - this.logEventsDataSource.add(this.console.nativeElement.innerHTML + message + "
"); + showCommand(message: string) { + this.showMessage({ + type: 'command', + message: message + }); + } - this.console.nativeElement.innerHTML += message += "
"; + showMessage(event: LogEvent) { + this.logEventsDataSource.add(event); + this.filteredEvents = this.getFilteredEvents(); this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; } + getFilteredEvents(): LogEvent[] { + if (this.selectedFilter === 'server requests') { + return this.logEventsDataSource.getItems().filter(n => n.type === 'server request' || n.type === 'command'); + } else if (this.selectedFilter === 'errors') { + return this.logEventsDataSource.getItems().filter(n => n.type === 'error' || n.type === 'command'); + } else if (this.selectedFilter === 'warnings') { + return this.logEventsDataSource.getItems().filter(n => n.type === 'warning' || n.type === 'command'); + } else if (this.selectedFilter === 'map updates') { + return this.logEventsDataSource.getItems().filter(n => n.type === 'map update' || n.type === 'command'); + } else { + return this.logEventsDataSource.getItems(); + } + } + printNode(node: Node): string { return `command_line: ${node.command_line}, compute_id: ${node.compute_id}, diff --git a/src/app/components/project-map/log-console/log-events-datasource.ts b/src/app/components/project-map/log-console/log-events-datasource.ts index 29fa4801..9bc21a23 100644 --- a/src/app/components/project-map/log-console/log-events-datasource.ts +++ b/src/app/components/project-map/log-console/log-events-datasource.ts @@ -1,9 +1,10 @@ import { Injectable } from '@angular/core'; import { DataSource } from '../../../cartography/datasources/datasource'; +import { LogEvent } from '../../../models/logEvent'; @Injectable() -export class LogEventsDataSource extends DataSource { - protected getItemKey(log: string) { +export class LogEventsDataSource extends DataSource { + protected getItemKey(log: LogEvent) { return log; } } diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 3f84ea0a..e49eaaf6 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -136,6 +136,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { ngOnInit() { this.settings = this.settingsService.getAll(); this.isTopologySummaryVisible = this.mapSettingsService.isTopologySummaryVisible; + this.isConsoleVisible = this.mapSettingsService.isLogConsoleVisible; this.progressService.activate(); const routeSub = this.route.paramMap.subscribe((paramMap: ParamMap) => { @@ -275,6 +276,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.ws = new WebSocket(this.projectService.notificationsPath(this.server, project.project_id)); this.ws.onmessage = (event: MessageEvent) => { + // console.log(event); this.projectWebServiceHandler.handleMessage(JSON.parse(event.data)); }; @@ -406,6 +408,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { public toggleShowConsole(visible: boolean) { this.isConsoleVisible = visible; + this.mapSettingsService.toggleLogConsole(this.isConsoleVisible); } public toggleShowTopologySummary(visible: boolean) { diff --git a/src/app/models/logEvent.ts b/src/app/models/logEvent.ts new file mode 100644 index 00000000..4f3e7110 --- /dev/null +++ b/src/app/models/logEvent.ts @@ -0,0 +1,4 @@ +export class LogEvent { + type: string; + message: string; +} diff --git a/src/app/services/mapsettings.service.ts b/src/app/services/mapsettings.service.ts index caf4a6c8..2f1764e5 100644 --- a/src/app/services/mapsettings.service.ts +++ b/src/app/services/mapsettings.service.ts @@ -5,6 +5,7 @@ import { Subject } from 'rxjs'; export class MapSettingsService { public isMapLocked = new Subject(); public isTopologySummaryVisible: boolean = false; + public isLogConsoleVisible: boolean = false; constructor() {} @@ -15,4 +16,8 @@ export class MapSettingsService { toggleTopologySummary(value: boolean) { this.isTopologySummaryVisible = value; } + + toggleLogConsole(value: boolean) { + this.isLogConsoleVisible = value; + } } From 40ef11edbe6f3e4aa5851f3fed52a633a7719c0a Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 26 Aug 2019 06:48:43 -0700 Subject: [PATCH 11/14] Update log-console.component.spec.ts --- .../log-console/log-console.component.spec.ts | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/app/components/project-map/log-console/log-console.component.spec.ts b/src/app/components/project-map/log-console/log-console.component.spec.ts index 342c7b48..0efc8bd5 100644 --- a/src/app/components/project-map/log-console/log-console.component.spec.ts +++ b/src/app/components/project-map/log-console/log-console.component.spec.ts @@ -1,6 +1,6 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { BrowserModule } from '@angular/platform-browser'; -import { NO_ERRORS_SCHEMA, EventEmitter } from '@angular/core'; +import { NO_ERRORS_SCHEMA, EventEmitter, inject } from '@angular/core'; import { MatMenuModule } from '@angular/material'; import { Server } from '../../../models/server'; import { LogConsoleComponent } from './log-console.component'; @@ -10,6 +10,9 @@ import { MockedNodeService, MockedNodesDataSource } from '../project-map.compone import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; import { of } from 'rxjs'; import { LogEventsDataSource } from './log-events-datasource'; +import { HttpServer, ServerErrorHandler } from '../../../services/http-server.service'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; +import { HttpClient } from '@angular/common/http'; export class MockedProjectWebServiceHandler { public nodeNotificationEmitter = new EventEmitter(); @@ -25,14 +28,17 @@ describe('LogConsoleComponent', () => { let mockedNodesDataSource: MockedNodesDataSource = new MockedNodesDataSource(); let mockedProjectWebServiceHandler: MockedProjectWebServiceHandler = new MockedProjectWebServiceHandler(); + let httpServer = new HttpServer({} as HttpClient, {} as ServerErrorHandler); + beforeEach(async(() => { TestBed.configureTestingModule({ - imports: [MatMenuModule, BrowserModule], + imports: [HttpClientTestingModule, MatMenuModule, BrowserModule], providers: [ { provide: ProjectWebServiceHandler, useValue: mockedProjectWebServiceHandler }, { provide: NodeService, useValue: mockedNodeService }, { provide: NodesDataSource, useValue: mockedNodesDataSource }, - { provide: LogEventsDataSource, useClass: LogEventsDataSource } + { provide: LogEventsDataSource, useClass: LogEventsDataSource }, + { provide: HttpServer, useValue: httpServer } ], declarations: [LogConsoleComponent], schemas: [NO_ERRORS_SCHEMA] @@ -56,7 +62,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Available commands: help, version, start all, start {node name}, stop all, stop {node name}, suspend all, suspend {node name}, reload all, reload {node name}, show {node name}.'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Available commands: help, version, start all, start {node name}, stop all, stop {node name}, suspend all, suspend {node name}, reload all, reload {node name}, show {node name}.'}); }); it('should call show message when version command entered', () => { @@ -65,7 +71,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Current version: 2019.2.0'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Current version: 2019.2.0'}); }); it('should call show message when unknown command entered', () => { @@ -74,7 +80,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Unknown syntax: xyz'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Unknown syntax: xyz'}); }); it('should call node service when start all entered', () => { @@ -84,7 +90,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Starting all nodes...'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Starting all nodes...'}); expect(mockedNodeService.startAll).toHaveBeenCalled(); }); @@ -95,7 +101,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Stopping all nodes...'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Stopping all nodes...'}); expect(mockedNodeService.stopAll).toHaveBeenCalled(); }); @@ -106,7 +112,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Suspending all nodes...'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Suspending all nodes...'}); expect(mockedNodeService.suspendAll).toHaveBeenCalled(); }); @@ -117,7 +123,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Reloading all nodes...'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Reloading all nodes...'}); expect(mockedNodeService.reloadAll).toHaveBeenCalled(); }); @@ -128,7 +134,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Starting node testNode...'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Starting node testNode...'}); expect(mockedNodeService.start).toHaveBeenCalled(); }); @@ -139,7 +145,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Stopping node testNode...'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Stopping node testNode...'}); expect(mockedNodeService.stop).toHaveBeenCalled(); }); @@ -150,7 +156,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Suspending node testNode...'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Suspending node testNode...'}); expect(mockedNodeService.suspend).toHaveBeenCalled(); }); @@ -161,7 +167,7 @@ describe('LogConsoleComponent', () => { component.handleCommand(); - expect(component.showMessage).toHaveBeenCalledWith('Reloading node testNode...'); + expect(component.showMessage).toHaveBeenCalledWith({type: 'command', message: 'Reloading node testNode...'}); expect(mockedNodeService.reload).toHaveBeenCalled(); }); }); From 69934fb870ab13107efe592ea822904194827383 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 26 Aug 2019 08:16:36 -0700 Subject: [PATCH 12/14] Support for log events added --- .../log-console/log-console.component.spec.ts | 3 ++ .../log-console/log-console.component.ts | 34 ++++++++++++++++--- .../project-map/project-map.component.ts | 1 - .../handlers/project-web-service-handler.ts | 13 +++++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/app/components/project-map/log-console/log-console.component.spec.ts b/src/app/components/project-map/log-console/log-console.component.spec.ts index 0efc8bd5..3ec36f58 100644 --- a/src/app/components/project-map/log-console/log-console.component.spec.ts +++ b/src/app/components/project-map/log-console/log-console.component.spec.ts @@ -18,6 +18,9 @@ export class MockedProjectWebServiceHandler { public nodeNotificationEmitter = new EventEmitter(); public linkNotificationEmitter = new EventEmitter(); public drawingNotificationEmitter = new EventEmitter(); + public infoNotificationEmitter = new EventEmitter(); + public warningNotificationEmitter = new EventEmitter(); + public errorNotificationEmitter = new EventEmitter(); } describe('LogConsoleComponent', () => { diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index 3febd6a9..6b1aed75 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -28,9 +28,12 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { private linkSubscription: Subscription; private drawingSubscription: Subscription; private serverRequestsSubscription: Subscription; + private errorSubscription: Subscription; + private warningSubscription: Subscription; + private infoSubscription: Subscription; command: string = ''; - filters: string[] = ['all', 'errors', 'warnings', 'map updates', 'server requests']; + filters: string[] = ['all', 'errors', 'warnings', 'info', 'map updates', 'server requests']; selectedFilter: string = 'all'; filteredEvents: LogEvent[] = []; @@ -79,6 +82,24 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { message: message }); }); + this.errorSubscription = this.projectWebServiceHandler.errorNotificationEmitter.subscribe((message) => { + this.showMessage({ + type: 'error', + message: message + }); + }); + this.errorSubscription = this.projectWebServiceHandler.warningNotificationEmitter.subscribe((message) => { + this.showMessage({ + type: 'warning', + message: message + }); + }); + this.errorSubscription = this.projectWebServiceHandler.infoNotificationEmitter.subscribe((message) => { + this.showMessage({ + type: 'info', + message: message + }); + }); } ngAfterViewInit() { @@ -90,6 +111,9 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.linkSubscription.unsubscribe(); this.drawingSubscription.unsubscribe(); this.serverRequestsSubscription.unsubscribe(); + this.errorSubscription.unsubscribe(); + this.warningSubscription.unsubscribe(); + this.infoSubscription.unsubscribe(); } applyFilter() { @@ -181,11 +205,13 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { getFilteredEvents(): LogEvent[] { if (this.selectedFilter === 'server requests') { - return this.logEventsDataSource.getItems().filter(n => n.type === 'server request' || n.type === 'command'); + return this.logEventsDataSource.getItems().filter(n => n.type === 'server request'); } else if (this.selectedFilter === 'errors') { - return this.logEventsDataSource.getItems().filter(n => n.type === 'error' || n.type === 'command'); + return this.logEventsDataSource.getItems().filter(n => n.type === 'error'); } else if (this.selectedFilter === 'warnings') { - return this.logEventsDataSource.getItems().filter(n => n.type === 'warning' || n.type === 'command'); + return this.logEventsDataSource.getItems().filter(n => n.type === 'warning'); + } else if (this.selectedFilter === 'info') { + return this.logEventsDataSource.getItems().filter(n => n.type === 'info'); } else if (this.selectedFilter === 'map updates') { return this.logEventsDataSource.getItems().filter(n => n.type === 'map update' || n.type === 'command'); } else { diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index e49eaaf6..dbba7a16 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -276,7 +276,6 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.ws = new WebSocket(this.projectService.notificationsPath(this.server, project.project_id)); this.ws.onmessage = (event: MessageEvent) => { - // console.log(event); this.projectWebServiceHandler.handleMessage(JSON.parse(event.data)); }; diff --git a/src/app/handlers/project-web-service-handler.ts b/src/app/handlers/project-web-service-handler.ts index c42379a9..e9405c62 100644 --- a/src/app/handlers/project-web-service-handler.ts +++ b/src/app/handlers/project-web-service-handler.ts @@ -19,6 +19,10 @@ export class ProjectWebServiceHandler { public linkNotificationEmitter = new EventEmitter(); public drawingNotificationEmitter = new EventEmitter(); + public infoNotificationEmitter = new EventEmitter(); + public warningNotificationEmitter = new EventEmitter(); + public errorNotificationEmitter = new EventEmitter(); + constructor( private nodesDataSource: NodesDataSource, private linksDataSource: LinksDataSource, @@ -62,5 +66,14 @@ export class ProjectWebServiceHandler { this.drawingsDataSource.remove(message.event as Drawing); this.drawingNotificationEmitter.emit(message); } + if (message.action === 'log.error') { + this.errorNotificationEmitter.emit(message.event); + } + if (message.action === 'log.warning') { + this.warningNotificationEmitter.emit(message.event); + } + if (message.action === 'log.info') { + this.infoNotificationEmitter.emit(message.event); + } } } From aef6d044b3e4afd3935d84cc5a827e97cd612562 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 28 Aug 2019 07:04:17 -0700 Subject: [PATCH 13/14] exchnaging filter to mat menu --- .../log-console/log-console.component.html | 23 +++++++++---- .../log-console/log-console.component.scss | 32 +++++++++---------- .../log-console/log-console.component.ts | 2 +- 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/src/app/components/project-map/log-console/log-console.component.html b/src/app/components/project-map/log-console/log-console.component.html index c7c2bea3..39cd7e9e 100644 --- a/src/app/components/project-map/log-console/log-console.component.html +++ b/src/app/components/project-map/log-console/log-console.component.html @@ -1,15 +1,26 @@
-
- Console - +
+
Console
+ + + + + + + + + +
@@ -22,10 +33,9 @@ {{event.message}}
-
- keyboard_arrow_right + keyboard_arrow_right
-
diff --git a/src/app/components/project-map/log-console/log-console.component.scss b/src/app/components/project-map/log-console/log-console.component.scss index f3428e8b..e3b1ec5d 100644 --- a/src/app/components/project-map/log-console/log-console.component.scss +++ b/src/app/components/project-map/log-console/log-console.component.scss @@ -11,22 +11,31 @@ font-size: 12px; } +.filterButton { + background: #263238; + color: white; + border: none; +} + +.consoleFiltering { + display: flex; +} + .consoleHeader { width: 100%; - height: 50px; + height: 30px; font-size: 12px; overflow: hidden; - margin-right: 5px; display: flex; - padding: 5px; + padding: 2px; justify-content: space-between; } .console { width: 596px; - height: 100px; + height: 120px; overflow-y: scroll; - margin: 2px; + padding: 2px; color: #dbd5d5; scrollbar-color: darkgrey #263238; scrollbar-width: thin; @@ -45,25 +54,16 @@ border: none; } -.divider { - width: 580px; - margin-left: 10px; - margin-right: 10px; - height: 2px; +.inputIcon { + margin-top: 2px; } mat-icon { - margin-top: 4px; font-size: 20px; width: 20px; height: 20px; } -mat-checkbox { - margin-right: 5px; - margin-left: 5px; -} - input:focus{ outline: none; } diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index 6b1aed75..a1177b80 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -187,7 +187,7 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { clearConsole() { this.filteredEvents = []; - this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; + this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight * 2; } showCommand(message: string) { From f257992ffcfcfebd849ea24e908b4d47694441c1 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 28 Aug 2019 07:43:49 -0700 Subject: [PATCH 14/14] Console log component modified --- .../project-map/log-console/log-console.component.html | 10 +--------- .../project-map/log-console/log-console.component.ts | 6 +++++- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/app/components/project-map/log-console/log-console.component.html b/src/app/components/project-map/log-console/log-console.component.html index 39cd7e9e..5db1f7da 100644 --- a/src/app/components/project-map/log-console/log-console.component.html +++ b/src/app/components/project-map/log-console/log-console.component.html @@ -2,14 +2,6 @@
Console
- @@ -29,7 +21,7 @@
- + {{event.message}}
diff --git a/src/app/components/project-map/log-console/log-console.component.ts b/src/app/components/project-map/log-console/log-console.component.ts index a1177b80..26d758e8 100644 --- a/src/app/components/project-map/log-console/log-console.component.ts +++ b/src/app/components/project-map/log-console/log-console.component.ts @@ -187,7 +187,7 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { clearConsole() { this.filteredEvents = []; - this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight * 2; + this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; } showCommand(message: string) { @@ -201,6 +201,10 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.logEventsDataSource.add(event); this.filteredEvents = this.getFilteredEvents(); this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; + + setTimeout( () => { + this.console.nativeElement.scrollTop = this.console.nativeElement.scrollHeight; + }, 100 ); } getFilteredEvents(): LogEvent[] {