From 753649a321a3a0fa4737d4c3a9eb707a6266ffb2 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 30 Jul 2019 07:21:55 -0700 Subject: [PATCH 001/146] Support for editing VPCS config files --- src/app/app.module.ts | 9 +++- .../edit-config-action.component.html | 4 ++ .../edit-config-action.component.ts | 30 +++++++++++++ .../context-menu/context-menu.component.html | 5 +++ .../config-editor.component.html | 10 +++++ .../config-editor.component.scss | 4 ++ .../config-editor/config-editor.component.ts | 43 +++++++++++++++++++ src/app/services/node.service.ts | 18 ++++++++ 8 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.ts create mode 100644 src/app/components/project-map/node-editors/config-editor/config-editor.component.html create mode 100644 src/app/components/project-map/node-editors/config-editor/config-editor.component.scss create mode 100644 src/app/components/project-map/node-editors/config-editor/config-editor.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4242bce2..475862b3 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -191,6 +191,8 @@ 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 { ConfigEditorDialogComponent } from './components/project-map/node-editors/config-editor/config-editor.component'; +import { EditConfigActionComponent } from './components/project-map/context-menu/actions/edit-config/edit-config-action.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -312,7 +314,9 @@ if (environment.production) { ConsoleComponent, NodesMenuComponent, ProjectMapMenuComponent, - HelpComponent + HelpComponent, + ConfigEditorDialogComponent, + EditConfigActionComponent ], imports: [ BrowserModule, @@ -404,7 +408,8 @@ if (environment.production) { SymbolsComponent, DeleteConfirmationDialogComponent, HelpDialogComponent, - StartCaptureDialogComponent + StartCaptureDialogComponent, + ConfigEditorDialogComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.html b/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.html new file mode 100644 index 00000000..3cd439d9 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.ts b/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.ts new file mode 100644 index 00000000..de87c525 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/edit-config/edit-config-action.component.ts @@ -0,0 +1,30 @@ +import { Component, Input } from '@angular/core'; +import { Node } from '../../../../../cartography/models/node'; +import { Project } from '../../../../../models/project'; +import { Server } from '../../../../../models/server'; +import { ConfigEditorDialogComponent } from '../../../node-editors/config-editor/config-editor.component'; +import { MatDialog } from '@angular/material'; + +@Component({ + selector: 'app-edit-config-action', + templateUrl: './edit-config-action.component.html' +}) +export class EditConfigActionComponent { + @Input() server: Server; + @Input() project: Project; + @Input() node: Node; + + constructor(private dialog: MatDialog) {} + + editConfig() { + const dialogRef = this.dialog.open(ConfigEditorDialogComponent, { + width: '600px', + height: '500px', + autoFocus: false + }); + let instance = dialogRef.componentInstance; + instance.server = this.server; + instance.project = this.project; + instance.node = this.node; + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index 2ebfeb6a..35ed76d8 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -32,6 +32,11 @@ [link]="links[0]" [linkNode]="linkNodes[0]" > + Configuration for node {{node.name}} + + + +
+ + +
diff --git a/src/app/components/project-map/node-editors/config-editor/config-editor.component.scss b/src/app/components/project-map/node-editors/config-editor/config-editor.component.scss new file mode 100644 index 00000000..d874a5ff --- /dev/null +++ b/src/app/components/project-map/node-editors/config-editor/config-editor.component.scss @@ -0,0 +1,4 @@ +.textArea { + width: 100%; + height: 350px; +} diff --git a/src/app/components/project-map/node-editors/config-editor/config-editor.component.ts b/src/app/components/project-map/node-editors/config-editor/config-editor.component.ts new file mode 100644 index 00000000..8a1124c5 --- /dev/null +++ b/src/app/components/project-map/node-editors/config-editor/config-editor.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit } from '@angular/core'; +import { Node } from '../../../../cartography/models/node'; +import { Project } from '../../../../models/project'; +import { Server } from '../../../../models/server'; +import { MatDialogRef } from '@angular/material'; +import { NodeService } from '../../../../services/node.service'; +import { ToasterService } from '../../../../services/toaster.service'; + +@Component({ + selector: 'app-config-editor', + templateUrl: './config-editor.component.html', + styleUrls: ['./config-editor.component.scss'] +}) +export class ConfigEditorDialogComponent implements OnInit { + server: Server; + project: Project; + node: Node; + + config: any; + + constructor( + public dialogRef: MatDialogRef, + public nodeService: NodeService, + private toasterService: ToasterService + ) {} + + ngOnInit() { + this.nodeService.getConfiguration(this.server, this.node).subscribe((config: any) => { + this.config = config; + }); + } + + onSaveClick() { + this.nodeService.saveConfiguration(this.server, this.node, this.config).subscribe((response) => { + this.dialogRef.close(); + this.toasterService.success(`Configuration for node ${this.node.name} saved.`); + }); + } + + onCancelClick() { + this.dialogRef.close(); + } +} diff --git a/src/app/services/node.service.ts b/src/app/services/node.service.ts index b0852956..c35ef48f 100644 --- a/src/app/services/node.service.ts +++ b/src/app/services/node.service.ts @@ -84,4 +84,22 @@ export class NodeService { "z": node.z }); } + + getConfiguration(server: Server, node: Node) { + let urlPath: string = `/projects/${node.project_id}/nodes/${node.node_id}` + + if (node.node_type === 'vpcs') { + urlPath += '/files/startup.vpc'; + return this.httpServer.get(server, urlPath, { responseType: 'text' as 'json'}); + } + } + + saveConfiguration(server: Server, node: Node, configuration: string) { + let urlPath: string = `/projects/${node.project_id}/nodes/${node.node_id}` + + if (node.node_type === 'vpcs') { + urlPath += '/files/startup.vpc'; + return this.httpServer.post(server, urlPath, configuration); + } + } } From 6a5aca2dcd6c522a5725b88c6d94a67c85e6ab9b Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 30 Jul 2019 08:44:43 -0700 Subject: [PATCH 002/146] Unit tests added --- .../config-editor.component.spec.ts | 86 +++++++++++++++++++ .../project-map/project-map.component.spec.ts | 8 ++ 2 files changed, 94 insertions(+) create mode 100644 src/app/components/project-map/node-editors/config-editor/config-editor.component.spec.ts diff --git a/src/app/components/project-map/node-editors/config-editor/config-editor.component.spec.ts b/src/app/components/project-map/node-editors/config-editor/config-editor.component.spec.ts new file mode 100644 index 00000000..e89cb86b --- /dev/null +++ b/src/app/components/project-map/node-editors/config-editor/config-editor.component.spec.ts @@ -0,0 +1,86 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { Server } from '../../../../models/server'; +import { + MatDialogModule, + MatFormFieldModule, + MatDialogRef, + MAT_DIALOG_DATA, + MatSnackBarModule +} from '@angular/material'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { ToasterService } from '../../../../services/toaster.service'; +import { of } from 'rxjs/internal/observable/of'; +import { ConfigEditorDialogComponent } from './config-editor.component'; +import { NodeService } from '../../../../services/node.service'; +import { FormsModule } from '@angular/forms'; +import { MockedNodeService } from '../../project-map.component.spec'; +import { Node } from '../../../../cartography/models/node'; + +describe('ConfigEditorDialogComponent', () => { + let component: ConfigEditorDialogComponent; + let fixture: ComponentFixture; + let server: Server; + let node: Node; + let toaster = { + success: jasmine.createSpy('success') + }; + let dialogRef = { + close: jasmine.createSpy('close') + }; + let mockedNodeService: MockedNodeService = new MockedNodeService(); + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + MatFormFieldModule, + NoopAnimationsModule, + MatSnackBarModule, + FormsModule + ], + providers: [ + { provide: MatDialogRef, useValue: dialogRef }, + { provide: MAT_DIALOG_DATA }, + { provide: NodeService, useValue: mockedNodeService }, + { provide: ToasterService, useValue: toaster } + ], + declarations: [ConfigEditorDialogComponent] + }).compileComponents(); + + server = new Server(); + server.host = 'localhost'; + server.port = 80; + + node = new Node(); + node.name = 'sample name'; + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ConfigEditorDialogComponent); + component = fixture.componentInstance; + component.server = server; + component.node = node; + fixture.detectChanges(); + }); + + it('should be created', () => { + expect(fixture).toBeDefined(); + expect(component).toBeTruthy(); + }); + + it('should call node service when save configuration chosen', () => { + spyOn(mockedNodeService, 'saveConfiguration').and.returnValue(of('sample config')); + + component.onSaveClick(); + + expect(mockedNodeService.saveConfiguration).toHaveBeenCalled(); + }); + + it('should not call node service when save configuration chosen', () => { + spyOn(mockedNodeService, 'saveConfiguration').and.returnValue(of('sample config')); + + component.onCancelClick(); + + expect(mockedNodeService.saveConfiguration).not.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..9482b832 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -94,6 +94,14 @@ export class MockedNodeService { duplicate(server: Server, node: Node) { return of(node); } + + getConfiguration(server: Server, node: Node) { + return of('sample config'); + } + + saveConfiguration(server: Server, node: Node, configuration: string) { + return of(configuration); + } } export class MockedDrawingService { From d94f6d3d7d91547d00d24a0e435edafdcb0407bd Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 1 Aug 2019 09:10:51 -0700 Subject: [PATCH 003/146] Keyboard shortcuts added --- .../progress/progress.component.spec.ts | 2 +- src/app/components/help/help.component.html | 13 +++++++ .../project-map/project-map.component.spec.ts | 11 +++++- .../project-map/project-map.component.ts | 38 +++++++++++++++++-- 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/src/app/common/progress/progress.component.spec.ts b/src/app/common/progress/progress.component.spec.ts index e5c8f4bb..735354d2 100644 --- a/src/app/common/progress/progress.component.spec.ts +++ b/src/app/common/progress/progress.component.spec.ts @@ -7,7 +7,7 @@ import { RouterTestingModule } from '@angular/router/testing'; import { Router } from '@angular/router'; import { BehaviorSubject, Observable } from 'rxjs'; -class MockedRouter { +export class MockedRouter { events: BehaviorSubject; constructor() { diff --git a/src/app/components/help/help.component.html b/src/app/components/help/help.component.html index 0eda8204..eab6611f 100644 --- a/src/app/components/help/help.component.html +++ b/src/app/components/help/help.component.html @@ -3,6 +3,19 @@
+ + + Useful shortcuts + + + ctrl + + to zoom in + ctrl + - to zoom out + ctrl + 0 to reset zoom + ctrl + a to select all items on map + ctrl + shift + a to deselect all items on map + ctrl + shift + s to go to preferences + + Third party components 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..dd45a04d 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -2,6 +2,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ProjectMapComponent } from './project-map.component'; import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material'; +import { Router } from '@angular/router'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ServerService } from '../../services/server.service'; import { ProjectService } from '../../services/project.service'; @@ -52,6 +53,8 @@ import { MapSettingService } from '../../services/mapsettings.service'; import { ProjectMapMenuComponent } from './project-map-menu/project-map-menu.component'; import { MockedToasterService } from '../../services/toaster.service.spec'; import { ToasterService } from '../../services/toaster.service'; +import { MapNodesDataSource, MapLinksDataSource, MapDrawingsDataSource, MapSymbolsDataSource } from '../../cartography/datasources/map-datasource'; +import { MockedRouter } from '../../common/progress/progress.component.spec'; export class MockedProgressService { public activate() {} @@ -201,6 +204,7 @@ describe('ProjectMapComponent', () => { let nodesDataSource = new MockedNodesDataSource(); let linksDataSource = new MockedLinksDataSource(); let mockedToasterService = new MockedToasterService(); + let router = new MockedRouter(); let nodeCreatedLabelStylesFixer; beforeEach(async(() => { @@ -245,7 +249,12 @@ describe('ProjectMapComponent', () => { { provide: NodeCreatedLabelStylesFixer, useValue: nodeCreatedLabelStylesFixer}, { provide: MapScaleService }, { provide: NodeCreatedLabelStylesFixer, useValue: nodeCreatedLabelStylesFixer}, - { provide: ToasterService, useValue: mockedToasterService } + { provide: ToasterService, useValue: mockedToasterService }, + { provide: MapNodesDataSource, useClass: MapNodesDataSource }, + { provide: MapLinksDataSource, useClass: LinksDataSource }, + { provide: MapDrawingsDataSource, useClass: MapDrawingsDataSource }, + { provide: MapSymbolsDataSource, useClass: MapSymbolsDataSource }, + { provide: Router, useValue: router} ], declarations: [ProjectMapComponent, ProjectMapMenuComponent, D3MapComponent, ...ANGULAR_MAP_DECLARATIONS], schemas: [NO_ERRORS_SCHEMA] diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 002d167b..247c795a 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { ActivatedRoute, ParamMap } from '@angular/router'; +import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { Observable, Subject, Subscription, from } from 'rxjs'; import { webSocket } from 'rxjs/webSocket'; @@ -51,6 +51,7 @@ import { LabelWidget } from '../../cartography/widgets/label'; import { MapLinkNodeToLinkNodeConverter } from '../../cartography/converters/map/map-link-node-to-link-node-converter'; import { ProjectMapMenuComponent } from './project-map-menu/project-map-menu.component'; import { ToasterService } from '../../services/toaster.service'; +import { MapNodesDataSource, MapLinksDataSource, MapDrawingsDataSource, MapSymbolsDataSource, Indexed } from '../../cartography/datasources/map-datasource'; @Component({ @@ -115,7 +116,12 @@ export class ProjectMapComponent implements OnInit, OnDestroy { private movingEventSource: MovingEventSource, private mapScaleService: MapScaleService, private nodeCreatedLabelStylesFixer: NodeCreatedLabelStylesFixer, - private toasterService: ToasterService + private toasterService: ToasterService, + private mapNodesDataSource: MapNodesDataSource, + private mapLinksDataSource: MapLinksDataSource, + private mapDrawingsDataSource: MapDrawingsDataSource, + private mapSymbolsDataSource: MapSymbolsDataSource, + private router: Router ) {} ngOnInit() { @@ -196,11 +202,37 @@ export class ProjectMapComponent implements OnInit, OnDestroy { addKeyboardListeners() { Mousetrap.bind('ctrl++', (event: Event) => { event.preventDefault(); + this.zoomIn(); }); Mousetrap.bind('ctrl+-', (event: Event) => { event.preventDefault(); - });; + this.zoomOut(); + }); + + Mousetrap.bind('ctrl+0', (event: Event) => { + event.preventDefault(); + this.resetZoom(); + }); + + Mousetrap.bind('ctrl+a', (event: Event) => { + event.preventDefault(); + let allNodes: Indexed[] = this.mapNodesDataSource.getItems(); + let allDrawings: Indexed[] = this.mapDrawingsDataSource.getItems(); + let allLinks: Indexed[] = this.mapLinksDataSource.getItems(); + let allSymbols: Indexed[] = this.mapSymbolsDataSource.getItems(); + this.selectionManager.setSelected(allNodes.concat(allDrawings).concat(allLinks).concat(allSymbols)); + }); + + Mousetrap.bind('ctrl+shift+a', (event: Event) => { + event.preventDefault(); + this.selectionManager.setSelected([]); + }); + + Mousetrap.bind('ctrl+shift+s', (event: Event) => { + event.preventDefault(); + this.router.navigate(['/server', this.server.id, 'preferences']); + }); } onProjectLoad(project: Project) { From 3f696a9200dc1bbbfae05833aa3a91c9c65a3466 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 5 Aug 2019 07:07:47 -0700 Subject: [PATCH 004/146] 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 031291612f63ba83e2cb46937ed1a7ec9e2e0aa6 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 5 Aug 2019 23:49:22 -0700 Subject: [PATCH 005/146] Update template-list-dialog.component.ts --- .../template-list-dialog/template-list-dialog.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/template/template-list-dialog/template-list-dialog.component.ts b/src/app/components/template/template-list-dialog/template-list-dialog.component.ts index dce539e3..471305f3 100644 --- a/src/app/components/template/template-list-dialog/template-list-dialog.component.ts +++ b/src/app/components/template/template-list-dialog/template-list-dialog.component.ts @@ -20,7 +20,7 @@ export class TemplateListDialogComponent implements OnInit { dataSource: TemplateDataSource; displayedColumns = ['name']; - @ViewChild('filter', {static: false}) filter: ElementRef; + @ViewChild('filter', {static: true}) filter: ElementRef; constructor( public dialogRef: MatDialogRef, From 4487ab5167e1958dca64d5eb008f37960e78fd9f Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 6 Aug 2019 00:15:28 -0700 Subject: [PATCH 006/146] Update template-list-dialog --- .../template-list-dialog.component.html | 2 +- .../template-list-dialog.component.scss | 23 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/app/components/template/template-list-dialog/template-list-dialog.component.html b/src/app/components/template/template-list-dialog/template-list-dialog.component.html index 346b52d8..3eea74e5 100644 --- a/src/app/components/template/template-list-dialog/template-list-dialog.component.html +++ b/src/app/components/template/template-list-dialog/template-list-dialog.component.html @@ -1,4 +1,4 @@ -
+
diff --git a/src/app/components/template/template-list-dialog/template-list-dialog.component.scss b/src/app/components/template/template-list-dialog/template-list-dialog.component.scss index 6c455eef..6b2a2818 100644 --- a/src/app/components/template/template-list-dialog/template-list-dialog.component.scss +++ b/src/app/components/template/template-list-dialog/template-list-dialog.component.scss @@ -16,3 +16,26 @@ font-size: 16px; flex-grow: 1; } + +div { + scrollbar-color: darkgrey #263238; + scrollbar-width: thin; +} + +mat-table { + scrollbar-color: darkgrey #263238; + scrollbar-width: thin; +} + +::-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; +} From 34a31449f3ae69f733a6e8768ae053b7abfb613d Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 6 Aug 2019 04:44:29 -0700 Subject: [PATCH 007/146] 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 008/146] 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 009/146] 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 010/146] 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 011/146] 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 c9bdfeba8f45af556a5c3a39587d809b3f9ccb34 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 7 Aug 2019 05:59:24 -0700 Subject: [PATCH 012/146] Delete button added --- .../components/project-map/project-map.component.html | 4 ++++ .../project-map/project-map.component.spec.ts | 7 +++++-- .../components/project-map/project-map.component.ts | 11 +++++++++-- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 42cbcd30..70b609b7 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -46,6 +46,10 @@ developer_board Servers + 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..38e0b2a4 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -20,7 +20,7 @@ import { DrawingsDataSource } from '../../cartography/datasources/drawings-datas import { CommonModule } from '@angular/common'; import { ANGULAR_MAP_DECLARATIONS } from '../../cartography/angular-map.imports'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { MockedSettingsService } from '../../services/settings.service.spec'; import { MockedServerService } from '../../services/server.service.spec'; import { MockedProjectService } from '../../services/project.service.spec'; @@ -52,6 +52,7 @@ import { MapSettingService } from '../../services/mapsettings.service'; import { ProjectMapMenuComponent } from './project-map-menu/project-map-menu.component'; import { MockedToasterService } from '../../services/toaster.service.spec'; import { ToasterService } from '../../services/toaster.service'; +import { MockedActivatedRoute } from '../snapshots/list-of-snapshots/list-of-snaphshots.component.spec'; export class MockedProgressService { public activate() {} @@ -202,6 +203,7 @@ describe('ProjectMapComponent', () => { let linksDataSource = new MockedLinksDataSource(); let mockedToasterService = new MockedToasterService(); let nodeCreatedLabelStylesFixer; + let mockedRouter = new MockedActivatedRoute; beforeEach(async(() => { nodeCreatedLabelStylesFixer = { @@ -245,7 +247,8 @@ describe('ProjectMapComponent', () => { { provide: NodeCreatedLabelStylesFixer, useValue: nodeCreatedLabelStylesFixer}, { provide: MapScaleService }, { provide: NodeCreatedLabelStylesFixer, useValue: nodeCreatedLabelStylesFixer}, - { provide: ToasterService, useValue: mockedToasterService } + { provide: ToasterService, useValue: mockedToasterService }, + { provide: Router, useValue: mockedRouter } ], declarations: [ProjectMapComponent, ProjectMapMenuComponent, D3MapComponent, ...ANGULAR_MAP_DECLARATIONS], schemas: [NO_ERRORS_SCHEMA] diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 002d167b..369524b1 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { ActivatedRoute, ParamMap } from '@angular/router'; +import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { Observable, Subject, Subscription, from } from 'rxjs'; import { webSocket } from 'rxjs/webSocket'; @@ -115,7 +115,8 @@ export class ProjectMapComponent implements OnInit, OnDestroy { private movingEventSource: MovingEventSource, private mapScaleService: MapScaleService, private nodeCreatedLabelStylesFixer: NodeCreatedLabelStylesFixer, - private toasterService: ToasterService + private toasterService: ToasterService, + private router: Router, ) {} ngOnInit() { @@ -408,6 +409,12 @@ export class ProjectMapComponent implements OnInit, OnDestroy { imageToUpload.src = window.URL.createObjectURL(file); } + public deleteProject() { + this.projectService.delete(this.server, this.project.project_id).subscribe(() => { + this.router.navigate(['/server', this.server.id, 'projects']); + }); + } + public ngOnDestroy() { this.drawingsDataSource.clear(); this.nodesDataSource.clear(); From 162806b2681f13439ef97111c15da57aebf7a13c Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 8 Aug 2019 05:44:35 -0700 Subject: [PATCH 013/146] Information dialog added --- src/app/app.module.ts | 13 +++- .../show-node-action.component.html | 4 ++ .../show-node-action.component.ts | 26 +++++++ .../context-menu/context-menu.component.html | 4 ++ .../info-dialog/info-dialog.component.html | 27 ++++++++ .../info-dialog/info-dialog.component.scss | 3 + .../info-dialog/info-dialog.component.ts | 31 +++++++++ src/app/services/info.service.ts | 67 +++++++++++++++++++ 8 files changed, 172 insertions(+), 3 deletions(-) create mode 100644 src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.ts create mode 100644 src/app/components/project-map/info-dialog/info-dialog.component.html create mode 100644 src/app/components/project-map/info-dialog/info-dialog.component.scss create mode 100644 src/app/components/project-map/info-dialog/info-dialog.component.ts create mode 100644 src/app/services/info.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4242bce2..75940652 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -191,6 +191,9 @@ 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 { ShowNodeActionComponent } from './components/project-map/context-menu/actions/show-node-action/show-node-action.component'; +import { InfoDialogComponent } from './components/project-map/info-dialog/info-dialog.component'; +import { InfoService } from './services/info.service'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -309,10 +312,12 @@ if (environment.production) { NodesMenuComponent, AdbutlerComponent, ConsoleDeviceActionComponent, + ShowNodeActionComponent, ConsoleComponent, NodesMenuComponent, ProjectMapMenuComponent, - HelpComponent + HelpComponent, + InfoDialogComponent ], imports: [ BrowserModule, @@ -388,7 +393,8 @@ if (environment.production) { NodeCreatedLabelStylesFixer, NonNegativeValidator, RotationValidator, - MapSettingService + MapSettingService, + InfoService ], entryComponents: [ AddServerDialogComponent, @@ -404,7 +410,8 @@ if (environment.production) { SymbolsComponent, DeleteConfirmationDialogComponent, HelpDialogComponent, - StartCaptureDialogComponent + StartCaptureDialogComponent, + InfoDialogComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.html b/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.html new file mode 100644 index 00000000..b92a0071 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.ts b/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.ts new file mode 100644 index 00000000..3f70d051 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/show-node-action/show-node-action.component.ts @@ -0,0 +1,26 @@ +import { Component, Input, OnInit, OnChanges } from '@angular/core'; +import { Node } from '../../../../../cartography/models/node'; +import { MatDialog } from '@angular/material'; +import { InfoDialogComponent } from '../../../info-dialog/info-dialog.component'; +import { Server } from '../../../../../models/server'; + +@Component({ + selector: 'app-show-node-action', + templateUrl: './show-node-action.component.html' +}) +export class ShowNodeActionComponent { + @Input() node: Node; + @Input() server: Server + + constructor(private dialog: MatDialog) {} + + showNode() { + const dialogRef = this.dialog.open(InfoDialogComponent, { + width: '600px', + autoFocus: false + }); + let instance = dialogRef.componentInstance; + instance.node = this.node; + instance.server = this.server; + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index 2ebfeb6a..9e857519 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -1,6 +1,10 @@
+ {{node.name}} + + + +
+ +
diff --git a/src/app/components/project-map/info-dialog/info-dialog.component.scss b/src/app/components/project-map/info-dialog/info-dialog.component.scss new file mode 100644 index 00000000..e28aaee8 --- /dev/null +++ b/src/app/components/project-map/info-dialog/info-dialog.component.scss @@ -0,0 +1,3 @@ +.textBox { + margin-top: 10px; +} diff --git a/src/app/components/project-map/info-dialog/info-dialog.component.ts b/src/app/components/project-map/info-dialog/info-dialog.component.ts new file mode 100644 index 00000000..11968f47 --- /dev/null +++ b/src/app/components/project-map/info-dialog/info-dialog.component.ts @@ -0,0 +1,31 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { MatDialogRef } from '@angular/material'; +import { Node } from '../../../cartography/models/node'; +import { InfoService } from '../../../services/info.service'; +import { Server } from '../../../models/server'; + +@Component({ + selector: 'app-info-dialog', + templateUrl: './info-dialog.component.html', + styleUrls: ['./info-dialog.component.scss'] +}) +export class InfoDialogComponent implements OnInit { + @Input() server: Server; + @Input() node: Node; + infoList: string[] = []; + commandLine: string = ''; + + constructor( + public dialogRef: MatDialogRef, + private infoService: InfoService + ) {} + + ngOnInit() { + this.infoList = this.infoService.getInfoAboutNode(this.node, this.server); + this.commandLine = this.infoService.getCommandLine(this.node); + } + + onCloseClick() { + this.dialogRef.close(); + } +} diff --git a/src/app/services/info.service.ts b/src/app/services/info.service.ts new file mode 100644 index 00000000..62f58f7a --- /dev/null +++ b/src/app/services/info.service.ts @@ -0,0 +1,67 @@ +import { Injectable } from "@angular/core"; +import { Node } from '../cartography/models/node'; +import { Port } from '../models/port'; +import { Server } from '../models/server'; + +@Injectable() +export class InfoService { + getInfoAboutNode(node: Node, server: Server): string[] { + let infoList: string[] = []; + if (node.node_type === 'cloud') { + infoList.push(`Cloud ${node.name} is always on.`); + } else if (node.node_type === 'nat') { + infoList.push(`NAT ${node.name} is always on.`); + } else if (node.node_type === 'ethernet-hub') { + infoList.push(`Ethernet hub ${node.name} is always on.`); + } else if (node.node_type === 'ethernet_switch') { + infoList.push(`Ethernet switch ${node.name} is always on.`); + } else if (node.node_type === 'frame_relay_switch') { + infoList.push(`Frame relay switch ${node.name} is always on.`); + } else if (node.node_type === 'atm_switch') { + infoList.push(`ATM switch ${node.name} is always on.`); + } else if (node.node_type === 'docker') { + infoList.push(`Docker ${node.name} is ${node.status}.`); + } else if (node.node_type === 'dynamips') { + infoList.push(`Dynamips ${node.name} is always on.`); + } else if (node.node_type === 'traceng') { + infoList.push(`TraceNG ${node.name} is always on.`); + } else if (node.node_type === 'virtualbox') { + infoList.push(`VirtualBox VM ${node.name} is ${node.status}.`); + } else if (node.node_type === 'vmware') { + infoList.push(`VMware VM ${node.name} is ${node.status}.`); + } else if (node.node_type === 'qemu') { + infoList.push(`QEMU VM ${node.name} is ${node.status}.`); + } else if (node.node_type === 'iou') { + infoList.push(`IOU ${node.name} is always on.`); + } else if (node.node_type === 'vpcs') { + infoList.push(`Node ${node.name} is ${node.status}.`); + } + infoList.push(`Running on server ${server.name} with port ${server.port}.`); + infoList.push(`Server ID is ${server.id}.`); + if (node.console_type !== 'none' && node.console_type !== 'null') { + infoList.push(`Console is on port ${node.console} and type is ${node.console_type}.`); + } + infoList = infoList.concat(this.getInfoAboutPorts(node.ports)); + return infoList; + } + + getInfoAboutPorts(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; + } + + getCommandLine(node: Node): string { + if (node.node_type === 'cloud' || "nat" || "ethernet_hub" || "ethernet_switch" || "frame_relay_switch" || "atm_switch" || "dynamips" || "traceng" || "iou") { + return 'Command line information is not supported for this type of node.'; + } else { + return node.command_line; + } + } +} From c70d9852f668c32110d3d771c10dafcd947beee2 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 8 Aug 2019 06:25:28 -0700 Subject: [PATCH 014/146] Displaying ports updated --- .../info-dialog/info-dialog.component.html | 12 +++++------- src/app/services/info.service.ts | 16 +++++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/app/components/project-map/info-dialog/info-dialog.component.html b/src/app/components/project-map/info-dialog/info-dialog.component.html index 4bf096d9..96a2234a 100644 --- a/src/app/components/project-map/info-dialog/info-dialog.component.html +++ b/src/app/components/project-map/info-dialog/info-dialog.component.html @@ -4,19 +4,17 @@
- - - {{info}} - - +
+ {{info}} +
Please start the node in order to get the command line information.
-
- {{node.command_line}} +
+ {{command_line}}
diff --git a/src/app/services/info.service.ts b/src/app/services/info.service.ts index 62f58f7a..0e722927 100644 --- a/src/app/services/info.service.ts +++ b/src/app/services/info.service.ts @@ -46,14 +46,12 @@ export class InfoService { } getInfoAboutPorts(ports: Port[]): string { - let response: string = `ports: ` + 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}, ` + response += `link_type: ${port.link_type}, + name: ${port.name}; ` }); + response = response.substring(0, response.length - 2); return response; } @@ -61,7 +59,11 @@ export class InfoService { if (node.node_type === 'cloud' || "nat" || "ethernet_hub" || "ethernet_switch" || "frame_relay_switch" || "atm_switch" || "dynamips" || "traceng" || "iou") { return 'Command line information is not supported for this type of node.'; } else { - return node.command_line; + if (node.status === 'started') { + return node.command_line; + } else { + return 'Please start the node in order to get the command line information.'; + } } } } From 46ef26931d207155e17de4da7d8782818c439c88 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 9 Aug 2019 04:14:55 -0700 Subject: [PATCH 015/146] Import/export buttons added --- .../project-map/project-map.component.html | 12 +++++-- .../project-map/project-map.component.ts | 32 +++++++++++++++++-- .../import-project-dialog.component.ts | 8 +++-- src/app/services/project.service.ts | 4 +++ 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 42cbcd30..5188ac6f 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -40,11 +40,19 @@ + + diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 002d167b..d723fd47 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -1,5 +1,5 @@ import { Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core'; -import { ActivatedRoute, ParamMap } from '@angular/router'; +import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { Observable, Subject, Subscription, from } from 'rxjs'; import { webSocket } from 'rxjs/webSocket'; @@ -51,6 +51,8 @@ import { LabelWidget } from '../../cartography/widgets/label'; import { MapLinkNodeToLinkNodeConverter } from '../../cartography/converters/map/map-link-node-to-link-node-converter'; import { ProjectMapMenuComponent } from './project-map-menu/project-map-menu.component'; import { ToasterService } from '../../services/toaster.service'; +import { ImportProjectDialogComponent } from '../projects/import-project-dialog/import-project-dialog.component'; +import { MatDialog } from '@angular/material'; @Component({ @@ -115,7 +117,9 @@ export class ProjectMapComponent implements OnInit, OnDestroy { private movingEventSource: MovingEventSource, private mapScaleService: MapScaleService, private nodeCreatedLabelStylesFixer: NodeCreatedLabelStylesFixer, - private toasterService: ToasterService + private toasterService: ToasterService, + private dialog: MatDialog, + private router: Router ) {} ngOnInit() { @@ -386,6 +390,30 @@ export class ProjectMapComponent implements OnInit, OnDestroy { resetZoom() { this.mapScaleService.resetToDefault(); } + + importProject() { + let uuid: string = ''; + const dialogRef = this.dialog.open(ImportProjectDialogComponent, { + width: '400px', + autoFocus: false + }); + let instance = dialogRef.componentInstance; + instance.server = this.server; + const subscription = dialogRef.componentInstance.onImportProject.subscribe((projectId: string) => { + uuid = projectId; + }); + + dialogRef.afterClosed().subscribe(() => { + subscription.unsubscribe(); + this.projectService.open(this.server, uuid).subscribe(() => { + this.router.navigate(['/server', this.server.id, 'project', uuid]); + }); + }); + } + + exportProject() { + window.location.href = `http://${this.server.host}:${this.server.port}/v2/projects/${this.project.project_id}/export`; + } public uploadImageFile(event) { this.readImageFile(event.target); diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts index 07a76027..bcb54385 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, Inject } from '@angular/core'; +import { Component, OnInit, Inject, EventEmitter } from '@angular/core'; import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material'; import { FileUploader, ParsedResponseHeaders, FileItem } from 'ng2-file-upload'; import { Server } from '../../../models/server'; @@ -26,6 +26,8 @@ export class ImportProjectDialogComponent implements OnInit { projectNameForm: FormGroup; submitted: boolean = false; isFirstStepCompleted: boolean = false; + uuid: string; + onImportProject = new EventEmitter(); constructor( private dialog: MatDialog, @@ -58,6 +60,7 @@ export class ImportProjectDialogComponent implements OnInit { status: number, headers: ParsedResponseHeaders ) => { + this.onImportProject.emit(this.uuid); this.resultMessage = 'Project was imported succesfully!'; this.isFinishEnabled = true; }; @@ -138,7 +141,8 @@ export class ImportProjectDialogComponent implements OnInit { } prepareUploadPath(): string { + this.uuid = uuid(); const projectName = this.projectNameForm.controls['projectName'].value; - return `http://${this.server.host}:${this.server.port}/v2/projects/${uuid()}/import?name=${projectName}`; + return `http://${this.server.host}:${this.server.port}/v2/projects/${this.uuid}/import?name=${projectName}`; } } diff --git a/src/app/services/project.service.ts b/src/app/services/project.service.ts index 4ca87f98..d5a7af51 100644 --- a/src/app/services/project.service.ts +++ b/src/app/services/project.service.ts @@ -49,6 +49,10 @@ export class ProjectService { return this.httpServer.delete(server, `/projects/${project_id}`); } + export(server: Server, project_id: string): Observable { + return this.httpServer.get(server, `/projects/${project_id}/export`) + } + notificationsPath(server: Server, project_id: string): string { return `ws://${server.host}:${server.port}/v2/projects/${project_id}/notifications/ws`; } From 2f1f6b5a35361d284d80b4b4085578ce19dd66ae Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 9 Aug 2019 04:33:54 -0700 Subject: [PATCH 016/146] Update project-map.component.spec.ts --- .../project-map/project-map.component.spec.ts | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) 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..a38c4d2d 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -1,7 +1,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; import { ProjectMapComponent } from './project-map.component'; -import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material'; +import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, MatDialogModule } from '@angular/material'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import { ServerService } from '../../services/server.service'; import { ProjectService } from '../../services/project.service'; @@ -20,7 +20,7 @@ import { DrawingsDataSource } from '../../cartography/datasources/drawings-datas import { CommonModule } from '@angular/common'; import { ANGULAR_MAP_DECLARATIONS } from '../../cartography/angular-map.imports'; import { NO_ERRORS_SCHEMA } from '@angular/core'; -import { ActivatedRoute } from '@angular/router'; +import { ActivatedRoute, Router } from '@angular/router'; import { MockedSettingsService } from '../../services/settings.service.spec'; import { MockedServerService } from '../../services/server.service.spec'; import { MockedProjectService } from '../../services/project.service.spec'; @@ -52,6 +52,7 @@ import { MapSettingService } from '../../services/mapsettings.service'; import { ProjectMapMenuComponent } from './project-map-menu/project-map-menu.component'; import { MockedToasterService } from '../../services/toaster.service.spec'; import { ToasterService } from '../../services/toaster.service'; +import { MockedActivatedRoute } from '../snapshots/list-of-snapshots/list-of-snaphshots.component.spec'; export class MockedProgressService { public activate() {} @@ -202,6 +203,7 @@ describe('ProjectMapComponent', () => { let linksDataSource = new MockedLinksDataSource(); let mockedToasterService = new MockedToasterService(); let nodeCreatedLabelStylesFixer; + let mockedRouter = new MockedActivatedRoute; beforeEach(async(() => { nodeCreatedLabelStylesFixer = { @@ -209,7 +211,7 @@ describe('ProjectMapComponent', () => { }; TestBed.configureTestingModule({ - imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule], + imports: [MatIconModule, MatDialogModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule], providers: [ { provide: ActivatedRoute }, { provide: ServerService, useClass: MockedServerService }, @@ -245,7 +247,8 @@ describe('ProjectMapComponent', () => { { provide: NodeCreatedLabelStylesFixer, useValue: nodeCreatedLabelStylesFixer}, { provide: MapScaleService }, { provide: NodeCreatedLabelStylesFixer, useValue: nodeCreatedLabelStylesFixer}, - { provide: ToasterService, useValue: mockedToasterService } + { provide: ToasterService, useValue: mockedToasterService }, + { provide: Router, useValue: mockedRouter } ], declarations: [ProjectMapComponent, ProjectMapMenuComponent, D3MapComponent, ...ANGULAR_MAP_DECLARATIONS], schemas: [NO_ERRORS_SCHEMA] From c0ef682e9c82d2cafa358f54513cddc27ce8fd6d Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 9 Aug 2019 06:32:58 -0700 Subject: [PATCH 017/146] Duplicate action added --- src/app/components/projects/projects.component.html | 3 +++ src/app/components/projects/projects.component.ts | 6 ++++++ src/app/services/project.service.spec.ts | 7 +++++++ src/app/services/project.service.ts | 4 ++++ 4 files changed, 20 insertions(+) diff --git a/src/app/components/projects/projects.component.html b/src/app/components/projects/projects.component.html index 7f785447..107c070b 100644 --- a/src/app/components/projects/projects.component.html +++ b/src/app/components/projects/projects.component.html @@ -40,6 +40,9 @@ + diff --git a/src/app/components/projects/projects.component.ts b/src/app/components/projects/projects.component.ts index ab50f90f..1c7fa38a 100644 --- a/src/app/components/projects/projects.component.ts +++ b/src/app/components/projects/projects.component.ts @@ -107,6 +107,12 @@ export class ProjectsComponent implements OnInit { ); } + duplicate(project: Project) { + this.projectService.duplicate(this.server, project.project_id, project.name).subscribe(() => { + this.refresh(); + }); + } + addBlankProject() { const dialogRef = this.dialog.open(AddBlankProjectDialogComponent, { width: '400px', diff --git a/src/app/services/project.service.spec.ts b/src/app/services/project.service.spec.ts index 2752923a..0bad72bc 100644 --- a/src/app/services/project.service.spec.ts +++ b/src/app/services/project.service.spec.ts @@ -132,6 +132,13 @@ describe('ProjectService', () => { expect(req.request.method).toEqual('DELETE'); }); + it('should duplicate the project', () => { + service.duplicate(server, 'projectId', 'projectName').subscribe(); + + const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/projects/projectId/duplicate'); + expect(req.request.method).toEqual('POST'); + }); + it('should get notifications path of project', () => { const path = service.notificationsPath(server, 'myproject'); expect(path).toEqual('ws://127.0.0.1:3080/v2/projects/myproject/notifications/ws'); diff --git a/src/app/services/project.service.ts b/src/app/services/project.service.ts index 4ca87f98..181e26c5 100644 --- a/src/app/services/project.service.ts +++ b/src/app/services/project.service.ts @@ -49,6 +49,10 @@ export class ProjectService { return this.httpServer.delete(server, `/projects/${project_id}`); } + duplicate(server: Server, project_id: string, project_name): Observable { + return this.httpServer.post(server, `/projects/${project_id}/duplicate`, { name: project_name }); + } + notificationsPath(server: Server, project_id: string): string { return `ws://${server.host}:${server.port}/v2/projects/${project_id}/notifications/ws`; } From cd5890ca2bf9954cfcbafd86ff761dbf876bb3f7 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 9 Aug 2019 07:43:22 -0700 Subject: [PATCH 018/146] Save as button added --- src/app/app.module.ts | 7 +- .../project-map/project-map.component.ts | 9 ++- .../save-project-dialog.component.css | 7 ++ .../save-project-dialog.component.html | 23 ++++++ .../save-project-dialog.component.ts | 77 +++++++++++++++++++ 5 files changed, 120 insertions(+), 3 deletions(-) create mode 100644 src/app/components/projects/save-project-dialog/save-project-dialog.component.css diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4242bce2..c2ea1386 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 { SaveProjectDialogComponent } from './components/projects/save-project-dialog/save-project-dialog.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -312,7 +313,8 @@ if (environment.production) { ConsoleComponent, NodesMenuComponent, ProjectMapMenuComponent, - HelpComponent + HelpComponent, + SaveProjectDialogComponent ], imports: [ BrowserModule, @@ -404,7 +406,8 @@ if (environment.production) { SymbolsComponent, DeleteConfirmationDialogComponent, HelpDialogComponent, - StartCaptureDialogComponent + StartCaptureDialogComponent, + SaveProjectDialogComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 424bb105..b4bc7371 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -54,6 +54,7 @@ import { ToasterService } from '../../services/toaster.service'; import { ImportProjectDialogComponent } from '../projects/import-project-dialog/import-project-dialog.component'; import { MatDialog } from '@angular/material'; import { AddBlankProjectDialogComponent } from '../projects/add-blank-project-dialog/add-blank-project-dialog.component'; +import { SaveProjectDialogComponent } from '../projects/save-project-dialog/save-project-dialog.component'; @Component({ @@ -402,7 +403,13 @@ export class ProjectMapComponent implements OnInit, OnDestroy { } saveProject() { - + const dialogRef = this.dialog.open(SaveProjectDialogComponent, { + width: '400px', + autoFocus: false + }); + let instance = dialogRef.componentInstance; + instance.server = this.server; + instance.project = this.project; } importProject() { diff --git a/src/app/components/projects/save-project-dialog/save-project-dialog.component.css b/src/app/components/projects/save-project-dialog/save-project-dialog.component.css new file mode 100644 index 00000000..acf081db --- /dev/null +++ b/src/app/components/projects/save-project-dialog/save-project-dialog.component.css @@ -0,0 +1,7 @@ +.file-name-form-field { + width: 100%; +} + +.project-snackbar { + background: #2196F3; +} diff --git a/src/app/components/projects/save-project-dialog/save-project-dialog.component.html b/src/app/components/projects/save-project-dialog/save-project-dialog.component.html index e69de29b..c772cb96 100644 --- a/src/app/components/projects/save-project-dialog/save-project-dialog.component.html +++ b/src/app/components/projects/save-project-dialog/save-project-dialog.component.html @@ -0,0 +1,23 @@ +

Save project as

+
+ + + Project name is required + Project name is incorrect + +
+ + +
+
diff --git a/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts b/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts index e69de29b..afb76ec0 100644 --- a/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts +++ b/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts @@ -0,0 +1,77 @@ +import { Component, OnInit, EventEmitter } from '@angular/core'; +import { Router } from '@angular/router'; +import { MatDialog, MatDialogRef } from '@angular/material'; +import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; +import { Project } from '../../../models/project'; +import { Server } from '../../../models/server'; +import { ProjectService } from '../../../services/project.service'; +import { v4 as uuid } from 'uuid'; +import { ProjectNameValidator } from '../models/projectNameValidator'; +import { ToasterService } from '../../../services/toaster.service'; + + +@Component({ + selector: 'app-save-project-dialog', + templateUrl: './save-project-dialog.component.html', + styleUrls: ['./save-project-dialog.component.css'], + providers: [ProjectNameValidator] +}) +export class SaveProjectDialogComponent implements OnInit { + server: Server; + project: Project; + projectNameForm: FormGroup; + onAddProject = new EventEmitter(); + + constructor( + public dialogRef: MatDialogRef, + private router: Router, + private dialog: MatDialog, + private projectService: ProjectService, + private toasterService: ToasterService, + private formBuilder: FormBuilder, + private projectNameValidator: ProjectNameValidator + ) { + this.projectNameForm = this.formBuilder.group({ + projectName: new FormControl(null, [Validators.required, projectNameValidator.get]) + }); + } + + ngOnInit() {} + + get form() { + return this.projectNameForm.controls; + } + + onAddClick(): void { + if (this.projectNameForm.invalid) { + return; + } + this.projectService.list(this.server).subscribe((projects: Project[]) => { + const projectName = this.projectNameForm.controls['projectName'].value; + let existingProject = projects.find(project => project.name === projectName); + + if (existingProject) { + this.toasterService.success(`Project with this name already exists.`); + } else { + this.addProject(); + } + }); + } + + onNoClick(): void { + this.dialogRef.close(); + } + + addProject(): void { + this.projectService.duplicate(this.server, this.project.project_id, this.projectNameForm.controls['projectName'].value).subscribe((project: Project) => { + this.dialogRef.close(); + this.toasterService.success(`Project ${project.name} added`); + }); + } + + onKeyDown(event) { + if (event.key === "Enter") { + this.onAddClick(); + } + } +} From 1abcad72d2cce8ff4c919aab471e69fa2d757a69 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 12 Aug 2019 01:58:10 -0700 Subject: [PATCH 019/146] Update project-map.component.ts --- src/app/components/project-map/project-map.component.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index b4bc7371..bedbfde5 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -433,7 +433,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy { } exportProject() { - window.location.href = `http://${this.server.host}:${this.server.port}/v2/projects/${this.project.project_id}/export`; + if (this.nodes.filter(node => node.node_type = 'virtualbox').length > 0) { + this.toasterService.error('Map with VirtualBox machines cannot be exported.') + } else { + window.location.href = `http://${this.server.host}:${this.server.port}/v2/projects/${this.project.project_id}/export`; + } } public uploadImageFile(event) { From 528842b713091e08724fafa526b3fb2f1c227f52 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 12 Aug 2019 04:05:04 -0700 Subject: [PATCH 020/146] Action created --- src/app/app.module.ts | 4 +- .../bring-to-front-action.component.html | 4 ++ .../bring-to-front-action.component.spec.ts | 0 .../bring-to-front-action.component.ts | 43 +++++++++++++++++++ .../context-menu/context-menu.component.html | 6 +++ 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts create mode 100644 src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4242bce2..cbe37e82 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 { BringToFrontActionComponent } from './components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -312,7 +313,8 @@ if (environment.production) { ConsoleComponent, NodesMenuComponent, ProjectMapMenuComponent, - HelpComponent + HelpComponent, + BringToFrontActionComponent ], imports: [ BrowserModule, diff --git a/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.html b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.html new file mode 100644 index 00000000..2a3518ab --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.ts b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.ts new file mode 100644 index 00000000..b72848fb --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.ts @@ -0,0 +1,43 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { Server } from '../../../../../models/server'; +import { Node } from '../../../../../cartography/models/node'; +import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; +import { NodeService } from '../../../../../services/node.service'; +import { Drawing } from '../../../../../cartography/models/drawing'; +import { DrawingsDataSource } from '../../../../../cartography/datasources/drawings-datasource'; +import { DrawingService } from '../../../../../services/drawing.service'; + +@Component({ + selector: 'app-bring-to-front-action', + templateUrl: './bring-to-front-action.component.html' +}) +export class BringToFrontActionComponent implements OnInit { + @Input() server: Server; + @Input() nodes: Node[]; + @Input() drawings: Drawing[]; + + constructor( + private nodesDataSource: NodesDataSource, + private drawingsDataSource: DrawingsDataSource, + private nodeService: NodeService, + private drawingService: DrawingService + ) {} + + ngOnInit() {} + + bringToFront() { + this.nodes.forEach((node) => { + node.z = 100; + this.nodesDataSource.update(node); + + this.nodeService.update(this.server, node).subscribe((node: Node) => {}); + }); + + this.drawings.forEach((drawing) => { + drawing.z = 100; + this.drawingsDataSource.update(drawing); + + this.drawingService.update(this.server, drawing).subscribe((drawing: Drawing) => {}); + }); + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index 2ebfeb6a..1824f2ad 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -44,6 +44,12 @@ [nodes]="nodes" [drawings]="drawings" > + Date: Mon, 12 Aug 2019 05:40:40 -0700 Subject: [PATCH 021/146] Unit tests added --- .../bring-to-front-action.component.spec.ts | 66 +++++++++++++++++++ .../project-map/project-map.component.spec.ts | 4 ++ 2 files changed, 70 insertions(+) diff --git a/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts index e69de29b..74a264f5 100644 --- a/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component.spec.ts @@ -0,0 +1,66 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { BringToFrontActionComponent } from './bring-to-front-action.component'; +import { MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule } from '@angular/material'; +import { CommonModule } from '@angular/common'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { MockedDrawingService, MockedDrawingsDataSource, MockedNodesDataSource, MockedNodeService } from '../../../project-map.component.spec'; +import { DrawingService } from '../../../../../services/drawing.service'; +import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; +import { DrawingsDataSource } from '../../../../../cartography/datasources/drawings-datasource'; +import { NodeService } from '../../../../../services/node.service'; +import { Node } from '../../../../../cartography/models/node'; +import { of } from 'rxjs'; +import { ComponentFactoryResolver } from '@angular/core'; +import { Drawing } from '../../../../../cartography/models/drawing'; + +describe('BringToFrontActionComponent', () => { + let component: BringToFrontActionComponent; + let fixture: ComponentFixture; + let drawingService = new MockedDrawingService(); + let drawingsDataSource = new MockedDrawingsDataSource(); + let nodeService = new MockedNodeService(); + let nodesDataSource = new MockedNodesDataSource(); + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MatIconModule, MatToolbarModule, MatMenuModule, MatCheckboxModule, CommonModule, NoopAnimationsModule], + providers: [ + { provide: DrawingService, useValue: drawingService }, + { provide: DrawingsDataSource, useValue: drawingsDataSource }, + { provide: NodeService, useValue: nodeService }, + { provide: NodesDataSource, useValue: nodesDataSource }, + ], + declarations: [BringToFrontActionComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(BringToFrontActionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should call node service when bring to front action called', () => { + spyOn(nodeService, 'update').and.returnValue(of()); + component.nodes = [{z: 0} as Node]; + component.drawings = []; + + component.bringToFront(); + + expect(nodeService.update).toHaveBeenCalled(); + }); + + it('should call drawing service when bring to front action called', () => { + spyOn(drawingService, 'update').and.returnValue(of()); + component.nodes = []; + component.drawings = [{z: 0} as Drawing]; + + component.bringToFront(); + + expect(drawingService.update).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..5d926762 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -94,6 +94,10 @@ export class MockedNodeService { duplicate(server: Server, node: Node) { return of(node); } + + update(server: Server, node: Node) { + return of(node); + } } export class MockedDrawingService { From 85817535207c30c81ffaac5384c696008cb1a780 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 12 Aug 2019 08:46:15 -0700 Subject: [PATCH 022/146] Initial implementation of topology summary --- .../topology-summary.component.html | 0 .../topology-summary.component.scss | 0 .../topology-summary.component.spec.ts | 0 .../topology-summary.component.ts | 47 +++++++++++++++++++ src/app/models/project-statistics.ts | 6 +++ src/app/services/project.service.ts | 4 ++ 6 files changed, 57 insertions(+) create mode 100644 src/app/components/topology-summary/topology-summary.component.html create mode 100644 src/app/components/topology-summary/topology-summary.component.scss create mode 100644 src/app/components/topology-summary/topology-summary.component.spec.ts create mode 100644 src/app/components/topology-summary/topology-summary.component.ts create mode 100644 src/app/models/project-statistics.ts diff --git a/src/app/components/topology-summary/topology-summary.component.html b/src/app/components/topology-summary/topology-summary.component.html new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/topology-summary/topology-summary.component.scss b/src/app/components/topology-summary/topology-summary.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/topology-summary/topology-summary.component.spec.ts b/src/app/components/topology-summary/topology-summary.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/topology-summary/topology-summary.component.ts b/src/app/components/topology-summary/topology-summary.component.ts new file mode 100644 index 00000000..e62673f8 --- /dev/null +++ b/src/app/components/topology-summary/topology-summary.component.ts @@ -0,0 +1,47 @@ +import { Component, OnInit, OnDestroy, Input } from '@angular/core'; +import { Project } from '../../models/project'; +import { Server } from '../../models/server'; +import { NodesDataSource } from '../../cartography/datasources/nodes-datasource'; +import { NodeService } from '../../services/node.service'; +import { Node } from '../../cartography/models/node'; +import { Subscription } from 'rxjs'; +import { ProjectService } from '../../services/project.service'; +import { ProjectStatistics } from '../../models/project-statistics'; + + +@Component({ + selector: 'app-topology-summary', + templateUrl: './topology-summary.component.html', + styleUrls: ['./topology-summary.component.scss'] +}) +export class TopologySummaryComponent implements OnInit, OnDestroy { + @Input() project: Project; + @Input() server: Server; + + private subscriptions: Subscription[]; + projectsStatistics: ProjectStatistics; + nodes: Node[] = []; + + //filters to introduce -> should be generic + + constructor( + private nodesDataSource: NodesDataSource, + private projectService: ProjectService + ) {} + + ngOnInit() { + this.subscriptions.push( + this.nodesDataSource.changes.subscribe((nodes: Node[]) => { + this.nodes = nodes; + }) + ); + + this.projectService.getStatistics(this.server, this.project.project_id).subscribe((stats: ProjectStatistics) => { + this.projectsStatistics = stats; + }); + } + + ngOnDestroy() { + this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe()); + } +} diff --git a/src/app/models/project-statistics.ts b/src/app/models/project-statistics.ts new file mode 100644 index 00000000..c26566ce --- /dev/null +++ b/src/app/models/project-statistics.ts @@ -0,0 +1,6 @@ +export class ProjectStatistics { + drawings: number; + links: number; + nodes: number; + snapshots: number +} diff --git a/src/app/services/project.service.ts b/src/app/services/project.service.ts index 4ca87f98..637dd624 100644 --- a/src/app/services/project.service.ts +++ b/src/app/services/project.service.ts @@ -49,6 +49,10 @@ export class ProjectService { return this.httpServer.delete(server, `/projects/${project_id}`); } + getStatistics(server: Server, project_id: string) { + return this.httpServer.get(server, `/projects/${project_id}/stats`); + } + notificationsPath(server: Server, project_id: string): string { return `ws://${server.host}:${server.port}/v2/projects/${project_id}/notifications/ws`; } From 909e197b9aa795e03ba63d1d026ea6ed4f875d02 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 14 Aug 2019 06:10:41 -0700 Subject: [PATCH 023/146] Filters added --- src/app/app.module.ts | 4 +- .../project-map/project-map.component.html | 1 + .../topology-summary.component.html | 53 +++++++++++++++ .../topology-summary.component.scss | 67 +++++++++++++++++++ .../topology-summary.component.ts | 61 +++++++++++++++-- src/app/services/project.service.ts | 2 +- 6 files changed, 179 insertions(+), 9 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4242bce2..852ee1cc 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 { TopologySummaryComponent } from './components/topology-summary/topology-summary.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -312,7 +313,8 @@ if (environment.production) { ConsoleComponent, NodesMenuComponent, ProjectMapMenuComponent, - HelpComponent + HelpComponent, + TopologySummaryComponent ], imports: [ BrowserModule, diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 42cbcd30..b0f64d5e 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/components/topology-summary/topology-summary.component.html b/src/app/components/topology-summary/topology-summary.component.html index e69de29b..f4ee0470 100644 --- a/src/app/components/topology-summary/topology-summary.component.html +++ b/src/app/components/topology-summary/topology-summary.component.html @@ -0,0 +1,53 @@ +
+
+ Topology summary ({{projectsStatistics.snapshots}} snapshots) + close +
+ +
+ Filters
+ Running state +
+
+ Sorting
+
+ + By name ascending
+ By name descending +
+
+
+ +
+
+
+ + + + + + + {{node.name}} +
+
+ {{node.console_type}} {{node.console_host}}:{{node.console}} +
+
+ +
+
diff --git a/src/app/components/topology-summary/topology-summary.component.scss b/src/app/components/topology-summary/topology-summary.component.scss index e69de29b..9840d4bc 100644 --- a/src/app/components/topology-summary/topology-summary.component.scss +++ b/src/app/components/topology-summary/topology-summary.component.scss @@ -0,0 +1,67 @@ +.summaryWrapper { + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); + position: fixed; + top: 20px; + right: 20px; + height: 400px; + width: 300px; + background: #263238; + color: white; + overflow: hidden; + font-size: 12px; +} + +.summaryHeaderMenu { + height: 24px; +} + +.summaryHeader { + width: 100%; + height: 24px; + display: flex; + justify-content: space-between; + margin-right: 5px; +} + +.summaryFilters { + margin-left: 5px; + margin-right: 5px; +} + +.summarySorting { + margin-left: 5px; + margin-right: 5px; +} + +.summaryContent { + margin-left: 5px; + margin-right: 5px; +} + +.title { + margin-left: 5px; + margin-top: 4px; +} + +.divider { + margin: 5px; + width: 290px; + height: 2px; +} + +.nodeRow { + width: 100%; + display: flex; + justify-content: space-between; +} + +mat-icon { + font-size: 18px; + width: 20px; + height: 20px; + margin-top: 4px; +} + +.radio-group { + margin-top: 5px; +} diff --git a/src/app/components/topology-summary/topology-summary.component.ts b/src/app/components/topology-summary/topology-summary.component.ts index e62673f8..bec42d2c 100644 --- a/src/app/components/topology-summary/topology-summary.component.ts +++ b/src/app/components/topology-summary/topology-summary.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, Input } from '@angular/core'; +import { Component, OnInit, OnDestroy, Input, AfterViewInit } from '@angular/core'; import { Project } from '../../models/project'; import { Server } from '../../models/server'; import { NodesDataSource } from '../../cartography/datasources/nodes-datasource'; @@ -15,33 +15,80 @@ import { ProjectStatistics } from '../../models/project-statistics'; styleUrls: ['./topology-summary.component.scss'] }) export class TopologySummaryComponent implements OnInit, OnDestroy { - @Input() project: Project; @Input() server: Server; + @Input() project: Project; - private subscriptions: Subscription[]; + private subscriptions: Subscription[] = []; projectsStatistics: ProjectStatistics; nodes: Node[] = []; - - //filters to introduce -> should be generic + filteredNodes: Node[] = []; + dataSource: Node[] = []; + displayedColumns: string[] = ['name', 'console']; + sortingOrder: string = 'asc'; + statusFilterEnabled: boolean = false; constructor( private nodesDataSource: NodesDataSource, - private projectService: ProjectService + private projectService: ProjectService, + private nodeService: NodeService ) {} ngOnInit() { this.subscriptions.push( this.nodesDataSource.changes.subscribe((nodes: Node[]) => { this.nodes = nodes; + if (this.sortingOrder === 'asc') { + this.filteredNodes = nodes.sort(this.compareAsc); + } else { + this.filteredNodes = nodes.sort(this.compareDesc); + } }) ); - this.projectService.getStatistics(this.server, this.project.project_id).subscribe((stats: ProjectStatistics) => { + this.projectService.getStatistics(this.server, this.project.project_id).subscribe((stats) => { this.projectsStatistics = stats; }); } + compareAsc(first: Node, second: Node) { + if (first.name < second.name) return -1; + return 1; + } + + compareDesc(first: Node, second: Node) { + if (first.name < second.name) return 1; + return -1; + } + ngOnDestroy() { this.subscriptions.forEach((subscription: Subscription) => subscription.unsubscribe()); } + + setSortingOrder(order: string) { + this.sortingOrder = order; + if (this.sortingOrder === 'asc') { + this.filteredNodes = this.filteredNodes.sort(this.compareAsc); + } else { + this.filteredNodes = this.filteredNodes.sort(this.compareDesc); + } + } + + applyStatusFilter(value: boolean) { + this.statusFilterEnabled = value; + this.applyFilters(); + } + + applyFilters() { + var nodes = this.nodes; + + if (this.statusFilterEnabled) { + nodes = nodes.filter(n => n.status === 'started'); + } + + if (this.sortingOrder === 'asc') { + this.filteredNodes = nodes.sort(this.compareAsc); + } else { + this.filteredNodes = nodes.sort(this.compareDesc); + } + } } diff --git a/src/app/services/project.service.ts b/src/app/services/project.service.ts index 637dd624..403cf9b0 100644 --- a/src/app/services/project.service.ts +++ b/src/app/services/project.service.ts @@ -49,7 +49,7 @@ export class ProjectService { return this.httpServer.delete(server, `/projects/${project_id}`); } - getStatistics(server: Server, project_id: string) { + getStatistics(server: Server, project_id: string): Observable { return this.httpServer.get(server, `/projects/${project_id}/stats`); } From 51ef91f8d36de186e605f614a59de38b368d859d Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 19 Aug 2019 00:59:04 -0700 Subject: [PATCH 024/146] Update topology summary component --- .../components/project-map/project-map.component.html | 9 +++++++-- .../components/project-map/project-map.component.scss | 4 ++++ src/app/components/project-map/project-map.component.ts | 5 +++++ .../topology-summary/topology-summary.component.html | 2 +- .../topology-summary/topology-summary.component.scss | 4 ++++ .../topology-summary/topology-summary.component.ts | 8 +++++++- 6 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index b0f64d5e..241abc4b 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 topology summary +
@@ -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..20f6f1f3 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 isTopologySummaryVisible: boolean = false; tools = { selection: true, @@ -362,6 +363,10 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.project.show_interface_labels = enabled; } + public toggleShowTopologySummary(visible: boolean) { + this.isTopologySummaryVisible = visible; + } + public hideMenu() { this.projectMapMenuComponent.resetDrawToolChoice() this.isProjectMapMenuVisible = false; diff --git a/src/app/components/topology-summary/topology-summary.component.html b/src/app/components/topology-summary/topology-summary.component.html index f4ee0470..f08c0dd6 100644 --- a/src/app/components/topology-summary/topology-summary.component.html +++ b/src/app/components/topology-summary/topology-summary.component.html @@ -1,7 +1,7 @@
Topology summary ({{projectsStatistics.snapshots}} snapshots) - close + close
diff --git a/src/app/components/topology-summary/topology-summary.component.scss b/src/app/components/topology-summary/topology-summary.component.scss index 9840d4bc..63e25338 100644 --- a/src/app/components/topology-summary/topology-summary.component.scss +++ b/src/app/components/topology-summary/topology-summary.component.scss @@ -65,3 +65,7 @@ mat-icon { .radio-group { margin-top: 5px; } + +.closeButton { + cursor: pointer; +} diff --git a/src/app/components/topology-summary/topology-summary.component.ts b/src/app/components/topology-summary/topology-summary.component.ts index bec42d2c..f758af53 100644 --- a/src/app/components/topology-summary/topology-summary.component.ts +++ b/src/app/components/topology-summary/topology-summary.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, Input, AfterViewInit } from '@angular/core'; +import { Component, OnInit, OnDestroy, Input, AfterViewInit, Output, EventEmitter } from '@angular/core'; import { Project } from '../../models/project'; import { Server } from '../../models/server'; import { NodesDataSource } from '../../cartography/datasources/nodes-datasource'; @@ -18,6 +18,8 @@ export class TopologySummaryComponent implements OnInit, OnDestroy { @Input() server: Server; @Input() project: Project; + @Output() closeTopologySummary = new EventEmitter(); + private subscriptions: Subscription[] = []; projectsStatistics: ProjectStatistics; nodes: Node[] = []; @@ -91,4 +93,8 @@ export class TopologySummaryComponent implements OnInit, OnDestroy { this.filteredNodes = nodes.sort(this.compareDesc); } } + + close() { + this.closeTopologySummary.emit(false); + } } From 3da59f20e09e74a44f8cdba1fad148c2de922456 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 19 Aug 2019 01:34:29 -0700 Subject: [PATCH 025/146] 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 0524099dce0c760ba5c884a0568cc095829f31f6 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 20 Aug 2019 04:44:14 -0700 Subject: [PATCH 026/146] Update info-dialog-component --- .../project-map/info-dialog/info-dialog.component.html | 2 +- src/app/services/info.service.ts | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/app/components/project-map/info-dialog/info-dialog.component.html b/src/app/components/project-map/info-dialog/info-dialog.component.html index 96a2234a..d178a63e 100644 --- a/src/app/components/project-map/info-dialog/info-dialog.component.html +++ b/src/app/components/project-map/info-dialog/info-dialog.component.html @@ -14,7 +14,7 @@ Please start the node in order to get the command line information.
- {{command_line}} + {{commandLine}}
diff --git a/src/app/services/info.service.ts b/src/app/services/info.service.ts index 0e722927..ed3860f4 100644 --- a/src/app/services/info.service.ts +++ b/src/app/services/info.service.ts @@ -56,7 +56,15 @@ export class InfoService { } getCommandLine(node: Node): string { - if (node.node_type === 'cloud' || "nat" || "ethernet_hub" || "ethernet_switch" || "frame_relay_switch" || "atm_switch" || "dynamips" || "traceng" || "iou") { + if (node.node_type === "cloud" || + node.node_type === "nat" || + node.node_type === "ethernet_hub" || + node.node_type === "ethernet_switch" || + node.node_type === "frame_relay_switch" || + node.node_type === "atm_switch" || + node.node_type === "dynamips" || + node.node_type === "traceng" || + node.node_type === "iou") { return 'Command line information is not supported for this type of node.'; } else { if (node.status === 'started') { From 8163b4d70961c4fcad7cd53daf335b7ac7264f17 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 20 Aug 2019 05:49:54 -0700 Subject: [PATCH 027/146] Unit tests added --- .../projects/projects.component.html | 2 +- .../projects/projects.component.spec.ts | 22 +++++++++++++++++++ src/app/services/project.service.spec.ts | 4 ++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/app/components/projects/projects.component.html b/src/app/components/projects/projects.component.html index 107c070b..90d28c2e 100644 --- a/src/app/components/projects/projects.component.html +++ b/src/app/components/projects/projects.component.html @@ -40,7 +40,7 @@ -
- Filters
- Running state + Filter by status
+
+ Started + Suspended + Stopped +
Sorting
@@ -29,9 +33,12 @@ {{node.name}}
-
+
{{node.console_type}} {{node.console_host}}:{{node.console}}
+
+ none +
diff --git a/src/app/components/topology-summary/topology-summary.component.scss b/src/app/components/topology-summary/topology-summary.component.scss index f51f82ab..a9629c20 100644 --- a/src/app/components/topology-summary/topology-summary.component.scss +++ b/src/app/components/topology-summary/topology-summary.component.scss @@ -36,7 +36,7 @@ .summaryContent { margin-left: 5px; margin-right: 5px; - max-height: 220px; + max-height: 240px; overflow: auto; scrollbar-color: darkgrey #263238; scrollbar-width: thin; @@ -80,10 +80,15 @@ mat-icon { outline: 1px solid #263238; } -.radio-group { +.radio-group-wrapper { margin-top: 5px; } +.radio-group { + display: flex; + justify-content: space-between; +} + .closeButton { cursor: pointer; } diff --git a/src/app/components/topology-summary/topology-summary.component.spec.ts b/src/app/components/topology-summary/topology-summary.component.spec.ts index 2119197d..3cbffe52 100644 --- a/src/app/components/topology-summary/topology-summary.component.spec.ts +++ b/src/app/components/topology-summary/topology-summary.component.spec.ts @@ -13,7 +13,7 @@ import { Project } from '../../models/project'; import { Node } from '../../cartography/models/node'; -fdescribe('TopologySummaryComponent', () => { +describe('TopologySummaryComponent', () => { let component: TopologySummaryComponent; let fixture: ComponentFixture; let mockedProjectService: MockedProjectService = new MockedProjectService(); diff --git a/src/app/components/topology-summary/topology-summary.component.ts b/src/app/components/topology-summary/topology-summary.component.ts index 0170312c..a53402e1 100644 --- a/src/app/components/topology-summary/topology-summary.component.ts +++ b/src/app/components/topology-summary/topology-summary.component.ts @@ -23,8 +23,6 @@ export class TopologySummaryComponent implements OnInit, OnDestroy { projectsStatistics: ProjectStatistics; nodes: Node[] = []; filteredNodes: Node[] = []; - dataSource: Node[] = []; - displayedColumns: string[] = ['name', 'console']; sortingOrder: string = 'asc'; startedStatusFilterEnabled: boolean = false; suspendedStatusFilterEnabled: boolean = false; diff --git a/src/app/services/mapsettings.service.ts b/src/app/services/mapsettings.service.ts index 640c5671..caf4a6c8 100644 --- a/src/app/services/mapsettings.service.ts +++ b/src/app/services/mapsettings.service.ts @@ -2,12 +2,17 @@ import { Injectable } from "@angular/core"; import { Subject } from 'rxjs'; @Injectable() -export class MapSettingService { +export class MapSettingsService { public isMapLocked = new Subject(); + public isTopologySummaryVisible: boolean = false; constructor() {} changeMapLockValue(value: boolean) { this.isMapLocked.next(value); } + + toggleTopologySummary(value: boolean) { + this.isTopologySummaryVisible = value; + } } From 8ad744213be25f3c62749f3bbaceb6e4c007aed1 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 22 Aug 2019 00:32:28 -0700 Subject: [PATCH 033/146] Review fixes --- src/app/components/project-map/project-map.component.ts | 7 +++++-- .../import-project-dialog.component.ts | 2 +- src/app/services/project.service.ts | 8 ++++++++ 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 766e7c50..409a612b 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -475,10 +475,13 @@ export class ProjectMapComponent implements OnInit, OnDestroy { exportProject() { if (this.nodes.filter(node => node.node_type === 'virtualbox').length > 0) { this.toasterService.error('Map with VirtualBox machines cannot be exported.') - } else if (this.nodes.filter(node => node.status === 'started').length > 0) { + } else if (this.nodes.filter(node => + (node.status === 'started' && node.node_type==='vpcs') || + (node.status === 'started' && node.node_type==='virtualbox') || + (node.status === 'started' && node.node_type==='vmware')).length > 0) { this.toasterService.error('Project with running nodes cannot be exported.') } else { - window.location.href = `http://${this.server.host}:${this.server.port}/v2/projects/${this.project.project_id}/export`; + location.assign(this.projectService.getExportPath(this.server, this.project)); } } diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts index bcb54385..1c1e8195 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.ts @@ -143,6 +143,6 @@ export class ImportProjectDialogComponent implements OnInit { prepareUploadPath(): string { this.uuid = uuid(); const projectName = this.projectNameForm.controls['projectName'].value; - return `http://${this.server.host}:${this.server.port}/v2/projects/${this.uuid}/import?name=${projectName}`; + return this.projectService.getUploadPath(this.server, uuid, projectName); } } diff --git a/src/app/services/project.service.ts b/src/app/services/project.service.ts index 4eee73a7..193722d6 100644 --- a/src/app/services/project.service.ts +++ b/src/app/services/project.service.ts @@ -49,6 +49,14 @@ export class ProjectService { return this.httpServer.delete(server, `/projects/${project_id}`); } + getUploadPath(server: Server, uuid: string, project_name: string) { + return `http://${server.host}:${server.port}/v2/projects/${uuid}/import?name=${project_name}`; + } + + getExportPath(server: Server, project: Project) { + return `http://${server.host}:${server.port}/v2/projects/${project.project_id}/export`; + } + export(server: Server, project_id: string): Observable { return this.httpServer.get(server, `/projects/${project_id}/export`) } From 44c924b654322616103653a455aa6217457a893e Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 22 Aug 2019 01:50:58 -0700 Subject: [PATCH 034/146] Update import-project-dialog.component.spec.ts --- .../import-project-dialog.component.spec.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts index bef5f1b9..dff8b671 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts @@ -46,6 +46,14 @@ export class MockedProjectService { list() { return of(this.projects); } + + getUploadPath(server: Server, uuid: string, project_name: string) { + return `http://${server.host}:${server.port}/v2/projects/${uuid}/import?name=${project_name}`; + } + + getExportPath(server: Server, project: Project) { + return `http://${server.host}:${server.port}/v2/projects/${project.project_id}/export`; + } } describe('ImportProjectDialogComponent', () => { From fee26eff87c6b0c322256b30f636f11c68e883df Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 22 Aug 2019 05:26:48 -0700 Subject: [PATCH 035/146] 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 036/146] 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 037/146] 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 038/146] 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 c2d40943ee0073ca239375be48491fcce88b6c07 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 28 Aug 2019 01:08:37 -0700 Subject: [PATCH 039/146] Test implementation --- package.json | 1 + .../project-map-menu.component.html | 8 + .../project-map-menu.component.ts | 266 +++++++++++++++++- .../project-map/project-map.component.scss | 2 +- .../project-map/project-map.component.ts | 1 + yarn.lock | 5 + 6 files changed, 281 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ff4897de..e6bdce04 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "raven-js": "^3.27.2", "rxjs": "^6.5.2", "rxjs-compat": "^6.5.2", + "save-svg-as-png": "^1.4.14", "tree-kill": "^1.2.1", "typeface-roboto": "^0.0.75", "yargs": "^13.3.0", diff --git a/src/app/components/project-map/project-map-menu/project-map-menu.component.html b/src/app/components/project-map/project-map-menu/project-map-menu.component.html index b0b20e55..5a91ddb2 100644 --- a/src/app/components/project-map/project-map-menu/project-map-menu.component.html +++ b/src/app/components/project-map/project-map-menu/project-map-menu.component.html @@ -57,6 +57,14 @@ (click)="changeLockValue()"> lock + { + let splittedElement = elem.split('-->'); + splittedSvg[i] = splittedElement[1]; + + test = splittedElement[1]; + console.log(test); + }); + + i += 2; + } + let svgString = splittedSvg.join(); + svgString = test; + + // var parser = new DOMParser(); + // var doc = parser.parseFromString(document.getElementsByTagName("svg")[0].outerHTML, "text/html"); + + var placeholder = document.createElement('div'); + placeholder.innerHTML = ` + + + + + image/svg+xml + + Switch + + + Jeremy Grossmann + + + + + GNS-3 + + + Created for the GNS-3 project (www.gns3.net) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + `; + var element = placeholder.firstChild; + svg.saveSvgAsPng(element, "plot.png"); + } + public addDrawing(selectedObject: string) { switch (selectedObject) { case 'rectangle': diff --git a/src/app/components/project-map/project-map.component.scss b/src/app/components/project-map/project-map.component.scss index 553b5a13..0149c433 100644 --- a/src/app/components/project-map/project-map.component.scss +++ b/src/app/components/project-map/project-map.component.scss @@ -80,7 +80,7 @@ g.node:hover { } .extended { - width: 700px !important; + width: 770px !important; height: 100%; overflow: hidden; } diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index 409a612b..34f6bbeb 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -43,6 +43,7 @@ import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProje import { MapLink } from '../../cartography/models/map/map-link'; import { MapLinkToLinkConverter } from '../../cartography/converters/map/map-link-to-link-converter'; import { MovingEventSource } from '../../cartography/events/moving-event-source'; +import { log } from 'util'; import { LinkWidget } from '../../cartography/widgets/link'; import { MapScaleService } from '../../services/mapScale.service'; import { NodeCreatedLabelStylesFixer } from './helpers/node-created-label-styles-fixer'; diff --git a/yarn.lock b/yarn.lock index 0d799b27..0860440e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7351,6 +7351,11 @@ saucelabs@^1.5.0: dependencies: https-proxy-agent "^2.2.1" +save-svg-as-png@^1.4.14: + version "1.4.14" + resolved "https://registry.npmjs.org/save-svg-as-png/-/save-svg-as-png-1.4.14.tgz#d5017bb9746adf00c146a17e63ed4badd1e10b40" + integrity sha512-hJqOFSdRvhBVD2pQSM+mJStvQGfnvQCCF6ULtAxdjF4lDwXYfWZ9Eug0fcRl05YyPL2yknCDBEOpbO4Fkw5qmg== + sax@0.5.x: version "0.5.8" resolved "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz#d472db228eb331c2506b0e8c15524adb939d12c1" From 26bc2df064d21a19f6ea4bd592459d725e199e1c Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 28 Aug 2019 02:03:17 -0700 Subject: [PATCH 040/146] Update project-map-menu.component.ts --- .../project-map-menu.component.ts | 252 +----------------- 1 file changed, 10 insertions(+), 242 deletions(-) diff --git a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts index bb2fdeae..3cdeb283 100644 --- a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts +++ b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts @@ -8,6 +8,7 @@ import { SymbolsDataSource } from '../../../cartography/datasources/symbols-data import * as svg from 'save-svg-as-png'; import { MapSymbolsDataSource } from '../../../cartography/datasources/map-datasource'; import { SymbolService } from '../../../services/symbol.service'; +import { Observable } from 'rxjs'; @Component({ @@ -39,260 +40,27 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { ngOnInit() {} - public takeScreenshot() { + public async takeScreenshot() { let splittedSvg = document.getElementsByTagName("svg")[0].outerHTML.split('image'); let i = 1; - let test = ''; + while (i < splittedSvg.length) { - let splittedImage = splittedSvg[i].split("\""); - let splittedUrl = splittedImage[1].split("/"); + var splittedImage = splittedSvg[i].split("\""); + var splittedUrl = splittedImage[1].split("/"); - this.symbolService.raw(this.server, splittedUrl[7]).subscribe((elem: string) => { - let splittedElement = elem.split('-->'); - splittedSvg[i] = splittedElement[1]; + let elem = await this.symbolService.raw(this.server, splittedUrl[7]).toPromise(); - test = splittedElement[1]; - console.log(test); - }); + let splittedElement = elem.split('-->'); + splittedSvg[i] = splittedElement[1].substring(2); i += 2; } let svgString = splittedSvg.join(); - svgString = test; - - // var parser = new DOMParser(); - // var doc = parser.parseFromString(document.getElementsByTagName("svg")[0].outerHTML, "text/html"); var placeholder = document.createElement('div'); - placeholder.innerHTML = ` - - - - - image/svg+xml - - Switch - - - Jeremy Grossmann - - - - - GNS-3 - - - Created for the GNS-3 project (www.gns3.net) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - `; + placeholder.innerHTML = svgString; var element = placeholder.firstChild; + svg.saveSvgAsPng(element, "plot.png"); } From eca520073b4b9a86376fb60050fb5f0df0043496 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 28 Aug 2019 03:59:48 -0700 Subject: [PATCH 041/146] Update project-map-menu.component.ts --- .../project-map-menu/project-map-menu.component.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts index 3cdeb283..deda40c5 100644 --- a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts +++ b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts @@ -45,21 +45,19 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { let i = 1; while (i < splittedSvg.length) { - var splittedImage = splittedSvg[i].split("\""); - var splittedUrl = splittedImage[1].split("/"); - + let splittedImage = splittedSvg[i].split("\""); + let splittedUrl = splittedImage[1].split("/"); + let elem = await this.symbolService.raw(this.server, splittedUrl[7]).toPromise(); - let splittedElement = elem.split('-->'); splittedSvg[i] = splittedElement[1].substring(2); - i += 2; } let svgString = splittedSvg.join(); - var placeholder = document.createElement('div'); + let placeholder = document.createElement('div'); placeholder.innerHTML = svgString; - var element = placeholder.firstChild; + let element = placeholder.firstChild; svg.saveSvgAsPng(element, "plot.png"); } From 94240ee783040fe50eff9420b0cf55081cf2781e Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 28 Aug 2019 04:19:20 -0700 Subject: [PATCH 042/146] Code cleaned up --- .../preferences/common/symbols/symbols.component.spec.ts | 4 ++++ .../project-map-menu/project-map-menu.component.spec.ts | 6 +++++- .../project-map-menu/project-map-menu.component.ts | 9 ++------- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/app/components/preferences/common/symbols/symbols.component.spec.ts b/src/app/components/preferences/common/symbols/symbols.component.spec.ts index 5646d491..a5ab9986 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.spec.ts +++ b/src/app/components/preferences/common/symbols/symbols.component.spec.ts @@ -14,6 +14,10 @@ export class MockedSymbolService { public list() { return of([]); } + + public raw() { + return of('') + } } describe('Symbols component', () => { diff --git a/src/app/components/project-map/project-map-menu/project-map-menu.component.spec.ts b/src/app/components/project-map/project-map-menu/project-map-menu.component.spec.ts index b43cd717..da54d891 100644 --- a/src/app/components/project-map/project-map-menu/project-map-menu.component.spec.ts +++ b/src/app/components/project-map/project-map-menu/project-map-menu.component.spec.ts @@ -10,12 +10,15 @@ import { ToolsService } from '../../../services/tools.service'; import { D3MapComponent } from '../../../cartography/components/d3-map/d3-map.component'; import { ANGULAR_MAP_DECLARATIONS } from '../../../cartography/angular-map.imports'; import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { SymbolService } from '../../../services/symbol.service'; +import { MockedSymbolService } from '../../preferences/common/symbols/symbols.component.spec'; describe('ProjectMapMenuComponent', () => { let component: ProjectMapMenuComponent; let fixture: ComponentFixture; let drawingService = new MockedDrawingService(); let mapSettingService = new MapSettingsService(); + let mockedSymbolService = new MockedSymbolService; beforeEach(async(() => { TestBed.configureTestingModule({ @@ -23,7 +26,8 @@ describe('ProjectMapMenuComponent', () => { providers: [ { provide: DrawingService, useValue: drawingService }, { provide: ToolsService }, - { provide: MapSettingsService, useValue: mapSettingService } + { provide: MapSettingsService, useValue: mapSettingService }, + { provide: SymbolService, useValue: mockedSymbolService} ], declarations: [ProjectMapMenuComponent, D3MapComponent, ...ANGULAR_MAP_DECLARATIONS], schemas: [NO_ERRORS_SCHEMA] diff --git a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts index deda40c5..1aa3a56f 100644 --- a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts +++ b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts @@ -4,11 +4,8 @@ import { Server } from '../../../models/server'; import { ToolsService } from '../../../services/tools.service'; import { MapSettingsService } from '../../../services/mapsettings.service'; import { DrawingService } from '../../../services/drawing.service'; -import { SymbolsDataSource } from '../../../cartography/datasources/symbols-datasource'; import * as svg from 'save-svg-as-png'; -import { MapSymbolsDataSource } from '../../../cartography/datasources/map-datasource'; import { SymbolService } from '../../../services/symbol.service'; -import { Observable } from 'rxjs'; @Component({ @@ -33,8 +30,6 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { private toolsService: ToolsService, private mapSettingsService: MapSettingsService, private drawingService: DrawingService, - private symbolsDataSource: SymbolsDataSource, - private mapSymbolsDataSource: MapSymbolsDataSource, private symbolService: SymbolService ) {} @@ -47,7 +42,7 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { while (i < splittedSvg.length) { let splittedImage = splittedSvg[i].split("\""); let splittedUrl = splittedImage[1].split("/"); - + let elem = await this.symbolService.raw(this.server, splittedUrl[7]).toPromise(); let splittedElement = elem.split('-->'); splittedSvg[i] = splittedElement[1].substring(2); @@ -59,7 +54,7 @@ export class ProjectMapMenuComponent implements OnInit, OnDestroy { placeholder.innerHTML = svgString; let element = placeholder.firstChild; - svg.saveSvgAsPng(element, "plot.png"); + svg.saveSvgAsPng(element, "screenshot.png"); } public addDrawing(selectedObject: string) { From aef6d044b3e4afd3935d84cc5a827e97cd612562 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 28 Aug 2019 07:04:17 -0700 Subject: [PATCH 043/146] 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 044/146] 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[] { From c4959b97da1b15c3952865db4f83095882175bff Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 29 Aug 2019 03:52:30 -0700 Subject: [PATCH 045/146] Release notes updated --- src/ReleaseNotes.txt | 21 +++++++++++-------- .../info-dialog/info-dialog.component.html | 3 --- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/ReleaseNotes.txt b/src/ReleaseNotes.txt index 9c0fe032..277bcbbe 100644 --- a/src/ReleaseNotes.txt +++ b/src/ReleaseNotes.txt @@ -1,16 +1,19 @@ GNS3 WebUI is web implementation of user interface for GNS3 software. -Current version: 2019.2.0 +Current version: 2019.3.0 What's New -- Help section added with information about third party components -- Showing progress when server starting -- Possibility to edit interface & node labels by using context menu -- Enhancements in moving elements on map -- Context menu extended with option to duplicate -- Main menu extended with option to lock all items on map +- Editing interface labels on double click +- Support for keyboard shortcuts +- Menu extended with option to delete currently opened project, export & import project +- Possibility to save current state of project +- Ability to duplicate project from projects page +- Node information dialog available from context menu +- Topology summary widget on map view +- Improvements in dialog styles Bug Fixes -- Removing issues with positioning interface labels while adding link between nodes on map +- Removing issues with opening console - Context menu now is correctly placed -- Entered text in text & style editor is now validated +- Text validation in dialogs +- Removing errors with creating WebSockets diff --git a/src/app/components/project-map/info-dialog/info-dialog.component.html b/src/app/components/project-map/info-dialog/info-dialog.component.html index d178a63e..529b00e4 100644 --- a/src/app/components/project-map/info-dialog/info-dialog.component.html +++ b/src/app/components/project-map/info-dialog/info-dialog.component.html @@ -10,9 +10,6 @@
-
- Please start the node in order to get the command line information. -
{{commandLine}}
From 63bcd6f4b201a29b9925e3ac232b89b4204f4d6e Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 29 Aug 2019 05:50:51 -0700 Subject: [PATCH 046/146] Overriding wrong styles --- src/ReleaseNotes.txt | 2 +- src/app/app.component.css | 3 +++ .../project-map/context-menu/context-menu.component.scss | 5 +++++ .../node-select-interface.component.html | 2 +- .../node-select-interface.component.scss | 4 ++++ .../node-select-interface/node-select-interface.component.ts | 2 +- src/app/components/project-map/project-map.component.scss | 4 ++++ src/styles.css | 4 ++++ 8 files changed, 23 insertions(+), 3 deletions(-) diff --git a/src/ReleaseNotes.txt b/src/ReleaseNotes.txt index 277bcbbe..e796ac23 100644 --- a/src/ReleaseNotes.txt +++ b/src/ReleaseNotes.txt @@ -1,6 +1,6 @@ GNS3 WebUI is web implementation of user interface for GNS3 software. -Current version: 2019.3.0 +Current version: 2019.2.0 What's New - Editing interface labels on double click diff --git a/src/app/app.component.css b/src/app/app.component.css index e69de29b..1bc4310f 100644 --- a/src/app/app.component.css +++ b/src/app/app.component.css @@ -0,0 +1,3 @@ +mat-menu-panel { + min-height: 0px; +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.scss b/src/app/components/project-map/context-menu/context-menu.component.scss index 6101a2b8..2e24dcaf 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.scss +++ b/src/app/components/project-map/context-menu/context-menu.component.scss @@ -1,3 +1,8 @@ .context-menu { position: absolute; + min-height: 0px; +} + +.mat-menu-panel ng-trigger ng-trigger-transformMenu ng-tns-c7-5 context-menu-items mat-menu-after mat-menu-below ng-star-inserted mat-elevation-z4 { + min-height: 0px!important; } diff --git a/src/app/components/project-map/node-select-interface/node-select-interface.component.html b/src/app/components/project-map/node-select-interface/node-select-interface.component.html index 33d07113..23c5bab7 100644 --- a/src/app/components/project-map/node-select-interface/node-select-interface.component.html +++ b/src/app/components/project-map/node-select-interface/node-select-interface.component.html @@ -1,6 +1,6 @@
- + - + Date: Thu, 29 Aug 2019 08:23:19 -0700 Subject: [PATCH 048/146] Release 2019.2.0-alpha.7 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ff4897de..51771960 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gns3-web-ui", - "version": "2019.2.0-alpha.6dev", + "version": "2019.2.0-alpha.7", "author": { "name": "GNS3 Technology Inc.", "email": "developers@gns3.com" From 583be8032a3bc77f3ed5aafd5b737d4a9b9b9ce1 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 30 Aug 2019 00:41:05 -0700 Subject: [PATCH 049/146] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 51771960..4eb5a7dc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gns3-web-ui", - "version": "2019.2.0-alpha.7", + "version": "2019.2.0-alpha.7dev", "author": { "name": "GNS3 Technology Inc.", "email": "developers@gns3.com" From b4eff2361f8eab3f7b4410a4c048c0073fd474c7 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 30 Aug 2019 04:59:08 -0700 Subject: [PATCH 050/146] Support for default telnet console added --- src/app/app.module.ts | 4 +++- ...nsole-device-action-browser.component.html | 4 ++++ ...le-device-action-browser.component.spec.ts | 0 ...console-device-action-browser.component.ts | 23 +++++++++++++++++++ .../context-menu/context-menu.component.html | 4 ++++ 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.html create mode 100644 src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.spec.ts create mode 100644 src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 505c9909..2df35267 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -197,6 +197,7 @@ import { ShowNodeActionComponent } from './components/project-map/context-menu/a import { InfoDialogComponent } from './components/project-map/info-dialog/info-dialog.component'; import { InfoService } from './services/info.service'; import { BringToFrontActionComponent } from './components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component'; +import { ConsoleDeviceActionBrowserComponent } from './components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -323,7 +324,8 @@ if (environment.production) { SaveProjectDialogComponent, TopologySummaryComponent, InfoDialogComponent, - BringToFrontActionComponent + BringToFrontActionComponent, + ConsoleDeviceActionBrowserComponent ], imports: [ BrowserModule, diff --git a/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.html b/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.html new file mode 100644 index 00000000..48f51b4f --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.spec.ts b/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.ts b/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.ts new file mode 100644 index 00000000..51a7f435 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component.ts @@ -0,0 +1,23 @@ +import { Component, Input } from '@angular/core'; +import { Node } from '../../../../../cartography/models/node'; +import { ToasterService } from '../../../../../services/toaster.service'; + +@Component({ + selector: 'app-console-device-action-browser', + templateUrl: './console-device-action-browser.component.html' +}) +export class ConsoleDeviceActionBrowserComponent { + @Input() node: Node; + + constructor( + private toasterService: ToasterService + ) {} + + openConsole() { + if(this.node.status !== "started") { + this.toasterService.error("This node must be started before a console can be opened"); + } else { + location.assign(`telnet://${this.node.console_host}:${this.node.console}/`); + } + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index 5ae6be95..f4754c95 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -12,6 +12,10 @@ [server]="server" [nodes]="nodes" > + Date: Mon, 2 Sep 2019 01:24:12 -0700 Subject: [PATCH 051/146] Export config added --- src/app/app.module.ts | 4 ++- .../export-config-action.component.html | 4 +++ .../export-config-action.component.ts | 33 +++++++++++++++++++ .../context-menu/context-menu.component.html | 12 ++++--- 4 files changed, 48 insertions(+), 5 deletions(-) create mode 100644 src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 7e43e027..83c14c7b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -199,6 +199,7 @@ import { ShowNodeActionComponent } from './components/project-map/context-menu/a import { InfoDialogComponent } from './components/project-map/info-dialog/info-dialog.component'; import { InfoService } from './services/info.service'; import { BringToFrontActionComponent } from './components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component'; +import { ExportConfigActionComponent } from './components/project-map/context-menu/actions/export-config/export-config-action.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -327,7 +328,8 @@ if (environment.production) { SaveProjectDialogComponent, TopologySummaryComponent, InfoDialogComponent, - BringToFrontActionComponent + BringToFrontActionComponent, + ExportConfigActionComponent ], imports: [ BrowserModule, diff --git a/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.html b/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.html new file mode 100644 index 00000000..5730195b --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts b/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts new file mode 100644 index 00000000..852e89ff --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts @@ -0,0 +1,33 @@ +import { Component, Input } from '@angular/core'; +import { Node } from '../../../../../cartography/models/node'; +import { NodeService } from '../../../../../services/node.service'; +import { Server } from '../../../../../models/server'; + +@Component({ + selector: 'app-export-config-action', + templateUrl: './export-config-action.component.html' +}) +export class ExportConfigActionComponent { + @Input() server: Server; + @Input() node: Node; + + constructor( + private nodeService: NodeService + ) {} + + exportConfig() { + this.nodeService.getConfiguration(this.server, this.node).subscribe((config: any) => { + this.downloadByHtmlTag(config); + }); + } + + private downloadByHtmlTag(config: string) { + const element = document.createElement('a'); + const fileType = 'vpc'; + element.setAttribute('href', `data:${fileType};charset=utf-8,${encodeURIComponent(config)}`); + element.setAttribute('download', 'configFile.vpc'); + + var event = new MouseEvent("click"); + element.dispatchEvent(event); + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index 69dd1ffa..87957817 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -36,11 +36,15 @@ [link]="links[0]" [linkNode]="linkNodes[0]" > - + Date: Mon, 2 Sep 2019 05:43:36 -0700 Subject: [PATCH 052/146] Code cleaned up --- src/app/app.module.ts | 4 +++- .../export-config-action.component.ts | 4 ++-- .../import-config-action.component.html | 4 ++++ .../import-config-action.component.ts | 19 +++++++++++++++++++ .../context-menu/context-menu.component.html | 8 ++++++-- 5 files changed, 34 insertions(+), 5 deletions(-) create mode 100644 src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 83c14c7b..2b86b4de 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -200,6 +200,7 @@ import { InfoDialogComponent } from './components/project-map/info-dialog/info-d import { InfoService } from './services/info.service'; import { BringToFrontActionComponent } from './components/project-map/context-menu/actions/bring-to-front-action/bring-to-front-action.component'; import { ExportConfigActionComponent } from './components/project-map/context-menu/actions/export-config/export-config-action.component'; +import { ImportConfigActionComponent } from './components/project-map/context-menu/actions/import-config/import-config-action.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -329,7 +330,8 @@ if (environment.production) { TopologySummaryComponent, InfoDialogComponent, BringToFrontActionComponent, - ExportConfigActionComponent + ExportConfigActionComponent, + ImportConfigActionComponent ], imports: [ BrowserModule, diff --git a/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts b/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts index 852e89ff..29b221cf 100644 --- a/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/export-config/export-config-action.component.ts @@ -23,9 +23,9 @@ export class ExportConfigActionComponent { private downloadByHtmlTag(config: string) { const element = document.createElement('a'); - const fileType = 'vpc'; + const fileType = 'text/plain'; element.setAttribute('href', `data:${fileType};charset=utf-8,${encodeURIComponent(config)}`); - element.setAttribute('download', 'configFile.vpc'); + element.setAttribute('download', `${this.node.name}_startup.vpc`); var event = new MouseEvent("click"); element.dispatchEvent(event); diff --git a/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.html b/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.html new file mode 100644 index 00000000..a8cc1358 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.ts b/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.ts new file mode 100644 index 00000000..5adba173 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/import-config/import-config-action.component.ts @@ -0,0 +1,19 @@ +import { Component, Input } from '@angular/core'; +import { Node } from '../../../../../cartography/models/node'; +import { NodeService } from '../../../../../services/node.service'; +import { Server } from '../../../../../models/server'; + +@Component({ + selector: 'app-import-config-action', + templateUrl: './import-config-action.component.html' +}) +export class ImportConfigActionComponent { + @Input() server: Server; + @Input() node: Node; + + constructor() {} + + importConfig() { + //needs implementation + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index 87957817..3bd5d4d5 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -36,15 +36,19 @@ [link]="links[0]" [linkNode]="linkNodes[0]" > - - + Date: Mon, 2 Sep 2019 07:08:08 -0700 Subject: [PATCH 053/146] Update log-console.component.ts --- .../project-map/log-console/log-console.component.ts | 4 ++-- 1 file changed, 2 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 26d758e8..84095b47 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 @@ -88,13 +88,13 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { message: message }); }); - this.errorSubscription = this.projectWebServiceHandler.warningNotificationEmitter.subscribe((message) => { + this.warningSubscription = this.projectWebServiceHandler.warningNotificationEmitter.subscribe((message) => { this.showMessage({ type: 'warning', message: message }); }); - this.errorSubscription = this.projectWebServiceHandler.infoNotificationEmitter.subscribe((message) => { + this.infoSubscription = this.projectWebServiceHandler.infoNotificationEmitter.subscribe((message) => { this.showMessage({ type: 'info', message: message From 2fe8cc72aa1f39ea3fee315e7d563ddf22835ae5 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 3 Sep 2019 08:22:55 -0700 Subject: [PATCH 054/146] Importing symbols added --- .../common/symbols/symbols.component.html | 17 +++++++++ .../common/symbols/symbols.component.scss | 17 +++++++++ .../common/symbols/symbols.component.ts | 38 +++++++++++++++++-- src/app/services/symbol.service.ts | 4 ++ 4 files changed, 72 insertions(+), 4 deletions(-) diff --git a/src/app/components/preferences/common/symbols/symbols.component.html b/src/app/components/preferences/common/symbols/symbols.component.html index 0b2858b7..4e27a7ca 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.html +++ b/src/app/components/preferences/common/symbols/symbols.component.html @@ -1,4 +1,21 @@ +



diff --git a/src/app/components/preferences/common/symbols/symbols.component.scss b/src/app/components/preferences/common/symbols/symbols.component.scss index 432de757..4d719f95 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.scss +++ b/src/app/components/preferences/common/symbols/symbols.component.scss @@ -8,6 +8,11 @@ outline: none; } +.menu { + display: flex; + justify-content: space-between; +} + .button { background: border-box; border-width: 0px; @@ -36,3 +41,15 @@ grid-row-gap: 3em; grid-column-gap: 1em; } + +.radio-selection { + width: 90%; +} + +.mat-radio-button ~ .mat-radio-button { + margin-left: 16px; +} + +.non-visible { + display: none; +} diff --git a/src/app/components/preferences/common/symbols/symbols.component.ts b/src/app/components/preferences/common/symbols/symbols.component.ts index f33407d3..f2b50e54 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.ts +++ b/src/app/components/preferences/common/symbols/symbols.component.ts @@ -24,14 +24,44 @@ export class SymbolsComponent implements OnInit { ngOnInit() { this.isSelected = this.symbol; - - this.symbolService.list(this.server).subscribe((symbols: Symbol[]) => { - this.symbols = symbols; - }); + this.loadSymbols(); } setSelected(symbol_id: string) { this.isSelected = symbol_id; this.symbolChanged.emit(this.isSelected); } + + loadSymbols() { + this.symbolService.list(this.server).subscribe((symbols: Symbol[]) => { + this.symbols = symbols; + }); + } + + public uploadSymbolFile(event) { + this.readSymbolFile(event.target); + } + + private readSymbolFile(symbolInput) { + let file: File = symbolInput.files[0]; + let fileName = symbolInput.files[0].name; + let fileReader: FileReader = new FileReader(); + let imageToUpload = new Image(); + + fileReader.onloadend = () => { + let image = fileReader.result; + let svg = this.createSvgFileForImage(image, imageToUpload); + this.symbolService.add(this.server, fileName, svg).subscribe(() => { + this.loadSymbols(); + }); + } + + imageToUpload.onload = () => { fileReader.readAsDataURL(file) }; + imageToUpload.src = window.URL.createObjectURL(file); + } + + private createSvgFileForImage(image: string|ArrayBuffer, imageToUpload: HTMLImageElement) { + return `\n\n` + } } diff --git a/src/app/services/symbol.service.ts b/src/app/services/symbol.service.ts index 3292645f..fba64d13 100644 --- a/src/app/services/symbol.service.ts +++ b/src/app/services/symbol.service.ts @@ -15,6 +15,10 @@ export class SymbolService { return this.symbols.getValue().find((symbol: Symbol) => symbol.symbol_id === symbol_id); } + add(server: Server, symbolName: string, symbol: string) { + return this.httpServer.post(server, `/symbols/${symbolName}/raw`, symbol) + } + load(server: Server): Observable { const subscription = this.list(server).subscribe((symbols: Symbol[]) => { const streams = symbols.map(symbol => this.raw(server, symbol.symbol_id)); From 6bca43563d8251ed0a07e5e726f76d6e2236f30a Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 3 Sep 2019 10:42:16 -0700 Subject: [PATCH 055/146] Filtering symbols added --- .../common/symbols/symbols.component.html | 10 +++++----- .../preferences/common/symbols/symbols.component.ts | 12 ++++++++++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/app/components/preferences/common/symbols/symbols.component.html b/src/app/components/preferences/common/symbols/symbols.component.html index 4e27a7ca..21f0882b 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.html +++ b/src/app/components/preferences/common/symbols/symbols.component.html @@ -1,9 +1,9 @@

+



-
+
diff --git a/src/app/components/preferences/common/symbols/symbols.component.ts b/src/app/components/preferences/common/symbols/symbols.component.ts index f2b50e54..c6932a09 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.ts +++ b/src/app/components/preferences/common/symbols/symbols.component.ts @@ -15,6 +15,7 @@ export class SymbolsComponent implements OnInit { @Output() symbolChanged = new EventEmitter(); symbols: Symbol[] = []; + filteredSymbols: Symbol[] = []; isSelected: string = ''; searchText: string = ''; @@ -27,6 +28,16 @@ export class SymbolsComponent implements OnInit { this.loadSymbols(); } + setFilter(filter: string) { + if (filter === 'all') { + this.filteredSymbols = this.symbols; + } else if (filter === 'builtin') { + this.filteredSymbols = this.symbols.filter(elem => elem.builtin); + } else { + this.filteredSymbols = this.symbols.filter(elem => !elem.builtin); + } + } + setSelected(symbol_id: string) { this.isSelected = symbol_id; this.symbolChanged.emit(this.isSelected); @@ -35,6 +46,7 @@ export class SymbolsComponent implements OnInit { loadSymbols() { this.symbolService.list(this.server).subscribe((symbols: Symbol[]) => { this.symbols = symbols; + this.filteredSymbols = symbols; }); } From df8e5825cc20ddbb26955508874a342da4e0521a Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 4 Sep 2019 02:03:16 -0700 Subject: [PATCH 056/146] Update save-project-dialog.component.ts --- .../save-project-dialog.component.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts b/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts index afb76ec0..97473c6e 100644 --- a/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts +++ b/src/app/components/projects/save-project-dialog/save-project-dialog.component.ts @@ -8,6 +8,7 @@ import { ProjectService } from '../../../services/project.service'; import { v4 as uuid } from 'uuid'; import { ProjectNameValidator } from '../models/projectNameValidator'; import { ToasterService } from '../../../services/toaster.service'; +import { NodesDataSource } from '../../../cartography/datasources/nodes-datasource'; @Component({ @@ -24,9 +25,8 @@ export class SaveProjectDialogComponent implements OnInit { constructor( public dialogRef: MatDialogRef, - private router: Router, - private dialog: MatDialog, private projectService: ProjectService, + private nodesDataSource: NodesDataSource, private toasterService: ToasterService, private formBuilder: FormBuilder, private projectNameValidator: ProjectNameValidator @@ -51,7 +51,12 @@ export class SaveProjectDialogComponent implements OnInit { let existingProject = projects.find(project => project.name === projectName); if (existingProject) { - this.toasterService.success(`Project with this name already exists.`); + this.toasterService.error(`Project with this name already exists.`); + } else if (this.nodesDataSource.getItems().filter(node => + (node.status === 'started' && node.node_type==='vpcs') || + (node.status === 'started' && node.node_type==='virtualbox') || + (node.status === 'started' && node.node_type==='vmware')).length > 0) { + this.toasterService.error('Please stop all nodes in order to save project.') } else { this.addProject(); } From 7450dd6731fed05e549cbfdc626cc130b783c820 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Wed, 4 Sep 2019 05:14:29 -0700 Subject: [PATCH 057/146] Ability to change symbol by context menu added --- src/app/app.module.ts | 9 +++- .../common/symbols/symbols.component.html | 11 ++++- .../common/symbols/symbols.component.scss | 4 ++ .../change-symbol-dialog.component.html | 12 ++++++ .../change-symbol-dialog.component.scss | 19 +++++++++ .../change-symbol-dialog.component.ts | 41 +++++++++++++++++++ .../change-symbol-action.component.html | 4 ++ .../change-symbol-action.component.spec.ts | 0 .../change-symbol-action.component.ts | 29 +++++++++++++ .../context-menu/context-menu.component.html | 5 +++ src/app/services/node.service.ts | 6 +++ 11 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.html create mode 100644 src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.scss create mode 100644 src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.ts create mode 100644 src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.spec.ts create mode 100644 src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 9145d6f3..f928860d 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -204,6 +204,8 @@ import { BringToFrontActionComponent } from './components/project-map/context-me import { ExportConfigActionComponent } from './components/project-map/context-menu/actions/export-config/export-config-action.component'; import { ImportConfigActionComponent } from './components/project-map/context-menu/actions/import-config/import-config-action.component'; import { ConsoleDeviceActionBrowserComponent } from './components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component'; +import { ChangeSymbolDialogComponent } from './components/project-map/change-symbol-dialog/change-symbol-dialog.component'; +import { ChangeSymbolActionComponent } from './components/project-map/context-menu/actions/change-symbol/change-symbol-action.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -336,7 +338,9 @@ if (environment.production) { BringToFrontActionComponent, ExportConfigActionComponent, ImportConfigActionComponent, - ConsoleDeviceActionBrowserComponent + ConsoleDeviceActionBrowserComponent, + ChangeSymbolDialogComponent, + ChangeSymbolActionComponent ], imports: [ BrowserModule, @@ -433,7 +437,8 @@ if (environment.production) { StartCaptureDialogComponent, ConfigEditorDialogComponent, SaveProjectDialogComponent, - InfoDialogComponent + InfoDialogComponent, + ChangeSymbolDialogComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/components/preferences/common/symbols/symbols.component.html b/src/app/components/preferences/common/symbols/symbols.component.html index 21f0882b..01c65e22 100644 --- a/src/app/components/preferences/common/symbols/symbols.component.html +++ b/src/app/components/preferences/common/symbols/symbols.component.html @@ -15,8 +15,15 @@ add Add symbol -

-

+
+
+ + + +
+ +
diff --git a/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.scss b/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.scss new file mode 100644 index 00000000..6deef2c4 --- /dev/null +++ b/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.scss @@ -0,0 +1,19 @@ +.symbolsWrapper { + height: 350px; + overflow-y: scroll; + scrollbar-color: darkgrey #263238; + scrollbar-width: thin; +} + +::-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/change-symbol-dialog/change-symbol-dialog.component.ts b/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.ts new file mode 100644 index 00000000..6fbd4bdb --- /dev/null +++ b/src/app/components/project-map/change-symbol-dialog/change-symbol-dialog.component.ts @@ -0,0 +1,41 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { MatDialogRef } from '@angular/material'; +import { Message } from '../../../models/message'; +import { Server } from '../../../models/server'; +import { Node } from '../../../cartography/models/node'; +import { Symbol } from '../../../models/symbol'; +import { NodeService } from '../../../services/node.service'; + +@Component({ + selector: 'app-change-symbol-dialog', + templateUrl: './change-symbol-dialog.component.html', + styleUrls: ['./change-symbol-dialog.component.scss'] +}) +export class ChangeSymbolDialogComponent implements OnInit { + @Input() server: Server; + @Input() node: Node; + symbol: string; + + constructor( + public dialogRef: MatDialogRef, + private nodeService: NodeService + ) {} + + ngOnInit() { + this.symbol = this.node.symbol; + } + + symbolChanged(chosenSymbol: string) { + this.symbol = chosenSymbol; + } + + onCloseClick() { + this.dialogRef.close(); + } + + onSelectClick() { + this.nodeService.updateSymbol(this.server, this.node, this.symbol).subscribe(() => { + this.onCloseClick() + }); + } +} diff --git a/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.html b/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.html new file mode 100644 index 00000000..71a7851e --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.ts b/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.ts new file mode 100644 index 00000000..af4f8d67 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/change-symbol/change-symbol-action.component.ts @@ -0,0 +1,29 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { Server } from '../../../../../models/server'; +import { Node } from '../../../../../cartography/models/node'; +import { MatDialog } from '@angular/material'; +import { ChangeSymbolDialogComponent } from '../../../change-symbol-dialog/change-symbol-dialog.component'; + +@Component({ + selector: 'app-change-symbol-action', + templateUrl: './change-symbol-action.component.html' +}) +export class ChangeSymbolActionComponent implements OnInit { + @Input() server: Server; + @Input() node: Node; + + constructor(private dialog: MatDialog) {} + + ngOnInit() {} + + changeSymbol() { + const dialogRef = this.dialog.open(ChangeSymbolDialogComponent, { + width: '1000px', + height: '500px', + autoFocus: false + }); + let instance = dialogRef.componentInstance; + instance.server = this.server; + instance.node = this.node; + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index 63d75132..91962af5 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -16,6 +16,11 @@ *ngIf="!projectService.isReadOnly(project) && nodes.length===1 && !isElectronApp && nodes[0].console_type!=='none'" [node]="nodes[0]" > + { + return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { + symbol: changedSymbol + }); + } + update(server: Server, node: Node): Observable { return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { x: Math.round(node.x), From 903448f1028152542cc4a44a72132caf887aef5a Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 5 Sep 2019 02:27:56 -0700 Subject: [PATCH 058/146] Dialog for editing project properties added --- src/app/app.module.ts | 7 +- .../edit-style-action.component.ts | 2 +- .../project-map/project-map.component.html | 4 ++ .../project-map/project-map.component.ts | 11 ++++ ...add-blank-project-dialog.component.spec.ts | 2 + .../confirmation-dialog.component.spec.ts | 2 + .../edit-project-dialog.component.html | 40 ++++++++++++ .../edit-project-dialog.component.scss | 3 + .../edit-project-dialog.component.ts | 64 +++++++++++++++++++ .../import-project-dialog.component.spec.ts | 2 + src/app/models/project.ts | 2 + src/app/services/project.service.ts | 13 ++++ 12 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 src/app/components/projects/edit-project-dialog/edit-project-dialog.component.html create mode 100644 src/app/components/projects/edit-project-dialog/edit-project-dialog.component.scss create mode 100644 src/app/components/projects/edit-project-dialog/edit-project-dialog.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index f928860d..6424c73f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -206,6 +206,7 @@ import { ImportConfigActionComponent } from './components/project-map/context-me import { ConsoleDeviceActionBrowserComponent } from './components/project-map/context-menu/actions/console-device-action-browser/console-device-action-browser.component'; import { ChangeSymbolDialogComponent } from './components/project-map/change-symbol-dialog/change-symbol-dialog.component'; import { ChangeSymbolActionComponent } from './components/project-map/context-menu/actions/change-symbol/change-symbol-action.component'; +import { EditProjectDialogComponent } from './components/projects/edit-project-dialog/edit-project-dialog.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -340,7 +341,8 @@ if (environment.production) { ImportConfigActionComponent, ConsoleDeviceActionBrowserComponent, ChangeSymbolDialogComponent, - ChangeSymbolActionComponent + ChangeSymbolActionComponent, + EditProjectDialogComponent ], imports: [ BrowserModule, @@ -438,7 +440,8 @@ if (environment.production) { ConfigEditorDialogComponent, SaveProjectDialogComponent, InfoDialogComponent, - ChangeSymbolDialogComponent + ChangeSymbolDialogComponent, + EditProjectDialogComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.ts b/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.ts index ea7e8cdf..9a6d04a2 100644 --- a/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.ts @@ -20,7 +20,7 @@ export class EditStyleActionComponent implements OnInit { editStyle() { const dialogRef = this.dialog.open(StyleEditorDialogComponent, { - width: '300px', + width: '800px', autoFocus: false }); let instance = dialogRef.componentInstance; diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index c307c7f1..b30b556c 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -54,6 +54,10 @@ save Save project as + + +
diff --git a/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.scss b/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.scss new file mode 100644 index 00000000..9c2173c2 --- /dev/null +++ b/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.scss @@ -0,0 +1,3 @@ +.form-field { + width: 100%; +} diff --git a/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.ts b/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.ts new file mode 100644 index 00000000..baaac059 --- /dev/null +++ b/src/app/components/projects/edit-project-dialog/edit-project-dialog.component.ts @@ -0,0 +1,64 @@ +import { Component, OnInit, Injectable } from '@angular/core'; +import { MatDialogRef } from '@angular/material'; +import { FormGroup, FormBuilder, FormControl, Validators } from '@angular/forms'; +import { Server } from '../../../models/server'; +import { Project } from '../../../models/project'; +import { ToasterService } from '../../../services/toaster.service'; +import { NonNegativeValidator } from '../../../validators/non-negative-validator'; +import { ProjectService } from '../../../services/project.service'; + +@Component({ + selector: 'app-edit-project-dialog', + templateUrl: './edit-project-dialog.component.html', + styleUrls: ['./edit-project-dialog.component.scss'] +}) +export class EditProjectDialogComponent implements OnInit { + server: Server; + project: Project; + formGroup: FormGroup; + + constructor( + public dialogRef: MatDialogRef, + private formBuilder: FormBuilder, + private projectService: ProjectService, + private toasterService: ToasterService, + private nonNegativeValidator: NonNegativeValidator + ) { + this.formGroup = this.formBuilder.group({ + projectName: new FormControl('', [Validators.required]), + width: new FormControl('', [Validators.required, nonNegativeValidator.get]), + height: new FormControl('', [Validators.required, nonNegativeValidator.get]), + nodeGridSize: new FormControl('', [Validators.required, nonNegativeValidator.get]), + drawingGridSize: new FormControl('', [Validators.required, nonNegativeValidator.get]) + }); + } + + ngOnInit() { + this.formGroup.controls['projectName'].setValue(this.project.name); + this.formGroup.controls['width'].setValue(this.project.scene_width); + this.formGroup.controls['height'].setValue(this.project.scene_height); + this.formGroup.controls['nodeGridSize'].setValue(this.project.grid_size); + this.formGroup.controls['drawingGridSize'].setValue(this.project.drawing_grid_size); + } + + onNoClick() { + this.dialogRef.close(); + } + + onYesClick() { + if (this.formGroup.valid) { + this.project.name = this.formGroup.get('projectName').value; + this.project.scene_width = this.formGroup.get('width').value; + this.project.scene_height = this.formGroup.get('height').value; + this.project.drawing_grid_size = this.formGroup.get('drawingGridSize').value; + this.project.grid_size = this.formGroup.get('nodeGridSize').value; + + this.projectService.update(this.server, this.project).subscribe((project: Project) => { + this.toasterService.success(`Project ${project.name} updated.`); + this.onNoClick(); + }) + } else { + this.toasterService.error(`Fill all required fields with correct values.`); + } + } +} diff --git a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts index dff8b671..5f46ed66 100644 --- a/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts +++ b/src/app/components/projects/import-project-dialog/import-project-dialog.component.spec.ts @@ -28,6 +28,8 @@ export class MockedProjectService { auto_close: false, auto_open: false, auto_start: false, + drawing_grid_size: 10, + grid_size: 10, filename: 'blank', name: 'blank', path: '', diff --git a/src/app/models/project.ts b/src/app/models/project.ts index 03760b35..d9e5d809 100644 --- a/src/app/models/project.ts +++ b/src/app/models/project.ts @@ -2,7 +2,9 @@ export class Project { auto_close: boolean; auto_open: boolean; auto_start: boolean; + drawing_grid_size: number; filename: string; + grid_size: number; name: string; path: string; project_id: string; diff --git a/src/app/services/project.service.ts b/src/app/services/project.service.ts index 193722d6..cd2ac96b 100644 --- a/src/app/services/project.service.ts +++ b/src/app/services/project.service.ts @@ -45,6 +45,19 @@ export class ProjectService { return this.httpServer.post(server, `/projects`, { name: project_name, project_id: project_id }); } + update(server: Server, project: Project) : Observable { + return this.httpServer.put(server, `/projects/${project.project_id}`, { + auto_close: project.auto_close, + auto_open: project.auto_open, + auto_start: project.auto_start, + drawing_grid_size: project.drawing_grid_size, + grid_size: project.grid_size, + name: project.name, + scene_width: project.scene_width, + scene_height: project.scene_height + }); + } + delete(server: Server, project_id: string): Observable { return this.httpServer.delete(server, `/projects/${project_id}`); } From f07353943c1cb009addca6cd77579f8be1b0fb21 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 5 Sep 2019 05:32:34 -0700 Subject: [PATCH 059/146] Filtering for projects added --- src/app/app.module.ts | 2 ++ .../components/projects/projects.component.css | 6 ++++++ .../projects/projects.component.html | 12 +++++++++++- .../components/projects/projects.component.ts | 4 +++- src/app/filters/projectsFilter.pipe.ts | 18 ++++++++++++++++++ 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/app/filters/projectsFilter.pipe.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 6424c73f..a977dbb4 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -207,6 +207,7 @@ import { ConsoleDeviceActionBrowserComponent } from './components/project-map/co import { ChangeSymbolDialogComponent } from './components/project-map/change-symbol-dialog/change-symbol-dialog.component'; import { ChangeSymbolActionComponent } from './components/project-map/context-menu/actions/change-symbol/change-symbol-action.component'; import { EditProjectDialogComponent } from './components/projects/edit-project-dialog/edit-project-dialog.component'; +import { ProjectsFilter } from './filters/projectsFilter.pipe'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -320,6 +321,7 @@ if (environment.production) { SearchFilter, DateFilter, NameFilter, + ProjectsFilter, ListOfSnapshotsComponent, CustomAdaptersComponent, NodesMenuComponent, diff --git a/src/app/components/projects/projects.component.css b/src/app/components/projects/projects.component.css index d7d423ad..5ed0ed20 100644 --- a/src/app/components/projects/projects.component.css +++ b/src/app/components/projects/projects.component.css @@ -7,3 +7,9 @@ height: 40px; margin: 20px; } + +.full-width { + width: 940px; + margin-left: -470px; + left: 50%; +} diff --git a/src/app/components/projects/projects.component.html b/src/app/components/projects/projects.component.html index 90d28c2e..f53b130f 100644 --- a/src/app/components/projects/projects.component.html +++ b/src/app/components/projects/projects.component.html @@ -24,9 +24,19 @@
+ +
+ + + +
+
- + Name diff --git a/src/app/components/projects/projects.component.ts b/src/app/components/projects/projects.component.ts index 1c7fa38a..787fd60b 100644 --- a/src/app/components/projects/projects.component.ts +++ b/src/app/components/projects/projects.component.ts @@ -29,6 +29,8 @@ export class ProjectsComponent implements OnInit { displayedColumns = ['name', 'actions']; settings: Settings; + searchText: string = ''; + @ViewChild(MatSort, {static: true}) sort: MatSort; constructor( @@ -157,7 +159,7 @@ export class ProjectDatabase { } export class ProjectDataSource extends DataSource { - constructor(private projectDatabase: ProjectDatabase, private sort: MatSort) { + constructor(public projectDatabase: ProjectDatabase, private sort: MatSort) { super(); } diff --git a/src/app/filters/projectsFilter.pipe.ts b/src/app/filters/projectsFilter.pipe.ts new file mode 100644 index 00000000..a0d637f4 --- /dev/null +++ b/src/app/filters/projectsFilter.pipe.ts @@ -0,0 +1,18 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { ProjectDataSource } from '../components/projects/projects.component'; + + +@Pipe({ + name: 'projectsfilter' +}) +export class ProjectsFilter implements PipeTransform { + transform(items: ProjectDataSource, searchText: string) { + if(!items) return []; + if(!searchText) return items; + + searchText = searchText.toLowerCase(); + return items.projectDatabase.data.filter( item => { + return item.filename.toLowerCase().includes(searchText); + }); + } +} From 9344174e8935df42a1eb88a7d367203e77a825ff Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 5 Sep 2019 05:48:04 -0700 Subject: [PATCH 060/146] Update projects.component.spec.ts --- .../components/projects/projects.component.spec.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/app/components/projects/projects.component.spec.ts b/src/app/components/projects/projects.component.spec.ts index 3f3a4d8a..880c1798 100644 --- a/src/app/components/projects/projects.component.spec.ts +++ b/src/app/components/projects/projects.component.spec.ts @@ -1,5 +1,5 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { MatIconModule, MatSortModule, MatTableModule, MatTooltipModule, MatDialogModule } from '@angular/material'; +import { MatIconModule, MatSortModule, MatTableModule, MatTooltipModule, MatDialogModule, MatFormFieldModule, MatInputModule } from '@angular/material'; import { RouterTestingModule } from '@angular/router/testing'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; @@ -16,6 +16,9 @@ import { ProgressService } from '../../common/progress/progress.service'; import { Server } from '../../models/server'; import { Settings } from '../../services/settings.service'; import { Project } from '../../models/project'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { NO_ERRORS_SCHEMA } from '@angular/core'; +import { ProjectsFilter } from '../../filters/projectsFilter.pipe'; describe('ProjectsComponent', () => { let component: ProjectsComponent; @@ -36,6 +39,10 @@ describe('ProjectsComponent', () => { MatSortModule, MatDialogModule, NoopAnimationsModule, + MatFormFieldModule, + MatInputModule, + FormsModule, + ReactiveFormsModule, RouterTestingModule.withRoutes([]) ], providers: [ @@ -44,7 +51,8 @@ describe('ProjectsComponent', () => { { provide: SettingsService, useClass: MockedSettingsService }, ProgressService ], - declarations: [ProjectsComponent] + declarations: [ProjectsComponent, ProjectsFilter], + schemas: [NO_ERRORS_SCHEMA] }).compileComponents(); serverService = TestBed.get(ServerService); From 92d09083277f70e96bd1968aced49e093158524c Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 6 Sep 2019 05:05:57 -0700 Subject: [PATCH 061/146] Servers summary added --- src/app/app.module.ts | 4 +- .../project-map/project-map.component.html | 2 +- .../topology-summary.component.html | 87 +++++++++++-------- .../topology-summary.component.scss | 34 +++++--- .../topology-summary.component.spec.ts | 11 ++- .../topology-summary.component.ts | 15 +++- src/app/material.imports.ts | 6 +- src/app/models/compute.ts | 19 ++++ src/app/services/compute.service.ts | 14 +++ 9 files changed, 142 insertions(+), 50 deletions(-) create mode 100644 src/app/models/compute.ts create mode 100644 src/app/services/compute.service.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index a977dbb4..3914b17b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -208,6 +208,7 @@ import { ChangeSymbolDialogComponent } from './components/project-map/change-sym import { ChangeSymbolActionComponent } from './components/project-map/context-menu/actions/change-symbol/change-symbol-action.component'; import { EditProjectDialogComponent } from './components/projects/edit-project-dialog/edit-project-dialog.component'; import { ProjectsFilter } from './filters/projectsFilter.pipe'; +import { ComputeService } from './services/compute.service'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -422,7 +423,8 @@ if (environment.production) { NonNegativeValidator, RotationValidator, MapSettingsService, - InfoService + InfoService, + ComputeService ], entryComponents: [ AddServerDialogComponent, diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index b30b556c..7c5f8cef 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -85,7 +85,7 @@ Show console - Show topology summary + Show topology/servers summary
diff --git a/src/app/components/topology-summary/topology-summary.component.html b/src/app/components/topology-summary/topology-summary.component.html index 3ca33e54..4200feb9 100644 --- a/src/app/components/topology-summary/topology-summary.component.html +++ b/src/app/components/topology-summary/topology-summary.component.html @@ -1,43 +1,62 @@
- Topology summary ({{projectsStatistics.snapshots}} snapshots) + + close
- -
- Filter by status
-
- Started - Suspended - Stopped +
+ +
+ Filter by status
+
+ Started + Suspended + Stopped +
+
+
+ Sorting
+
+ + By name ascending + By name descending + +
+
+ +
+
+
+ + + + + + + {{node.name}} +
+
+ {{node.console_type}} {{node.console_host}}:{{node.console}} +
+
+ none +
+
-
- Sorting
-
- - By name ascending - By name descending - -
-
- -
-
-
- - - - - - - {{node.name}} -
-
- {{node.console_type}} {{node.console_host}}:{{node.console}} -
-
- none +
+ +
+
+
+ {{compute.name}} +
+
+ {{compute.host}} +
+
+ {{server.location}} +
diff --git a/src/app/components/topology-summary/topology-summary.component.scss b/src/app/components/topology-summary/topology-summary.component.scss index a9629c20..a61e2504 100644 --- a/src/app/components/topology-summary/topology-summary.component.scss +++ b/src/app/components/topology-summary/topology-summary.component.scss @@ -17,7 +17,7 @@ .summaryHeader { width: 100%; - height: 24px; + height: 34px; display: flex; justify-content: space-between; margin-right: 5px; @@ -36,15 +36,29 @@ .summaryContent { margin-left: 5px; margin-right: 5px; - max-height: 240px; + max-height: 230px; overflow: auto; scrollbar-color: darkgrey #263238; scrollbar-width: thin; } -.title { +.summaryContentServers { + margin-left: 5px; + margin-right: 5px; + max-height: 350px; + overflow: auto; + scrollbar-color: darkgrey #263238; + scrollbar-width: thin; +} + +.titleButton { margin-left: 5px; margin-top: 4px; + outline: none; +} + +.marked { + color: #0097a7; } .divider { @@ -60,13 +74,6 @@ padding-right: 5px; } -mat-icon { - font-size: 18px; - width: 20px; - height: 20px; - margin-top: 4px; -} - ::-webkit-scrollbar { width: 0.5em; } @@ -91,9 +98,16 @@ mat-icon { .closeButton { cursor: pointer; + font-size: 24px; + margin-top: 8px; + margin-right: 5px; } .filterBox { display: flex; justify-content: space-between; } + +.notvisible { + display: none; +} diff --git a/src/app/components/topology-summary/topology-summary.component.spec.ts b/src/app/components/topology-summary/topology-summary.component.spec.ts index 3cbffe52..d697e371 100644 --- a/src/app/components/topology-summary/topology-summary.component.spec.ts +++ b/src/app/components/topology-summary/topology-summary.component.spec.ts @@ -11,13 +11,21 @@ import { NodesDataSource } from '../../cartography/datasources/nodes-datasource' import { NO_ERRORS_SCHEMA } from '@angular/core'; import { Project } from '../../models/project'; import { Node } from '../../cartography/models/node'; +import { Server } from '../../models/server'; +import { ComputeService } from '../../services/compute.service'; +export class MockedComputeService { + getComputes(server: Server) { + return of([]); + } +} describe('TopologySummaryComponent', () => { let component: TopologySummaryComponent; let fixture: ComponentFixture; let mockedProjectService: MockedProjectService = new MockedProjectService(); let mockedNodesDataSource: MockedNodesDataSource = new MockedNodesDataSource(); + let mockedComputeService: MockedComputeService = new MockedComputeService(); beforeEach(async(() => { TestBed.configureTestingModule({ @@ -32,7 +40,8 @@ describe('TopologySummaryComponent', () => { ], providers: [ { provide: ProjectService, useValue: mockedProjectService }, - { provide: NodesDataSource, useValue: mockedNodesDataSource } + { provide: NodesDataSource, useValue: mockedNodesDataSource }, + { provide: ComputeService, useValue: mockedComputeService} ], declarations: [TopologySummaryComponent], schemas: [NO_ERRORS_SCHEMA] diff --git a/src/app/components/topology-summary/topology-summary.component.ts b/src/app/components/topology-summary/topology-summary.component.ts index a53402e1..cb7ba9e8 100644 --- a/src/app/components/topology-summary/topology-summary.component.ts +++ b/src/app/components/topology-summary/topology-summary.component.ts @@ -6,6 +6,8 @@ import { Node } from '../../cartography/models/node'; import { Subscription } from 'rxjs'; import { ProjectService } from '../../services/project.service'; import { ProjectStatistics } from '../../models/project-statistics'; +import { Compute } from '../../models/compute'; +import { ComputeService } from '../../services/compute.service'; @Component({ @@ -27,10 +29,13 @@ export class TopologySummaryComponent implements OnInit, OnDestroy { startedStatusFilterEnabled: boolean = false; suspendedStatusFilterEnabled: boolean = false; stoppedStatusFilterEnabled: boolean = false; + computes: Compute[] = []; + isTopologyVisible: boolean = true; constructor( private nodesDataSource: NodesDataSource, - private projectService: ProjectService + private projectService: ProjectService, + private computeService: ComputeService ) {} ngOnInit() { @@ -48,6 +53,14 @@ export class TopologySummaryComponent implements OnInit, OnDestroy { this.projectService.getStatistics(this.server, this.project.project_id).subscribe((stats) => { this.projectsStatistics = stats; }); + + this.computeService.getComputes(this.server).subscribe((computes) => { + this.computes = computes; + }); + } + + toogleTopologyVisibility(value: boolean) { + this.isTopologyVisible = value; } compareAsc(first: Node, second: Node) { diff --git a/src/app/material.imports.ts b/src/app/material.imports.ts index fdc33412..ac93b2a2 100644 --- a/src/app/material.imports.ts +++ b/src/app/material.imports.ts @@ -20,7 +20,8 @@ import { MatStepperModule, MatRadioModule, MatGridListModule, - MatTabsModule + MatTabsModule, + MatTreeModule } from '@angular/material'; export const MATERIAL_IMPORTS = [ @@ -45,5 +46,6 @@ export const MATERIAL_IMPORTS = [ MatStepperModule, MatRadioModule, MatGridListModule, - MatTabsModule + MatTabsModule, + MatTreeModule ]; diff --git a/src/app/models/compute.ts b/src/app/models/compute.ts new file mode 100644 index 00000000..83c16bf2 --- /dev/null +++ b/src/app/models/compute.ts @@ -0,0 +1,19 @@ +export interface Capabilities { + node_types: string[]; + platform: string; + version: string; +} + +export interface Compute { + capabilities: Capabilities; + compute_id: string; + connected: boolean; + cpu_usage_percent: number; + host: string; + last_error?: any; + memory_usage_percent: number; + name: string; + port: number; + protocol: string; + user: string; +} diff --git a/src/app/services/compute.service.ts b/src/app/services/compute.service.ts new file mode 100644 index 00000000..6cc49de7 --- /dev/null +++ b/src/app/services/compute.service.ts @@ -0,0 +1,14 @@ +import { Injectable } from '@angular/core'; +import { HttpServer } from './http-server.service'; +import { Server } from '../models/server'; +import { Compute } from '../models/compute'; +import { Observable } from 'rxjs'; + +@Injectable() +export class ComputeService { + constructor(private httpServer: HttpServer) {} + + getComputes(server: Server): Observable { + return this.httpServer.get(server, '/computes') as Observable; + } +} From 03dbac5abaf3c52047603c3896d3d755ad24388e Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 6 Sep 2019 06:18:03 -0700 Subject: [PATCH 062/146] Console updated --- .../log-console/log-console.component.html | 12 ++++++------ .../project-map/log-console/log-console.component.ts | 3 ++- 2 files changed, 8 insertions(+), 7 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 5db1f7da..0d3b16f8 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 @@ -6,12 +6,12 @@ keyboard_arrow_down - - - - - - + + + + + +
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 84095b47..f14af008 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 @@ -116,7 +116,8 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.infoSubscription.unsubscribe(); } - applyFilter() { + applyFilter(filter: string) { + this.selectedFilter = filter; this.filteredEvents = this.getFilteredEvents(); } From 00597accacb350a5aab20e6d54416a61f0ed0609 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 6 Sep 2019 08:18:26 -0700 Subject: [PATCH 063/146] Option to show interface labels should be saved for opened project --- .../project-map/project-map.component.html | 6 +++--- .../components/project-map/project-map.component.ts | 12 ++++++++++-- src/app/services/mapsettings.service.ts | 5 +++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 7c5f8cef..6014383b 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -8,7 +8,7 @@ [drawings]="drawings" [width]="project.scene_width" [height]="project.scene_height" - [show-interface-labels]="project.show_interface_labels" + [show-interface-labels]="isInterfaceLabelVisible" [readonly]="inReadOnlyMode" (nodeDragged)="onNodeDragged($event)" (drawingDragged)="onDrawingDragged($event)" @@ -24,7 +24,7 @@ [drawings]="drawings" [width]="project.scene_width" [height]="project.scene_height" - [show-interface-labels]="project.show_interface_labels" + [show-interface-labels]="isInterfaceLabelVisible" [selection-tool]="tools.selection" [moving-tool]="tools.moving" [draw-link-tool]="tools.draw_link" @@ -78,7 +78,7 @@
- + Show interface labels diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index c76cb4b3..de987e06 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -78,6 +78,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { public isProjectMapMenuVisible: boolean = false; public isConsoleVisible: boolean = false; public isTopologySummaryVisible: boolean = false; + public isInterfaceLabelVisible: boolean = false; tools = { selection: true, @@ -156,6 +157,12 @@ export class ProjectMapComponent implements OnInit, OnDestroy { }), mergeMap((project: Project) => { this.project = project; + + if (this.mapSettingsService.interfaceLabels.has(project.project_id)) { + this.isInterfaceLabelVisible = this.mapSettingsService.interfaceLabels.get(project.project_id); + } else { + this.isInterfaceLabelVisible = this.project.show_interface_labels; + } this.recentlyOpenedProjectService.setServerId(this.server.id.toString()); this.recentlyOpenedProjectService.setProjectId(this.project.project_id); @@ -403,8 +410,9 @@ export class ProjectMapComponent implements OnInit, OnDestroy { this.toolsService.drawLinkToolActivation(this.tools.draw_link); } - public toggleShowInterfaceLabels(enabled: boolean) { - this.project.show_interface_labels = enabled; + public toggleShowInterfaceLabels(visible: boolean) { + this.isInterfaceLabelVisible = visible; + this.mapSettingsService.toggleShowInterfaceLabels(this.project.project_id, this.isInterfaceLabelVisible); } public toggleShowConsole(visible: boolean) { diff --git a/src/app/services/mapsettings.service.ts b/src/app/services/mapsettings.service.ts index 2f1764e5..ec9f8e54 100644 --- a/src/app/services/mapsettings.service.ts +++ b/src/app/services/mapsettings.service.ts @@ -6,6 +6,7 @@ export class MapSettingsService { public isMapLocked = new Subject(); public isTopologySummaryVisible: boolean = false; public isLogConsoleVisible: boolean = false; + public interfaceLabels: Map = new Map(); constructor() {} @@ -20,4 +21,8 @@ export class MapSettingsService { toggleLogConsole(value: boolean) { this.isLogConsoleVisible = value; } + + toggleShowInterfaceLabels(projectId: string, value: boolean) { + this.interfaceLabels.set(projectId, value); + } } From cd5edebd98a229759b21867034d5519a3513cc8c Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 6 Sep 2019 08:51:13 -0700 Subject: [PATCH 064/146] Reload action added --- src/app/app.module.ts | 4 ++- .../reload-node-action.component.html | 4 +++ .../reload-node-action.component.spec.ts | 0 .../reload-node-action.component.ts | 31 +++++++++++++++++++ .../context-menu/context-menu.component.html | 3 ++ 5 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.spec.ts create mode 100644 src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 3914b17b..d14e9e91 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -209,6 +209,7 @@ import { ChangeSymbolActionComponent } from './components/project-map/context-me import { EditProjectDialogComponent } from './components/projects/edit-project-dialog/edit-project-dialog.component'; import { ProjectsFilter } from './filters/projectsFilter.pipe'; import { ComputeService } from './services/compute.service'; +import { ReloadNodeActionComponent } from './components/project-map/context-menu/actions/reload-node-action/reload-node-action.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -345,7 +346,8 @@ if (environment.production) { ConsoleDeviceActionBrowserComponent, ChangeSymbolDialogComponent, ChangeSymbolActionComponent, - EditProjectDialogComponent + EditProjectDialogComponent, + ReloadNodeActionComponent ], imports: [ BrowserModule, diff --git a/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.html b/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.html new file mode 100644 index 00000000..f8884c90 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.ts b/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.ts new file mode 100644 index 00000000..7cee91cc --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/reload-node-action/reload-node-action.component.ts @@ -0,0 +1,31 @@ +import { Component, Input, OnInit, OnChanges } from '@angular/core'; +import { Server } from '../../../../../models/server'; +import { NodeService } from '../../../../../services/node.service'; +import { Node } from '../../../../../cartography/models/node'; + +@Component({ + selector: 'app-reload-node-action', + templateUrl: './reload-node-action.component.html' +}) +export class ReloadNodeActionComponent implements OnInit { + @Input() server: Server; + @Input() nodes: Node[]; + + filteredNodes: Node[] = []; + + constructor(private nodeService: NodeService) {} + + ngOnInit() { + this.nodes.forEach((node) => { + if (node.node_type === 'vpcs' || node.node_type === 'qemu' || node.node_type === 'virtualbox' || node.node_type === 'vmware') { + this.filteredNodes.push(node); + } + }); + } + + reloadNodes() { + this.filteredNodes.forEach((node) => { + this.nodeService.reload(this.server, node).subscribe((n: Node) => {}); + }); + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index 91962af5..ebfb04cf 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -7,6 +7,9 @@ > + Date: Mon, 9 Sep 2019 02:27:48 -0700 Subject: [PATCH 065/146] Action to suspend added --- src/app/app.module.ts | 4 ++- .../suspend-node-action.component.html | 4 +++ .../suspend-node-action.component.spec.ts | 0 .../suspend-node-action.component.ts | 36 +++++++++++++++++++ .../context-menu/context-menu.component.html | 1 + 5 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.spec.ts create mode 100644 src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index d14e9e91..3edba25a 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -210,6 +210,7 @@ import { EditProjectDialogComponent } from './components/projects/edit-project-d import { ProjectsFilter } from './filters/projectsFilter.pipe'; import { ComputeService } from './services/compute.service'; import { ReloadNodeActionComponent } from './components/project-map/context-menu/actions/reload-node-action/reload-node-action.component'; +import { SuspendNodeActionComponent } from './components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -347,7 +348,8 @@ if (environment.production) { ChangeSymbolDialogComponent, ChangeSymbolActionComponent, EditProjectDialogComponent, - ReloadNodeActionComponent + ReloadNodeActionComponent, + SuspendNodeActionComponent ], imports: [ BrowserModule, diff --git a/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.html b/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.html new file mode 100644 index 00000000..de0b01c3 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.ts b/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.ts new file mode 100644 index 00000000..17688b62 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component.ts @@ -0,0 +1,36 @@ +import { Component, Input, OnInit, OnChanges } from '@angular/core'; +import { Server } from '../../../../../models/server'; +import { NodeService } from '../../../../../services/node.service'; +import { Node } from '../../../../../cartography/models/node'; + +@Component({ + selector: 'app-suspend-node-action', + templateUrl: './suspend-node-action.component.html' +}) +export class SuspendNodeActionComponent implements OnInit, OnChanges { + @Input() server: Server; + @Input() nodes: Node[]; + isNodeWithStartedStatus: boolean; + + constructor(private nodeService: NodeService) {} + + ngOnInit() { + } + + ngOnChanges(changes) { + if(changes.nodes) { + this.isNodeWithStartedStatus = false; + this.nodes.forEach((node) => { + if (node.status === 'started') { + this.isNodeWithStartedStatus = true; + } + }); + } + } + + suspendNodes() { + this.nodes.forEach((node) => { + this.nodeService.suspend(this.server, node).subscribe((n: Node) => {}); + }); + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index ebfb04cf..091a6fcf 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -6,6 +6,7 @@ [node]="nodes[0]" > + Date: Mon, 9 Sep 2019 06:57:42 -0700 Subject: [PATCH 066/146] Dialog for VPCS added --- src/app/app.module.ts | 9 ++- src/app/cartography/models/node.ts | 1 + .../config-action.component.html | 4 ++ .../config-action.component.spec.ts | 0 .../config-action/config-action.component.ts | 58 +++++++++++++++++++ .../context-menu/context-menu.component.html | 4 ++ .../configurator/configurator.component.scss | 7 +++ .../vpcs/configurator-vpcs.component.html | 39 +++++++++++++ .../vpcs/configurator-vpcs.component.ts | 58 +++++++++++++++++++ src/app/services/node.service.ts | 11 ++++ 10 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 src/app/components/project-map/context-menu/actions/config-action/config-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/config-action/config-action.component.spec.ts create mode 100644 src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts create mode 100644 src/app/components/project-map/node-editors/configurator/configurator.component.scss create mode 100644 src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.html create mode 100644 src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 3edba25a..fbcdc4ff 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -211,6 +211,8 @@ import { ProjectsFilter } from './filters/projectsFilter.pipe'; import { ComputeService } from './services/compute.service'; import { ReloadNodeActionComponent } from './components/project-map/context-menu/actions/reload-node-action/reload-node-action.component'; import { SuspendNodeActionComponent } from './components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component'; +import { ConfigActionComponent } from './components/project-map/context-menu/actions/config-action/config-action.component'; +import { ConfiguratorDialogVpcsComponent } from './components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -349,7 +351,9 @@ if (environment.production) { ChangeSymbolActionComponent, EditProjectDialogComponent, ReloadNodeActionComponent, - SuspendNodeActionComponent + SuspendNodeActionComponent, + ConfigActionComponent, + ConfiguratorDialogVpcsComponent ], imports: [ BrowserModule, @@ -449,7 +453,8 @@ if (environment.production) { SaveProjectDialogComponent, InfoDialogComponent, ChangeSymbolDialogComponent, - EditProjectDialogComponent + EditProjectDialogComponent, + ConfiguratorDialogVpcsComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/cartography/models/node.ts b/src/app/cartography/models/node.ts index 5caf995f..3478617f 100644 --- a/src/app/cartography/models/node.ts +++ b/src/app/cartography/models/node.ts @@ -5,6 +5,7 @@ export class Node { command_line: string; compute_id: string; console: number; + console_auto_start: boolean; console_host: string; console_type: string; first_port_name: string; diff --git a/src/app/components/project-map/context-menu/actions/config-action/config-action.component.html b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.html new file mode 100644 index 00000000..3290ba3a --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/config-action/config-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts new file mode 100644 index 00000000..5d9d0974 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts @@ -0,0 +1,58 @@ +import { Component, Input, OnInit, OnChanges } from '@angular/core'; +import { Server } from '../../../../../models/server'; +import { Node } from '../../../../../cartography/models/node'; +import { MatDialog, MatDialogRef } from '@angular/material'; +import { ConfiguratorDialogVpcsComponent } from '../../../node-editors/configurator/vpcs/configurator-vpcs.component'; + + +@Component({ + selector: 'app-config-node-action', + templateUrl: './config-action.component.html' +}) +export class ConfigActionComponent { + @Input() server: Server; + @Input() node: Node; + private conf = { + width: '600px', + autoFocus: false + }; + dialogRef; + + constructor(private dialog: MatDialog) {} + + configureNode() { + if (this.node.node_type === 'vpcs') { + this.dialogRef = this.dialog.open(ConfiguratorDialogVpcsComponent, this.conf); + } else if (this.node.node_type === 'ethernet_hub') { + + } else if (this.node.node_type === 'ethernet_switch') { + + } else if (this.node.node_type === 'cloud') { + + } else if (this.node.node_type === 'dynamips') { + + } else if (this.node.node_type === 'iou') { + + } else if (this.node.node_type === 'qemu') { + + } else if (this.node.node_type === 'virtualbox') { + + } else if (this.node.node_type === 'vmware') { + + } else if (this.node.node_type === 'docker') { + + } else if (this.node.node_type === 'nat') { + + } else if (this.node.node_type === 'frame_relay_switch') { + + } else if (this.node.node_type === 'atm_switch') { + + } else if (this.node.node_type === 'traceng') { + + } + + let instance = this.dialogRef.componentInstance; + instance.server = this.server; + instance.node = this.node; + } +} diff --git a/src/app/components/project-map/context-menu/context-menu.component.html b/src/app/components/project-map/context-menu/context-menu.component.html index 091a6fcf..177d607d 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.html +++ b/src/app/components/project-map/context-menu/context-menu.component.html @@ -5,6 +5,10 @@ [server]="server" [node]="nodes[0]" > + diff --git a/src/app/components/project-map/node-editors/configurator/configurator.component.scss b/src/app/components/project-map/node-editors/configurator/configurator.component.scss new file mode 100644 index 00000000..ae93f5c6 --- /dev/null +++ b/src/app/components/project-map/node-editors/configurator/configurator.component.scss @@ -0,0 +1,7 @@ +.form-field { + width: 100%; +} + +.select { + width: 100%; +} diff --git a/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.html b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.html new file mode 100644 index 00000000..e4edc149 --- /dev/null +++ b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.html @@ -0,0 +1,39 @@ +

Configurator for node {{node.name}}

+ + + +
+ + +
diff --git a/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts new file mode 100644 index 00000000..c2073860 --- /dev/null +++ b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts @@ -0,0 +1,58 @@ +import { Component, OnInit, Input } from "@angular/core"; +import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; +import { VpcsConfigurationService } from '../../../../../services/vpcs-configuration.service'; +import { Node } from '../../../../../cartography/models/node'; +import { Server } from '../../../../../models/server'; +import { NodeService } from '../../../../../services/node.service'; +import { ToasterService } from '../../../../../services/toaster.service'; +import { MatDialogRef } from '@angular/material'; + + +@Component({ + selector: 'app-configurator-vpcs', + templateUrl: './configurator-vpcs.component.html', + styleUrls: ['../configurator.component.scss'] +}) +export class ConfiguratorDialogVpcsComponent implements OnInit { + server: Server; + node: Node; + + inputForm: FormGroup; + consoleTypes: string[] = []; + categories = []; + + constructor( + public dialogRef: MatDialogRef, + public nodeService: NodeService, + private toasterService: ToasterService, + private formBuilder: FormBuilder, + private vpcsConfigurationService: VpcsConfigurationService + ) { + this.inputForm = this.formBuilder.group({ + name: new FormControl('', Validators.required) + }); + } + + ngOnInit() { + this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.node = node; + this.getConfiguration(); + }) + } + + getConfiguration() { + this.consoleTypes = this.vpcsConfigurationService.getConsoleTypes(); + this.categories = this.vpcsConfigurationService.getCategories(); + } + + onSaveClick() { + this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.toasterService.success(`Node ${this.node.name} updated.`); + this.onCancelClick(); + }); + } + + onCancelClick() { + this.dialogRef.close(); + } +} diff --git a/src/app/services/node.service.ts b/src/app/services/node.service.ts index 111b5106..9beb0d6f 100644 --- a/src/app/services/node.service.ts +++ b/src/app/services/node.service.ts @@ -86,6 +86,13 @@ export class NodeService { }); } + updateNode(server: Server, node: Node): Observable { + return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { + console_type: node.console_type, + name: node.name + }); + } + delete(server: Server, node: Node) { return this.httpServer.delete(server, `/projects/${node.project_id}/nodes/${node.node_id}`); } @@ -99,6 +106,10 @@ export class NodeService { }); } + getNode(server: Server, node: Node) { + return this.httpServer.get(server, `/projects/${node.project_id}/nodes/${node.node_id}`) + } + getConfiguration(server: Server, node: Node) { let urlPath: string = `/projects/${node.project_id}/nodes/${node.node_id}` From 96e297ff6a1f68910180f8b24b2819e18d5db1cf Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 9 Sep 2019 08:56:14 -0700 Subject: [PATCH 067/146] Validation added --- .../config-action/config-action.component.ts | 9 +- .../configurator-ethernet-hub.component.html | 31 +++++++ .../configurator-ethernet-hub.component.ts | 83 +++++++++++++++++++ .../vpcs/configurator-vpcs.component.ts | 12 ++- 4 files changed, 127 insertions(+), 8 deletions(-) create mode 100644 src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.html create mode 100644 src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts diff --git a/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts index 5d9d0974..43cd50cd 100644 --- a/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts @@ -3,6 +3,7 @@ import { Server } from '../../../../../models/server'; import { Node } from '../../../../../cartography/models/node'; import { MatDialog, MatDialogRef } from '@angular/material'; import { ConfiguratorDialogVpcsComponent } from '../../../node-editors/configurator/vpcs/configurator-vpcs.component'; +import { ConfiguratorDialogEthernetHubComponent } from '../../../node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component'; @Component({ @@ -24,7 +25,7 @@ export class ConfigActionComponent { if (this.node.node_type === 'vpcs') { this.dialogRef = this.dialog.open(ConfiguratorDialogVpcsComponent, this.conf); } else if (this.node.node_type === 'ethernet_hub') { - + this.dialogRef = this.dialog.open(ConfiguratorDialogEthernetHubComponent, this.conf); } else if (this.node.node_type === 'ethernet_switch') { } else if (this.node.node_type === 'cloud') { @@ -43,11 +44,11 @@ export class ConfigActionComponent { } else if (this.node.node_type === 'nat') { - } else if (this.node.node_type === 'frame_relay_switch') { + } else if (this.node.node_type === 'frame_relay_switch') { - } else if (this.node.node_type === 'atm_switch') { + } else if (this.node.node_type === 'atm_switch') { - } else if (this.node.node_type === 'traceng') { + } else if (this.node.node_type === 'traceng') { } diff --git a/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.html b/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.html new file mode 100644 index 00000000..c60a7f67 --- /dev/null +++ b/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.html @@ -0,0 +1,31 @@ +

Configurator for node {{node.name}}

+ + + +
+ + +
diff --git a/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts b/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts new file mode 100644 index 00000000..05966da7 --- /dev/null +++ b/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts @@ -0,0 +1,83 @@ +import { Component, OnInit, Input } from "@angular/core"; +import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; +import { VpcsConfigurationService } from '../../../../../services/vpcs-configuration.service'; +import { Node } from '../../../../../cartography/models/node'; +import { Server } from '../../../../../models/server'; +import { NodeService } from '../../../../../services/node.service'; +import { ToasterService } from '../../../../../services/toaster.service'; +import { MatDialogRef } from '@angular/material'; + + +@Component({ + selector: 'app-configurator-ethernet-hub', + templateUrl: './configurator-ethernet-hub.component.html', + styleUrls: ['../configurator.component.scss'] +}) +export class ConfiguratorDialogEthernetHubComponent implements OnInit { + server: Server; + node: Node; + numberOfPorts: number; + inputForm: FormGroup; + consoleTypes: string[] = []; + categories = []; + + constructor( + public dialogRef: MatDialogRef, + public nodeService: NodeService, + private toasterService: ToasterService, + private formBuilder: FormBuilder, + private vpcsConfigurationService: VpcsConfigurationService + ) { + this.inputForm = this.formBuilder.group({ + name: new FormControl('', Validators.required) + }); + } + + ngOnInit() { + this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.node = node; + this.getConfiguration(); + }) + } + + getConfiguration() { + this.consoleTypes = this.vpcsConfigurationService.getConsoleTypes(); + this.categories = this.vpcsConfigurationService.getCategories(); + } + + onSaveClick() { + if (this.inputForm.valid) { + for(let i=0; i { + this.toasterService.success(`Node ${this.node.name} updated.`); + this.onCancelClick(); + }); + } else { + this.toasterService.error(`Fill all required fields.`) + } + } + + onCancelClick() { + this.dialogRef.close(); + } +} diff --git a/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts index c2073860..042e60fd 100644 --- a/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts +++ b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts @@ -46,10 +46,14 @@ export class ConfiguratorDialogVpcsComponent implements OnInit { } onSaveClick() { - this.nodeService.updateNode(this.server, this.node).subscribe(() => { - this.toasterService.success(`Node ${this.node.name} updated.`); - this.onCancelClick(); - }); + if (this.inputForm.valid) { + this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.toasterService.success(`Node ${this.node.name} updated.`); + this.onCancelClick(); + }); + } else { + this.toasterService.error(`Fill all required fields.`); + } } onCancelClick() { From 0fe44b2235f801325d57e5b12917a66a00c02a8d Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 9 Sep 2019 09:33:10 -0700 Subject: [PATCH 068/146] Dialog for ethernet hubs added --- src/app/app.module.ts | 7 +++++-- src/app/cartography/models/node.ts | 10 ++++++++++ .../configurator-ethernet-hub.component.ts | 20 ++++--------------- src/app/services/node.service.ts | 3 ++- 4 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/app/app.module.ts b/src/app/app.module.ts index fbcdc4ff..dc540c2f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -213,6 +213,7 @@ import { ReloadNodeActionComponent } from './components/project-map/context-menu import { SuspendNodeActionComponent } from './components/project-map/context-menu/actions/suspend-node-action/suspend-node-action.component'; import { ConfigActionComponent } from './components/project-map/context-menu/actions/config-action/config-action.component'; import { ConfiguratorDialogVpcsComponent } from './components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component'; +import { ConfiguratorDialogEthernetHubComponent } from './components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -353,7 +354,8 @@ if (environment.production) { ReloadNodeActionComponent, SuspendNodeActionComponent, ConfigActionComponent, - ConfiguratorDialogVpcsComponent + ConfiguratorDialogVpcsComponent, + ConfiguratorDialogEthernetHubComponent ], imports: [ BrowserModule, @@ -454,7 +456,8 @@ if (environment.production) { InfoDialogComponent, ChangeSymbolDialogComponent, EditProjectDialogComponent, - ConfiguratorDialogVpcsComponent + ConfiguratorDialogVpcsComponent, + ConfiguratorDialogEthernetHubComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/cartography/models/node.ts b/src/app/cartography/models/node.ts index 3478617f..358a1dcc 100644 --- a/src/app/cartography/models/node.ts +++ b/src/app/cartography/models/node.ts @@ -1,6 +1,15 @@ import { Label } from './label'; import { Port } from '../../models/port'; +export class PortsMapping { + name: string; + port_number: number; +} + +export class Properties { + ports_mapping: PortsMapping[]; +} + export class Node { command_line: string; compute_id: string; @@ -19,6 +28,7 @@ export class Node { port_segment_size: number; ports: Port[]; project_id: string; + properties: Properties; status: string; symbol: string; symbol_url: string; // @TODO: full URL to symbol, move to MapNode once converters are moved to app module diff --git a/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts b/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts index 05966da7..ebc74b47 100644 --- a/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts +++ b/src/app/components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component.ts @@ -36,6 +36,7 @@ export class ConfiguratorDialogEthernetHubComponent implements OnInit { ngOnInit() { this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { this.node = node; + this.numberOfPorts = this.node.ports.length; this.getConfiguration(); }) } @@ -47,27 +48,14 @@ export class ConfiguratorDialogEthernetHubComponent implements OnInit { onSaveClick() { if (this.inputForm.valid) { + this.node.properties.ports_mapping = []; for(let i=0; i { this.toasterService.success(`Node ${this.node.name} updated.`); this.onCancelClick(); diff --git a/src/app/services/node.service.ts b/src/app/services/node.service.ts index 9beb0d6f..c94bd3c5 100644 --- a/src/app/services/node.service.ts +++ b/src/app/services/node.service.ts @@ -89,7 +89,8 @@ export class NodeService { updateNode(server: Server, node: Node): Observable { return this.httpServer.put(server, `/projects/${node.project_id}/nodes/${node.node_id}`, { console_type: node.console_type, - name: node.name + name: node.name, + properties: node.properties }); } From bdf8e89dfa2f25bac215d7e0af1db3bf919fa360 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 10 Sep 2019 03:05:54 -0700 Subject: [PATCH 069/146] Support for ethernet switches --- src/app/app.module.ts | 9 ++- ...t-switches-template-details.component.html | 60 +---------------- ...net-switches-template-details.component.ts | 33 ++-------- .../common/ports/ports.component.html | 66 +++++++++++++++++++ .../common/ports/ports.component.scss | 0 .../common/ports/ports.component.spec.ts | 0 .../common/ports/ports.component.ts | 48 ++++++++++++++ .../config-action/config-action.component.ts | 3 +- .../configurator/configurator.component.scss | 20 ++++++ ...onfigurator-ethernet-switch.component.html | 35 ++++++++++ .../configurator-ethernet-switch.component.ts | 63 ++++++++++++++++++ .../vpcs/configurator-vpcs.component.ts | 2 - 12 files changed, 247 insertions(+), 92 deletions(-) create mode 100644 src/app/components/preferences/common/ports/ports.component.html create mode 100644 src/app/components/preferences/common/ports/ports.component.scss create mode 100644 src/app/components/preferences/common/ports/ports.component.spec.ts create mode 100644 src/app/components/preferences/common/ports/ports.component.ts create mode 100644 src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.html create mode 100644 src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index dc540c2f..a094098b 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -214,6 +214,8 @@ import { SuspendNodeActionComponent } from './components/project-map/context-men import { ConfigActionComponent } from './components/project-map/context-menu/actions/config-action/config-action.component'; import { ConfiguratorDialogVpcsComponent } from './components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component'; import { ConfiguratorDialogEthernetHubComponent } from './components/project-map/node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component'; +import { ConfiguratorDialogEthernetSwitchComponent } from './components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component'; +import { PortsComponent } from './components/preferences/common/ports/ports.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -355,7 +357,9 @@ if (environment.production) { SuspendNodeActionComponent, ConfigActionComponent, ConfiguratorDialogVpcsComponent, - ConfiguratorDialogEthernetHubComponent + ConfiguratorDialogEthernetHubComponent, + ConfiguratorDialogEthernetSwitchComponent, + PortsComponent ], imports: [ BrowserModule, @@ -457,7 +461,8 @@ if (environment.production) { ChangeSymbolDialogComponent, EditProjectDialogComponent, ConfiguratorDialogVpcsComponent, - ConfiguratorDialogEthernetHubComponent + ConfiguratorDialogEthernetHubComponent, + ConfiguratorDialogEthernetSwitchComponent ], bootstrap: [AppComponent] }) diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.html b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.html index f798570b..8089383b 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.html +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.html @@ -57,69 +57,13 @@ - + Port settings - - - - - - - - - - - - - - - - - - - - - - - -
Port number {{element.port_number}} VLAN {{element.vlan}} Type {{element.type}} EtherType {{element.ethertype}}

- - - - - - - - - - {{type}} - - - - - - - {{type}} - - - - +
diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.ts b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.ts index f3a33a97..6ffd3415 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.ts +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, OnInit, ViewChild } from "@angular/core"; import { ActivatedRoute, Router } from '@angular/router'; import { ServerService } from '../../../../../services/server.service'; import { Server } from '../../../../../models/server'; @@ -6,8 +6,8 @@ import { ToasterService } from '../../../../../services/toaster.service'; import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; import { BuiltInTemplatesService } from '../../../../../services/built-in-templates.service'; import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template'; -import { PortsMappingEntity } from '../../../../../models/ethernetHub/ports-mapping-enity'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; +import { PortsComponent } from '../../../common/ports/ports.component'; @Component({ @@ -16,20 +16,13 @@ import { BuiltInTemplatesConfigurationService } from '../../../../../services/bu styleUrls: ['./ethernet-switches-template-details.component.scss', '../../../preferences.component.scss'] }) export class EthernetSwitchesTemplateDetailsComponent implements OnInit { + @ViewChild(PortsComponent, {static: false}) portsComponent: PortsComponent; server: Server; ethernetSwitchTemplate: EthernetSwitchTemplate; inputForm: FormGroup; - ethernetPorts: PortsMappingEntity[] = []; - dataSource: PortsMappingEntity[] = []; - newPort: PortsMappingEntity; - isSymbolSelectionOpened: boolean = false; - categories = []; consoleTypes: string[] = []; - portTypes: string[] = []; - etherTypes: string[] = []; - displayedColumns: string[] = ['port_number', 'vlan', 'type', 'ethertype']; constructor( private route: ActivatedRoute, @@ -45,11 +38,6 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit { defaultName: new FormControl('', Validators.required), symbol: new FormControl('', Validators.required) }); - - this.newPort = { - name: '', - port_number: 0, - }; } ngOnInit() { @@ -61,8 +49,6 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit { this.getConfiguration(); this.builtInTemplatesService.getTemplate(this.server, template_id).subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => { this.ethernetSwitchTemplate = ethernetSwitchTemplate; - this.ethernetPorts = this.ethernetSwitchTemplate.ports_mapping; - this.dataSource = this.ethernetSwitchTemplate.ports_mapping; }); }); } @@ -70,18 +56,6 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit { getConfiguration() { this.categories = this.builtInTemplatesConfigurationService.getCategoriesForEthernetSwitches(); this.consoleTypes = this.builtInTemplatesConfigurationService.getConsoleTypesForEthernetSwitches(); - this.portTypes = this.builtInTemplatesConfigurationService.getPortTypesForEthernetSwitches(); - this.etherTypes = this.builtInTemplatesConfigurationService.getEtherTypesForEthernetSwitches(); - } - - onAdd() { - this.ethernetPorts.push(this.newPort); - this.dataSource = [...this.ethernetPorts]; - - this.newPort = { - name: '', - port_number: 0, - }; } goBack() { @@ -92,6 +66,7 @@ export class EthernetSwitchesTemplateDetailsComponent implements OnInit { if (this.inputForm.invalid) { this.toasterService.error(`Fill all required fields`); } else { + this.ethernetSwitchTemplate.ports_mapping = this.portsComponent.ethernetPorts; this.builtInTemplatesService.saveTemplate(this.server, this.ethernetSwitchTemplate).subscribe((ethernetSwitchTemplate: EthernetSwitchTemplate) => { this.toasterService.success("Changes saved"); }); diff --git a/src/app/components/preferences/common/ports/ports.component.html b/src/app/components/preferences/common/ports/ports.component.html new file mode 100644 index 00000000..2fcc2f00 --- /dev/null +++ b/src/app/components/preferences/common/ports/ports.component.html @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Port number {{element.port_number}} VLAN {{element.vlan}} Type {{element.type}} EtherType {{element.ethertype}} Actions + +

+ + + + + + + + + + {{type}} + + + + + + + {{type}} + + + + diff --git a/src/app/components/preferences/common/ports/ports.component.scss b/src/app/components/preferences/common/ports/ports.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/preferences/common/ports/ports.component.spec.ts b/src/app/components/preferences/common/ports/ports.component.spec.ts new file mode 100644 index 00000000..e69de29b diff --git a/src/app/components/preferences/common/ports/ports.component.ts b/src/app/components/preferences/common/ports/ports.component.ts new file mode 100644 index 00000000..efc2d393 --- /dev/null +++ b/src/app/components/preferences/common/ports/ports.component.ts @@ -0,0 +1,48 @@ +import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core"; +import { Server } from '../../../../models/server'; +import { PortsMappingEntity } from '../../../../models/ethernetHub/ports-mapping-enity'; +import { BuiltInTemplatesConfigurationService } from '../../../../services/built-in-templates-configuration.service'; + + +@Component({ + selector: 'app-ports', + templateUrl: './ports.component.html', + styleUrls: ['../../preferences.component.scss'] +}) +export class PortsComponent implements OnInit { + @Input() ethernetPorts: PortsMappingEntity[] = []; + newPort: PortsMappingEntity = { + name: '', + port_number: 0, + }; + + portTypes: string[] = []; + etherTypes: string[] = []; + displayedColumns: string[] = ['port_number', 'vlan', 'type', 'ethertype', 'action']; + + constructor( + private builtInTemplatesConfigurationService: BuiltInTemplatesConfigurationService + ) {} + + ngOnInit() { + this.getConfiguration(); + } + + getConfiguration() { + this.etherTypes = this.builtInTemplatesConfigurationService.getEtherTypesForEthernetSwitches(); + this.portTypes = this.builtInTemplatesConfigurationService.getPortTypesForEthernetSwitches(); + } + + onAdd() { + this.ethernetPorts.push(this.newPort); + + this.newPort = { + name: '', + port_number: 0, + }; + } + + delete(port: PortsMappingEntity) { + this.ethernetPorts = this.ethernetPorts.filter(n => n !== port); + } +} diff --git a/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts index 43cd50cd..c1bccc72 100644 --- a/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/config-action/config-action.component.ts @@ -4,6 +4,7 @@ import { Node } from '../../../../../cartography/models/node'; import { MatDialog, MatDialogRef } from '@angular/material'; import { ConfiguratorDialogVpcsComponent } from '../../../node-editors/configurator/vpcs/configurator-vpcs.component'; import { ConfiguratorDialogEthernetHubComponent } from '../../../node-editors/configurator/ethernet_hub/configurator-ethernet-hub.component'; +import { ConfiguratorDialogEthernetSwitchComponent } from '../../../node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component'; @Component({ @@ -27,7 +28,7 @@ export class ConfigActionComponent { } else if (this.node.node_type === 'ethernet_hub') { this.dialogRef = this.dialog.open(ConfiguratorDialogEthernetHubComponent, this.conf); } else if (this.node.node_type === 'ethernet_switch') { - + this.dialogRef = this.dialog.open(ConfiguratorDialogEthernetSwitchComponent, this.conf); } else if (this.node.node_type === 'cloud') { } else if (this.node.node_type === 'dynamips') { diff --git a/src/app/components/project-map/node-editors/configurator/configurator.component.scss b/src/app/components/project-map/node-editors/configurator/configurator.component.scss index ae93f5c6..d914988c 100644 --- a/src/app/components/project-map/node-editors/configurator/configurator.component.scss +++ b/src/app/components/project-map/node-editors/configurator/configurator.component.scss @@ -5,3 +5,23 @@ .select { width: 100%; } + +.default-content { + max-height: 400px; + overflow-y: scroll; + scrollbar-color: darkgrey #263238; + scrollbar-width: thin; +} + +::-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/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.html b/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.html new file mode 100644 index 00000000..900d1abd --- /dev/null +++ b/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.html @@ -0,0 +1,35 @@ +

Configurator for node {{node.name}}

+ + + +
+ + +
diff --git a/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.ts b/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.ts new file mode 100644 index 00000000..41e27483 --- /dev/null +++ b/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.ts @@ -0,0 +1,63 @@ +import { Component, OnInit, Input, ViewChild } from "@angular/core"; +import { FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms'; +import { Node } from '../../../../../cartography/models/node'; +import { Server } from '../../../../../models/server'; +import { NodeService } from '../../../../../services/node.service'; +import { ToasterService } from '../../../../../services/toaster.service'; +import { MatDialogRef } from '@angular/material'; +import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; +import { PortsComponent } from '../../../../../components/preferences/common/ports/ports.component'; + + +@Component({ + selector: 'app-configurator-ethernet-switch', + templateUrl: './configurator-ethernet-switch.component.html', + styleUrls: ['../configurator.component.scss'] +}) +export class ConfiguratorDialogEthernetSwitchComponent implements OnInit { + @ViewChild(PortsComponent, {static: false}) portsComponent: PortsComponent; + server: Server; + node: Node; + + inputForm: FormGroup; + consoleTypes: string[] = []; + + constructor( + public dialogRef: MatDialogRef, + public nodeService: NodeService, + private toasterService: ToasterService, + private formBuilder: FormBuilder, + private ethernetSwitchesConfigurationService: BuiltInTemplatesConfigurationService + ) { + this.inputForm = this.formBuilder.group({ + name: new FormControl('', Validators.required) + }); + } + + ngOnInit() { + this.nodeService.getNode(this.server, this.node).subscribe((node: Node) => { + this.node = node; + this.getConfiguration(); + }) + } + + getConfiguration() { + this.consoleTypes = this.ethernetSwitchesConfigurationService.getConsoleTypesForEthernetSwitches(); + } + + onSaveClick() { + if (this.inputForm.valid) { + this.node.properties.ports_mapping = this.portsComponent.ethernetPorts; + this.nodeService.updateNode(this.server, this.node).subscribe(() => { + this.toasterService.success(`Node ${this.node.name} updated.`); + this.onCancelClick(); + }); + } else { + this.toasterService.error(`Fill all required fields.`); + } + } + + onCancelClick() { + this.dialogRef.close(); + } +} diff --git a/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts index 042e60fd..0ff0526b 100644 --- a/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts +++ b/src/app/components/project-map/node-editors/configurator/vpcs/configurator-vpcs.component.ts @@ -19,7 +19,6 @@ export class ConfiguratorDialogVpcsComponent implements OnInit { inputForm: FormGroup; consoleTypes: string[] = []; - categories = []; constructor( public dialogRef: MatDialogRef, @@ -42,7 +41,6 @@ export class ConfiguratorDialogVpcsComponent implements OnInit { getConfiguration() { this.consoleTypes = this.vpcsConfigurationService.getConsoleTypes(); - this.categories = this.vpcsConfigurationService.getCategories(); } onSaveClick() { From 32dc9e3c0750343ce9b78f9111c8865e9fde8958 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 10 Sep 2019 03:57:46 -0700 Subject: [PATCH 070/146] Update ethernet-switches-template-details.component.spec.ts --- .../ethernet-switches-template-details.component.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.spec.ts b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.spec.ts index 108d2f91..3eeef4f5 100644 --- a/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.spec.ts +++ b/src/app/components/preferences/built-in/ethernet-switches/ethernet-switches-template-details/ethernet-switches-template-details.component.spec.ts @@ -17,6 +17,7 @@ import { BuiltInTemplatesService } from '../../../../../services/built-in-templa import { EthernetSwitchTemplate } from '../../../../../models/templates/ethernet-switch-template'; import { EthernetSwitchesTemplateDetailsComponent } from './ethernet-switches-template-details.component'; import { BuiltInTemplatesConfigurationService } from '../../../../../services/built-in-templates-configuration.service'; +import { PortsComponent } from '../../../common/ports/ports.component'; export class MockedBuiltInTemplatesService { public getTemplate(server: Server, template_id: string) { @@ -68,6 +69,7 @@ describe('EthernetSwitchesTemplateDetailsComponent', () => { it('should call save template', () => { spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate)); + component.portsComponent = {ethernetPorts: []} as PortsComponent; component.inputForm.controls['templateName'].setValue('template name'); component.inputForm.controls['defaultName'].setValue('default name'); component.inputForm.controls['symbol'].setValue('symbol'); @@ -102,7 +104,7 @@ describe('EthernetSwitchesTemplateDetailsComponent', () => { expect(mockedBuiltInTemplatesService.saveTemplate).not.toHaveBeenCalled(); }); - it('should call save template when symbol path is empty', () => { + it('should not call save template when symbol path is empty', () => { spyOn(mockedBuiltInTemplatesService, 'saveTemplate').and.returnValue(of({} as EthernetSwitchTemplate)); component.inputForm.controls['templateName'].setValue('template name'); component.inputForm.controls['defaultName'].setValue('default name'); From 9ab7616d891cf4f7941510abfe0ed1df355f5ab0 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Tue, 10 Sep 2019 04:07:08 -0700 Subject: [PATCH 071/146] Fix for configurator name --- .../configurator-ethernet-switch.component.html | 2 +- .../ethernet-switch/configurator-ethernet-switch.component.ts | 3 ++- .../ethernet_hub/configurator-ethernet-hub.component.html | 2 +- .../ethernet_hub/configurator-ethernet-hub.component.ts | 2 ++ .../configurator/vpcs/configurator-vpcs.component.html | 2 +- .../configurator/vpcs/configurator-vpcs.component.ts | 3 ++- 6 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.html b/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.html index 900d1abd..826a0154 100644 --- a/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.html +++ b/src/app/components/project-map/node-editors/configurator/ethernet-switch/configurator-ethernet-switch.component.html @@ -1,4 +1,4 @@ -

Configurator for node {{node.name}}

+

Configurator for node {{name}}