mirror of
https://github.com/GNS3/gns3-web-ui.git
synced 2024-12-19 04:57:51 +00:00
Merge pull request #516 from GNS3/Ability-to-lock-single-item-on-map
Ability to lock single item on map
This commit is contained in:
commit
6cf670d5cf
@ -238,6 +238,7 @@ import { QemuImageCreatorComponent } from './components/project-map/node-editors
|
||||
import { ChooseNameDialogComponent } from './components/projects/choose-name-dialog/choose-name-dialog.component';
|
||||
import { PacketCaptureService } from './services/packet-capture.service';
|
||||
import { StartCaptureOnStartedLinkActionComponent } from './components/project-map/context-menu/actions/start-capture-on-started-link/start-capture-on-started-link.component';
|
||||
import { LockActionComponent } from './components/project-map/context-menu/actions/lock-action/lock-action.component';
|
||||
|
||||
if (environment.production) {
|
||||
Raven.config('https://b2b1cfd9b043491eb6b566fd8acee358@sentry.io/842726', {
|
||||
@ -401,7 +402,8 @@ if (environment.production) {
|
||||
TracengTemplateDetailsComponent,
|
||||
QemuImageCreatorComponent,
|
||||
ChooseNameDialogComponent,
|
||||
StartCaptureOnStartedLinkActionComponent
|
||||
StartCaptureOnStartedLinkActionComponent,
|
||||
LockActionComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
|
@ -94,8 +94,10 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
|
||||
).subscribe((evt: DraggableDrag<any>) => {
|
||||
if (!this.isMapLocked) {
|
||||
const selected = this.selectionManager.getSelected();
|
||||
const selectedNodes = selected.filter(item => item instanceof MapNode);
|
||||
// update nodes
|
||||
let mapNodes = selected.filter(item => item instanceof MapNode);
|
||||
const lockedNodes = mapNodes.filter((item: MapNode) => item.locked);
|
||||
const selectedNodes = mapNodes.filter((item: MapNode) => !item.locked);
|
||||
selectedNodes.forEach((node: MapNode) => {
|
||||
node.x += evt.dx;
|
||||
node.y += evt.dy;
|
||||
@ -116,52 +118,52 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
|
||||
// update drawings
|
||||
selected
|
||||
.filter(item => item instanceof MapDrawing)
|
||||
.forEach((drawing: MapDrawing) => {
|
||||
drawing.x += evt.dx;
|
||||
drawing.y += evt.dy;
|
||||
this.drawingsWidget.redrawDrawing(svg, drawing);
|
||||
});
|
||||
let mapDrawings = selected.filter(item => item instanceof MapDrawing);
|
||||
const selectedDrawings = mapDrawings.filter((item: MapDrawing) => !item.locked);
|
||||
selectedDrawings.forEach((drawing: MapDrawing) => {
|
||||
drawing.x += evt.dx;
|
||||
drawing.y += evt.dy;
|
||||
this.drawingsWidget.redrawDrawing(svg, drawing);
|
||||
});
|
||||
|
||||
// update labels
|
||||
selected
|
||||
.filter(item => item instanceof MapLabel)
|
||||
.forEach((label: MapLabel) => {
|
||||
const isParentNodeSelected = selectedNodes.filter(node => node.id === label.nodeId).length > 0;
|
||||
if (isParentNodeSelected) {
|
||||
return;
|
||||
}
|
||||
let mapLabels = selected.filter(item => item instanceof MapLabel);
|
||||
const selectedLabels = mapLabels.filter((item: MapLabel) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0);
|
||||
selectedLabels.forEach((label: MapLabel) => {
|
||||
const isParentNodeSelected = selectedNodes.filter(node => node.id === label.nodeId).length > 0;
|
||||
if (isParentNodeSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const node = this.graphDataManager.getNodes().filter(node => node.id === label.nodeId)[0];
|
||||
node.label.x += evt.dx;
|
||||
node.label.y += evt.dy;
|
||||
this.labelWidget.redrawLabel(svg, label);
|
||||
});
|
||||
const node = this.graphDataManager.getNodes().filter(node => node.id === label.nodeId)[0];
|
||||
node.label.x += evt.dx;
|
||||
node.label.y += evt.dy;
|
||||
this.labelWidget.redrawLabel(svg, label);
|
||||
});
|
||||
|
||||
// update interface labels
|
||||
selected
|
||||
.filter(item => item instanceof MapLinkNode)
|
||||
.forEach((interfaceLabel: MapLinkNode) => {
|
||||
const isParentNodeSelected = selectedNodes.filter(node => node.id === interfaceLabel.nodeId).length > 0;
|
||||
if (isParentNodeSelected) {
|
||||
return;
|
||||
}
|
||||
let mapLinkNodes = selected.filter(item => item instanceof MapLinkNode);
|
||||
const selectedLinkNodes = mapLinkNodes.filter((item: MapLinkNode) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0);
|
||||
selectedLinkNodes.forEach((interfaceLabel: MapLinkNode) => {
|
||||
const isParentNodeSelected = selectedNodes.filter(node => node.id === interfaceLabel.nodeId).length > 0;
|
||||
if (isParentNodeSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
const link = this.graphDataManager
|
||||
.getLinks()
|
||||
.filter(link => link.nodes[0].id === interfaceLabel.id || link.nodes[1].id === interfaceLabel.id)[0];
|
||||
if (link.nodes[0].id === interfaceLabel.id) {
|
||||
link.nodes[0].label.x += evt.dx;
|
||||
link.nodes[0].label.y += evt.dy;
|
||||
}
|
||||
if (link.nodes[1].id === interfaceLabel.id) {
|
||||
link.nodes[1].label.x += evt.dx;
|
||||
link.nodes[1].label.y += evt.dy;
|
||||
}
|
||||
const link = this.graphDataManager
|
||||
.getLinks()
|
||||
.filter(link => link.nodes[0].id === interfaceLabel.id || link.nodes[1].id === interfaceLabel.id)[0];
|
||||
if (link.nodes[0].id === interfaceLabel.id) {
|
||||
link.nodes[0].label.x += evt.dx;
|
||||
link.nodes[0].label.y += evt.dy;
|
||||
}
|
||||
if (link.nodes[1].id === interfaceLabel.id) {
|
||||
link.nodes[1].label.x += evt.dx;
|
||||
link.nodes[1].label.y += evt.dy;
|
||||
}
|
||||
|
||||
this.linksWidget.redrawLink(svg, link);
|
||||
});
|
||||
this.linksWidget.redrawLink(svg, link);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@ -173,39 +175,41 @@ export class DraggableSelectionComponent implements OnInit, OnDestroy {
|
||||
).subscribe((evt: DraggableEnd<any>) => {
|
||||
if (!this.isMapLocked) {
|
||||
const selected = this.selectionManager.getSelected();
|
||||
const selectedNodes = selected.filter(item => item instanceof MapNode);
|
||||
|
||||
let mapNodes = selected.filter(item => item instanceof MapNode);
|
||||
const lockedNodes = mapNodes.filter((item: MapNode) => item.locked);
|
||||
const selectedNodes = mapNodes.filter((item: MapNode) => !item.locked);
|
||||
selectedNodes.forEach((item: MapNode) => {
|
||||
this.nodesEventSource.dragged.emit(new DraggedDataEvent<MapNode>(item, evt.dx, evt.dy));
|
||||
});
|
||||
|
||||
selected
|
||||
.filter(item => item instanceof MapDrawing)
|
||||
.forEach((item: MapDrawing) => {
|
||||
this.drawingsEventSource.dragged.emit(new DraggedDataEvent<MapDrawing>(item, evt.dx, evt.dy));
|
||||
});
|
||||
let mapDrawings = selected.filter(item => item instanceof MapDrawing);
|
||||
const selectedDrawings = mapDrawings.filter((item: MapDrawing) => !item.locked);
|
||||
selectedDrawings.forEach((item: MapDrawing) => {
|
||||
this.drawingsEventSource.dragged.emit(new DraggedDataEvent<MapDrawing>(item, evt.dx, evt.dy));
|
||||
});
|
||||
|
||||
selected
|
||||
.filter(item => item instanceof MapLabel)
|
||||
.forEach((label: MapLabel) => {
|
||||
const isParentNodeSelected = selectedNodes.filter(node => node.id === label.nodeId).length > 0;
|
||||
if (isParentNodeSelected) {
|
||||
return;
|
||||
}
|
||||
let mapLabels = selected.filter(item => item instanceof MapLabel);
|
||||
const selectedLabels = mapLabels.filter((item: MapLabel) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0);
|
||||
selectedLabels.forEach((label: MapLabel) => {
|
||||
const isParentNodeSelected = selectedNodes.filter(node => node.id === label.nodeId).length > 0;
|
||||
if (isParentNodeSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.nodesEventSource.labelDragged.emit(new DraggedDataEvent<MapLabel>(label, evt.dx, evt.dy));
|
||||
});
|
||||
this.nodesEventSource.labelDragged.emit(new DraggedDataEvent<MapLabel>(label, evt.dx, evt.dy));
|
||||
});
|
||||
|
||||
selected
|
||||
.filter(item => item instanceof MapLinkNode)
|
||||
.forEach((label: MapLinkNode) => {
|
||||
const isParentNodeSelected = selectedNodes.filter(node => node.id === label.nodeId).length > 0;
|
||||
if (isParentNodeSelected) {
|
||||
return;
|
||||
}
|
||||
this.linksEventSource.interfaceDragged.emit(new DraggedDataEvent<MapLinkNode>(label, evt.dx, evt.dy));
|
||||
});
|
||||
}
|
||||
let mapLinkNodes = selected.filter(item => item instanceof MapLinkNode);
|
||||
const selectedLinkNodes = mapLinkNodes.filter((item: MapLinkNode) => lockedNodes.filter((node) => node.id === item.nodeId).length === 0)
|
||||
selectedLinkNodes.forEach((label: MapLinkNode) => {
|
||||
const isParentNodeSelected = selectedNodes.filter(node => node.id === label.nodeId).length > 0;
|
||||
if (isParentNodeSelected) {
|
||||
return;
|
||||
}
|
||||
this.linksEventSource.interfaceDragged.emit(new DraggedDataEvent<MapLinkNode>(label, evt.dx, evt.dy));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ export class DrawingToMapDrawingConverter implements Converter<Drawing, MapDrawi
|
||||
mapDrawing.projectId = drawing.project_id;
|
||||
mapDrawing.rotation = drawing.rotation;
|
||||
mapDrawing.svg = drawing.svg;
|
||||
mapDrawing.locked = drawing.locked;
|
||||
mapDrawing.x = drawing.x;
|
||||
mapDrawing.y = drawing.y;
|
||||
mapDrawing.z = drawing.z;
|
||||
|
@ -14,6 +14,7 @@ export class MapDrawingToDrawingConverter implements Converter<MapDrawing, Drawi
|
||||
drawing.project_id = mapDrawing.projectId;
|
||||
drawing.rotation = mapDrawing.rotation;
|
||||
drawing.svg = mapDrawing.svg;
|
||||
drawing.locked = mapDrawing.locked;
|
||||
drawing.x = mapDrawing.x;
|
||||
drawing.y = mapDrawing.y;
|
||||
drawing.z = mapDrawing.z;
|
||||
|
@ -20,6 +20,7 @@ export class MapNodeToNodeConverter implements Converter<MapNode, Node> {
|
||||
node.first_port_name = mapNode.firstPortName;
|
||||
node.height = mapNode.height;
|
||||
node.label = mapNode.label ? this.mapLabelToLabel.convert(mapNode.label) : undefined;
|
||||
node.locked = mapNode.locked;
|
||||
node.name = mapNode.name;
|
||||
node.node_directory = mapNode.nodeDirectory;
|
||||
node.node_type = mapNode.nodeType;
|
||||
|
@ -29,6 +29,7 @@ export class NodeToMapNodeConverter implements Converter<Node, MapNode> {
|
||||
mapNode.firstPortName = node.first_port_name;
|
||||
mapNode.height = node.height;
|
||||
mapNode.label = this.labelToMapLabel.convert(node.label, { node_id: node.node_id });
|
||||
mapNode.locked = node.locked;
|
||||
mapNode.name = node.name;
|
||||
mapNode.nodeDirectory = node.node_directory;
|
||||
mapNode.nodeType = node.node_type;
|
||||
|
@ -5,6 +5,7 @@ export class Drawing {
|
||||
project_id: string;
|
||||
rotation: number;
|
||||
svg: string;
|
||||
locked: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
|
@ -6,6 +6,7 @@ export class MapDrawing implements Indexed {
|
||||
projectId: string;
|
||||
rotation: number;
|
||||
svg: string;
|
||||
locked: boolean;
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
|
@ -12,6 +12,7 @@ export class MapNode implements Indexed {
|
||||
firstPortName: string;
|
||||
height: number;
|
||||
label: MapLabel;
|
||||
locked: boolean;
|
||||
name: string;
|
||||
nodeDirectory: string;
|
||||
nodeType: string;
|
||||
|
@ -69,6 +69,7 @@ export class Node {
|
||||
first_port_name: string;
|
||||
height: number;
|
||||
label: Label;
|
||||
locked: boolean;
|
||||
name: string;
|
||||
node_directory: string;
|
||||
node_id: string;
|
||||
|
@ -48,6 +48,7 @@ describe('DrawingDraggedComponent', () => {
|
||||
};
|
||||
const mapDrawing: MapDrawing = {
|
||||
id: 'sampleId',
|
||||
locked: false,
|
||||
projectId: 'sampleprojectId',
|
||||
rotation: 0,
|
||||
svg: 'sampleSvg',
|
||||
|
@ -51,6 +51,7 @@ describe('DrawingResizedComponent', () => {
|
||||
};
|
||||
const mapDrawing: MapDrawing = {
|
||||
id: 'sampleId',
|
||||
locked: false,
|
||||
projectId: 'sampleprojectId',
|
||||
rotation: 0,
|
||||
svg: 'sampleSvg',
|
||||
|
@ -72,6 +72,7 @@ describe('LinkCreatedComponent', () => {
|
||||
firstPortName: 'sampleFirstPortName',
|
||||
height: 0,
|
||||
label: {} as MapLabel,
|
||||
locked: false,
|
||||
name: 'sampleName',
|
||||
nodeDirectory: 'sampleNodeDirectory',
|
||||
nodeType: 'sampleNodeType',
|
||||
|
@ -52,6 +52,7 @@ describe('NodeDraggedComponent', () => {
|
||||
firstPortName: 'sampleFirstPortName',
|
||||
height: 0,
|
||||
label: {} as MapLabel,
|
||||
locked: false,
|
||||
name: 'sampleName',
|
||||
nodeDirectory: 'sampleNodeDirectory',
|
||||
nodeType: 'sampleNodeType',
|
||||
|
@ -0,0 +1,4 @@
|
||||
<button mat-menu-item (click)="lock()">
|
||||
<mat-icon>lock</mat-icon>
|
||||
<span>{{command}}</span>
|
||||
</button>
|
@ -0,0 +1,48 @@
|
||||
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-lock-action',
|
||||
templateUrl: './lock-action.component.html'
|
||||
})
|
||||
export class LockActionComponent implements OnInit {
|
||||
@Input() server: Server;
|
||||
@Input() nodes: Node[];
|
||||
@Input() drawings: Drawing[];
|
||||
command: string;
|
||||
|
||||
constructor(
|
||||
private nodesDataSource: NodesDataSource,
|
||||
private drawingsDataSource: DrawingsDataSource,
|
||||
private nodeService: NodeService,
|
||||
private drawingService: DrawingService
|
||||
) {}
|
||||
|
||||
ngOnInit() {
|
||||
if (this.nodes.length === 1 && this.drawings.length === 0) {
|
||||
this.command = this.nodes[0].locked ? 'Unlock item' : 'Lock item';
|
||||
} else if (this.nodes.length === 0 && this.drawings.length === 1) {
|
||||
this.command = this.drawings[0].locked ? 'Unlock item' : 'Lock item';
|
||||
} else {
|
||||
this.command = 'Lock/unlock items';
|
||||
}
|
||||
}
|
||||
|
||||
lock() {
|
||||
this.nodes.forEach((node) => {
|
||||
node.locked = !node.locked;
|
||||
this.nodeService.updateNode(this.server, node).subscribe((node) => { this.nodesDataSource.update(node) });
|
||||
});
|
||||
|
||||
this.drawings.forEach((drawing) => {
|
||||
drawing.locked = ! drawing.locked;
|
||||
this.drawingService.update(this.server, drawing).subscribe((drawing) => { this.drawingsDataSource.update(drawing) });
|
||||
});
|
||||
}
|
||||
}
|
@ -121,6 +121,12 @@
|
||||
[server]="server"
|
||||
[link]="links[0]"
|
||||
></app-suspend-link-action>
|
||||
<app-lock-action
|
||||
*ngIf="!projectService.isReadOnly(project) && (drawings.length>0 || nodes.length>0)"
|
||||
[server]="server"
|
||||
[nodes]="nodes"
|
||||
[drawings]="drawings"
|
||||
></app-lock-action>
|
||||
<app-delete-action
|
||||
*ngIf="!projectService.isReadOnly(project) && (drawings.length>0 || nodes.length>0 || links.length>0) && linkNodes.length === 0"
|
||||
[server]="server"
|
||||
|
@ -111,6 +111,7 @@ describe('DrawingService', () => {
|
||||
drawing.z = 30;
|
||||
drawing.rotation = 0;
|
||||
drawing.svg = '<svg></svg>';
|
||||
drawing.locked = false;
|
||||
|
||||
service.update(server, drawing).subscribe();
|
||||
|
||||
@ -121,7 +122,8 @@ describe('DrawingService', () => {
|
||||
y: 20,
|
||||
z: 30,
|
||||
rotation: 0,
|
||||
svg: '<svg></svg>'
|
||||
svg: '<svg></svg>',
|
||||
locked: false
|
||||
});
|
||||
}));
|
||||
|
||||
|
@ -55,6 +55,7 @@ export class DrawingService {
|
||||
|
||||
update(server: Server, drawing: Drawing): Observable<Drawing> {
|
||||
return this.httpServer.put<Drawing>(server, `/projects/${drawing.project_id}/drawings/${drawing.drawing_id}`, {
|
||||
locked: drawing.locked,
|
||||
svg: drawing.svg,
|
||||
rotation: drawing.rotation,
|
||||
x: Math.round(drawing.x),
|
||||
|
@ -90,6 +90,7 @@ export class NodeService {
|
||||
return this.httpServer.put<Node>(server, `/projects/${node.project_id}/nodes/${node.node_id}`, {
|
||||
console_type: node.console_type,
|
||||
console_auto_start: node.console_auto_start,
|
||||
locked: node.locked,
|
||||
name: node.name,
|
||||
properties: node.properties
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user