diff --git a/package.json b/package.json index 189e1178..18af0055 100644 --- a/package.json +++ b/package.json @@ -38,24 +38,26 @@ }, "private": true, "dependencies": { - "@angular/animations": "^8.2.8", - "@angular/cdk": "^8.2.1", - "@angular/common": "^8.2.8", - "@angular/compiler": "^8.2.8", - "@angular/core": "^8.2.8", - "@angular/forms": "^8.2.8", + "@angular/animations": "^8.2.11", + "@angular/cdk": "^8.2.3", + "@angular/common": "^8.2.11", + "@angular/compiler": "^8.2.11", + "@angular/core": "^8.2.11", + "@angular/forms": "^8.2.11", "@angular/http": "^7.2.15", - "@angular/material": "^8.2.1", - "@angular/platform-browser": "^8.2.8", - "@angular/platform-browser-dynamic": "^8.2.8", - "@angular/router": "^8.2.8", + "@angular/material": "^8.2.3", + "@angular/platform-browser": "^8.2.11", + "@angular/platform-browser-dynamic": "^8.2.11", + "@angular/router": "^8.2.11", "angular-persistence": "^1.0.1", + "angular-resizable-element": "^3.2.6", + "angular2-draggable": "^2.3.2", "angular2-hotkeys": "^2.1.5", "angular2-indexeddb": "^1.2.3", "bootstrap": "4.3.1", "command-exists": "^1.2.8", - "core-js": "^3.2.1", - "css-tree": "^1.0.0-alpha.34", + "core-js": "^3.3.2", + "css-tree": "^1.0.0-alpha.36", "d3-ng2-service": "^2.1.0", "file-saver": "^2.0.2", "hammerjs": "^2.0.8", @@ -69,50 +71,50 @@ "rxjs": "^6.5.3", "rxjs-compat": "^6.5.3", "save-svg-as-png": "^1.4.14", - "svg-crowbar": "^0.2.3", + "svg-crowbar": "^0.2.4", "tree-kill": "^1.2.1", "typeface-roboto": "^0.0.75", - "xterm": "^4.0.0", - "yargs": "^13.3.0", - "zone.js": "^0.9.1" + "xterm": "^4.1.0", + "yargs": "^14.2.0", + "zone.js": "^0.10.2" }, "devDependencies": { - "@angular-devkit/build-angular": "^0.801.3", - "@angular/cli": "^8.3.6", - "@angular/compiler-cli": "^8.2.8", - "@angular/language-service": "^8.2.8", - "@sentry/cli": "^1.47.2", + "@angular-devkit/build-angular": "^0.803.10", + "@angular/cli": "^8.3.10", + "@angular/compiler-cli": "^8.2.11", + "@angular/language-service": "^8.2.11", + "@sentry/cli": "^1.48.0", "@sentry/electron": "^0.17.4", - "@types/jasmine": "^3.3.16", - "@types/jasminewd2": "^2.0.7", - "@types/node": "^12.6.9", + "@types/jasmine": "^3.4.4", + "@types/jasminewd2": "^2.0.8", + "@types/node": "^12.11.1", "codelyzer": "^5.1.2", - "electron": "5.0.8", - "electron-builder": "21.1.5", - "jasmine-core": "~3.4.0", + "electron": "6.0.12", + "electron-builder": "21.2.0", + "jasmine-core": "~3.5.0", "jasmine-spec-reporter": "~4.2.1", "jquery": "^3.4.1", - "karma": "~4.2.0", - "karma-chrome-launcher": "~3.0.0", + "karma": "~4.4.0", + "karma-chrome-launcher": "~3.1.0", "karma-cli": "~2.0.0", "karma-coverage-istanbul-reporter": "^2.1.0", "karma-jasmine": "~2.0.1", "karma-jasmine-html-reporter": "^1.4.2", "license-checker": "^25.0.1", "node-sass": "^4.12.0", - "popper.js": "^1.15.0", + "popper.js": "^1.16.0", "prettier": "^1.18.2", "protractor": "~5.4.2", "replace": "^1.1.1", "ts-mockito": "^2.5.0", - "ts-node": "~8.3.0", - "tslint": "~5.18.0", + "ts-node": "~8.4.1", + "tslint": "~5.20.0", "tslint-config-prettier": "^1.18.0", - "typescript": ">=3.4.0 <3.5.0" + "typescript": ">=3.4.0 <3.6.0" }, "greenkeeper": { "ignore": [ "typescript" ] } -} +} \ No newline at end of file diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 178309aa..419f3aef 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -242,6 +242,7 @@ import { StartCaptureOnStartedLinkActionComponent } from './components/project-m import { LockActionComponent } from './components/project-map/context-menu/actions/lock-action/lock-action.component'; import { NavigationDialogComponent } from './components/projects/navigation-dialog/navigation-dialog.component'; import { ScreenshotDialogComponent } from './components/project-map/screenshot-dialog/screenshot-dialog.component'; +import { ResizableModule } from 'angular-resizable-element'; if (environment.production) { Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', { @@ -425,6 +426,7 @@ if (environment.production) { NgxElectronModule, FileUploadModule, MatSidenavModule, + ResizableModule, MATERIAL_IMPORTS ], providers: [ diff --git a/src/app/cartography/components/d3-map/d3-map.component.ts b/src/app/cartography/components/d3-map/d3-map.component.ts index 72da69fe..07c2673e 100644 --- a/src/app/cartography/components/d3-map/d3-map.component.ts +++ b/src/app/cartography/components/d3-map/d3-map.component.ts @@ -153,6 +153,10 @@ export class D3MapComponent implements OnInit, OnChanges, OnDestroy { }); } + public applyMapSettingsChanges() { + this.redraw(); + } + public createGraph(domElement: HTMLElement) { const rootElement = select(domElement); this.svg = rootElement.select('svg'); diff --git a/src/app/cartography/widgets/drawing.ts b/src/app/cartography/widgets/drawing.ts index 0b8808ab..2f55b8dc 100644 --- a/src/app/cartography/widgets/drawing.ts +++ b/src/app/cartography/widgets/drawing.ts @@ -12,6 +12,8 @@ import { MapDrawing } from '../models/map/map-drawing'; import { SelectionManager } from '../managers/selection-manager'; import { LineElement } from '../models/drawings/line-element'; import { EllipseElement } from '../models/drawings/ellipse-element'; +import { RectElement } from '../models/drawings/rect-element'; +import { MapSettingsService } from '../../services/mapsettings.service'; @Injectable() export class DrawingWidget implements Widget { @@ -23,7 +25,8 @@ export class DrawingWidget implements Widget { private rectDrawingWidget: RectDrawingWidget, private lineDrawingWidget: LineDrawingWidget, private ellipseDrawingWidget: EllipseDrawingWidget, - private selectionManager: SelectionManager + private selectionManager: SelectionManager, + private mapSettingsService: MapSettingsService ) { this.drawingWidgets = [ this.textDrawingWidget, @@ -50,6 +53,42 @@ export class DrawingWidget implements Widget { widget.draw(drawing_body_merge); }); + drawing_body_merge.select('.layer_label_wrapper').remove(); + if (this.mapSettingsService.isLayerNumberVisible) { + drawing_body_merge + .filter(n => ((n.element instanceof RectElement) || (n.element instanceof EllipseElement))) + .append('rect') + .attr('class', 'layer_label_wrapper') + .attr('width', '26') + .attr('height', '26') + .attr('x', n => n.element ? n.element.width/2 - 13 : 0) + .attr('y', n => n.element ? n.element.height/2 - 13 : 0) + .attr('fill', 'red'); + } + + drawing_body_merge.select('.layer_label').remove(); + if (this.mapSettingsService.isLayerNumberVisible) { + drawing_body_merge + .filter(n => ((n.element instanceof RectElement) || (n.element instanceof EllipseElement))) + .append('text') + .attr('class', 'layer_label') + .text((elem) => elem.z) + .attr('x', function(n) { + if(n.z >= 100 ) return n.element ? n.element.width/2 - 13 : 0 + else if(n.z >= 10 ) return n.element ? n.element.width/2 - 9 : 0 + else return n.element.width/2 - 5 + }) + .attr('y', n => n.element ? n.element.height/2 + 5 : 0) + .attr('style', () => { + const styles: string[] = []; + styles.push(`font-family: "Noto Sans"`); + styles.push(`font-size: 11pt`); + styles.push(`font-weight: bold`); + return styles.join('; '); + }) + .attr('fill', `#ffffff`); + } + drawing_body_merge .select('line.top') .attr('stroke', 'transparent') diff --git a/src/app/cartography/widgets/node.ts b/src/app/cartography/widgets/node.ts index 1f387386..dc41df38 100644 --- a/src/app/cartography/widgets/node.ts +++ b/src/app/cartography/widgets/node.ts @@ -10,6 +10,7 @@ import { SelectionManager } from '../managers/selection-manager'; import { LabelWidget } from './label'; import { NodesEventSource } from '../events/nodes-event-source'; import { ClickedDataEvent } from '../events/event-source'; +import { MapSettingsService } from '../../services/mapsettings.service'; @Injectable() export class NodeWidget implements Widget { @@ -20,7 +21,8 @@ export class NodeWidget implements Widget { private graphDataManager: GraphDataManager, private selectionManager: SelectionManager, private labelWidget: LabelWidget, - private nodesEventSource: NodesEventSource + private nodesEventSource: NodesEventSource, + private mapSettingsService: MapSettingsService ) {} public draw(view: SVGSelection) { @@ -42,6 +44,40 @@ export class NodeWidget implements Widget { this.nodesEventSource.clicked.emit(new ClickedDataEvent(node, event.pageX, event.pageY)); }); + node_body_merge.select('.layer_label_wrapper').remove(); + if (this.mapSettingsService.isLayerNumberVisible) { + node_body_merge + .append('rect') + .attr('class', 'layer_label_wrapper') + .attr('width', '26') + .attr('height', '26') + .attr('x', (n: MapNode) => n.width/2 - 13) + .attr('y', (n: MapNode) => n.height/2 - 13) + .attr('fill', 'red'); + } + + node_body_merge.select('.layer_label').remove(); + if (this.mapSettingsService.isLayerNumberVisible) { + node_body_merge + .append('text') + .attr('class', 'layer_label') + .text((n: MapNode) => { return n.z}) + .attr('x', function(n: MapNode) { + if(n.z >= 100 ) return n.width/2 - 13 + else if(n.z >= 10 ) return n.width/2 - 9 + else return n.width/2 - 5 + }) + .attr('y', (n: MapNode) => n.height/2 + 5) + .attr('style', () => { + const styles: string[] = []; + styles.push(`font-family: "Noto Sans"`); + styles.push(`font-size: 11pt`); + styles.push(`font-weight: bold`); + return styles.join('; '); + }) + .attr('fill', `#ffffff`); + } + // update image of node node_body_merge .select('image') diff --git a/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.html b/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.html index 9e6258d3..6c23bb7b 100644 --- a/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.html +++ b/src/app/components/project-map/context-menu/actions/edit-style-action/edit-style-action.component.html @@ -1,4 +1,4 @@ - 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 9a6d04a2..36b30cd7 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 @@ -1,22 +1,26 @@ -import { Component, OnInit, Input } from '@angular/core'; +import { Component, Input, OnChanges } from '@angular/core'; import { Drawing } from '../../../../../cartography/models/drawing'; import { Server } from '../../../../../models/server'; import { MatDialog } from '@angular/material'; import { Project } from '../../../../../models/project'; import { StyleEditorDialogComponent } from '../../../drawings-editors/style-editor/style-editor.component'; +import { ImageElement } from '../../../../../cartography/models/drawings/image-element'; @Component({ selector: 'app-edit-style-action', templateUrl: './edit-style-action.component.html' }) -export class EditStyleActionComponent implements OnInit { +export class EditStyleActionComponent implements OnChanges { @Input() server: Server; @Input() project: Project; @Input() drawing: Drawing; + isImageDrawing: boolean = false; constructor(private dialog: MatDialog) {} - ngOnInit() {} + ngOnChanges() { + this.isImageDrawing = this.drawing.element instanceof ImageElement; + } editStyle() { const dialogRef = this.dialog.open(StyleEditorDialogComponent, { 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 0d3b16f8..ac93623b 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,9 +1,15 @@ -
+
-
Console
@@ -20,7 +26,7 @@
-
+
{{event.message}}
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 e3b1ec5d..0b052a23 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 @@ -15,6 +15,11 @@ background: #263238; color: white; border: none; + margin-top: 0px; + outline: none; + color: #dbd5d5; + font-weight: bold; + padding: 0px; } .consoleFiltering { 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 22c9091f..01a54848 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 @@ -12,6 +12,7 @@ import { Port } from '../../../models/port'; import { LogEventsDataSource } from './log-events-datasource'; import { HttpServer } from '../../../services/http-server.service'; import { LogEvent } from '../../../models/logEvent'; +import { ResizeEvent } from 'angular-resizable-element'; @Component({ @@ -44,6 +45,9 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { private regexShow: RegExp = /^show (.*?)$/; private regexConsole: RegExp = /^console (.*?)$/; + public style: object = {}; + public styleInside: object = { height: `120px` }; + constructor( private projectWebServiceHandler: ProjectWebServiceHandler, private nodeService: NodeService, @@ -124,6 +128,33 @@ export class LogConsoleComponent implements OnInit, AfterViewInit, OnDestroy { this.infoSubscription.unsubscribe(); } + validate(event: ResizeEvent): boolean { + if ( + event.rectangle.width && + event.rectangle.height && + (event.rectangle.width < 600 || + event.rectangle.height < 180) + ) { + return false; + } + return true; + } + + onResizeEnd(event: ResizeEvent): void { + this.style = { + position: 'fixed', + left: `${event.rectangle.left}px`, + top: `${event.rectangle.top}px`, + width: `${event.rectangle.width}px`, + height: `${event.rectangle.height}px` + }; + + this.styleInside = { + height: `${event.rectangle.height - 60}px`, + width: `${event.rectangle.width}px` + }; + } + applyFilter(filter: string) { this.selectedFilter = filter; this.filteredEvents = this.getFilteredEvents(); diff --git a/src/app/components/project-map/project-map.component.html b/src/app/components/project-map/project-map.component.html index c912c2f3..50484916 100644 --- a/src/app/components/project-map/project-map.component.html +++ b/src/app/components/project-map/project-map.component.html @@ -94,6 +94,9 @@ Show notifications + + Show layers +
diff --git a/src/app/components/project-map/project-map.component.ts b/src/app/components/project-map/project-map.component.ts index a616a0c8..86722b89 100644 --- a/src/app/components/project-map/project-map.component.ts +++ b/src/app/components/project-map/project-map.component.ts @@ -79,10 +79,11 @@ export class ProjectMapComponent implements OnInit, OnDestroy { public server: Server; public ws: WebSocket; public isProjectMapMenuVisible: boolean = false; - public isConsoleVisible: boolean = false; - public isTopologySummaryVisible: boolean = false; + public isConsoleVisible: boolean = true; + public isTopologySummaryVisible: boolean = true; public isInterfaceLabelVisible: boolean = false; public notificationsVisibility: boolean = false; + public layersVisibility: boolean = false; tools = { selection: true, @@ -238,6 +239,7 @@ export class ProjectMapComponent implements OnInit, OnDestroy { })); this.notificationsVisibility = localStorage.getItem('notificationsVisibility') === 'true' ? true : false; + this.layersVisibility = localStorage.getItem('layersVisibility') === 'true' ? true : false; this.addKeyboardListeners(); } @@ -618,6 +620,17 @@ export class ProjectMapComponent implements OnInit, OnDestroy { } } + public toggleLayers(visible: boolean) { + this.layersVisibility = visible; + this.mapSettingsService.toggleLayers(visible); + if (this.layersVisibility) { + localStorage.setItem('layersVisibility', 'true'); + } else { + localStorage.removeItem('layersVisibility') + } + this.mapChild.applyMapSettingsChanges(); + } + private showMessage(msg) { if (this.notificationsVisibility) { if (msg.type === 'error') this.toasterService.error(msg.message); diff --git a/src/app/components/topology-summary/topology-summary.component.html b/src/app/components/topology-summary/topology-summary.component.html index 83500e4f..f93bbaab 100644 --- a/src/app/components/topology-summary/topology-summary.component.html +++ b/src/app/components/topology-summary/topology-summary.component.html @@ -1,4 +1,12 @@ -
+
@@ -29,7 +37,9 @@
-
+
diff --git a/src/app/components/topology-summary/topology-summary.component.scss b/src/app/components/topology-summary/topology-summary.component.scss index 87512793..a61cb2c9 100644 --- a/src/app/components/topology-summary/topology-summary.component.scss +++ b/src/app/components/topology-summary/topology-summary.component.scss @@ -36,7 +36,6 @@ .summaryContent { margin-left: 5px; margin-right: 5px; - max-height: 180px; overflow: auto; scrollbar-color: darkgrey #263238; scrollbar-width: thin; @@ -62,8 +61,9 @@ } .divider { - margin: 5px; - width: 290px; + margin-top: 5px; + margin-bottom: 5px; + width: 100%; height: 2px; } diff --git a/src/app/components/topology-summary/topology-summary.component.ts b/src/app/components/topology-summary/topology-summary.component.ts index 29405692..f1e129e1 100644 --- a/src/app/components/topology-summary/topology-summary.component.ts +++ b/src/app/components/topology-summary/topology-summary.component.ts @@ -9,6 +9,7 @@ import { ProjectStatistics } from '../../models/project-statistics'; import { Compute } from '../../models/compute'; import { ComputeService } from '../../services/compute.service'; import { LinksDataSource } from '../../cartography/datasources/links-datasource'; +import { ResizeEvent } from 'angular-resizable-element'; @Component({ @@ -22,6 +23,8 @@ export class TopologySummaryComponent implements OnInit, OnDestroy { @Output() closeTopologySummary = new EventEmitter(); + public style: object = {}; + public styleInside: object = { height: `180px` }; private subscriptions: Subscription[] = []; projectsStatistics: ProjectStatistics; nodes: Node[] = []; @@ -63,6 +66,32 @@ export class TopologySummaryComponent implements OnInit, OnDestroy { }); } + validate(event: ResizeEvent): boolean { + if ( + event.rectangle.width && + event.rectangle.height && + (event.rectangle.width < 290 || + event.rectangle.height < 260) + ) { + return false; + } + return true; + } + + onResizeEnd(event: ResizeEvent): void { + this.style = { + position: 'fixed', + left: `${event.rectangle.left}px`, + top: `${event.rectangle.top}px`, + width: `${event.rectangle.width}px`, + height: `${event.rectangle.height}px` + }; + + this.styleInside = { + height: `${event.rectangle.height - 220}px` + }; + } + toogleTopologyVisibility(value: boolean) { this.isTopologyVisible = value; } diff --git a/src/app/services/mapsettings.service.ts b/src/app/services/mapsettings.service.ts index ec9f8e54..2c14f21d 100644 --- a/src/app/services/mapsettings.service.ts +++ b/src/app/services/mapsettings.service.ts @@ -6,9 +6,12 @@ export class MapSettingsService { public isMapLocked = new Subject(); public isTopologySummaryVisible: boolean = false; public isLogConsoleVisible: boolean = false; + public isLayerNumberVisible: boolean = false; public interfaceLabels: Map = new Map(); - constructor() {} + constructor() { + this.isLayerNumberVisible = localStorage.getItem('layersVisibility') === 'true' ? true : false; + } changeMapLockValue(value: boolean) { this.isMapLocked.next(value); @@ -22,6 +25,10 @@ export class MapSettingsService { this.isLogConsoleVisible = value; } + toggleLayers(value: boolean) { + this.isLayerNumberVisible = value; + } + toggleShowInterfaceLabels(projectId: string, value: boolean) { this.interfaceLabels.set(projectId, value); } diff --git a/yarn.lock b/yarn.lock index 6964db2d..95488ec6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1066,6 +1066,20 @@ angular-persistence@^1.0.1: resolved "https://registry.npmjs.org/angular-persistence/-/angular-persistence-1.0.1.tgz#79ffe7317f1f7aed88e69f07705f0ac32ccdb9da" integrity sha1-ef/nMX8feu2I5p8HcF8KwyzNudo= +angular-resizable-element@^3.2.6: + version "3.2.6" + resolved "https://registry.npmjs.org/angular-resizable-element/-/angular-resizable-element-3.2.6.tgz#1df9b14853691e00b99c74492e729b7a35cf70a0" + integrity sha512-8vp5w4YFIrZ2M8EmGpIt/yMwLBjkUJe7aPLPxDDQhi5HQWF0HLJ6lb4tXgEzW572roxNnHFg105EM6XGAMZDIg== + dependencies: + tslib "^1.9.0" + +angular2-draggable@^2.3.2: + version "2.3.2" + resolved "https://registry.npmjs.org/angular2-draggable/-/angular2-draggable-2.3.2.tgz#54ca569a6b3aa9ca1a8a4d663d3eee3024c48af3" + integrity sha512-rw2O/icgVang8uSVIU7nmm59f1DceSAUQkOuSGYnKbv/h8EbhJ9099sCjh/I5LymZBza1XPKeFZofIvhekdE+A== + dependencies: + tslib "^1.9.0" + angular2-hotkeys@^2.1.5: version "2.1.5" resolved "https://registry.npmjs.org/angular2-hotkeys/-/angular2-hotkeys-2.1.5.tgz#d4d5df7cecd231d556089832609283f37674fdea"