diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 21337c79..48274cd0 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -41,6 +41,8 @@ import { MapComponent } from './cartography/map/map.component'; import { CreateSnapshotDialogComponent, ProjectMapComponent } from './project-map/project-map.component'; import { ServersComponent, AddServerDialogComponent } from './servers/servers.component'; import { NodeContextMenuComponent } from './shared/node-context-menu/node-context-menu.component'; +import {NodeService} from "./shared/services/node.service"; +import { StartNodeActionComponent } from './shared/node-context-menu/actions/start-node-action/start-node-action.component'; @NgModule({ @@ -55,6 +57,7 @@ import { NodeContextMenuComponent } from './shared/node-context-menu/node-contex DefaultLayoutComponent, ProgressDialogComponent, NodeContextMenuComponent, + StartNodeActionComponent, ], imports: [ NgbModule.forRoot(), @@ -82,6 +85,7 @@ import { NodeContextMenuComponent } from './shared/node-context-menu/node-contex ProjectService, SymbolService, ServerService, + NodeService, IndexedDbService, HttpServer, SnapshotService, diff --git a/src/app/cartography/map/map.component.ts b/src/app/cartography/map/map.component.ts index 0c719b52..b82dad4b 100644 --- a/src/app/cartography/map/map.component.ts +++ b/src/app/cartography/map/map.component.ts @@ -94,9 +94,12 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy { this.graphLayout = new GraphLayout(); this.graphLayout.draw(this.svg, this.graphContext); + this.graphLayout.getNodesWidget().setOnContextMenuCallback((event: any, node: Node) => { this.nodeContextMenu.open(node, event.clientY, event.clientX); }); + + } } diff --git a/src/app/project-map/project-map.component.ts b/src/app/project-map/project-map.component.ts index 04cd01c4..41747acf 100644 --- a/src/app/project-map/project-map.component.ts +++ b/src/app/project-map/project-map.component.ts @@ -26,6 +26,9 @@ import { ProgressDialogService } from "../shared/progress-dialog/progress-dialog import { ProgressDialogComponent } from "../shared/progress-dialog/progress-dialog.component"; import { ToastyService } from "ng2-toasty"; import {Drawing} from "../cartography/shared/models/drawing.model"; +import {StartNodeAction} from "../shared/node-context-menu/actions/start-node-action"; +import {NodeService} from "../shared/services/node.service"; +import {StopNodeAction} from "../shared/node-context-menu/actions/stop-node-action"; @Component({ @@ -52,6 +55,7 @@ export class ProjectMapComponent implements OnInit { private projectService: ProjectService, private symbolService: SymbolService, private snapshotService: SnapshotService, + private nodeService: NodeService, private dialog: MatDialog, private progressDialogService: ProgressDialogService, private toastyService: ToastyService) { @@ -105,6 +109,7 @@ export class ProjectMapComponent implements OnInit { n.icon = this.symbolService.get(n.symbol); }); + this.setUpNodeActions(); this.setUpWS(project); }); @@ -166,6 +171,16 @@ export class ProjectMapComponent implements OnInit { }); } + setUpNodeActions() { + this.mapChild.nodeContextMenu.clearActions(); + + const start_node_action = new StartNodeAction(this.server, this.nodeService); + this.mapChild.nodeContextMenu.registerAction(start_node_action); + + const stop_node_action = new StopNodeAction(this.server, this.nodeService); + this.mapChild.nodeContextMenu.registerAction(stop_node_action); + } + public createSnapshotModal() { const dialogRef = this.dialog.open(CreateSnapshotDialogComponent, { width: '250px', diff --git a/src/app/shared/node-context-menu/actions/start-node-action.ts b/src/app/shared/node-context-menu/actions/start-node-action.ts new file mode 100644 index 00000000..4274a826 --- /dev/null +++ b/src/app/shared/node-context-menu/actions/start-node-action.ts @@ -0,0 +1,25 @@ +import {NodeContextMenuAction} from "../node-context-menu-action"; +import {Node} from "../../../cartography/shared/models/node.model"; +import {Server} from "../../models/server"; +import {NodeService} from "../../services/node.service"; + + +export class StartNodeAction implements NodeContextMenuAction { + constructor(private server: Server, private nodeService: NodeService) {} + + icon(node: Node) { + return "play_arrow"; + } + + label(node: Node) { + return "Start"; + } + + isVisible(node: Node) { + return node.status === 'stopped'; + } + + onClick(node: Node) { + this.nodeService.start() + } +} diff --git a/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.html b/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.html new file mode 100644 index 00000000..81565936 --- /dev/null +++ b/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.html @@ -0,0 +1,3 @@ +<p> + start-node-action works! +</p> diff --git a/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.scss b/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.scss new file mode 100644 index 00000000..e69de29b diff --git a/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.spec.ts b/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.spec.ts new file mode 100644 index 00000000..7c7f46b3 --- /dev/null +++ b/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { StartNodeActionComponent } from './start-node-action.component'; + +describe('StartNodeActionComponent', () => { + let component: StartNodeActionComponent; + let fixture: ComponentFixture<StartNodeActionComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ StartNodeActionComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(StartNodeActionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.ts b/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.ts new file mode 100644 index 00000000..16b2c37c --- /dev/null +++ b/src/app/shared/node-context-menu/actions/start-node-action/start-node-action.component.ts @@ -0,0 +1,15 @@ +import { Component, OnInit } from '@angular/core'; + +@Component({ + selector: 'app-start-node-action', + templateUrl: './start-node-action.component.html', + styleUrls: ['./start-node-action.component.scss'] +}) +export class StartNodeActionComponent implements OnInit { + + constructor() { } + + ngOnInit() { + } + +} diff --git a/src/app/shared/node-context-menu/actions/stop-node-action.ts b/src/app/shared/node-context-menu/actions/stop-node-action.ts new file mode 100644 index 00000000..cb6a6588 --- /dev/null +++ b/src/app/shared/node-context-menu/actions/stop-node-action.ts @@ -0,0 +1,26 @@ +import {NodeContextMenuAction} from "../node-context-menu-action"; +import {Node} from "../../../cartography/shared/models/node.model"; +import {Server} from "../../models/server"; +import {Project} from "../../models/project"; +import {NodeService} from "../../services/node.service"; + + +export class StopNodeAction implements NodeContextMenuAction { + constructor(server: Server, nodeService: NodeService) {} + + icon(node: Node) { + return "stop"; + } + + label(node: Node) { + return "Stop"; + } + + isVisible(node: Node) { + return node.status === 'started'; + } + + onClick(node: Node) { + + } +} diff --git a/src/app/shared/node-context-menu/node-context-menu-action.ts b/src/app/shared/node-context-menu/node-context-menu-action.ts new file mode 100644 index 00000000..5a415d84 --- /dev/null +++ b/src/app/shared/node-context-menu/node-context-menu-action.ts @@ -0,0 +1,8 @@ +import {Node} from "../../cartography/shared/models/node.model"; + +export interface NodeContextMenuAction { + icon(node: Node): string; + label(node: Node): string; + isVisible(node: Node): boolean; + onClick(node: Node); +} diff --git a/src/app/shared/node-context-menu/node-context-menu.component.html b/src/app/shared/node-context-menu/node-context-menu.component.html index ff526bb0..8c0ec14e 100644 --- a/src/app/shared/node-context-menu/node-context-menu.component.html +++ b/src/app/shared/node-context-menu/node-context-menu.component.html @@ -1,13 +1,17 @@ <div class="context-menu" [style.left]="leftPosition" [style.top]="topPosition" *ngIf="node"> <span [matMenuTriggerFor]="contextMenu"></span> <mat-menu #contextMenu="matMenu"> - <button mat-menu-item *ngIf="node.status == 'stopped'"> - <mat-icon>play_arrow</mat-icon> - <span>Start</span> - </button> - <button mat-menu-item *ngIf="node.status == 'started'"> - <mat-icon>stop</mat-icon> - <span>Stop</span> - </button> + <!--<button mat-menu-item *ngIf="node.status == 'stopped'">--> + <!--<mat-icon>play_arrow</mat-icon>--> + <!--<span>Start</span>--> + <!--</button>--> + <!--<ng-container *ngFor="let action of actions">--> + <!--<button mat-menu-item *ngIf="action.isVisible(node)" (click)="action.onClick(node)">--> + <!--<mat-icon>{{ action.icon(node) }}</mat-icon>--> + <!--<span>{{ action.label(node) }}</span>--> + <!--</button>--> + <!--</ng-container>--> + + </mat-menu> </div> diff --git a/src/app/shared/node-context-menu/node-context-menu.component.ts b/src/app/shared/node-context-menu/node-context-menu.component.ts index 623541be..1613e8bd 100644 --- a/src/app/shared/node-context-menu/node-context-menu.component.ts +++ b/src/app/shared/node-context-menu/node-context-menu.component.ts @@ -2,6 +2,7 @@ import {ChangeDetectorRef, Component, Input, OnInit, ViewChild} from '@angular/c import {MatMenuTrigger} from "@angular/material"; import {DomSanitizer} from "@angular/platform-browser"; import {Node} from "../../cartography/shared/models/node.model"; +import {NodeContextMenuAction} from "./node-context-menu-action"; @Component({ @@ -15,6 +16,7 @@ export class NodeContextMenuComponent implements OnInit { private topPosition; private leftPosition; private node: Node; + private actions: NodeContextMenuAction[] = []; constructor( private sanitizer: DomSanitizer, @@ -36,4 +38,12 @@ export class NodeContextMenuComponent implements OnInit { this.contextMenu.openMenu(); } + public registerAction(action: NodeContextMenuAction) { + this.actions.push(action); + } + + public clearActions() { + this.actions = []; + } + } diff --git a/src/app/shared/services/node.service.spec.ts b/src/app/shared/services/node.service.spec.ts new file mode 100644 index 00000000..dd1ad6a0 --- /dev/null +++ b/src/app/shared/services/node.service.spec.ts @@ -0,0 +1,15 @@ +import { TestBed, inject } from '@angular/core/testing'; + +import { NodeService } from './node.service'; + +describe('NodeService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [NodeService] + }); + }); + + it('should be created', inject([NodeService], (service: NodeService) => { + expect(service).toBeTruthy(); + })); +}); diff --git a/src/app/shared/services/node.service.ts b/src/app/shared/services/node.service.ts new file mode 100644 index 00000000..d7a65756 --- /dev/null +++ b/src/app/shared/services/node.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { Project } from '../models/project'; +import { Node } from '../../cartography/shared/models/node.model'; +import { Observable } from 'rxjs/Observable'; + +import 'rxjs/add/operator/map'; +import { Server } from "../models/server"; +import { HttpServer } from "./http-server.service"; + + +@Injectable() +export class NodeService { + + constructor(private httpServer: HttpServer) { } + + start(server: Server, node: Node): Observable<Node> { + return this.httpServer + .post(server, `/projects/${node.project_id}/nodes/${node.node_id}/start`, {}) + .map(response => response.json() as Node); + } + + stop(server: Server, node: Node): Observable<Node> { + return this.httpServer + .post(server, `/projects/${node.project_id}/nodes/${node.node_id}/stop`, {}) + .map(response => response.json() as Node); + } + +}