GUI2 Handle node additions and removals in Topology view
Change-Id: Ic16fc1325fe338e2136f1cc70febc621342be4f2
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html
index b673b24..58606e9 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.html
@@ -89,7 +89,7 @@
<svg:g onos-hostnodesvg [host]="host"
*ngFor="let host of regionData.hosts[visibleLayerIdx()]"
onosDraggableNode [draggableNode]="host" [draggableInGraph]="graph"
- (newLocation)="nodeMoved('host', device.id, $event)"
+ (newLocation)="nodeMoved('host', host.id, $event)"
(selectedEvent)="updateSelected($event)"
[labelToggle]="hostLabelToggle"
[scale]="scale">
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts
index ebc70aa..48d973b 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/forcesvg.component.ts
@@ -57,10 +57,7 @@
HostNodeSvgComponent,
LinkSvgComponent
} from './visuals';
-import {
- BackgroundSvgComponent,
- LocationType
-} from '../backgroundsvg/backgroundsvg.component';
+import {LocationType} from '../backgroundsvg/backgroundsvg.component';
interface UpdateMeta {
id: string;
@@ -130,6 +127,28 @@
}
}
+ /**
+ * Recursive method to compare 2 objects attribute by attribute and update
+ * the first where a change is detected
+ * @param existingNode 1st object
+ * @param updatedNode 2nd object
+ */
+ private static updateObject(existingNode: Object, updatedNode: Object): number {
+ let changed: number = 0;
+ for (const key of Object.keys(updatedNode)) {
+ const o = updatedNode[key];
+ if (key === 'id') {
+ continue;
+ } else if (o && typeof o === 'object' && o.constructor === Object) {
+ changed += ForceSvgComponent.updateObject(existingNode[key], updatedNode[key]);
+ } else if (existingNode[key] !== updatedNode[key]) {
+ changed++;
+ existingNode[key] = updatedNode[key];
+ }
+ }
+ return changed;
+ }
+
@HostListener('window:resize', ['$event'])
onResize(event) {
this.graph.initSimulation(this.options);
@@ -310,25 +329,32 @@
case ModelEventType.DEVICE_ADDED_OR_UPDATED:
if (memo === ModelEventMemo.ADDED) {
this.regionData.devices[this.visibleLayerIdx()].push(<Device>data);
+ this.graph.nodes.push(<Device>data);
+ this.log.debug('Device added', (<Device>data).id);
} else if (memo === ModelEventMemo.UPDATED) {
const oldDevice: Device =
this.regionData.devices[this.visibleLayerIdx()]
.find((d) => d.id === subject);
- this.compareDevice(oldDevice, <Device>data);
+ const changes = ForceSvgComponent.updateObject(oldDevice, <Device>data);
+ if (changes > 0) {
+ this.log.debug('Device ', oldDevice.id, memo, ' - ', changes, 'changes');
+ }
} else {
this.log.warn('Device ', memo, ' - not yet implemented', data);
}
- this.log.warn('Device ', memo, ' - not yet implemented', data);
break;
case ModelEventType.HOST_ADDED_OR_UPDATED:
if (memo === ModelEventMemo.ADDED) {
this.regionData.hosts[this.visibleLayerIdx()].push(<Host>data);
- this.log.warn('Host added - not yet implemented', data);
+ this.graph.nodes.push(<Host>data);
+ this.log.debug('Host added', (<Host>data).id);
} else if (memo === ModelEventMemo.UPDATED) {
const oldHost: Host = this.regionData.hosts[this.visibleLayerIdx()]
.find((h) => h.id === subject);
- this.compareHost(oldHost, <Host>data);
- this.log.warn('Host updated - not yet implemented', data);
+ const changes = ForceSvgComponent.updateObject(oldHost, <Host>data);
+ if (changes > 0) {
+ this.log.debug('Host ', oldHost.id, memo, ' - ', changes, 'changes');
+ }
} else {
this.log.warn('Host change', memo, ' - unexpected');
}
@@ -338,9 +364,9 @@
const removeIdx: number =
this.regionData.devices[this.visibleLayerIdx()]
.findIndex((d) => d.id === subject);
- const removeCmpt: DeviceNodeSvgComponent =
- this.devices.find((dc) => dc.device.id === subject);
- this.log.warn('Device ', subject, 'removed - not yet implemented', removeIdx, removeCmpt.device.id);
+ this.regionData.devices[this.visibleLayerIdx()].splice(removeIdx, 1);
+ this.removeRelatedLinks(subject);
+ this.log.debug('Device ', subject, 'removed. Links', this.regionData.links);
} else {
this.log.warn('Device removed - unexpected memo', memo);
}
@@ -350,33 +376,53 @@
const removeIdx: number =
this.regionData.hosts[this.visibleLayerIdx()]
.findIndex((h) => h.id === subject);
- const removeCmpt: HostNodeSvgComponent =
- this.hosts.find((hc) => hc.host.id === subject);
- this.log.warn('Host ', subject, 'removed - not yet implemented', removeIdx, removeCmpt.host.id);
+ this.regionData.hosts[this.visibleLayerIdx()].splice(removeIdx, 1);
+ this.removeRelatedLinks(subject);
+ this.log.warn('Host ', subject, 'removed');
} else {
this.log.warn('Host removed - unexpected memo', memo);
}
break;
case ModelEventType.LINK_ADDED_OR_UPDATED:
- this.log.warn('link added or updated - not yet implemented', subject);
+ if (memo === ModelEventMemo.ADDED &&
+ this.regionData.links.findIndex((l) => l.id === subject) === -1) {
+ const listLen = this.regionData.links.push(<RegionLink>data);
+ const epA = ForceSvgComponent.extractNodeName(
+ this.regionData.links[listLen - 1].epA);
+ this.regionData.links[listLen - 1].source =
+ this.graph.nodes.find((node) =>
+ node.id === epA);
+ const epB = ForceSvgComponent.extractNodeName(
+ this.regionData.links[listLen - 1].epB);
+ this.regionData.links[listLen - 1].target =
+ this.graph.nodes.find((node) =>
+ node.id === epB);
+ this.log.debug('Link added', subject);
+ } else if (memo === ModelEventMemo.UPDATED) {
+ const oldLink = this.regionData.links.find((l) => l.id === subject);
+ const changes = ForceSvgComponent.updateObject(oldLink, <RegionLink>data);
+ this.log.debug('Link ', subject, '. Updated', changes, 'items');
+ } else {
+ this.log.warn('Link added or updated - unexpected memo', memo);
+ }
break;
default:
this.log.error('Unexpected model event', type, 'for', subject);
}
+ this.ref.markForCheck();
+ this.graph.initSimulation(this.options);
}
- private compareDevice(oldDevice: Device, updatedDevice: Device) {
- if (oldDevice.master !== updatedDevice.master) {
- this.log.debug('Mastership has changed for', updatedDevice.id, 'to', updatedDevice.master);
- }
- if (oldDevice.online !== updatedDevice.online) {
- this.log.debug('Status has changed for', updatedDevice.id, 'to', updatedDevice.online);
- }
- }
-
- private compareHost(oldHost: Host, updatedHost: Host) {
- if (oldHost.configured !== updatedHost.configured) {
- this.log.debug('Configured has changed for', updatedHost.id, 'to', updatedHost.configured);
+ private removeRelatedLinks(subject: string) {
+ const len = this.regionData.links.length;
+ for (let i = 0; i < len; i++) {
+ const linkIdx = this.regionData.links.findIndex((l) =>
+ (ForceSvgComponent.extractNodeName(l.epA) === subject ||
+ ForceSvgComponent.extractNodeName(l.epB) === subject));
+ if (linkIdx >= 0) {
+ this.regionData.links.splice(linkIdx, 1);
+ this.log.debug('Link ', linkIdx, 'removed on attempt', i);
+ }
}
}
diff --git a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/node.ts b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/node.ts
index ce5441f..af280a4 100644
--- a/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/node.ts
+++ b/web/gui2/src/main/webapp/app/view/topology/layer/forcesvg/models/node.ts
@@ -111,6 +111,9 @@
name: string;
locType: LocationType;
uiType: string;
+ channelId: string;
+ managementAddress: string;
+ protocol: string;
}
export interface HostProps {
diff --git a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html
index 8644ac1..8f3378f 100644
--- a/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html
+++ b/web/gui2/src/main/webapp/app/view/topology/topology/topology.component.html
@@ -56,7 +56,7 @@
are driven by the d3.force engine
-->
<svg:svg #svgZoom xmlns:svg="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000" id="topo2"
- preserveAspectRatio="xMaxYMax none">
+ preserveAspectRatio="xMaxYMax meet">
<svg:desc>The main SVG canvas of the Topology View</svg:desc>
<svg:g *ngIf="force.regionData?.devices[0].length +
force.regionData?.devices[1].length +