From 67741ca6014086041fa7562a9850691a47c1a9e4 Mon Sep 17 00:00:00 2001 From: Piotr Pekala Date: Mon, 17 Jun 2019 06:50:26 -0700 Subject: [PATCH] Duplication option added --- src/app/app.module.ts | 2 + .../duplicate-action.component.html | 4 + .../duplicate-action.component.spec.ts | 78 +++++++++++++++++++ .../duplicate-action.component.ts | 41 ++++++++++ .../context-menu/context-menu.component.html | 6 ++ .../project-map/project-map.component.spec.ts | 8 ++ src/app/services/drawing.service.spec.ts | 23 ++++++ src/app/services/drawing.service.ts | 10 +++ src/app/services/node.service.spec.ts | 11 +++ src/app/services/node.service.ts | 9 +++ 10 files changed, 192 insertions(+) create mode 100644 src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.html create mode 100644 src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.spec.ts create mode 100644 src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index be596dd9..f79f122f 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -186,6 +186,7 @@ import { DefaultConsoleService } from './services/settings/default-console.servi import { NodeCreatedLabelStylesFixer } from './components/project-map/helpers/node-created-label-styles-fixer'; import { NonNegativeValidator } from './validators/non-negative-validator'; import { RotationValidator } from './validators/rotation-validator'; +import { DuplicateActionComponent } from './components/project-map/context-menu/actions/duplicate-action/duplicate-action.component'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -220,6 +221,7 @@ if (environment.production) { EditStyleActionComponent, EditTextActionComponent, DeleteActionComponent, + DuplicateActionComponent, PacketFiltersActionComponent, StartCaptureActionComponent, StopCaptureActionComponent, diff --git a/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.html b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.html new file mode 100644 index 00000000..a07e95df --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.html @@ -0,0 +1,4 @@ + diff --git a/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.spec.ts b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.spec.ts new file mode 100644 index 00000000..b9fe197d --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.spec.ts @@ -0,0 +1,78 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +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'; +import { DuplicateActionComponent } from './duplicate-action.component'; + +describe('DuplicateActionComponent', () => { + let component: DuplicateActionComponent; + 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: [DuplicateActionComponent] + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(DuplicateActionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should call duplicate action in drawing service', () => { + let drawing = { drawing_id: '1' } as Drawing; + component.drawings = [drawing]; + component.nodes = []; + spyOn(mockedDrawingService, 'duplicate').and.returnValue(of()); + + component.duplicate(); + + expect(mockedDrawingService.duplicate).toHaveBeenCalled(); + }); + + it('should call duplicate action in node service', () => { + let node = { node_id: '1' } as Node; + component.nodes = [node]; + component.drawings = []; + spyOn(mockedNodeService, 'duplicate').and.returnValue(of()); + + component.duplicate(); + + expect(mockedNodeService.duplicate).toHaveBeenCalled(); + }); + + it('should call duplicate action in both services', () => { + let drawing = { drawing_id: '1' } as Drawing; + component.drawings = [drawing]; + let node = { node_id: '1' } as Node; + component.nodes = [node]; + spyOn(mockedDrawingService, 'duplicate').and.returnValue(of()); + spyOn(mockedNodeService, 'duplicate').and.returnValue(of()); + + component.duplicate(); + + expect(mockedDrawingService.duplicate).toHaveBeenCalled(); + expect(mockedNodeService.duplicate).toHaveBeenCalled(); + }); +}); diff --git a/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.ts b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-action.component.ts new file mode 100644 index 00000000..0da39a24 --- /dev/null +++ b/src/app/components/project-map/context-menu/actions/duplicate-action/duplicate-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 { Drawing } from '../../../../../cartography/models/drawing'; +import { Project } from '../../../../../models/project'; +import { NodeService } from '../../../../../services/node.service'; +import { DrawingService } from '../../../../../services/drawing.service'; +import { NodesDataSource } from '../../../../../cartography/datasources/nodes-datasource'; +import { DrawingsDataSource } from '../../../../../cartography/datasources/drawings-datasource'; + +@Component({ +selector: 'app-duplicate-action', +templateUrl: './duplicate-action.component.html' +}) +export class DuplicateActionComponent { + @Input() server: Server; + @Input() project: Project; + @Input() drawings: Drawing[]; + @Input() nodes: Node[]; + + constructor( + private nodeService: NodeService, + private nodesDataSource: NodesDataSource, + private drawingService: DrawingService, + private drawingsDataSource: DrawingsDataSource + ) {} + + duplicate() { + for(let node of this.nodes) { + this.nodeService.duplicate(this.server, node).subscribe((node: Node) => { + this.nodesDataSource.add(node); + }); + } + + for(let drawing of this.drawings) { + this.drawingService.duplicate(this.server, drawing.project_id, drawing).subscribe((drawing: Drawing) => { + this.drawingsDataSource.add(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 0d80158f..a1bdf228 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 @@ -8,6 +8,12 @@ [server]="server" [nodes]="nodes" > + { const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/projects/myproject/drawings/id'); expect(req.request.method).toEqual('DELETE'); })); + + it('should duplicate drawing', inject([DrawingService], (service: DrawingService) => { + const drawing = new Drawing(); + drawing.project_id = "project_id_1"; + drawing.drawing_id = "drawing_id_1"; + drawing.x = 100; + drawing.y = 90; + drawing.z = 1; + drawing.rotation = 0; + drawing.svg = ""; + + service.duplicate(server, drawing.project_id, drawing).subscribe(); + + const req = httpTestingController.expectOne(`http://127.0.0.1:3080/v2/projects/${drawing.project_id}/drawings`); + expect(req.request.method).toEqual('POST'); + expect(req.request.body).toEqual({ + svg: drawing.svg, + rotation: 0, + x: 110, + y: 100, + z: 1 + }); + })); }); diff --git a/src/app/services/drawing.service.ts b/src/app/services/drawing.service.ts index 53443c0f..d883260b 100644 --- a/src/app/services/drawing.service.ts +++ b/src/app/services/drawing.service.ts @@ -19,6 +19,16 @@ export class DrawingService { }); } + duplicate(server: Server, project_id: string, drawing: Drawing) { + return this.httpServer.post(server, `/projects/${project_id}/drawings`, { + svg: drawing.svg, + rotation: drawing.rotation, + x: drawing.x + 10, + y: drawing.y + 10, + z: drawing.z + }); + } + updatePosition(server: Server, drawing: Drawing, x: number, y: number): Observable { return this.httpServer.put(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, { x: Math.round(x), diff --git a/src/app/services/node.service.spec.ts b/src/app/services/node.service.spec.ts index d8e08a7b..6559f9d2 100644 --- a/src/app/services/node.service.spec.ts +++ b/src/app/services/node.service.spec.ts @@ -215,4 +215,15 @@ describe('NodeService', () => { const req = httpTestingController.expectOne('http://127.0.0.1:3080/v2/projects/myproject/nodes/id'); expect(req.request.method).toEqual('DELETE'); })); + + it('should duplicate node', inject([NodeService], (service: NodeService) => { + const node = new Node(); + node.project_id = "project_id_1"; + node.node_id = "node_id_1"; + + service.duplicate(server, node).subscribe(); + + const req = httpTestingController.expectOne(`http://127.0.0.1:3080/v2/projects/${node.project_id}/nodes/${node.node_id}/duplicate`); + expect(req.request.method).toEqual('POST'); + })); }); diff --git a/src/app/services/node.service.ts b/src/app/services/node.service.ts index f33f8105..b0852956 100644 --- a/src/app/services/node.service.ts +++ b/src/app/services/node.service.ts @@ -75,4 +75,13 @@ export class NodeService { delete(server: Server, node: Node) { return this.httpServer.delete(server, `/projects/${node.project_id}/nodes/${node.node_id}`); } + + duplicate(server: Server, node: Node) { + return this.httpServer.post(server, `/projects/${node.project_id}/nodes/${node.node_id}/duplicate`, + { + "x": node.x + 10, + "y": node.y + 10, + "z": node.z + }); + } }