From fb1a64fe5d56bff965d3bae762d3cf18e6042ca5 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Thu, 21 Feb 2019 04:03:14 -0800 Subject: [PATCH 1/4] Ability to delete project added --- src/app/components/projects/projects.component.html | 6 +++--- .../components/projects/projects.component.spec.ts | 13 ++++++++++++- src/app/services/project.service.spec.ts | 6 +++++- 3 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/app/components/projects/projects.component.html b/src/app/components/projects/projects.component.html index 46248aa1..945b2663 100644 --- a/src/app/components/projects/projects.component.html +++ b/src/app/components/projects/projects.component.html @@ -43,9 +43,9 @@ - - - + diff --git a/src/app/components/projects/projects.component.spec.ts b/src/app/components/projects/projects.component.spec.ts index 976b948a..29e82cec 100644 --- a/src/app/components/projects/projects.component.spec.ts +++ b/src/app/components/projects/projects.component.spec.ts @@ -25,6 +25,7 @@ describe('ProjectsComponent', () => { let serverService: ServerService; let server: Server; let progressService: ProgressService; + let mockedProjectService: MockedProjectService = new MockedProjectService(); beforeEach(async(() => { TestBed.configureTestingModule({ @@ -39,7 +40,7 @@ describe('ProjectsComponent', () => { ], providers: [ { provide: ServerService, useClass: MockedServerService }, - { provide: ProjectService, useClass: MockedProjectService }, + { provide: ProjectService, useValue: mockedProjectService }, { provide: SettingsService, useClass: MockedSettingsService }, ProgressService ], @@ -74,6 +75,16 @@ describe('ProjectsComponent', () => { expect(component).toBeTruthy(); }); + it('should remove item after delete action', () => { + spyOn(mockedProjectService, 'delete').and.returnValue(of()); + let project = new Project(); + project.project_id = '1'; + + component.delete(project); + + expect(mockedProjectService.delete).toHaveBeenCalled(); + }); + describe('ProjectComponent open', () => { let project: Project; diff --git a/src/app/services/project.service.spec.ts b/src/app/services/project.service.spec.ts index 69d47f14..2752923a 100644 --- a/src/app/services/project.service.spec.ts +++ b/src/app/services/project.service.spec.ts @@ -8,9 +8,9 @@ import { getTestServer } from './testing'; import { ProjectService } from './project.service'; import { SettingsService } from './settings.service'; import { MockedSettingsService } from './settings.service.spec'; -import { Observable, of } from 'rxjs'; import { Project } from '../models/project'; import { AppTestingModule } from '../testing/app-testing/app-testing.module'; +import { of } from 'rxjs'; /** * Mocks ProjectsService so it's not based on settings @@ -37,6 +37,10 @@ export class MockedProjectService { links(server: Server, project_id: string) { return of([]); } + + delete(server: Server, project_id: string) { + return of(project_id); + } } describe('ProjectService', () => { From f553c7a2002a888502bf4318950cd5d705c0a53e Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Fri, 22 Feb 2019 00:17:00 -0800 Subject: [PATCH 2/4] Deletion supported in context menu --- src/app/app.module.ts | 2 + .../delete-action.component.html | 4 ++ .../delete-action.component.spec.ts | 66 +++++++++++++++++++ .../delete-action/delete-action.component.ts | 41 ++++++++++++ .../context-menu/context-menu.component.html | 6 ++ .../project-map/project-map.component.spec.ts | 4 ++ 6 files changed, 123 insertions(+) create mode 100644 src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts create mode 100644 src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index fdbce4fe..7cecaf5f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -164,6 +164,7 @@ import { SymbolsMenuComponent } from './components/preferences/common/symbols-me import { SearchFilter } from './filters/searchFilter.pipe'; import { RecentlyOpenedProjectService } from './services/recentlyOpenedProject.service'; import { ServerManagementService } from './services/server-management.service'; +import { DeleteActionComponent } from './components/project-map/context-menu/actions/delete-action/delete-action.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -198,6 +199,7 @@ if (environment.production) { MoveLayerUpActionComponent, EditStyleActionComponent, EditTextActionComponent, + DeleteActionComponent, ProjectMapShortcutsComponent, SettingsComponent, PreferencesComponent, diff --git a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.html b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.html new file mode 100644 index 00000000..a0819a60 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts new file mode 100644 index 00000000..558026cb --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts @@ -0,0 +1,66 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { DeleteActionComponent } from './delete-action.component'; +import { MatIconModule, MatMenuModule } from '@angular/material'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; +import { DrawingsDataSource } from '../../../../../cartography/datasources/drawings-datasource'; +import { NodeService } from '../../../../../services/node.service'; +import { DrawingService } from '../../../../../services/drawing.service'; +import { MockedDrawingService, MockedNodeService } from '../../../project-map.component.spec'; +import { Node } from '../../../../../cartography/models/node'; +import { Drawing } from '../../../../../cartography/models/drawing'; +import { of } from 'rxjs'; + +describe('DeleteActionComponent', () => { + let component: DeleteActionComponent; + let fixture: ComponentFixture; + let mockedNodeService: MockedNodeService = new MockedNodeService(); + let mockedDrawingService: MockedDrawingService = new MockedDrawingService(); + + beforeEach(async(() => { + TestBed.configureTestingModule({ + imports: [MatIconModule, MatMenuModule, NoopAnimationsModule], + providers: [ + { provide: NodesDataSource, useClass: NodesDataSource }, + { provide: DrawingsDataSource, useClass: DrawingsDataSource }, + { provide: NodeService, useValue: mockedNodeService }, + { provide: DrawingService, useValue: mockedDrawingService }, + ], + declarations: [DeleteActionComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DeleteActionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should call delete action in drawing service', () => { + let node = { node_id: '1' } as Node; + component.nodes = [node]; + let drawing = { drawing_id: '1' } as Drawing; + component.drawings = [drawing]; + spyOn(mockedDrawingService, 'delete').and.returnValue(of()); + + component.delete(); + + expect(mockedDrawingService.delete).toHaveBeenCalled(); + }); + + it('should call delete action in node service', () => { + let node = { node_id: '1' } as Node; + component.nodes = [node]; + let drawing = { drawing_id: '1' } as Drawing; + component.drawings = [drawing]; + spyOn(mockedNodeService, 'delete').and.returnValue(of()); + + component.delete(); + + expect(mockedNodeService.delete).toHaveBeenCalled(); + }); +}); diff --git a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts new file mode 100644 index 00000000..de466ac3 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts @@ -0,0 +1,41 @@ +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-delete-action', + templateUrl: './delete-action.component.html' +}) +export class DeleteActionComponent 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() {} + + delete() { + this.nodes.forEach((node) => { + this.nodesDataSource.remove(node); + + this.nodeService.delete(this.server, node).subscribe((node: Node) => {}); + }); + + this.drawings.forEach((drawing) => { + this.drawingsDataSource.remove(drawing); + + this.drawingService.delete(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 3146bbbc..3c7e6b37 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 @@ -26,5 +26,11 @@ [nodes]="nodes" [drawings]="drawings" > + 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 b0ecc3d0..27574d81 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -53,6 +53,10 @@ export class MockedNodeService { updatePosition(): Observable { return of(this.node); } + + delete(server: Server, node: Node) { + return of(); + } } export class MockedDrawingService { From c063620cbfb1fa29c6e55bde0d625d765c008895 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 25 Feb 2019 01:42:39 -0800 Subject: [PATCH 3/4] Support for client offset in scrolled area --- .../drawing-adding.component.ts | 4 +-- .../text-editor/text-editor.component.ts | 8 +++--- src/app/cartography/widgets/drawings.ts | 28 +++++++++---------- .../delete-action/delete-action.component.ts | 14 +++++++++- .../context-menu/context-menu.component.html | 5 ++-- .../context-menu/context-menu.component.ts | 5 +++- .../draw-link-tool.component.html | 2 +- .../draw-link-tool.component.ts | 11 ++++++-- .../node-select-interface.component.html | 2 +- .../node-select-interface.component.ts | 28 ++++++++++++++++++- .../project-map/project-map.component.html | 2 +- .../project-map/project-map.component.ts | 12 ++++++-- src/app/services/link.service.ts | 5 ++++ 13 files changed, 92 insertions(+), 34 deletions(-) diff --git a/src/app/cartography/components/drawing-adding/drawing-adding.component.ts b/src/app/cartography/components/drawing-adding/drawing-adding.component.ts index c4cb1e6c..4553ae81 100644 --- a/src/app/cartography/components/drawing-adding/drawing-adding.component.ts +++ b/src/app/cartography/components/drawing-adding/drawing-adding.component.ts @@ -25,8 +25,8 @@ export class DrawingAddingComponent implements OnInit, OnDestroy { activate() { let listener = (event: MouseEvent) => { - let x = event.clientX - this.context.getZeroZeroTransformationPoint().x; - let y = event.clientY - this.context.getZeroZeroTransformationPoint().y; + let x = event.pageX - this.context.getZeroZeroTransformationPoint().x; + let y = event.pageY - this.context.getZeroZeroTransformationPoint().y; this.drawingsEventSource.pointToAddSelected.emit(new AddedDataEvent(x, y)); this.deactivate(); diff --git a/src/app/cartography/components/text-editor/text-editor.component.ts b/src/app/cartography/components/text-editor/text-editor.component.ts index f8b9fa8e..10549b48 100644 --- a/src/app/cartography/components/text-editor/text-editor.component.ts +++ b/src/app/cartography/components/text-editor/text-editor.component.ts @@ -45,8 +45,8 @@ export class TextEditorComponent implements OnInit, OnDestroy { activateTextAdding() { let addTextListener = (event: MouseEvent) => { - this.leftPosition = event.clientX.toString() + 'px'; - this.topPosition = (event.clientY + window.pageYOffset).toString() + 'px'; + this.leftPosition = event.pageX.toString() + 'px'; + this.topPosition = event.pageY.toString() + 'px'; this.renderer.setStyle(this.temporaryTextElement.nativeElement, 'display', 'initial'); this.temporaryTextElement.nativeElement.focus(); @@ -54,8 +54,8 @@ export class TextEditorComponent implements OnInit, OnDestroy { this.drawingsEventSource.textAdded.emit( new TextAddedDataEvent( this.temporaryTextElement.nativeElement.innerText.replace(/\n$/, ''), - event.clientX, - event.clientY + event.pageX, + event.pageY ) ); this.deactivateTextAdding(); diff --git a/src/app/cartography/widgets/drawings.ts b/src/app/cartography/widgets/drawings.ts index 819bb828..aa240980 100644 --- a/src/app/cartography/widgets/drawings.ts +++ b/src/app/cartography/widgets/drawings.ts @@ -111,15 +111,15 @@ export class DrawingsWidget implements Widget { } } } else { - dy = y - (evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y); - y = evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y; + dy = y - (evt.sourceEvent.pageY - this.context.getZeroZeroTransformationPoint().y); + y = evt.sourceEvent.pageY - this.context.getZeroZeroTransformationPoint().y; if (datum.element.height + dy < 0) { isReflectedVertical = false; y = topEdge; datum.element.height = Math.abs(datum.element.height + evt.dy); } else { - datum.y = evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y; + datum.y = evt.sourceEvent.pageY - this.context.getZeroZeroTransformationPoint().y; datum.element.height += dy; if (datum.element instanceof EllipseElement) { (datum.element as EllipseElement).cy = @@ -143,7 +143,7 @@ export class DrawingsWidget implements Widget { let top = drag() .on('start', (datum: MapDrawing) => { - y = event.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y; + y = event.sourceEvent.pageY - this.context.getZeroZeroTransformationPoint().y; bottomEdge = y + datum.element.height; document.body.style.cursor = 'ns-resize'; }) @@ -151,15 +151,15 @@ export class DrawingsWidget implements Widget { const evt = event; if (!isReflectedVertical) { - dy = y - (evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y); - y = evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y; + dy = y - (evt.sourceEvent.pageY - this.context.getZeroZeroTransformationPoint().y); + y = evt.sourceEvent.pageY - this.context.getZeroZeroTransformationPoint().y; if (datum.element.height + dy < 0) { y = bottomEdge; isReflectedVertical = true; datum.element.height = Math.abs(datum.element.height + evt.dy); } else { - datum.y = evt.sourceEvent.clientY - this.context.getZeroZeroTransformationPoint().y; + datum.y = evt.sourceEvent.pageY - this.context.getZeroZeroTransformationPoint().y; datum.element.height += dy; if (datum.element instanceof EllipseElement) { (datum.element as EllipseElement).cy = @@ -207,7 +207,7 @@ export class DrawingsWidget implements Widget { let isReflectedHorizontal: boolean = false; let right = drag() .on('start', (datum: MapDrawing) => { - x = event.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x; + x = event.sourceEvent.pageX - this.context.getZeroZeroTransformationPoint().x; leftEdge = x + datum.element.width; document.body.style.cursor = 'ew-resize'; }) @@ -215,15 +215,15 @@ export class DrawingsWidget implements Widget { const evt = event; if (!isReflectedHorizontal) { - dx = x - (evt.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x); - x = evt.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x; + dx = x - (evt.sourceEvent.pageX - this.context.getZeroZeroTransformationPoint().x); + x = evt.sourceEvent.pageX - this.context.getZeroZeroTransformationPoint().x; if (datum.element.width + dx < 0) { x = leftEdge; isReflectedHorizontal = true; datum.element.width = Math.abs(datum.element.width + evt.dx); } else { - datum.x = evt.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x; + datum.x = evt.sourceEvent.pageX - this.context.getZeroZeroTransformationPoint().x; datum.element.width += dx; if (datum.element instanceof EllipseElement) { (datum.element as EllipseElement).cx = @@ -290,15 +290,15 @@ export class DrawingsWidget implements Widget { datum.element.width = datum.element.width + evt.dx < 0 ? 1 : (datum.element.width += evt.dx); } } else { - dx = x - (evt.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x); - x = evt.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x; + dx = x - (evt.sourceEvent.pageX - this.context.getZeroZeroTransformationPoint().x); + x = evt.sourceEvent.pageX - this.context.getZeroZeroTransformationPoint().x; if (datum.element.width + dx < 0) { x = rightEdge; isReflectedHorizontal = false; datum.element.width = Math.abs(datum.element.width + evt.dx); } else { - datum.x = evt.sourceEvent.clientX - this.context.getZeroZeroTransformationPoint().x; + datum.x = evt.sourceEvent.pageX - this.context.getZeroZeroTransformationPoint().x; datum.element.width += dx; if (datum.element instanceof EllipseElement) { (datum.element as EllipseElement).cx = diff --git a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts index de466ac3..26629dfc 100644 --- a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts +++ b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.ts @@ -6,6 +6,9 @@ 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'; +import { Link } from '../../../../../models/link'; +import { LinkService } from '../../../../../services/link.service'; +import { LinksDataSource } from '../../../../../cartography/datasources/links-datasource'; @Component({ selector: 'app-delete-action', @@ -15,12 +18,15 @@ export class DeleteActionComponent implements OnInit { @Input() server: Server; @Input() nodes: Node[]; @Input() drawings: Drawing[]; + @Input() links: Link[]; constructor( private nodesDataSource: NodesDataSource, private drawingsDataSource: DrawingsDataSource, + private linksDataSource: LinksDataSource, private nodeService: NodeService, - private drawingService: DrawingService + private drawingService: DrawingService, + private linkService: LinkService ) {} ngOnInit() {} @@ -37,5 +43,11 @@ export class DeleteActionComponent implements OnInit { this.drawingService.delete(this.server, drawing).subscribe((drawing: Drawing) => {}); }); + + this.links.forEach((link) => { + this.linksDataSource.remove(link); + + this.linkService.deleteLink(this.server, link).subscribe(() => {}); + }); } } 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 3c7e6b37..0060c9f1 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 @@ -15,13 +15,13 @@ [drawing]="drawings[0]" > diff --git a/src/app/components/project-map/context-menu/context-menu.component.ts b/src/app/components/project-map/context-menu/context-menu.component.ts index 45da4d2f..ed34f146 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.ts +++ b/src/app/components/project-map/context-menu/context-menu.component.ts @@ -8,6 +8,7 @@ import { ProjectService } from '../../../services/project.service'; import { Drawing } from '../../../cartography/models/drawing'; import { TextElement } from '../../../cartography/models/drawings/text-element'; import { Label } from '../../../cartography/models/label'; +import { Link } from '../../../models/link'; @Component({ @@ -27,6 +28,7 @@ export class ContextMenuComponent implements OnInit { drawings: Drawing[] = []; nodes: Node[] = []; labels: Label[] = []; + links: Link[] = []; hasTextCapabilities: boolean = false; @@ -74,12 +76,13 @@ export class ContextMenuComponent implements OnInit { this.contextMenu.openMenu(); } - public openMenuForListOfElements(drawings: Drawing[], nodes: Node[], labels: Label[], top: number, left: number) { + public openMenuForListOfElements(drawings: Drawing[], nodes: Node[], labels: Label[], links: Link[], top: number, left: number) { this.resetCapabilities(); this.drawings = drawings; this.nodes = nodes; this.labels = labels; + this.links = links; this.setPosition(top, left); this.contextMenu.openMenu(); diff --git a/src/app/components/project-map/draw-link-tool/draw-link-tool.component.html b/src/app/components/project-map/draw-link-tool/draw-link-tool.component.html index 9bbaf0d3..72be0c62 100644 --- a/src/app/components/project-map/draw-link-tool/draw-link-tool.component.html +++ b/src/app/components/project-map/draw-link-tool/draw-link-tool.component.html @@ -1 +1 @@ - + diff --git a/src/app/components/project-map/draw-link-tool/draw-link-tool.component.ts b/src/app/components/project-map/draw-link-tool/draw-link-tool.component.ts index 55cab9cf..63adb2f9 100644 --- a/src/app/components/project-map/draw-link-tool/draw-link-tool.component.ts +++ b/src/app/components/project-map/draw-link-tool/draw-link-tool.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, ViewChild } from '@angular/core'; +import { Component, OnInit, OnDestroy, ViewChild, Input } from '@angular/core'; import { Subscription } from 'rxjs'; import { NodeSelectInterfaceComponent } from '../../../components/project-map/node-select-interface/node-select-interface.component'; import { DrawingLineWidget } from '../../../cartography/widgets/drawing-line'; @@ -7,6 +7,8 @@ import { LinksEventSource } from '../../../cartography/events/links-event-source import { MapNode } from '../../../cartography/models/map/map-node'; import { MapPort } from '../../../cartography/models/map/map-port'; import { MapLinkCreated } from '../../../cartography/events/links'; +import { Link } from '../../../models/link'; +import { MapNodeToNodeConverter } from '../../../cartography/converters/map/map-node-to-node-converter'; @Component({ selector: 'app-draw-link-tool', @@ -14,6 +16,7 @@ import { MapLinkCreated } from '../../../cartography/events/links'; styleUrls: ['./draw-link-tool.component.scss'] }) export class DrawLinkToolComponent implements OnInit, OnDestroy { + @Input() links: Link[]; @ViewChild(NodeSelectInterfaceComponent) nodeSelectInterfaceMenu: NodeSelectInterfaceComponent; private nodeClicked$: Subscription; @@ -21,12 +24,14 @@ export class DrawLinkToolComponent implements OnInit, OnDestroy { constructor( private drawingLineTool: DrawingLineWidget, private nodesEventSource: NodesEventSource, - private linksEventSource: LinksEventSource + private linksEventSource: LinksEventSource, + private mapNodeToNode: MapNodeToNodeConverter ) {} ngOnInit() { this.nodeClicked$ = this.nodesEventSource.clicked.subscribe(clickedEvent => { - this.nodeSelectInterfaceMenu.open(clickedEvent.datum, clickedEvent.y, clickedEvent.x); + let node = this.mapNodeToNode.convert(clickedEvent.datum); + this.nodeSelectInterfaceMenu.open(node, clickedEvent.y, clickedEvent.x); }); } 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 b4321348..33d07113 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,7 +1,7 @@
- diff --git a/src/app/components/project-map/node-select-interface/node-select-interface.component.ts b/src/app/components/project-map/node-select-interface/node-select-interface.component.ts index fd5daace..4253fc3c 100644 --- a/src/app/components/project-map/node-select-interface/node-select-interface.component.ts +++ b/src/app/components/project-map/node-select-interface/node-select-interface.component.ts @@ -3,6 +3,8 @@ import { MatMenuTrigger } from '@angular/material'; import { DomSanitizer } from '@angular/platform-browser'; import { Node } from '../../../cartography/models/node'; import { Port } from '../../../models/port'; +import { Link } from '../../../models/link'; +import { LinkNode } from '../../../models/link-node'; @Component({ selector: 'app-node-select-interface', @@ -10,6 +12,7 @@ import { Port } from '../../../models/port'; styleUrls: ['./node-select-interface.component.scss'] }) export class NodeSelectInterfaceComponent implements OnInit { + @Input() links: Link[]; @Output() onChooseInterface = new EventEmitter(); @ViewChild(MatMenuTrigger) contextMenu: MatMenuTrigger; @@ -17,8 +20,12 @@ export class NodeSelectInterfaceComponent implements OnInit { protected topPosition; protected leftPosition; public node: Node; + public availablePorts: Port[]; - constructor(private sanitizer: DomSanitizer, private changeDetector: ChangeDetectorRef) {} + constructor( + private sanitizer: DomSanitizer, + private changeDetector: ChangeDetectorRef + ) {} ngOnInit() { this.setPosition(0, 0); @@ -32,10 +39,29 @@ export class NodeSelectInterfaceComponent implements OnInit { public open(node: Node, top: number, left: number) { this.node = node; + this.filterNodePorts(); this.setPosition(top, left); this.contextMenu.openMenu(); } + public filterNodePorts() { + let linkNodes: LinkNode[] = []; + this.links.forEach((link: Link) => { + link.nodes.forEach((linkNode: LinkNode) => { + if(linkNode.node_id === this.node.node_id) { + linkNodes.push(linkNode); + } + }); + }); + + this.availablePorts = []; + this.node.ports.forEach((port: Port) => { + if(linkNodes.filter((linkNode: LinkNode) => linkNode.port_number === port.port_number).length === 0){ + this.availablePorts.push(port); + } + }); + } + public chooseInterface(port: Port) { this.onChooseInterface.emit({ node: this.node, diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index 4dbbede1..c79bad23 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -141,7 +141,7 @@ - + { const node = this.mapNodeToNode.convert(eventNode.node); - this.contextMenu.openMenuForNode(node, eventNode.event.clientY, eventNode.event.clientX); + this.contextMenu.openMenuForNode(node, eventNode.event.pageY, eventNode.event.pageX); }); const onDrawingContextMenu = this.drawingsWidget.onContextMenu.subscribe((eventDrawing: DrawingContextMenu) => { const drawing = this.mapDrawingToDrawing.convert(eventDrawing.drawing); - this.contextMenu.openMenuForDrawing(drawing, eventDrawing.event.clientY, eventDrawing.event.clientX); + this.contextMenu.openMenuForDrawing(drawing, eventDrawing.event.pageY, eventDrawing.event.pageX); }); const onContextMenu = this.selectionTool.contextMenuOpened.subscribe((event) => { @@ -233,6 +236,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { let drawings: Drawing[] = []; let nodes: Node[] = []; let labels: Label[] = []; + let links: Link[] = []; selectedItems.forEach((elem) => { if (elem instanceof MapDrawing) { @@ -241,10 +245,12 @@ export class ProjectMapComponent implements OnInit, OnDestroy { nodes.push(this.mapNodeToNode.convert(elem)); } else if (elem instanceof MapLabel) { labels.push(this.mapLabelToLabel.convert(elem)); + } else if (elem instanceof MapLink) { + links.push(this.mapLinkToLink.convert(elem)) } }); - this.contextMenu.openMenuForListOfElements(drawings, nodes, labels, event.clientY, event.clientX); + this.contextMenu.openMenuForListOfElements(drawings, nodes, labels, links, event.pageY, event.pageX); }); this.subscriptions.push(onNodeContextMenu); diff --git a/src/app/services/link.service.ts b/src/app/services/link.service.ts index 479697a2..37d2ebfa 100644 --- a/src/app/services/link.service.ts +++ b/src/app/services/link.service.ts @@ -12,6 +12,11 @@ import { LinkNode } from '../models/link-node'; export class LinkService { constructor(private httpServer: HttpServer) {} + deleteLink(server: Server, link: Link) { + //return this.httpServer.delete(server, `/compute/projects/${link.project_id}/vpcs/nodes/${link.nodes[0].node_id}/adapters/0/ports/0/nio`) + return this.httpServer.delete(server, `/projects/${link.project_id}/links/${link.link_id}`) + } + createLink(server: Server, source_node: Node, source_port: Port, target_node: Node, target_port: Port) { return this.httpServer.post(server, `/projects/${source_node.project_id}/links`, { nodes: [ From 1535166837ec693422e898c8856845eb8a8dbf1a Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 25 Feb 2019 03:20:21 -0800 Subject: [PATCH 4/4] Unit tests added --- .../delete-action.component.spec.ts | 22 ++++++++++++++++++- .../context-menu.component.spec.ts | 2 +- .../project-map/project-map.component.spec.ts | 7 ++++++ 3 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts index 558026cb..ec6a8f5c 100644 --- a/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts +++ b/src/app/components/project-map/context-menu/actions/delete-action/delete-action.component.spec.ts @@ -6,16 +6,20 @@ import { NodesDataSource } from '../../../../../cartography/datasources/nodes-da import { DrawingsDataSource } from '../../../../../cartography/datasources/drawings-datasource'; import { NodeService } from '../../../../../services/node.service'; import { DrawingService } from '../../../../../services/drawing.service'; -import { MockedDrawingService, MockedNodeService } from '../../../project-map.component.spec'; +import { MockedDrawingService, MockedNodeService, MockedLinkService } from '../../../project-map.component.spec'; import { Node } from '../../../../../cartography/models/node'; import { Drawing } from '../../../../../cartography/models/drawing'; import { of } from 'rxjs'; +import { LinksDataSource } from '../../../../../cartography/datasources/links-datasource'; +import { LinkService } from '../../../../../services/link.service'; +import { Link } from '../../../../../models/link'; describe('DeleteActionComponent', () => { let component: DeleteActionComponent; let fixture: ComponentFixture; let mockedNodeService: MockedNodeService = new MockedNodeService(); let mockedDrawingService: MockedDrawingService = new MockedDrawingService(); + let mockedLinkService: MockedLinkService = new MockedLinkService(); beforeEach(async(() => { TestBed.configureTestingModule({ @@ -23,8 +27,10 @@ describe('DeleteActionComponent', () => { providers: [ { provide: NodesDataSource, useClass: NodesDataSource }, { provide: DrawingsDataSource, useClass: DrawingsDataSource }, + { provide: LinksDataSource, useClass: LinksDataSource }, { provide: NodeService, useValue: mockedNodeService }, { provide: DrawingService, useValue: mockedDrawingService }, + { provide: LinkService, useValue: mockedLinkService } ], declarations: [DeleteActionComponent] }).compileComponents(); @@ -45,6 +51,7 @@ describe('DeleteActionComponent', () => { component.nodes = [node]; let drawing = { drawing_id: '1' } as Drawing; component.drawings = [drawing]; + component.links = []; spyOn(mockedDrawingService, 'delete').and.returnValue(of()); component.delete(); @@ -57,10 +64,23 @@ describe('DeleteActionComponent', () => { component.nodes = [node]; let drawing = { drawing_id: '1' } as Drawing; component.drawings = [drawing]; + component.links = []; spyOn(mockedNodeService, 'delete').and.returnValue(of()); component.delete(); expect(mockedNodeService.delete).toHaveBeenCalled(); }); + + it('should call delete action in link service', () => { + component.nodes = []; + component.drawings = []; + let link = { link_id: '1', project_id: '1' } as Link; + component.links = [link]; + spyOn(mockedLinkService, 'deleteLink').and.returnValue(of()); + + component.delete(); + + expect(mockedLinkService.deleteLink).toHaveBeenCalled(); + }); }); diff --git a/src/app/components/project-map/context-menu/context-menu.component.spec.ts b/src/app/components/project-map/context-menu/context-menu.component.spec.ts index 30c60aef..7832fb7e 100644 --- a/src/app/components/project-map/context-menu/context-menu.component.spec.ts +++ b/src/app/components/project-map/context-menu/context-menu.component.spec.ts @@ -70,7 +70,7 @@ describe('ContextMenuComponent', () => { component.contextMenu = { openMenu() {} } as MatMenuTrigger; var spy = spyOn(component, 'resetCapabilities'); spyOn(component, 'setPosition').and.callFake(() => {}); - component.openMenuForListOfElements([], [], [], 0, 0); + component.openMenuForListOfElements([], [], [], [], 0, 0); expect(spy.calls.any()).toBeTruthy(); }); 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 27574d81..f5805c56 100644 --- a/src/app/components/project-map/project-map.component.spec.ts +++ b/src/app/components/project-map/project-map.component.spec.ts @@ -37,6 +37,8 @@ import { MapLabelToLabelConverter } from '../../cartography/converters/map/map-l import { SelectionManager } from '../../cartography/managers/selection-manager'; import { SelectionTool } from '../../cartography/tools/selection-tool'; import { RecentlyOpenedProjectService } from '../../services/recentlyOpenedProject.service'; +import { MapLinkToLinkConverter } from '../../cartography/converters/map/map-link-to-link-converter'; +import { Link } from '../../models/link'; export class MockedProgressService { public activate() {} @@ -91,6 +93,10 @@ export class MockedDrawingService { export class MockedLinkService { constructor() {} + deleteLink(_server: Server, link: Link){ + return of({}) + } + createLink() { return of({}); } @@ -148,6 +154,7 @@ describe('ProjectMapComponent', () => { { provide: MapNodeToNodeConverter }, { provide: MapDrawingToDrawingConverter }, { provide: MapLabelToLabelConverter }, + { provide: MapLinkToLinkConverter }, { provide: NodesDataSource }, { provide: LinksDataSource }, { provide: DrawingsDataSource, useValue: drawingsDataSource },