diff --git a/angular.json b/angular.json
index f4430c7a..66e1b1ba 100644
--- a/angular.json
+++ b/angular.json
@@ -151,7 +151,7 @@
}
},
"gns3-web-ui-e2e": {
- "root": "",
+ "root": "e2e",
"sourceRoot": "e2e",
"projectType": "application",
"architect": {
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index e3c4580f..962c7e1e 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -6,26 +6,6 @@ import { CdkTableModule } from "@angular/cdk/table";
import { HttpClientModule } from '@angular/common/http';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
-import {
- MatButtonModule,
- MatCardModule,
- MatMenuModule,
- MatToolbarModule,
- MatIconModule,
- MatFormFieldModule,
- MatInputModule,
- MatTableModule,
- MatDialogModule,
- MatProgressBarModule,
- MatProgressSpinnerModule,
- MatSnackBarModule,
- MatCheckboxModule,
- MatListModule,
- MatExpansionModule,
- MatSortModule,
- MatSelectModule,
- MatTooltipModule
-} from '@angular/material';
import { D3Service } from 'd3-ng2-service';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
@@ -52,14 +32,13 @@ import { DefaultLayoutComponent } from './layouts/default-layout/default-layout.
import { ProgressDialogComponent } from './common/progress-dialog/progress-dialog.component';
import { AppComponent } from './app.component';
-import { CreateSnapshotDialogComponent, ProjectMapComponent } from './components/project-map/project-map.component';
+import { ProjectMapComponent } from './components/project-map/project-map.component';
import { ServersComponent, AddServerDialogComponent } from './components/servers/servers.component';
import { NodeContextMenuComponent } from './components/project-map/node-context-menu/node-context-menu.component';
import { StartNodeActionComponent } from './components/project-map/node-context-menu/actions/start-node-action/start-node-action.component';
import { StopNodeActionComponent } from './components/project-map/node-context-menu/actions/stop-node-action/stop-node-action.component';
import { ApplianceComponent } from './components/appliance/appliance.component';
import { ApplianceListDialogComponent } from './components/appliance/appliance-list-dialog/appliance-list-dialog.component';
-import { NodeSelectInterfaceComponent } from './components/project-map/node-select-interface/node-select-interface.component';
import { CartographyModule } from './cartography/cartography.module';
import { ToasterService } from './services/toaster.service';
import { ProjectWebServiceHandler } from "./handlers/project-web-service-handler";
@@ -67,7 +46,7 @@ import { LinksDataSource } from "./cartography/datasources/links-datasource";
import { NodesDataSource } from "./cartography/datasources/nodes-datasource";
import { SymbolsDataSource } from "./cartography/datasources/symbols-datasource";
import { SelectionManager } from "./cartography/managers/selection-manager";
-import { InRectangleHelper } from "./cartography/components/map/helpers/in-rectangle-helper";
+import { InRectangleHelper } from "./cartography/helpers/in-rectangle-helper";
import { DrawingsDataSource } from "./cartography/datasources/drawings-datasource";
import { MoveLayerDownActionComponent } from './components/project-map/node-context-menu/actions/move-layer-down-action/move-layer-down-action.component';
import { MoveLayerUpActionComponent } from './components/project-map/node-context-menu/actions/move-layer-up-action/move-layer-up-action.component';
@@ -84,6 +63,10 @@ import { environment } from "../environments/environment";
import { RavenState } from "./common/error-handlers/raven-state-communicator";
import { ServerDiscoveryComponent } from "./components/servers/server-discovery/server-discovery.component";
import { ServerDatabase } from './services/server.database';
+import { CreateSnapshotDialogComponent } from './components/snapshots/create-snapshot-dialog/create-snapshot-dialog.component';
+import { SnapshotsComponent } from './components/snapshots/snapshots.component';
+import { SnapshotMenuItemComponent } from './components/snapshots/snapshot-menu-item/snapshot-menu-item.component';
+import { MATERIAL_IMPORTS } from './material.imports';
if (environment.production) {
@@ -105,6 +88,8 @@ if (environment.production) {
ServersComponent,
AddServerDialogComponent,
CreateSnapshotDialogComponent,
+ SnapshotMenuItemComponent,
+ SnapshotsComponent,
ProjectsComponent,
DefaultLayoutComponent,
ProgressDialogComponent,
@@ -113,7 +98,6 @@ if (environment.production) {
StopNodeActionComponent,
ApplianceComponent,
ApplianceListDialogComponent,
- NodeSelectInterfaceComponent,
MoveLayerDownActionComponent,
MoveLayerUpActionComponent,
ProjectMapShortcutsComponent,
@@ -130,28 +114,11 @@ if (environment.production) {
FormsModule,
BrowserAnimationsModule,
CdkTableModule,
- MatButtonModule,
- MatMenuModule,
- MatCardModule,
- MatToolbarModule,
- MatIconModule,
- MatFormFieldModule,
- MatInputModule,
- MatTableModule,
- MatDialogModule,
- MatProgressBarModule,
- MatProgressSpinnerModule,
- MatSnackBarModule,
- MatCheckboxModule,
- MatListModule,
- MatExpansionModule,
- MatSortModule,
- MatSelectModule,
- MatTooltipModule,
CartographyModule,
HotkeyModule.forRoot(),
PersistenceModule,
- NgxElectronModule
+ NgxElectronModule,
+ ...MATERIAL_IMPORTS
],
providers: [
SettingsService,
diff --git a/src/app/cartography/cartography.module.ts b/src/app/cartography/cartography.module.ts
index e84bda0c..93a24a5d 100644
--- a/src/app/cartography/cartography.module.ts
+++ b/src/app/cartography/cartography.module.ts
@@ -1,12 +1,71 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MapComponent } from './components/map/map.component';
+import { CssFixer } from './helpers/css-fixer';
+import { FontFixer } from './helpers/font-fixer';
+import { MultiLinkCalculatorHelper } from './helpers/multi-link-calculator-helper';
+import { SvgToDrawingConverter } from './helpers/svg-to-drawing-converter';
+import { QtDasharrayFixer } from './helpers/qt-dasharray-fixer';
+import { LayersManager } from './managers/layers-manager';
+import { MapChangeDetectorRef } from './services/map-change-detector-ref';
+import { GraphLayout } from './widgets/graph-layout';
+import { LinksWidget } from './widgets/links';
+import { NodesWidget } from './widgets/nodes';
+import { DrawingsWidget } from './widgets/drawings';
+import { DrawingLineWidget } from './widgets/drawing-line';
+import { SelectionTool } from './tools/selection-tool';
+import { MovingTool } from './tools/moving-tool';
+import { LayersWidget } from './widgets/layers';
+import { LinkWidget } from './widgets/link';
+import { InterfaceStatusWidget } from './widgets/interface-status';
+import { InterfaceLabelWidget } from './widgets/interface-label';
+import { EllipseDrawingWidget } from './widgets/drawings/ellipse-drawing';
+import { ImageDrawingWidget } from './widgets/drawings/image-drawing';
+import { RectDrawingWidget } from './widgets/drawings/rect-drawing';
+import { TextDrawingWidget } from './widgets/drawings/text-drawing';
+import { LineDrawingWidget } from './widgets/drawings/line-drawing';
+import { Context } from './models/context';
+import { DrawLinkToolComponent } from './components/draw-link-tool/draw-link-tool.component';
+import { NodeSelectInterfaceComponent } from './components/node-select-interface/node-select-interface.component';
+import { MatMenuModule, MatIconModule } from '@angular/material';
@NgModule({
imports: [
- CommonModule
+ CommonModule,
+ MatMenuModule,
+ MatIconModule
+ ],
+ declarations: [
+ MapComponent,
+ DrawLinkToolComponent,
+ NodeSelectInterfaceComponent
+ ],
+ providers: [
+ CssFixer,
+ FontFixer,
+ MultiLinkCalculatorHelper,
+ SvgToDrawingConverter,
+ QtDasharrayFixer,
+ LayersManager,
+ MapChangeDetectorRef,
+ GraphLayout,
+ LinksWidget,
+ NodesWidget,
+ DrawingsWidget,
+ DrawingLineWidget,
+ SelectionTool,
+ MovingTool,
+ LayersWidget,
+ LinkWidget,
+ InterfaceStatusWidget,
+ InterfaceLabelWidget,
+ EllipseDrawingWidget,
+ ImageDrawingWidget,
+ LineDrawingWidget,
+ RectDrawingWidget,
+ TextDrawingWidget,
+ Context,
],
- declarations: [MapComponent],
exports: [MapComponent]
})
export class CartographyModule { }
diff --git a/src/app/cartography/components/draw-link-tool/draw-link-tool.component.html b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.html
new file mode 100644
index 00000000..16188157
--- /dev/null
+++ b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/app/cartography/components/draw-link-tool/draw-link-tool.component.scss b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.scss
new file mode 100644
index 00000000..e69de29b
diff --git a/src/app/cartography/components/draw-link-tool/draw-link-tool.component.spec.ts b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.spec.ts
new file mode 100644
index 00000000..d75619ca
--- /dev/null
+++ b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DrawLinkToolComponent } from './draw-link-tool.component';
+
+describe('DrawLinkToolComponent', () => {
+ let component: DrawLinkToolComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ DrawLinkToolComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(DrawLinkToolComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ // it('should create', () => {
+ // expect(component).toBeTruthy();
+ // });
+});
diff --git a/src/app/cartography/components/draw-link-tool/draw-link-tool.component.ts b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.ts
new file mode 100644
index 00000000..53a6800b
--- /dev/null
+++ b/src/app/cartography/components/draw-link-tool/draw-link-tool.component.ts
@@ -0,0 +1,66 @@
+import { Component, OnInit, Output, EventEmitter, OnDestroy, ViewChild } from '@angular/core';
+import { Port } from '../../../models/port';
+import { DrawingLineWidget } from '../../widgets/drawing-line';
+import { Node } from '../../models/node';
+import { NodesWidget, NodeEvent } from '../../widgets/nodes';
+import { Subscription } from 'rxjs';
+import { NodeSelectInterfaceComponent } from '../node-select-interface/node-select-interface.component';
+
+
+export class LinkCreated {
+ constructor(
+ public sourceNode: Node,
+ public sourcePort: Port,
+ public targetNode: Node,
+ public targetPort: Port
+ ){}
+}
+
+@Component({
+ selector: 'app-draw-link-tool',
+ templateUrl: './draw-link-tool.component.html',
+ styleUrls: ['./draw-link-tool.component.scss']
+})
+export class DrawLinkToolComponent implements OnInit, OnDestroy {
+ @ViewChild(NodeSelectInterfaceComponent) nodeSelectInterfaceMenu: NodeSelectInterfaceComponent;
+
+ @Output('linkCreated') linkCreated = new EventEmitter();
+
+ private onNodeClicked: Subscription;
+
+ constructor(
+ private drawingLineTool: DrawingLineWidget,
+ private nodesWidget: NodesWidget
+ ) { }
+
+ ngOnInit() {
+ this.onNodeClicked = this.nodesWidget.onNodeClicked.subscribe((eventNode: NodeEvent) => {
+ this.nodeSelectInterfaceMenu.open(
+ eventNode.node,
+ eventNode.event.clientY,
+ eventNode.event.clientX
+ );
+ });
+ }
+
+ ngOnDestroy() {
+ if(this.drawingLineTool.isDrawing()) {
+ this.drawingLineTool.stop();
+ }
+ this.onNodeClicked.unsubscribe();
+ }
+
+ public onChooseInterface(event) {
+ const node: Node = event.node;
+ const port: Port = event.port;
+ if (this.drawingLineTool.isDrawing()) {
+ const data = this.drawingLineTool.stop();
+ this.linkCreated.emit(new LinkCreated(data['node'], data['port'], node, port));
+ } else {
+ this.drawingLineTool.start(node.x + node.width / 2., node.y + node.height / 2., {
+ 'node': node,
+ 'port': port
+ });
+ }
+ }
+}
diff --git a/src/app/cartography/components/map/map.component.html b/src/app/cartography/components/map/map.component.html
index 68e33fff..20564aff 100644
--- a/src/app/cartography/components/map/map.component.html
+++ b/src/app/cartography/components/map/map.component.html
@@ -1,2 +1,6 @@
-
+
+
+
\ No newline at end of file
diff --git a/src/app/cartography/components/map/map.component.ts b/src/app/cartography/components/map/map.component.ts
index 1a69bff0..2b19dc8e 100644
--- a/src/app/cartography/components/map/map.component.ts
+++ b/src/app/cartography/components/map/map.component.ts
@@ -1,16 +1,24 @@
import {
- Component, ElementRef, HostListener, Input, OnChanges, OnDestroy, OnInit, SimpleChange
+ Component, ElementRef, HostListener, Input, OnChanges, OnDestroy, OnInit, SimpleChange, EventEmitter, Output
} from '@angular/core';
import { D3, D3Service } from 'd3-ng2-service';
-import { select, Selection } from 'd3-selection';
+import { Selection } from 'd3-selection';
import { Node } from "../../models/node";
-import { Link } from "../../models/link";
+import { Link } from "../../../models/link";
import { GraphLayout } from "../../widgets/graph-layout";
import { Context } from "../../models/context";
import { Size } from "../../models/size";
import { Drawing } from "../../models/drawing";
-import { Symbol } from "../../models/symbol";
+import { Symbol } from '../../../models/symbol';
+import { NodeEvent, NodesWidget } from '../../widgets/nodes';
+import { Subscription } from 'rxjs';
+import { InterfaceLabelWidget } from '../../widgets/interface-label';
+import { SelectionTool } from '../../tools/selection-tool';
+import { MovingTool } from '../../tools/moving-tool';
+import { LinksWidget } from '../../widgets/links';
+import { MapChangeDetectorRef } from '../../services/map-change-detector-ref';
+import { LinkCreated } from '../draw-link-tool/draw-link-tool.component';
@Component({
@@ -27,20 +35,60 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
@Input() width = 1500;
@Input() height = 600;
+ @Output() onNodeDragged: EventEmitter;
+ @Output() onLinkCreated = new EventEmitter();
+
private d3: D3;
private parentNativeElement: any;
private svg: Selection;
- private graphContext: Context;
- public graphLayout: GraphLayout;
+ private isReady = false;
- constructor(protected element: ElementRef,
- protected d3Service: D3Service
- ) {
+ private onNodeDraggingSubscription: Subscription;
+ private onChangesDetected: Subscription;
+
+ protected settings = {
+ 'show_interface_labels': true
+ };
+
+ constructor(
+ private context: Context,
+ private mapChangeDetectorRef: MapChangeDetectorRef,
+ protected element: ElementRef,
+ protected d3Service: D3Service,
+ protected nodesWidget: NodesWidget,
+ protected linksWidget: LinksWidget,
+ protected interfaceLabelWidget: InterfaceLabelWidget,
+ protected selectionToolWidget: SelectionTool,
+ protected movingToolWidget: MovingTool,
+ public graphLayout: GraphLayout
+ ) {
this.d3 = d3Service.getD3();
this.parentNativeElement = element.nativeElement;
+ this.onNodeDragged = nodesWidget.onNodeDragged;
}
+ @Input('show-interface-labels')
+ set showInterfaceLabels(value) {
+ this.settings.show_interface_labels = value;
+ this.interfaceLabelWidget.setEnabled(value);
+ this.mapChangeDetectorRef.detectChanges();
+ }
+
+ @Input('moving-tool')
+ set movingTool(value) {
+ this.movingToolWidget.setEnabled(value);
+ this.mapChangeDetectorRef.detectChanges();
+ }
+
+ @Input('selection-tool')
+ set selectionTool(value) {
+ this.selectionToolWidget.setEnabled(value);
+ this.mapChangeDetectorRef.detectChanges();
+ }
+
+ @Input('draw-link-tool') drawLinkTool: boolean;
+
ngOnChanges(changes: { [propKey: string]: SimpleChange }) {
if (
(changes['width'] && !changes['width'].isFirstChange()) ||
@@ -67,37 +115,37 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
ngOnDestroy() {
this.graphLayout.disconnect(this.svg);
+ this.onNodeDraggingSubscription.unsubscribe();
+ this.onChangesDetected.unsubscribe();
}
ngOnInit() {
- const d3 = this.d3;
-
- let rootElement: Selection;
-
if (this.parentNativeElement !== null) {
- rootElement = d3.select(this.parentNativeElement);
-
- this.svg = rootElement.select('svg');
-
- this.graphContext = new Context(true);
-
- this.graphContext.size = this.getSize();
-
- this.graphLayout = new GraphLayout();
- this.graphLayout.connect(this.svg, this.graphContext);
-
- this.graphLayout.getNodesWidget().addOnNodeDraggingCallback((event: any, n: Node) => {
- const linksWidget = this.graphLayout.getLinksWidget();
- linksWidget.select(this.svg).each(function(this: SVGGElement, link: Link) {
- if (link.target.node_id === n.node_id || link.source.node_id === n.node_id) {
- const selection = select(this);
- linksWidget.revise(selection);
- }
- });
- });
-
- this.graphLayout.draw(this.svg, this.graphContext);
+ this.createGraph(this.parentNativeElement);
}
+ this.context.size = this.getSize();
+
+ this.onNodeDraggingSubscription = this.nodesWidget.onNodeDragging.subscribe((eventNode: NodeEvent) => {
+ const links = this.links.filter((link) => link.target.node_id === eventNode.node.node_id || link.source.node_id === eventNode.node.node_id)
+
+ links.forEach((link) => {
+ this.linksWidget.redrawLink(this.svg, link);
+ });
+ });
+
+ this.onChangesDetected = this.mapChangeDetectorRef.changesDetected.subscribe(() => {
+ if (this.isReady) {
+ this.reload();
+ }
+ });
+ }
+
+ public createGraph(domElement: HTMLElement) {
+ const rootElement = this.d3.select(domElement);
+ this.svg = rootElement.select('svg');
+ this.graphLayout.connect(this.svg, this.context);
+ this.graphLayout.draw(this.svg, this.context);
+ this.isReady = true;
}
public getSize(): Size {
@@ -112,9 +160,13 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
return new Size(width, height);
}
+ protected linkCreated(evt) {
+ this.onLinkCreated.emit(evt);
+ }
+
private changeLayout() {
if (this.parentNativeElement != null) {
- this.graphContext.size = this.getSize();
+ this.context.size = this.getSize();
}
this.graphLayout.setNodes(this.nodes);
@@ -156,7 +208,7 @@ export class MapComponent implements OnInit, OnChanges, OnDestroy {
}
public redraw() {
- this.graphLayout.draw(this.svg, this.graphContext);
+ this.graphLayout.draw(this.svg, this.context);
}
public reload() {
diff --git a/src/app/components/project-map/node-select-interface/node-select-interface.component.html b/src/app/cartography/components/node-select-interface/node-select-interface.component.html
similarity index 83%
rename from src/app/components/project-map/node-select-interface/node-select-interface.component.html
rename to src/app/cartography/components/node-select-interface/node-select-interface.component.html
index d912c26b..8900bba8 100644
--- a/src/app/components/project-map/node-select-interface/node-select-interface.component.html
+++ b/src/app/cartography/components/node-select-interface/node-select-interface.component.html
@@ -1,6 +1,6 @@