diff --git a/awx/network_ui/static/network_ui/Makefile b/awx/network_ui/static/network_ui/Makefile
index b24ed19334..b23f0a55b2 100644
--- a/awx/network_ui/static/network_ui/Makefile
+++ b/awx/network_ui/static/network_ui/Makefile
@@ -28,8 +28,8 @@ istanbul:
cp vendor/*.js js/
-simple-server:
- python -m SimpleHTTPServer
+simple-server: lint main lessc
+ python -m SimpleHTTPServer 8080
deploy: main
diff --git a/awx/network_ui/static/network_ui/designs/device_detail.yml b/awx/network_ui/static/network_ui/designs/device_detail.yml
new file mode 100644
index 0000000000..810655123e
--- /dev/null
+++ b/awx/network_ui/static/network_ui/designs/device_detail.yml
@@ -0,0 +1,19 @@
+finite_state_machine_id: 131
+name: fsm
+states:
+- id: 2
+ label: Ready
+ x: 517
+ y: 588
+- id: 3
+ label: Disable
+ x: 770
+ y: 455
+- id: 1
+ label: Start
+ x: 507
+ y: 336
+transitions:
+- from_state: Start
+ label: start
+ to_state: Ready
diff --git a/awx/network_ui/static/network_ui/designs/mode.yml b/awx/network_ui/static/network_ui/designs/mode.yml
new file mode 100644
index 0000000000..8a2a17c1d6
--- /dev/null
+++ b/awx/network_ui/static/network_ui/designs/mode.yml
@@ -0,0 +1,65 @@
+finite_state_machine_id: 130
+name: mode
+states:
+- id: 1
+ label: Start
+ x: 568
+ y: -379
+- id: 2
+ label: Interface
+ x: 340
+ y: 1053
+- id: 3
+ label: Rack
+ x: 571
+ y: 486
+- id: 4
+ label: Process
+ x: 833
+ y: 1051
+- id: 5
+ label: MultiSite
+ x: 569
+ y: -88
+- id: 6
+ label: Device
+ x: 558
+ y: 821
+- id: 7
+ label: Site
+ x: 564
+ y: 201
+transitions:
+- from_state: Rack
+ label: onMouseWheel
+ to_state: Site
+- from_state: MultiSite
+ label: onMouseWheel
+ to_state: Site
+- from_state: Device
+ label: onMouseWheel
+ to_state: Process
+- from_state: Site
+ label: onMouseWheel
+ to_state: Rack
+- from_state: Device
+ label: onMouseWheel
+ to_state: Interface
+- from_state: Rack
+ label: onMouseWheel
+ to_state: Device
+- from_state: Interface
+ label: onMouseWheel
+ to_state: Device
+- from_state: Device
+ label: onMouseWheel
+ to_state: Rack
+- from_state: Start
+ label: start
+ to_state: MultiSite
+- from_state: Process
+ label: onMouseWheel
+ to_state: Device
+- from_state: Site
+ label: onMouseWheel
+ to_state: MultiSite
diff --git a/awx/network_ui/static/network_ui/designs/rack.yml b/awx/network_ui/static/network_ui/designs/rack.yml
new file mode 100644
index 0000000000..9ea4bbd27c
--- /dev/null
+++ b/awx/network_ui/static/network_ui/designs/rack.yml
@@ -0,0 +1,72 @@
+finite_state_machine_id: 131
+name: fsm
+states:
+- id: 5
+ label: Selected2
+ x: 220
+ y: 810
+- id: 7
+ label: EditLabel
+ x: 600
+ y: 934
+- id: 2
+ label: Ready
+ x: 532
+ y: 560
+- id: 3
+ label: Disable
+ x: 760
+ y: 468
+- id: 6
+ label: Selected3
+ x: 249
+ y: 1047
+- id: 4
+ label: Selected1
+ x: 214
+ y: 566
+- id: 1
+ label: Start
+ x: 582
+ y: 334
+- id: 8
+ label: Move
+ x: -69
+ y: 861
+transitions:
+- from_state: Selected1
+ label: onMouseMove
+ to_state: Move
+- from_state: Selected3
+ label: onMouseMove
+ to_state: Move
+- from_state: Move
+ label: onMouseUp
+ to_state: Selected2
+- from_state: Start
+ label: start
+ to_state: Ready
+- from_state: Ready
+ label: onMouseDown
+ to_state: Selected1
+- from_state: Selected1
+ label: onMouseUp
+ to_state: Selected2
+- from_state: Selected2
+ label: onMouseDown
+ to_state: Selected3
+- from_state: EditLabel
+ label: onKeyDown
+ to_state: Selected2
+- from_state: Selected3
+ label: onMouseUp
+ to_state: EditLabel
+- from_state: EditLabel
+ label: onMouseDown
+ to_state: Ready
+- from_state: Selected2
+ label: onMouseDown
+ to_state: Ready
+- from_state: Selected2
+ label: onKeyDown
+ to_state: Ready
diff --git a/awx/network_ui/static/network_ui/designs/site.yml b/awx/network_ui/static/network_ui/designs/site.yml
new file mode 100644
index 0000000000..9ea4bbd27c
--- /dev/null
+++ b/awx/network_ui/static/network_ui/designs/site.yml
@@ -0,0 +1,72 @@
+finite_state_machine_id: 131
+name: fsm
+states:
+- id: 5
+ label: Selected2
+ x: 220
+ y: 810
+- id: 7
+ label: EditLabel
+ x: 600
+ y: 934
+- id: 2
+ label: Ready
+ x: 532
+ y: 560
+- id: 3
+ label: Disable
+ x: 760
+ y: 468
+- id: 6
+ label: Selected3
+ x: 249
+ y: 1047
+- id: 4
+ label: Selected1
+ x: 214
+ y: 566
+- id: 1
+ label: Start
+ x: 582
+ y: 334
+- id: 8
+ label: Move
+ x: -69
+ y: 861
+transitions:
+- from_state: Selected1
+ label: onMouseMove
+ to_state: Move
+- from_state: Selected3
+ label: onMouseMove
+ to_state: Move
+- from_state: Move
+ label: onMouseUp
+ to_state: Selected2
+- from_state: Start
+ label: start
+ to_state: Ready
+- from_state: Ready
+ label: onMouseDown
+ to_state: Selected1
+- from_state: Selected1
+ label: onMouseUp
+ to_state: Selected2
+- from_state: Selected2
+ label: onMouseDown
+ to_state: Selected3
+- from_state: EditLabel
+ label: onKeyDown
+ to_state: Selected2
+- from_state: Selected3
+ label: onMouseUp
+ to_state: EditLabel
+- from_state: EditLabel
+ label: onMouseDown
+ to_state: Ready
+- from_state: Selected2
+ label: onMouseDown
+ to_state: Ready
+- from_state: Selected2
+ label: onKeyDown
+ to_state: Ready
diff --git a/awx/network_ui/static/network_ui/designs/stream.yml b/awx/network_ui/static/network_ui/designs/stream.yml
new file mode 100644
index 0000000000..bb832259b1
--- /dev/null
+++ b/awx/network_ui/static/network_ui/designs/stream.yml
@@ -0,0 +1,42 @@
+finite_state_machine_id: 82
+name: src/transition
+states:
+- id: 4
+ label: Connecting
+ x: 344
+ y: 312
+- id: 5
+ label: Selecting
+ x: 311
+ y: 23
+- id: 1
+ label: Ready
+ x: 36
+ y: 28
+- id: 3
+ label: Connected
+ x: 55
+ y: 317
+- id: 2
+ label: Start
+ x: 43
+ y: -188
+transitions:
+- from_state: Ready
+ label: onNewStream
+ to_state: Selecting
+- from_state: Start
+ label: start
+ to_state: Ready
+- from_state: Connected
+ label: start
+ to_state: Ready
+- from_state: Connecting
+ label: onMouseUp
+ to_state: Ready
+- from_state: Connecting
+ label: onMouseUp
+ to_state: Connected
+- from_state: Selecting
+ label: onMouseUp
+ to_state: Connecting
diff --git a/awx/network_ui/static/network_ui/designs/toolbox.yml b/awx/network_ui/static/network_ui/designs/toolbox.yml
new file mode 100644
index 0000000000..99ed20522c
--- /dev/null
+++ b/awx/network_ui/static/network_ui/designs/toolbox.yml
@@ -0,0 +1,49 @@
+finite_state_machine_id: 120
+name: toolbox
+states:
+- id: 6
+ label: Dropping
+ x: 1197
+ y: 427
+- id: 4
+ label: Selected
+ x: 889
+ y: 713
+- id: 2
+ label: Ready
+ x: 892
+ y: 429
+- id: 3
+ label: Scrolling
+ x: 567
+ y: 431
+- id: 1
+ label: Start
+ x: 892
+ y: 216
+- id: 5
+ label: Move
+ x: 1197
+ y: 708
+transitions:
+- from_state: Start
+ label: start
+ to_state: Ready
+- from_state: Move
+ label: onMouseUp
+ to_state: Dropping
+- from_state: Dropping
+ label: start
+ to_state: Ready
+- from_state: Ready
+ label: onMouseDown
+ to_state: Selected
+- from_state: Ready
+ label: onMouseWheel
+ to_state: Scrolling
+- from_state: Scrolling
+ label: start
+ to_state: Ready
+- from_state: Selected
+ label: onMouseMove
+ to_state: Move
diff --git a/awx/network_ui/static/network_ui/index.html b/awx/network_ui/static/network_ui/index.html
index e5cc3d53ae..1c91728390 100644
--- a/awx/network_ui/static/network_ui/index.html
+++ b/awx/network_ui/static/network_ui/index.html
@@ -5,7 +5,7 @@
-
+
diff --git a/awx/network_ui/static/network_ui/package.json b/awx/network_ui/static/network_ui/package.json
index 080d9b9e41..ab0fbca2c8 100644
--- a/awx/network_ui/static/network_ui/package.json
+++ b/awx/network_ui/static/network_ui/package.json
@@ -21,7 +21,8 @@
"mathjs": "",
"reconnectingwebsocket": "^1.0.0",
"require": "",
- "webpack": ""
+ "webpack": "",
+ "titlecase": ""
},
"devDependencies": {
"eslint": "^3.17.1",
diff --git a/awx/network_ui/static/network_ui/src/configuration.directive.js b/awx/network_ui/static/network_ui/src/configuration.directive.js
new file mode 100644
index 0000000000..3f182c737f
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/configuration.directive.js
@@ -0,0 +1,5 @@
+
+function configuration () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/configuration.html' };
+}
+exports.configuration = configuration;
diff --git a/awx/network_ui/static/network_ui/src/device.detail.directive.js b/awx/network_ui/static/network_ui/src/device.detail.directive.js
new file mode 100644
index 0000000000..dafbe3b6dd
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/device.detail.directive.js
@@ -0,0 +1,5 @@
+
+function deviceDetail () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/device_detail.html' };
+}
+exports.deviceDetail = deviceDetail;
diff --git a/awx/network_ui/static/network_ui/src/device.detail.fsm.js b/awx/network_ui/static/network_ui/src/device.detail.fsm.js
new file mode 100644
index 0000000000..3bc52d1131
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/device.detail.fsm.js
@@ -0,0 +1,72 @@
+var inherits = require('inherits');
+var fsm = require('./fsm.js');
+var models = require('./models.js');
+
+function _State () {
+}
+inherits(_State, fsm._State);
+
+
+function _Ready () {
+ this.name = 'Ready';
+}
+inherits(_Ready, _State);
+var Ready = new _Ready();
+exports.Ready = Ready;
+
+function _Disable () {
+ this.name = 'Disable';
+}
+inherits(_Disable, _State);
+var Disable = new _Disable();
+exports.Disable = Disable;
+
+function _Start () {
+ this.name = 'Start';
+}
+inherits(_Start, _State);
+var Start = new _Start();
+exports.Start = Start;
+
+
+
+
+
+
+_Start.prototype.start = function (controller) {
+
+ controller.changeState(Ready);
+
+};
+_Start.prototype.start.transitions = ['Ready'];
+
+
+_Ready.prototype.onPasteProcess = function (controller, msg_type, message) {
+
+ console.log([msg_type, message]);
+
+ var i=0;
+ var devices = controller.scope.devices;
+ var device = null;
+ var x = controller.scope.scaledX;
+ var y = controller.scope.scaledY;
+ var app = null;
+
+ for(i=0; i < devices.length; i++) {
+ device = devices[i];
+ if (device.is_selected(x, y)) {
+ console.log(device);
+
+ app = new models.Application(device.process_id_seq(),
+ message.process.name,
+ message.process.type,
+ controller.scope.scaledX,
+ controller.scope.scaledY);
+ device.processes.push(app);
+ console.log(device.processes);
+ break;
+ } else {
+ console.log([x,y, device.x, device.y]);
+ }
+ }
+};
diff --git a/awx/network_ui/static/network_ui/src/group.js b/awx/network_ui/static/network_ui/src/group.js
index f0bcdd5cae..043f375ef0 100644
--- a/awx/network_ui/static/network_ui/src/group.js
+++ b/awx/network_ui/static/network_ui/src/group.js
@@ -2,6 +2,7 @@ var inherits = require('inherits');
var fsm = require('./fsm.js');
var models = require('./models.js');
var messages = require('./messages.js');
+var titlecase = require('titlecase');
function _State () {
}
@@ -57,6 +58,14 @@ inherits(_Ready, _State);
var Ready = new _Ready();
exports.Ready = Ready;
+function _Disable () {
+ this.name = 'Disable';
+}
+inherits(_Disable, _State);
+var Disable = new _Disable();
+exports.Disable = Disable;
+
+
function _EditLabel () {
this.name = 'EditLabel';
}
@@ -78,6 +87,11 @@ inherits(_Placing, _State);
var Placing = new _Placing();
exports.Placing = Placing;
+_State.prototype.onUnselectAll = function (controller, msg_type, $event) {
+
+ controller.changeState(Ready);
+ controller.next_controller.handle_message(msg_type, $event);
+};
_Resize.prototype.onMouseUp = function (controller, msg_type, $event) {
@@ -119,7 +133,8 @@ _Resize.prototype.onMouseMove = function (controller) {
groups[i].y2 = groups[i].y2 + diffY;
}
- membership_old_new = groups[i].update_membership(controller.scope.devices);
+ membership_old_new = groups[i].update_membership(controller.scope.devices,
+ controller.scope.groups);
for(j = 0; j < membership_old_new[0].length; j++) {
membership_old_new[0][j].selected = false;
}
@@ -145,6 +160,16 @@ _Resize.prototype.onMouseMove = function (controller) {
controller.scope.pressedScaledY = controller.scope.scaledY;
};
+_Resize.prototype.start = function (controller) {
+
+ var groups = controller.scope.selected_groups;
+
+ var i = 0;
+ for (i = 0; i < groups.length; i++) {
+ groups[i].moving = true;
+ }
+};
+
_Resize.prototype.end = function (controller) {
var groups = controller.scope.selected_groups;
@@ -156,6 +181,10 @@ _Resize.prototype.end = function (controller) {
groups[i].devices[j].selected = false;
}
}
+
+ for (i = 0; i < groups.length; i++) {
+ groups[i].moving = false;
+ }
};
@@ -242,7 +271,8 @@ _Move.prototype.onMouseMove = function (controller) {
groups[i].x2 = groups[i].x2 + diffX;
groups[i].y2 = groups[i].y2 + diffY;
- membership_old_new = groups[i].update_membership(controller.scope.devices);
+ membership_old_new = groups[i].update_membership(controller.scope.devices,
+ controller.scope.groups);
for(j = 0; j < membership_old_new[0].length; j++) {
membership_old_new[0][j].selected = false;
}
@@ -281,6 +311,16 @@ _Move.prototype.onMouseDown = function (controller) {
};
_Move.prototype.onMouseDown.transitions = ['Selected1'];
+_Move.prototype.start = function (controller) {
+
+ var groups = controller.scope.selected_groups;
+
+ var i = 0;
+ for (i = 0; i < groups.length; i++) {
+ groups[i].moving = true;
+ }
+};
+
_Move.prototype.end = function (controller) {
var groups = controller.scope.selected_groups;
@@ -292,6 +332,10 @@ _Move.prototype.end = function (controller) {
groups[i].devices[j].selected = false;
}
}
+
+ for (i = 0; i < groups.length; i++) {
+ groups[i].moving = false;
+ }
};
@@ -363,12 +407,48 @@ _Ready.prototype.onMouseDown = function (controller, msg_type, $event) {
_Ready.prototype.onMouseDown.transitions = ['Selected1', 'CornerSelected'];
-_Ready.prototype.onNewGroup = function (controller) {
+_Ready.prototype.onNewGroup = function (controller, msg_type, message) {
controller.scope.hide_groups = false;
+ controller.scope.new_group_type = message.type;
controller.changeState(Placing);
};
_Ready.prototype.onNewGroup.transitions = ['Placing'];
+_Ready.prototype.onPasteGroup = function (controller, msg_type, message) {
+
+ var scope = controller.scope;
+ scope.hide_groups = false;
+
+ scope.pressedX = scope.mouseX;
+ scope.pressedY = scope.mouseY;
+ scope.pressedScaledX = scope.scaledX;
+ scope.pressedScaledY = scope.scaledY;
+
+ var group = new models.Group(controller.scope.group_id_seq(),
+ message.group.name,
+ message.group.type,
+ scope.scaledX,
+ scope.scaledY,
+ scope.scaledX + message.group.x2,
+ scope.scaledY + message.group.y2,
+ false);
+
+ scope.send_control_message(new messages.GroupCreate(scope.client_id,
+ group.id,
+ group.x1,
+ group.y1,
+ group.x2,
+ group.y2,
+ group.name,
+ group.type));
+
+ scope.groups.push(group);
+ scope.selected_groups.push(group);
+ group.selected = true;
+ controller.changeState(Selected2);
+};
+_Ready.prototype.onPasteGroup.transitions = ['Selected2'];
+
_EditLabel.prototype.start = function (controller) {
@@ -482,6 +562,8 @@ _Selected2.prototype.onKeyDown = function (controller, msg_type, $event) {
groups[i].y2,
groups[i].name));
}
+ } else {
+ controller.next_controller.handle_message(msg_type, $event);
}
};
_Selected2.prototype.onKeyDown.transitions = ['Ready'];
@@ -502,7 +584,8 @@ _Placing.prototype.onMouseDown = function (controller) {
var id = scope.group_id_seq();
group = new models.Group(id,
- "Group" + id,
+ titlecase.toTitleCase("" + scope.new_group_type + id),
+ scope.new_group_type,
scope.scaledX,
scope.scaledY,
scope.scaledX,
@@ -514,13 +597,16 @@ _Placing.prototype.onMouseDown = function (controller) {
group.y1,
group.x2,
group.y2,
- group.name));
+ group.name,
+ group.type));
scope.groups.push(group);
scope.selected_groups.push(group);
group.selected = true;
group.selected_corner = models.BOTTOM_RIGHT;
+ controller.scope.new_group_type = null;
+
controller.changeState(Resize);
};
_Placing.prototype.onMouseDown.transitions = ['CornerSelected'];
diff --git a/awx/network_ui/static/network_ui/src/hotkeys.fsm.js b/awx/network_ui/static/network_ui/src/hotkeys.fsm.js
index 5ae9c78f6f..9ec1ba6d04 100644
--- a/awx/network_ui/static/network_ui/src/hotkeys.fsm.js
+++ b/awx/network_ui/static/network_ui/src/hotkeys.fsm.js
@@ -43,11 +43,19 @@ _Enabled.prototype.onKeyDown = function(controller, msg_type, $event) {
var scope = controller.scope;
+ if ($event.key === 'c' && ($event.ctrlKey || $event.metaKey)) {
+ scope.first_controller.handle_message("CopySelected", $event);
+ }
+
if ($event.key === 'l') {
scope.first_controller.handle_message("NewLink", $event);
return;
}
+ if ($event.key === 'm') {
+ scope.first_controller.handle_message("NewStream", $event);
+ }
+
if ($event.key === 'd') {
scope.debug.hidden = !scope.debug.hidden;
return;
@@ -74,13 +82,28 @@ _Enabled.prototype.onKeyDown = function(controller, msg_type, $event) {
return;
}
else if ($event.key === 'a') {
- scope.first_controller.handle_message("NewDevice", new messages.NewDevice("rack"));
+ scope.first_controller.handle_message("NewGroup", new messages.NewGroup("rack"));
return;
}
else if ($event.key === 'h') {
scope.first_controller.handle_message("NewDevice", new messages.NewDevice("host"));
return;
}
+ else if ($event.key === 'g') {
+ scope.first_controller.handle_message("NewGroup", new messages.NewGroup("group"));
+ return;
+ }
+ else if ($event.key === 'e') {
+ scope.first_controller.handle_message("NewGroup", new messages.NewGroup("site"));
+ return;
+ }
+ else if ($event.key === '0') {
+ scope.panX = 0;
+ scope.panY = 0;
+ scope.current_scale = 1.0;
+ scope.updateScaledXY();
+ scope.updatePanAndScale();
+ }
controller.next_controller.handle_message(msg_type, $event);
};
diff --git a/awx/network_ui/static/network_ui/src/inventory.toolbox.clip.path.directive.js b/awx/network_ui/static/network_ui/src/inventory.toolbox.clip.path.directive.js
new file mode 100644
index 0000000000..204528e5b7
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/inventory.toolbox.clip.path.directive.js
@@ -0,0 +1,5 @@
+
+function inventoryToolboxClipPath () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/inventory_toolbox_clip_path.html' };
+}
+exports.inventoryToolboxClipPath = inventoryToolboxClipPath;
diff --git a/awx/network_ui/static/network_ui/src/inventory.toolbox.directive.js b/awx/network_ui/static/network_ui/src/inventory.toolbox.directive.js
new file mode 100644
index 0000000000..8459a0631d
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/inventory.toolbox.directive.js
@@ -0,0 +1,5 @@
+
+function inventoryToolbox () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/inventory_toolbox.html' };
+}
+exports.inventoryToolbox = inventoryToolbox;
diff --git a/awx/network_ui/static/network_ui/src/main.js b/awx/network_ui/static/network_ui/src/main.js
index 1222f6b011..122ed230d4 100644
--- a/awx/network_ui/static/network_ui/src/main.js
+++ b/awx/network_ui/static/network_ui/src/main.js
@@ -1,6 +1,11 @@
var networkUI = require('./network.ui.app.js');
+var networkWidgets = require('./network.widgets.app.js');
var tablesUI = require('./tables.ui.app.js');
var tower = require('./tower.app.js');
+var ngTouch = require('./ngTouch.js');
exports.networkUI = networkUI.networkUI;
-+exports.tablesUI = tablesUI.tablesUI;
+exports.tablesUI = tablesUI.tablesUI;
exports.tower = tower.tower;
+exports.ngTouch = ngTouch;
+exports.networkWidgets = networkWidgets;
+
diff --git a/awx/network_ui/static/network_ui/src/map.directive.js b/awx/network_ui/static/network_ui/src/map.directive.js
new file mode 100644
index 0000000000..d0bb5af3aa
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/map.directive.js
@@ -0,0 +1,5 @@
+
+function map () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/map.html' };
+}
+exports.map = map;
diff --git a/awx/network_ui/static/network_ui/src/messages.js b/awx/network_ui/static/network_ui/src/messages.js
index 5b9e098c4a..6e848e4ddb 100644
--- a/awx/network_ui/static/network_ui/src/messages.js
+++ b/awx/network_ui/static/network_ui/src/messages.js
@@ -247,6 +247,38 @@ function NewDevice(type) {
}
exports.NewDevice = NewDevice;
+function PasteDevice(device) {
+ this.device = device;
+}
+exports.PasteDevice = PasteDevice;
+
+function PasteProcess(process) {
+ this.process = process;
+}
+exports.PasteProcess = PasteProcess;
+
+
+function NewGroup(type) {
+ this.type = type;
+}
+exports.NewGroup = NewGroup;
+
+function PasteGroup(group) {
+ this.group = group;
+}
+exports.PasteGroup = PasteGroup;
+
+function PasteRack(group) {
+ this.group = group;
+}
+exports.PasteRack = PasteRack;
+
+function PasteSite(group) {
+ this.group = group;
+}
+exports.PasteSite = PasteSite;
+
+
function GroupMove(sender, id, x1, y1, x2, y2, previous_x1, previous_y1, previous_x2, previous_y2) {
this.msg_type = "GroupMove";
this.sender = sender;
@@ -262,7 +294,7 @@ function GroupMove(sender, id, x1, y1, x2, y2, previous_x1, previous_y1, previou
}
exports.GroupMove = GroupMove;
-function GroupCreate(sender, id, x1, y1, x2, y2, name) {
+function GroupCreate(sender, id, x1, y1, x2, y2, name, type) {
this.msg_type = "GroupCreate";
this.sender = sender;
this.id = id;
@@ -271,6 +303,7 @@ function GroupCreate(sender, id, x1, y1, x2, y2, name) {
this.x2 = x2;
this.y2 = y2;
this.name = name;
+ this.type = type;
}
exports.GroupCreate = GroupCreate;
@@ -328,3 +361,46 @@ function TableCellEdit(sender, sheet, col, row, old_value, new_value) {
this.new_value = new_value;
}
exports.TableCellEdit = TableCellEdit;
+
+function StreamCreate(sender, id, from_id, to_id, label) {
+ this.msg_type = "StreamCreate";
+ this.sender = sender;
+ this.id = id;
+ this.from_id = from_id;
+ this.to_id = to_id;
+ this.label = label;
+}
+exports.StreamCreate = StreamCreate;
+
+function StreamDestroy(sender, id, from_id, to_id, label) {
+ this.msg_type = "StreamDestroy";
+ this.sender = sender;
+ this.id = id;
+ this.from_id = from_id;
+ this.to_id = to_id;
+ this.label = label;
+}
+exports.StreamDestroy = StreamDestroy;
+
+function StreamLabelEdit(sender, id, label, previous_label) {
+ this.msg_type = "StreamLabelEdit";
+ this.sender = sender;
+ this.id = id;
+ this.label = label;
+ this.previous_label = previous_label;
+}
+exports.StreamLabelEdit = StreamLabelEdit;
+
+function StreamSelected(sender, id) {
+ this.msg_type = "StreamSelected";
+ this.sender = sender;
+ this.id = id;
+}
+exports.StreamSelected = StreamSelected;
+
+function StreamUnSelected(sender, id) {
+ this.msg_type = "StreamUnSelected";
+ this.sender = sender;
+ this.id = id;
+}
+exports.StreamUnSelected = StreamUnSelected;
diff --git a/awx/network_ui/static/network_ui/src/mode.fsm.js b/awx/network_ui/static/network_ui/src/mode.fsm.js
new file mode 100644
index 0000000000..5858ad5737
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/mode.fsm.js
@@ -0,0 +1,201 @@
+var inherits = require('inherits');
+var fsm = require('./fsm.js');
+var move = require('./move.js');
+var group = require('./group.js');
+var rack_fsm = require('./rack.fsm.js');
+var site_fsm = require('./site.fsm.js');
+
+function _State () {
+}
+inherits(_State, fsm._State);
+
+
+function _Start () {
+ this.name = 'Start';
+}
+inherits(_Start, _State);
+var Start = new _Start();
+exports.Start = Start;
+
+function _Interface () {
+ this.name = 'Interface';
+}
+inherits(_Interface, _State);
+var Interface = new _Interface();
+exports.Interface = Interface;
+
+function _Site () {
+ this.name = 'Site';
+}
+inherits(_Site, _State);
+var Site = new _Site();
+exports.Site = Site;
+
+function _Process () {
+ this.name = 'Process';
+}
+inherits(_Process, _State);
+var Process = new _Process();
+exports.Process = Process;
+
+function _MultiSite () {
+ this.name = 'MultiSite';
+}
+inherits(_MultiSite, _State);
+var MultiSite = new _MultiSite();
+exports.MultiSite = MultiSite;
+
+function _Rack () {
+ this.name = 'Rack';
+}
+inherits(_Rack, _State);
+var Rack = new _Rack();
+exports.Rack = Rack;
+
+function _Device () {
+ this.name = 'Device';
+}
+inherits(_Device, _State);
+var Device = new _Device();
+exports.Device = Device;
+
+
+_State.prototype.start = function (controller) {
+ controller.scope.current_mode = controller.state.name;
+};
+
+
+_Start.prototype.start = function (controller) {
+
+ controller.changeState(Rack);
+
+};
+_Start.prototype.start.transitions = ['MultiSite'];
+
+
+
+_Interface.prototype.onMouseWheel = function (controller, msg_type, $event) {
+
+ //controller.changeState(Device);
+
+ controller.next_controller.handle_message(msg_type, $event);
+
+};
+_Interface.prototype.onMouseWheel.transitions = ['Device'];
+
+_Site.prototype.start = function (controller) {
+ controller.scope.current_mode = controller.state.name;
+ controller.scope.rack_toolbox.enabled = true;
+ controller.scope.rack_controller.changeState(rack_fsm.Ready);
+};
+
+_Site.prototype.end = function (controller) {
+
+ controller.scope.rack_toolbox.enabled = false;
+ controller.scope.rack_controller.changeState(rack_fsm.Disable);
+};
+
+
+_Site.prototype.onMouseWheel = function (controller, msg_type, $event) {
+
+
+ if (controller.scope.current_scale < 0.1) {
+ controller.changeState(MultiSite);
+ } else if (controller.scope.current_scale > 0.5) {
+ controller.changeState(Rack);
+ }
+
+ controller.next_controller.handle_message(msg_type, $event);
+
+};
+_Site.prototype.onMouseWheel.transitions = ['MultiSite', 'Rack'];
+
+
+
+_Process.prototype.onMouseWheel = function (controller, msg_type, $event) {
+
+ controller.next_controller.handle_message(msg_type, $event);
+
+ //controller.changeState(Device);
+
+};
+_Process.prototype.onMouseWheel.transitions = ['Device'];
+
+_MultiSite.prototype.start = function (controller) {
+ controller.scope.current_mode = controller.state.name;
+ controller.scope.site_toolbox.enabled = true;
+ controller.scope.site_controller.changeState(site_fsm.Ready);
+};
+
+_MultiSite.prototype.end = function (controller) {
+
+ controller.scope.site_toolbox.enabled = false;
+ controller.scope.site_controller.changeState(site_fsm.Disable);
+};
+
+
+_MultiSite.prototype.onMouseWheel = function (controller, msg_type, $event) {
+
+ if (controller.scope.current_scale > 0.1) {
+ controller.changeState(Site);
+ }
+
+ controller.next_controller.handle_message(msg_type, $event);
+};
+_MultiSite.prototype.onMouseWheel.transitions = ['Site'];
+
+_Device.prototype.start = function (controller) {
+ controller.scope.current_mode = controller.state.name;
+ controller.scope.app_toolbox.enabled = true;
+};
+
+_Device.prototype.end = function (controller) {
+
+ controller.scope.app_toolbox.enabled = false;
+};
+
+_Device.prototype.onMouseWheel = function (controller, msg_type, $event) {
+
+ //controller.changeState(Process);
+
+ //controller.changeState(Interface);
+
+ //controller.changeState(Site);
+
+ if (controller.scope.current_scale < 5) {
+ controller.changeState(Rack);
+ }
+
+ controller.next_controller.handle_message(msg_type, $event);
+};
+_Device.prototype.onMouseWheel.transitions = ['Process', 'Interface', 'Rack'];
+
+
+_Rack.prototype.start = function (controller) {
+ controller.scope.current_mode = controller.state.name;
+ controller.scope.inventory_toolbox.enabled = true;
+ controller.scope.move_controller.changeState(move.Ready);
+ controller.scope.group_controller.changeState(group.Ready);
+};
+
+_Rack.prototype.end = function (controller) {
+
+ controller.scope.inventory_toolbox.enabled = false;
+ controller.scope.move_controller.changeState(move.Disable);
+ controller.scope.group_controller.changeState(group.Disable);
+};
+
+_Rack.prototype.onMouseWheel = function (controller, msg_type, $event) {
+
+ if (controller.scope.current_scale < 0.5) {
+ controller.changeState(Site);
+ }
+
+ if (controller.scope.current_scale > 5) {
+ controller.changeState(Device);
+ }
+
+ controller.next_controller.handle_message(msg_type, $event);
+};
+_Rack.prototype.onMouseWheel.transitions = ['Site', 'Device'];
+
diff --git a/awx/network_ui/static/network_ui/src/models.js b/awx/network_ui/static/network_ui/src/models.js
index 15b3d79b37..54b71a809e 100644
--- a/awx/network_ui/static/network_ui/src/models.js
+++ b/awx/network_ui/static/network_ui/src/models.js
@@ -17,10 +17,14 @@ function Device(id, name, x, y, type) {
this.edit_label = false;
this.status = null;
this.working = false;
+ this.moving = false;
+ this.icon = false;
this.tasks = [];
this.shape = type === "router" ? "circular" : "rectangular";
this.interface_seq = util.natural_numbers(0);
this.interfaces = [];
+ this.process_id_seq = util.natural_numbers(0);
+ this.processes = [];
}
exports.Device = Device;
@@ -47,6 +51,18 @@ function Interface(id, name) {
}
exports.Interface = Interface;
+Interface.prototype.remote_interface = function () {
+
+ if (this.link === null) {
+ return null;
+ }
+ if (this.link.to_interface === this) {
+ return this.link.from_interface;
+ } else {
+ return this.link.to_interface;
+ }
+};
+
Interface.prototype.is_selected = function (x, y) {
if (this.link === null || this.device === null) {
@@ -65,6 +81,9 @@ Interface.prototype.dot = function () {
if (this.link === null || this.device === null) {
return;
}
+ if (this.link.to_device === null || this.link.from_device === null) {
+ return;
+ }
var p;
if (this.device.shape === "circular") {
@@ -309,18 +328,24 @@ exports.Task = Task;
Task.prototype.describeArc = util.describeArc;
-function Group(id, name, x1, y1, x2, y2, selected) {
+function Group(id, name, type, x1, y1, x2, y2, selected) {
this.id = id;
this.name = name;
+ this.type = type;
this.x1 = x1;
this.y1 = y1;
this.x2 = x2;
this.y2 = y2;
this.selected = selected;
+ this.moving = false;
this.highlighted = false;
this.fsm = null;
this.selected_corner = null;
this.devices = [];
+ this.links = [];
+ this.groups = [];
+ this.streams = [];
+ this.icon_size = type === 'site' ? 500 : 100;
}
exports.Group = Group;
@@ -338,6 +363,19 @@ Group.prototype.is_highlighted = function (x, y) {
};
+Group.prototype.is_icon_selected = function (x, y) {
+
+ return ((x > this.left_extent() &&
+ x < this.right_extent() &&
+ y > this.top_extent() &&
+ y < this.bottom_extent()) ||
+ (x > this.centerX() - this.icon_size &&
+ x < this.centerX() + this.icon_size &&
+ y > this.centerY() - this.icon_size &&
+ y < this.centerY() + this.icon_size));
+
+};
+
var TOP_LEFT = 0;
exports.TOP_LEFT = TOP_LEFT;
var TOP_RIGHT = 1;
@@ -377,6 +415,18 @@ Group.prototype.has_corner_selected = function (x, y) {
return false;
};
+Group.prototype.corners = function () {
+
+ return [{x: this.left_extent(),
+ y: this.top_extent()},
+ {x: this.right_extent(),
+ y: this.top_extent()},
+ {x: this.left_extent(),
+ y: this.bottom_extent()},
+ {x: this.left_extent(),
+ y: this.bottom_extent()}];
+};
+
Group.prototype.select_corner = function (x, y) {
var corners = [[util.distance(this.x1, this.y1, x, y), TOP_LEFT],
@@ -384,8 +434,6 @@ Group.prototype.select_corner = function (x, y) {
[util.distance(this.x1, this.y2, x, y), BOTTOM_LEFT],
[util.distance(this.x2, this.y1, x, y), TOP_RIGHT]];
- console.log(corners);
-
corners.sort(function(a, b) {
return a[0] - b[0];
});
@@ -473,7 +521,15 @@ Group.prototype.right_extent = function (scaledX) {
return (this.x1 > x2? this.x1 : x2);
};
-Group.prototype.update_membership = function (devices) {
+Group.prototype.centerX = function (scaledX) {
+ return (this.right_extent(scaledX) + this.left_extent(scaledX)) / 2;
+};
+
+Group.prototype.centerY = function (scaledY) {
+ return (this.bottom_extent(scaledY) + this.top_extent(scaledY)) / 2;
+};
+
+Group.prototype.update_membership = function (devices, groups) {
var i = 0;
var y1 = this.top_extent();
var x1 = this.left_extent();
@@ -491,5 +547,260 @@ Group.prototype.update_membership = function (devices) {
device_ids.push(devices[i].id);
}
}
- return [old_devices, this.devices, device_ids];
+ var old_groups = this.groups;
+ this.groups = [];
+ var group_ids = [];
+ for (i = 0; i < groups.length; i++) {
+ if (groups[i].left_extent() > x1 &&
+ groups[i].top_extent() > y1 &&
+ groups[i].right_extent() < x2 &&
+ groups[i].bottom_extent() < y2) {
+ this.groups.push(groups[i]);
+ group_ids.push(groups[i].id);
+ }
+ }
+ return [old_devices, this.devices, device_ids, old_groups, this.groups, group_ids];
+};
+
+
+function ToolBox(id, name, type, x, y, width, height) {
+ this.id = id;
+ this.name = name;
+ this.type = type;
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ this.items = [];
+ this.spacing = 200;
+ this.scroll_offset = 0;
+ this.selected_item = null;
+ this.enabled = true;
+}
+exports.ToolBox = ToolBox;
+
+
+function Configuration(id, name, type, x, y, content) {
+ this.id = id;
+ this.name = name;
+ this.type = type;
+ this.x = x;
+ this.y = y;
+ this.height = 50;
+ this.width = 50;
+ this.size = 50;
+ this.content = content;
+ this.selected = null;
+ this.enabled = true;
+ this.icon = false;
+}
+exports.Configuration = Configuration;
+
+function Application(id, name, type, x, y) {
+ this.id = id;
+ this.name = name;
+ this.type = type;
+ this.x = x;
+ this.y = y;
+ this.height = 50;
+ this.width = 50;
+ this.size = 50;
+ this.selected = null;
+ this.enabled = true;
+ this.icon = false;
+}
+exports.Application = Application;
+
+function Stream(id, from_device, to_device, label) {
+ this.id = id;
+ this.from_device = from_device;
+ this.to_device = to_device;
+ this.selected = false;
+ this.remote_selected = false;
+ this.label = label;
+ this.offset = 0;
+}
+exports.Stream = Stream;
+
+Stream.prototype.toJSON = function () {
+ return {to_device: this.to_device.id,
+ from_device: this.from_device.id};
+};
+
+Stream.prototype.slope_rad = function () {
+ //Return the slope in radians for this transition.
+ var x1 = this.from_device.x;
+ var y1 = this.from_device.y;
+ var x2 = this.to_device.x;
+ var y2 = this.to_device.y;
+ return Math.atan2(y2 - y1, x2 - x1) + Math.PI;
+};
+
+Stream.prototype.slope = function () {
+ //Return the slope in degrees for this transition.
+ var x1 = this.from_device.x;
+ var y1 = this.from_device.y;
+ var x2 = this.to_device.x;
+ var y2 = this.to_device.y;
+ return Math.atan2(y2 - y1, x2 - x1) * 180 / Math.PI + 180;
+};
+
+Stream.prototype.flip_text_rotate = function () {
+ var slope = this.slope();
+ if (slope > 90 && slope < 270) {
+ return 180;
+ } else {
+ return 0;
+ }
+};
+
+Stream.prototype.flip_text_offset = function () {
+ var slope = this.slope();
+ if (slope > 90 && slope < 270) {
+ return 10;
+ } else {
+ return 0;
+ }
+};
+
+Stream.prototype.pslope = function () {
+ //Return the slope of a perpendicular line to this
+ //transition
+ var x1 = this.from_device.x;
+ var y1 = this.from_device.y;
+ var x2 = this.to_device.x;
+ var y2 = this.to_device.y;
+ var slope = (y2 - y1)/(x2 - x1);
+ //var intercept = - slope * x1;
+ var pslope = 1/slope;
+ return Math.atan(pslope) * 180 / Math.PI + 180;
+};
+
+Stream.prototype.perpendicular = function (x, y) {
+ //Find the perpendicular line through x, y to this transition.
+ var x1 = this.from_device.x;
+ var y1 = this.from_device.y;
+ var x2 = this.to_device.x;
+ var y2 = this.to_device.y;
+ var slope = (y2 - y1)/(x2 - x1);
+ var intercept = y1 - slope * x1;
+ var pslope = -1/slope;
+ var pintercept = y - pslope * x;
+
+ var xi = (pintercept - intercept) / (slope - pslope);
+ var yi = pslope * xi + pintercept;
+ return {x1:x, y1:y, x2: xi, y2: yi};
+};
+
+Stream.prototype.is_selected = function (x, y) {
+ // Is the distance to the mouse location less than 25 if on the label side
+ // or 5 on the other from the shortest line to the transition?
+ console.log("is_selected");
+ var phi = this.slope_rad();
+ console.log({"phi": phi});
+ console.log({'x': this.from_device.x, 'y': this.from_device.y});
+ console.log({'x': this.to_device.x, 'y': this.to_device.y});
+ console.log({'x': x, 'y': y});
+ var p1 = util.cartesianToPolar(this.from_device.x, this.from_device.y);
+ var p2 = util.cartesianToPolar(this.to_device.x, this.to_device.y);
+ var p3 = util.cartesianToPolar(x, y);
+ console.log(p1);
+ p1.theta -= phi;
+ console.log(p1);
+ console.log(p2);
+ p2.theta -= phi;
+ console.log(p2);
+ p3.theta -= phi;
+
+ p1 = util.polarToCartesian_rad(0, 0, p1.r, p1.theta);
+ p2 = util.polarToCartesian_rad(0, 0, p2.r, p2.theta);
+ p3 = util.polarToCartesian_rad(0, 0, p3.r, p3.theta);
+ p2.y -= this.arc_offset2();
+ console.log(p1);
+ console.log(p2);
+ console.log(p3);
+ var max_x = Math.max(p1.x, p2.x);
+ var min_x = Math.min(p1.x, p2.x);
+ var max_y = Math.max(p1.y, p2.y) + 5;
+ var min_y = Math.min(p1.y, p2.y) - 25 ;
+
+ return p3.x > min_x && p3.x < max_x && p3.y > min_y && p3.y < max_y;
+};
+
+Stream.prototype.length = function () {
+ //Return the length of this transition.
+ var x1 = this.from_device.x;
+ var y1 = this.from_device.y;
+ var x2 = this.to_device.x;
+ var y2 = this.to_device.y;
+ return Math.sqrt(Math.pow(x1-x2, 2) + Math.pow(y1-y2, 2));
+};
+
+
+Stream.prototype.inter_length = function () {
+ //Return the length of this transition between states.
+ return this.length() - this.from_device.size - this.to_device.size;
+};
+
+Stream.prototype.arc_r = function () {
+ return this.inter_length();
+};
+
+Stream.prototype.arc_r2 = function () {
+ var offset_to_r = [2, 1, 0.75, 0.6, 0.55, 0.53, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5];
+ return this.length() * offset_to_r[this.offset];
+};
+
+Stream.prototype.arc_offset = function () {
+ var r = this.arc_r();
+ var offset = r - (Math.sin(this.arc_angle_rad()) * r);
+ return offset;
+};
+
+Stream.prototype.arc_offset2 = function () {
+ var r = this.arc_r2();
+ var theta = Math.acos((this.length() / 2) / r);
+ var offset = r * (1 - Math.sin(theta));
+ return offset;
+};
+
+Stream.prototype.arc_angle_rad = function () {
+ return Math.acos((this.inter_length() / 2) / this.arc_r());
+};
+
+Stream.prototype.arc_angle_tan_rad = function () {
+ return Math.PI/2 - Math.acos((this.inter_length() / 2) / this.arc_r());
+};
+
+Stream.prototype.arc_angle_tan = function () {
+ return this.arc_angle_tan_rad() * 180 / Math.PI;
+};
+
+Stream.prototype.arc_angle_tan_rad2 = function () {
+ var r = this.arc_r2();
+ var l = this.length();
+ var phi = this.end_arc_angle_rad();
+ return Math.PI/2 - Math.acos((l/2 - Math.cos(phi) * this.to_device.size) / r);
+};
+
+Stream.prototype.arc_angle_tan2 = function () {
+ return this.arc_angle_tan_rad2() * 180 / Math.PI;
+};
+
+Stream.prototype.end_arc_angle_rad = function () {
+ var r = this.arc_r2();
+ var l = this.length();
+ return Math.acos((this.to_device.size / 2) / r) - Math.acos((l/2)/r);
+};
+
+Stream.prototype.end_arc_angle = function () {
+ return this.end_arc_angle_rad() * 180 / Math.PI;
+};
+
+Stream.prototype.start_arc_angle_rad = function () {
+ return Math.acos((this.from_device.size / 2) / this.arc_r2()) - Math.acos((this.length()/2)/this.arc_r2());
+};
+
+Stream.prototype.start_arc_angle = function () {
+ return this.start_arc_angle_rad() * 180 / Math.PI;
};
diff --git a/awx/network_ui/static/network_ui/src/move.js b/awx/network_ui/static/network_ui/src/move.js
index 60b813ffc7..4f29f0da98 100644
--- a/awx/network_ui/static/network_ui/src/move.js
+++ b/awx/network_ui/static/network_ui/src/move.js
@@ -15,6 +15,13 @@ inherits(_Ready, _State);
var Ready = new _Ready();
exports.Ready = Ready;
+function _Disable () {
+ this.name = 'Disable';
+}
+inherits(_Disable, _State);
+var Disable = new _Disable();
+exports.Disable = Disable;
+
function _Start () {
this.name = 'Start';
}
@@ -67,6 +74,13 @@ inherits(_Placing, _State);
var Placing = new _Placing();
exports.Placing = Placing;
+
+_State.prototype.onUnselectAll = function (controller, msg_type, $event) {
+
+ controller.changeState(Ready);
+ controller.next_controller.handle_message(msg_type, $event);
+};
+
_Ready.prototype.onNewDevice = function (controller, msg_type, message) {
var scope = controller.scope;
@@ -128,6 +142,47 @@ _Ready.prototype.onNewDevice = function (controller, msg_type, message) {
};
_Ready.prototype.onNewDevice.transitions = ['Placing'];
+_Ready.prototype.onPasteDevice = function (controller, msg_type, message) {
+
+ var scope = controller.scope;
+ var device = null;
+ var intf = null;
+ var process = null;
+ var i = 0;
+
+ scope.pressedX = scope.mouseX;
+ scope.pressedY = scope.mouseY;
+ scope.pressedScaledX = scope.scaledX;
+ scope.pressedScaledY = scope.scaledY;
+
+ device = new models.Device(controller.scope.device_id_seq(),
+ message.device.name,
+ scope.scaledX,
+ scope.scaledY,
+ message.device.type);
+ scope.devices.push(device);
+ scope.send_control_message(new messages.DeviceCreate(scope.client_id,
+ device.id,
+ device.x,
+ device.y,
+ device.name,
+ device.type));
+ for (i=0; i < message.device.interfaces.length; i++) {
+ intf = new models.Interface(message.device.interfaces[i].id, message.device.interfaces[i].name);
+ device.interfaces.push(intf);
+ }
+ for (i=0; i < message.device.processes.length; i++) {
+ process = new models.Application(message.device.processes[i].id,
+ message.device.processes[i].name,
+ message.device.processes[i].type, 0, 0);
+ device.processes.push(process);
+ }
+ scope.selected_devices.push(device);
+ device.selected = true;
+ controller.changeState(Selected2);
+};
+_Ready.prototype.onPasteDevice.transitions = ['Selected2'];
+
_Ready.prototype.onMouseDown = function (controller, msg_type, $event) {
var last_selected = controller.scope.select_items($event.shiftKey);
@@ -162,6 +217,29 @@ _Selected2.prototype.onNewDevice = function (controller, msg_type, message) {
};
_Selected2.prototype.onNewDevice.transitions = ['Ready'];
+_Selected2.prototype.onCopySelected = function (controller) {
+
+ var devices = controller.scope.selected_devices;
+ var device_copy = null;
+ var process_copy = null;
+ var interface_copy = null;
+ var i = 0;
+ var j = 0;
+ for(i=0; i < devices.length; i++) {
+ device_copy = new models.Device(0, devices[i].name, 0, 0, devices[i].type);
+ device_copy.icon = true;
+ for(j=0; j < devices[i].processes.length; j++) {
+ process_copy = new models.Application(0, devices[i].processes[j].name, devices[i].processes[j].name, 0, 0);
+ device_copy.processes.push(process_copy);
+ }
+ for(j=0; j < devices[i].interfaces.length; j++) {
+ interface_copy = new models.Interface(devices[i].interfaces[j].id, devices[i].interfaces[j].name);
+ device_copy.interfaces.push(interface_copy);
+ }
+ controller.scope.inventory_toolbox.items.push(device_copy);
+ }
+};
+
_Selected2.prototype.onMouseDown = function (controller, msg_type, $event) {
var last_selected = null;
@@ -256,7 +334,6 @@ _Selected2.prototype.onKeyDown = function (controller, msg_type, $event) {
};
_Selected2.prototype.onKeyDown.transitions = ['Ready'];
-
_Selected1.prototype.onMouseMove = function (controller) {
controller.changeState(Move);
@@ -277,6 +354,33 @@ _Selected1.prototype.onTouchEnd = _Selected1.prototype.onMouseUp;
_Selected1.prototype.onMouseDown = util.noop;
+_Move.prototype.start = function (controller) {
+
+ var devices = controller.scope.selected_devices;
+ var i = 0;
+ var j = 0;
+ for (i = 0; i < devices.length; i++) {
+ devices[i].moving = true;
+ for (j = 0; j < controller.scope.devices.length; j++) {
+ console.log(Math.pow(devices[i].x - controller.scope.devices[j].x, 2) +
+ Math.pow(devices[i].y - controller.scope.devices[j].y, 2));
+ if ((Math.pow(devices[i].x - controller.scope.devices[j].x, 2) +
+ Math.pow(devices[i].y - controller.scope.devices[j].y, 2)) < 160000) {
+ controller.scope.devices[j].moving = true;
+ }
+ }
+ }
+};
+
+_Move.prototype.end = function (controller) {
+
+ var devices = controller.scope.devices;
+ var i = 0;
+ for (i = 0; i < devices.length; i++) {
+ devices[i].moving = false;
+ }
+};
+
_Move.prototype.onMouseMove = function (controller) {
var devices = controller.scope.selected_devices;
@@ -313,7 +417,7 @@ _Move.prototype.onMouseMove = function (controller) {
//TODO: Improve the performance of this code from O(n^2) to O(n) or better
for (i = 0; i < groups.length; i++) {
- membership_old_new = groups[i].update_membership(controller.scope.devices);
+ membership_old_new = groups[i].update_membership(controller.scope.devices, controller.scope.groups);
controller.scope.send_control_message(new messages.GroupMembership(controller.scope.client_id,
groups[i].id,
membership_old_new[2]));
diff --git a/awx/network_ui/static/network_ui/src/network.ui.app.js b/awx/network_ui/static/network_ui/src/network.ui.app.js
index eda65ee413..503fa19c3b 100644
--- a/awx/network_ui/static/network_ui/src/network.ui.app.js
+++ b/awx/network_ui/static/network_ui/src/network.ui.app.js
@@ -8,13 +8,23 @@ var router = require('./router.directive.js');
var switchd = require('./switch.directive.js');
var host = require('./host.directive.js');
var link = require('./link.directive.js');
+var stream = require('./stream.directive.js');
var rack = require('./rack.directive.js');
+var rackIcon = require('./rack.icon.directive.js');
var group = require('./group.directive.js');
+var site = require('./site.directive.js');
+var siteIcon = require('./site.icon.directive.js');
+var process = require('./process.directive.js');
+var configuration = require('./configuration.directive.js');
+var map = require('./map.directive.js');
+var deviceDetail = require('./device.detail.directive.js');
var defaultd = require('./default.directive.js');
var quadrants = require('./quadrants.directive.js');
var stencil = require('./stencil.directive.js');
var layer = require('./layer.directive.js');
var button = require('./button.directive.js');
+var inventoryToolbox = require('./inventory.toolbox.directive.js');
+var inventoryToolboxClipPath = require('./inventory.toolbox.clip.path.directive.js');
var statusLight = require('./status.light.directive.js');
var taskStatus = require('./task.status.directive.js');
var debug = require('./debug.directive.js');
@@ -32,13 +42,23 @@ var networkUI = angular.module('networkUI', [
.directive('awxNetSwitch', switchd.switchd)
.directive('awxNetHost', host.host)
.directive('awxNetLink', link.link)
+ .directive('awxNetStream', stream.stream)
.directive('awxNetRack', rack.rack)
.directive('awxNetGroup', group.group)
+ .directive('awxNetSite', site.site)
+ .directive('awxNetSiteIcon', siteIcon.siteIcon)
+ .directive('awxNetRackIcon', rackIcon.rackIcon)
+ .directive('awxNetProcess', process.process)
+ .directive('awxNetConfiguration', configuration.configuration)
+ .directive('awxNetMap', map.map)
+ .directive('awxNetDeviceDetail', deviceDetail.deviceDetail)
.directive('awxNetDefault', defaultd.defaultd)
.directive('awxNetQuadrants', quadrants.quadrants)
.directive('awxNetStencil', stencil.stencil)
.directive('awxNetLayer', layer.layer)
.directive('awxNetButton', button.button)
+ .directive('awxNetInventoryToolbox', inventoryToolbox.inventoryToolbox)
+ .directive('awxNetInventoryToolboxClipPath', inventoryToolboxClipPath.inventoryToolboxClipPath)
.directive('awxNetStatusLight', statusLight.statusLight)
.directive('awxNetTaskStatus', taskStatus.taskStatus)
.directive('awxNetworkUi', awxNetworkUI.awxNetworkUI);
diff --git a/awx/network_ui/static/network_ui/src/network.ui.controller.js b/awx/network_ui/static/network_ui/src/network.ui.controller.js
index d320d65971..c05299cc1e 100644
--- a/awx/network_ui/static/network_ui/src/network.ui.controller.js
+++ b/awx/network_ui/static/network_ui/src/network.ui.controller.js
@@ -1,13 +1,16 @@
-
-
-//console.log = function () { };
var angular = require('angular');
var fsm = require('./fsm.js');
var null_fsm = require('./null.fsm.js');
+var mode_fsm = require('./mode.fsm.js');
+var device_detail_fsm = require('./device.detail.fsm.js');
+var rack_fsm = require('./rack.fsm.js');
+var site_fsm = require('./site.fsm.js');
var hotkeys = require('./hotkeys.fsm.js');
+var toolbox_fsm = require('./toolbox.fsm.js');
var view = require('./view.js');
var move = require('./move.js');
var link = require('./link.js');
+var stream_fsm = require('./stream.fsm.js');
var group = require('./group.js');
var buttons = require('./buttons.js');
var time = require('./time.js');
@@ -20,9 +23,10 @@ var ReconnectingWebSocket = require('reconnectingwebsocket');
var NetworkUIController = function($scope, $document, $location, $window) {
window.scope = $scope;
+ var i = 0;
$scope.api_token = '';
- $scope.disconnected = false;
+ $scope.disconnected = true;
$scope.topology_id = $location.search().topology_id || 0;
// Create a web socket to connect to the backend server
@@ -45,6 +49,8 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.onMouseMoveResult = "";
$scope.onMouseMoveResult = "";
$scope.current_scale = 1.0;
+ $scope.current_mode = null;
+ $scope.current_location = ["Earth", "Site1", "Spine1", "Eth1"];
$scope.panX = 0;
$scope.panY = 0;
$scope.mouseX = 0;
@@ -63,15 +69,8 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.selected_items = [];
$scope.selected_groups = [];
$scope.new_link = null;
- $scope.null_controller = new fsm.FSMController($scope, null_fsm.Start, null);
- $scope.hotkeys_controller = new fsm.FSMController($scope, hotkeys.Start, $scope.null_controller);
- $scope.view_controller = new fsm.FSMController($scope, view.Start, $scope.hotkeys_controller);
- $scope.move_controller = new fsm.FSMController($scope, move.Start, $scope.view_controller);
- $scope.link_controller = new fsm.FSMController($scope, link.Start, $scope.move_controller);
- $scope.group_controller = new fsm.FSMController($scope, group.Start, $scope.link_controller);
- $scope.buttons_controller = new fsm.FSMController($scope, buttons.Start, $scope.group_controller);
- $scope.time_controller = new fsm.FSMController($scope, time.Start, $scope.buttons_controller);
- $scope.first_controller = $scope.time_controller;
+ $scope.new_stream = null;
+ $scope.new_group_type = null;
$scope.last_key = "";
$scope.last_key_code = null;
$scope.last_event = null;
@@ -89,6 +88,7 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.link_id_seq = util.natural_numbers(0);
$scope.group_id_seq = util.natural_numbers(0);
$scope.message_id_seq = util.natural_numbers(0);
+ $scope.stream_id_seq = util.natural_numbers(0);
$scope.time_pointer = -1;
$scope.frame = 0;
$scope.recording = false;
@@ -99,9 +99,108 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.stencils = [];
$scope.links = [];
$scope.groups = [];
+ $scope.processes = [];
+ $scope.configurations = [];
+ $scope.streams = [];
+ $scope.view_port = {'x': 0,
+ 'y': 0,
+ 'width': 0,
+ 'height': 0};
+ $scope.null_controller = new fsm.FSMController($scope, null_fsm.Start, null);
+ $scope.hotkeys_controller = new fsm.FSMController($scope, hotkeys.Start, $scope.null_controller);
+ $scope.view_controller = new fsm.FSMController($scope, view.Start, $scope.hotkeys_controller);
+ $scope.device_detail_controller = new fsm.FSMController($scope, device_detail_fsm.Start, $scope.view_controller);
+ $scope.move_controller = new fsm.FSMController($scope, move.Start, $scope.device_detail_controller);
+ $scope.link_controller = new fsm.FSMController($scope, link.Start, $scope.move_controller);
+ $scope.stream_controller = new fsm.FSMController($scope, stream_fsm.Start, $scope.link_controller);
+ $scope.group_controller = new fsm.FSMController($scope, group.Start, $scope.stream_controller);
+ $scope.rack_controller = new fsm.FSMController($scope, rack_fsm.Disable, $scope.group_controller);
+ $scope.site_controller = new fsm.FSMController($scope, site_fsm.Disable, $scope.rack_controller);
+ $scope.buttons_controller = new fsm.FSMController($scope, buttons.Start, $scope.site_controller);
+ $scope.time_controller = new fsm.FSMController($scope, time.Start, $scope.buttons_controller);
+ $scope.app_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.time_controller);
+ //App Toolbox Setup
+ $scope.app_toolbox = new models.ToolBox(0, 'Application', 'app', 10, 200, 150, $scope.graph.height - 200 - 100);
+ $scope.app_toolbox.spacing = 150;
+ $scope.app_toolbox.enabled = false;
+ $scope.app_toolbox_controller.toolbox = $scope.app_toolbox;
+ $scope.app_toolbox_controller.dropped_action = function (selected_item) {
+ $scope.first_controller.handle_message("PasteProcess", new messages.PasteProcess(selected_item));
+ };
+ $scope.app_toolbox.items.push(new models.Application(0, 'BGP', 'process', 0, 0));
+ $scope.app_toolbox.items.push(new models.Application(0, 'OSPF', 'process', 0, 0));
+ $scope.app_toolbox.items.push(new models.Application(0, 'STP', 'process', 0, 0));
+ $scope.app_toolbox.items.push(new models.Application(0, 'Zero Pipeline', 'process', 0, 0));
+ for(i = 0; i < $scope.app_toolbox.items.length; i++) {
+ $scope.app_toolbox.items[i].icon = true;
+ }
+ $scope.inventory_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.app_toolbox_controller);
+
+ //Inventory Toolbox Setup
+ $scope.inventory_toolbox = new models.ToolBox(0, 'Inventory', 'device', 10, 200, 150, $scope.graph.height - 200 - 100);
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router6', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Switch6', 0, 0, 'switch'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Host6', 0, 0, 'host'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router7', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router8', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router9', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router10', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router11', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router12', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router13', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router14', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router15', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router16', 0, 0, 'router'));
+ $scope.inventory_toolbox.spacing = 150;
+ $scope.inventory_toolbox.enabled = true;
+ $scope.inventory_toolbox_controller.toolbox = $scope.inventory_toolbox;
+ $scope.inventory_toolbox_controller.remove_on_drop = true;
+ $scope.inventory_toolbox_controller.dropped_action = function (selected_item) {
+ $scope.first_controller.handle_message("PasteDevice", new messages.PasteDevice(selected_item));
+ };
+
+ for(i = 0; i < $scope.inventory_toolbox.items.length; i++) {
+ $scope.inventory_toolbox.items[i].icon = true;
+ }
+ //End Inventory Toolbox Setup
+ $scope.rack_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.inventory_toolbox_controller);
+ //Rack Toolbox Setup
+ $scope.rack_toolbox = new models.ToolBox(0, 'Rack', 'rack', 10, 200, 150, $scope.graph.height - 200 - 100);
+ $scope.rack_toolbox.items.push(new models.Group(0, 'Rack3', 'rack', 0, 0, 200, 1000, 'false'));
+ $scope.rack_toolbox.spacing = 200;
+ $scope.rack_toolbox.enabled = false;
+ $scope.rack_toolbox_controller.remove_on_drop = false;
+ $scope.rack_toolbox_controller.toolbox = $scope.rack_toolbox;
+ $scope.rack_toolbox_controller.dropped_action = function (selected_item) {
+ $scope.first_controller.handle_message("PasteRack", new messages.PasteRack(selected_item));
+ };
+ for(i = 0; i < $scope.rack_toolbox.items.length; i++) {
+ $scope.rack_toolbox.items[i].icon = true;
+ $scope.rack_toolbox.items[i].selected = false;
+ }
+ //End Rack Toolbox Setup
+ $scope.site_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.rack_toolbox_controller);
+ //Site Toolbox Setup
+ $scope.site_toolbox = new models.ToolBox(0, 'Sites', 'sites', 10, 200, 150, $scope.graph.height - 200 - 100);
+ $scope.site_toolbox.items.push(new models.Group(0, 'Site3', 'site', 0, 0, 1000, 1000, 'false'));
+ $scope.site_toolbox.spacing = 200;
+ $scope.site_toolbox.enabled = false;
+ $scope.site_toolbox_controller.remove_on_drop = false;
+ $scope.site_toolbox_controller.toolbox = $scope.site_toolbox;
+ $scope.site_toolbox_controller.dropped_action = function (selected_item) {
+ $scope.first_controller.handle_message("PasteSite", new messages.PasteSite(selected_item));
+ };
+ for(i = 0; i < $scope.site_toolbox.items.length; i++) {
+ $scope.site_toolbox.items[i].icon = true;
+ $scope.site_toolbox.items[i].selected = false;
+ }
+ //End Site Toolbox Setup
+
+ $scope.mode_controller = new fsm.FSMController($scope, mode_fsm.Start, $scope.site_toolbox_controller);
+ $scope.first_controller = $scope.mode_controller;
var getMouseEventResult = function (mouseEvent) {
return "(" + mouseEvent.x + ", " + mouseEvent.y + ")";
};
@@ -109,6 +208,10 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.updateScaledXY = function() {
$scope.scaledX = ($scope.mouseX - $scope.panX) / $scope.current_scale;
$scope.scaledY = ($scope.mouseY - $scope.panY) / $scope.current_scale;
+ $scope.view_port.x = - $scope.panX / $scope.current_scale;
+ $scope.view_port.y = - $scope.panY / $scope.current_scale;
+ $scope.view_port.width = $scope.graph.width / $scope.current_scale;
+ $scope.view_port.height = $scope.graph.height / $scope.current_scale;
};
$scope.updatePanAndScale = function() {
@@ -488,6 +591,8 @@ var NetworkUIController = function($scope, $document, $location, $window) {
new models.Button("CONFIGURE", 520, 10, 90, 30, $scope.onConfigureButton)
];
+ $scope.buttons = [];
+
var LAYERS_X = 160;
$scope.layers = [
@@ -518,7 +623,8 @@ var NetworkUIController = function($scope, $document, $location, $window) {
new models.Button("Router", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 1, 70, 30, function () {$scope.first_controller.handle_message("NewDevice", new messages.NewDevice("router"));}),
new models.Button("Host", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 2, 70, 30, function () {$scope.first_controller.handle_message("NewDevice", new messages.NewDevice("host"));}),
new models.Button("Link", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 3, 70, 30, function () { $scope.first_controller.handle_message("NewLink");}),
- new models.Button("Group", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 4, 70, 30, function () { $scope.first_controller.handle_message("NewGroup");}),
+ new models.Button("Group", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 4, 70, 30, function () { $scope.first_controller.handle_message("NewGroup", new messages.NewGroup("group"));}),
+ new models.Button("Site", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 5, 70, 30, function () { $scope.first_controller.handle_message("NewGroup", new messages.NewGroup("site"));}),
];
$scope.all_buttons = [];
@@ -663,6 +769,23 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.devices.push(device);
};
+ $scope.onGroupCreate = function(data) {
+ $scope.create_group(data);
+ };
+
+ $scope.create_group = function(data) {
+ var group = new models.Group(data.id,
+ data.name,
+ data.type,
+ data.x1,
+ data.y1,
+ data.x2,
+ data.y2,
+ false);
+ $scope.group_id_seq = util.natural_numbers(data.id);
+ $scope.groups.push(group);
+ };
+
$scope.forDevice = function(device_id, data, fn) {
var i = 0;
for (i = 0; i < $scope.devices.length; i++) {
@@ -1088,6 +1211,7 @@ var NetworkUIController = function($scope, $document, $location, $window) {
}
new_group = new models.Group(group.id,
group.name,
+ group.type,
group.x1,
group.y1,
group.x2,
@@ -1244,6 +1368,26 @@ var NetworkUIController = function($scope, $document, $location, $window) {
$scope.layers[i].x = $scope.graph.width - 140;
}
};
+
+ $scope.update_offsets = function () {
+
+ var i = 0;
+ var streams = $scope.streams;
+ var map = new Map();
+ var stream = null;
+ var key = null;
+ for (i = 0; i < streams.length; i++) {
+ stream = streams[i];
+ key = "" + stream.from_device.id + "_" + stream.to_device.id;
+ map.set(key, 0);
+ }
+ for (i = 0; i < streams.length; i++) {
+ stream = streams[i];
+ key = "" + stream.from_device.id + "_" + stream.to_device.id;
+ stream.offset = map.get(key);
+ map.set(key, stream.offset + 1);
+ }
+ };
};
exports.NetworkUIController = NetworkUIController;
diff --git a/awx/network_ui/static/network_ui/src/network.widgets.app.js b/awx/network_ui/static/network_ui/src/network.widgets.app.js
new file mode 100644
index 0000000000..c2846e7235
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/network.widgets.app.js
@@ -0,0 +1,66 @@
+
+//console.log = function () { };
+var angular = require('angular');
+var NetworkWidgetsController = require('./network.widgets.controller.js');
+var cursor = require('./cursor.directive.js');
+var touch = require('./touch.directive.js');
+var router = require('./router.directive.js');
+var switchd = require('./switch.directive.js');
+var host = require('./host.directive.js');
+var link = require('./link.directive.js');
+var stream = require('./stream.directive.js');
+var rack = require('./rack.directive.js');
+var rackIcon = require('./rack.icon.directive.js');
+var group = require('./group.directive.js');
+var site = require('./site.directive.js');
+var siteIcon = require('./site.icon.directive.js');
+var process = require('./process.directive.js');
+var configuration = require('./configuration.directive.js');
+var map = require('./map.directive.js');
+var deviceDetail = require('./device.detail.directive.js');
+var defaultd = require('./default.directive.js');
+var quadrants = require('./quadrants.directive.js');
+var stencil = require('./stencil.directive.js');
+var layer = require('./layer.directive.js');
+var button = require('./button.directive.js');
+var inventoryToolbox = require('./inventory.toolbox.directive.js');
+var inventoryToolboxClipPath = require('./inventory.toolbox.clip.path.directive.js');
+var statusLight = require('./status.light.directive.js');
+var taskStatus = require('./task.status.directive.js');
+var debug = require('./debug.directive.js');
+var awxNetworkWidgets = require('./network.widgets.directive.js');
+
+var networkWidgets = angular.module('networkWidgets', [
+ 'monospaced.mousewheel',
+ 'ngTouch'
+ ])
+ .controller('NetworkWidgetsController', NetworkWidgetsController.NetworkWidgetsController)
+ .directive('awxNetCursor', cursor.cursor)
+ .directive('awxNetTouch', touch.touch)
+ .directive('awxNetDebug', debug.debug)
+ .directive('awxNetRouter', router.router)
+ .directive('awxNetSwitch', switchd.switchd)
+ .directive('awxNetHost', host.host)
+ .directive('awxNetLink', link.link)
+ .directive('awxNetStream', stream.stream)
+ .directive('awxNetRack', rack.rack)
+ .directive('awxNetGroup', group.group)
+ .directive('awxNetSite', site.site)
+ .directive('awxNetSiteIcon', siteIcon.siteIcon)
+ .directive('awxNetRackIcon', rackIcon.rackIcon)
+ .directive('awxNetProcess', process.process)
+ .directive('awxNetConfiguration', configuration.configuration)
+ .directive('awxNetMap', map.map)
+ .directive('awxNetDeviceDetail', deviceDetail.deviceDetail)
+ .directive('awxNetDefault', defaultd.defaultd)
+ .directive('awxNetQuadrants', quadrants.quadrants)
+ .directive('awxNetStencil', stencil.stencil)
+ .directive('awxNetLayer', layer.layer)
+ .directive('awxNetButton', button.button)
+ .directive('awxNetInventoryToolbox', inventoryToolbox.inventoryToolbox)
+ .directive('awxNetInventoryToolboxClipPath', inventoryToolboxClipPath.inventoryToolboxClipPath)
+ .directive('awxNetStatusLight', statusLight.statusLight)
+ .directive('awxNetTaskStatus', taskStatus.taskStatus)
+ .directive('awxNetworkWidgets', awxNetworkWidgets.awxNetworkWidgets);
+
+exports.networkWidgets = networkWidgets;
diff --git a/awx/network_ui/static/network_ui/src/network.widgets.controller.js b/awx/network_ui/static/network_ui/src/network.widgets.controller.js
new file mode 100644
index 0000000000..e8b60572c5
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/network.widgets.controller.js
@@ -0,0 +1,1426 @@
+// This is not production code. It is a development environment for UI widgets.
+// Do not refactor this code with the production code in network.ui.controller.js
+// This code is separate so that it can be broken without breaking the main UI code.
+//console.log = function () { };
+var angular = require('angular');
+var fsm = require('./fsm.js');
+var null_fsm = require('./null.fsm.js');
+var mode_fsm = require('./mode.fsm.js');
+var device_detail_fsm = require('./device.detail.fsm.js');
+var rack_fsm = require('./rack.fsm.js');
+var site_fsm = require('./site.fsm.js');
+var hotkeys = require('./hotkeys.fsm.js');
+var toolbox_fsm = require('./toolbox.fsm.js');
+var view = require('./view.js');
+var move = require('./move.js');
+var link = require('./link.js');
+var stream_fsm = require('./stream.fsm.js');
+var group = require('./group.js');
+var buttons = require('./buttons.js');
+var time = require('./time.js');
+var util = require('./util.js');
+var models = require('./models.js');
+var messages = require('./messages.js');
+var svg_crowbar = require('./svg-crowbar.js');
+
+var NetworkWidgetsController = function($scope, $document, $location, $window) {
+
+ window.scope = $scope;
+ var i = 0;
+
+ $scope.topology_id = 0;
+
+ $scope.control_socket = {
+ on_message: util.noop
+ };
+ $scope.history = [];
+ $scope.client_id = 1;
+ $scope.onMouseDownResult = "";
+ $scope.onMouseUpResult = "";
+ $scope.onMouseEnterResult = "";
+ $scope.onMouseLeaveResult = "";
+ $scope.onMouseMoveResult = "";
+ $scope.current_scale = 1.01;
+ $scope.current_mode = null;
+ $scope.current_location = [];
+ $scope.panX = 100;
+ $scope.panY = 100;
+ $scope.mouseX = 0;
+ $scope.mouseY = 0;
+ $scope.scaledX = 0;
+ $scope.scaledY = 0;
+ $scope.pressedX = 0;
+ $scope.pressedY = 0;
+ $scope.pressedScaledX = 0;
+ $scope.pressedScaledY = 0;
+ $scope.lastPanX = 0;
+ $scope.lastPanY = 0;
+ $scope.selected_devices = [];
+ $scope.selected_links = [];
+ $scope.selected_interfaces = [];
+ $scope.selected_items = [];
+ $scope.selected_groups = [];
+ $scope.new_link = null;
+ $scope.new_stream = null;
+ $scope.new_group_type = null;
+ $scope.last_key = "";
+ $scope.last_key_code = null;
+ $scope.last_event = null;
+ $scope.cursor = {'x':100, 'y': 100, 'hidden': false};
+
+ $scope.debug = {'hidden': true};
+ $scope.hide_buttons = false;
+ $scope.hide_links = false;
+ $scope.hide_interfaces = false;
+ $scope.hide_groups = false;
+ $scope.graph = {'width': window.innerWidth,
+ 'right_column': window.innerWidth - 300,
+ 'height': window.innerHeight};
+ $scope.device_id_seq = util.natural_numbers(0);
+ $scope.link_id_seq = util.natural_numbers(0);
+ $scope.group_id_seq = util.natural_numbers(0);
+ $scope.message_id_seq = util.natural_numbers(0);
+ $scope.stream_id_seq = util.natural_numbers(0);
+ $scope.time_pointer = -1;
+ $scope.frame = 0;
+ $scope.recording = false;
+ $scope.replay = false;
+ $scope.touch_data = {};
+ $scope.touches = [];
+ $scope.devices = [];
+ $scope.stencils = [];
+ $scope.links = [];
+ $scope.groups = [];
+ $scope.processes = [];
+ $scope.configurations = [];
+ $scope.streams = [];
+ $scope.view_port = {'x': 0,
+ 'y': 0,
+ 'width': 0,
+ 'height': 0};
+
+ $scope.null_controller = new fsm.FSMController($scope, null_fsm.Start, null);
+ $scope.hotkeys_controller = new fsm.FSMController($scope, hotkeys.Start, $scope.null_controller);
+ $scope.view_controller = new fsm.FSMController($scope, view.Start, $scope.hotkeys_controller);
+ $scope.device_detail_controller = new fsm.FSMController($scope, device_detail_fsm.Start, $scope.view_controller);
+ $scope.move_controller = new fsm.FSMController($scope, move.Start, $scope.device_detail_controller);
+ $scope.link_controller = new fsm.FSMController($scope, link.Start, $scope.move_controller);
+ $scope.stream_controller = new fsm.FSMController($scope, stream_fsm.Start, $scope.link_controller);
+ $scope.group_controller = new fsm.FSMController($scope, group.Start, $scope.stream_controller);
+ $scope.rack_controller = new fsm.FSMController($scope, rack_fsm.Disable, $scope.group_controller);
+ $scope.site_controller = new fsm.FSMController($scope, site_fsm.Disable, $scope.rack_controller);
+ $scope.buttons_controller = new fsm.FSMController($scope, buttons.Start, $scope.site_controller);
+ $scope.time_controller = new fsm.FSMController($scope, time.Start, $scope.buttons_controller);
+ $scope.app_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.time_controller);
+ //App Toolbox Setup
+ $scope.app_toolbox = new models.ToolBox(0, 'Application', 'app', 10, 200, 150, $scope.graph.height - 200 - 100);
+ $scope.app_toolbox.spacing = 150;
+ $scope.app_toolbox.enabled = false;
+ $scope.app_toolbox_controller.toolbox = $scope.app_toolbox;
+ $scope.app_toolbox_controller.dropped_action = function (selected_item) {
+ $scope.first_controller.handle_message("PasteProcess", new messages.PasteProcess(selected_item));
+ };
+ $scope.app_toolbox.items.push(new models.Application(0, 'BGP', 'process', 0, 0));
+ $scope.app_toolbox.items.push(new models.Application(0, 'OSPF', 'process', 0, 0));
+ $scope.app_toolbox.items.push(new models.Application(0, 'STP', 'process', 0, 0));
+ $scope.app_toolbox.items.push(new models.Application(0, 'Zero Pipeline', 'process', 0, 0));
+
+ for(i = 0; i < $scope.app_toolbox.items.length; i++) {
+ $scope.app_toolbox.items[i].icon = true;
+ }
+
+ $scope.inventory_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.app_toolbox_controller);
+
+ //Inventory Toolbox Setup
+ $scope.inventory_toolbox = new models.ToolBox(0, 'Inventory', 'device', 10, 200, 150, $scope.graph.height - 200 - 100);
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router6', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Switch6', 0, 0, 'switch'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Host6', 0, 0, 'host'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router7', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router8', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router9', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router10', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router11', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router12', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router13', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router14', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router15', 0, 0, 'router'));
+ $scope.inventory_toolbox.items.push(new models.Device(0, 'Router16', 0, 0, 'router'));
+ $scope.inventory_toolbox.spacing = 150;
+ $scope.inventory_toolbox.enabled = true;
+ $scope.inventory_toolbox_controller.toolbox = $scope.inventory_toolbox;
+ $scope.inventory_toolbox_controller.remove_on_drop = true;
+ $scope.inventory_toolbox_controller.dropped_action = function (selected_item) {
+ $scope.first_controller.handle_message("PasteDevice", new messages.PasteDevice(selected_item));
+ };
+
+ for(i = 0; i < $scope.inventory_toolbox.items.length; i++) {
+ $scope.inventory_toolbox.items[i].icon = true;
+ }
+ //End Inventory Toolbox Setup
+ $scope.rack_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.inventory_toolbox_controller);
+ //Rack Toolbox Setup
+ $scope.rack_toolbox = new models.ToolBox(0, 'Rack', 'rack', 10, 200, 150, $scope.graph.height - 200 - 100);
+ $scope.rack_toolbox.items.push(new models.Group(0, 'Rack3', 'rack', 0, 0, 200, 1000, 'false'));
+ $scope.rack_toolbox.spacing = 200;
+ $scope.rack_toolbox.enabled = false;
+ $scope.rack_toolbox_controller.remove_on_drop = false;
+ $scope.rack_toolbox_controller.toolbox = $scope.rack_toolbox;
+ $scope.rack_toolbox_controller.dropped_action = function (selected_item) {
+ $scope.first_controller.handle_message("PasteRack", new messages.PasteRack(selected_item));
+ };
+ for(i = 0; i < $scope.rack_toolbox.items.length; i++) {
+ $scope.rack_toolbox.items[i].icon = true;
+ $scope.rack_toolbox.items[i].selected = false;
+ }
+ //End Rack Toolbox Setup
+ $scope.site_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.rack_toolbox_controller);
+ //Site Toolbox Setup
+ $scope.site_toolbox = new models.ToolBox(0, 'Sites', 'sites', 10, 200, 150, $scope.graph.height - 200 - 100);
+ $scope.site_toolbox.items.push(new models.Group(0, 'Site3', 'site', 0, 0, 1000, 1000, 'false'));
+ $scope.site_toolbox.spacing = 200;
+ $scope.site_toolbox.enabled = false;
+ $scope.site_toolbox_controller.remove_on_drop = false;
+ $scope.site_toolbox_controller.toolbox = $scope.site_toolbox;
+ $scope.site_toolbox_controller.dropped_action = function (selected_item) {
+ $scope.first_controller.handle_message("PasteSite", new messages.PasteSite(selected_item));
+ };
+ for(i = 0; i < $scope.site_toolbox.items.length; i++) {
+ $scope.site_toolbox.items[i].icon = true;
+ $scope.site_toolbox.items[i].selected = false;
+ }
+ //End Site Toolbox Setup
+
+ $scope.mode_controller = new fsm.FSMController($scope, mode_fsm.Start, $scope.site_toolbox_controller);
+ $scope.first_controller = $scope.mode_controller;
+
+ var dids = $scope.device_id_seq;
+ var mids = $scope.message_id_seq;
+ var gids = $scope.group_id_seq;
+ var lids = $scope.link_id_seq;
+
+
+ $scope.initial_messages = [
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":100,"y":100,"name":"Router1","type":"router","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":300,"y":100,"name":"Switch1","type":"switch","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":500,"y":100,"name":"HostA","type":"host","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":700,"y":100,"name":"Host1","type":"host","message_id":mids()}],
+
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":100,"y":300,"name":"Router2","type":"router","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":100,"y":500,"name":"Router3","type":"router","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":5,"id":1,"name":"eth1","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":6,"id":1,"name":"eth1","message_id":mids()}],
+ ["LinkCreate", {"msg_type":"LinkCreate","id":lids(),"sender":0,"name":"","from_device_id":5,"to_device_id":6,"from_interface_id":1,"to_interface_id":1,"message_id":mids()}],
+
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":300,"y":300,"name":"Switch2","type":"switch","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":300,"y":500,"name":"Switch3","type":"switch","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":7,"id":1,"name":"eth1","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":8,"id":1,"name":"eth1","message_id":mids()}],
+ ["LinkCreate", {"msg_type":"LinkCreate","id":lids(),"sender":0,"name":"","from_device_id":7,"to_device_id":8,"from_interface_id":1,"to_interface_id":1,"message_id":mids()}],
+
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":500,"y":300,"name":"HostB","type":"host","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":500,"y":500,"name":"HostC","type":"host","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":9,"id":1,"name":"eth1","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":10,"id":1,"name":"eth1","message_id":mids()}],
+ ["LinkCreate", {"msg_type":"LinkCreate","id":lids(),"sender":0,"name":"","from_device_id":9,"to_device_id":10,"from_interface_id":1,"to_interface_id":1,"message_id":mids()}],
+
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":700,"y":300,"name":"Host2","type":"host","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":700,"y":500,"name":"Host3","type":"host","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":11,"id":1,"name":"eth1","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":12,"id":1,"name":"eth1","message_id":mids()}],
+ ["LinkCreate", {"msg_type":"LinkCreate","id":lids(),"sender":0,"name":"","from_device_id":11,"to_device_id":12,"from_interface_id":1,"to_interface_id":1,"message_id":mids()}],
+
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":100,"y":700,"name":"Router4","type":"router","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":300,"y":700,"name":"Switch4","type":"switch","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":500,"y":700,"name":"HostD","type":"host","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":700,"y":700,"name":"Host4","type":"host","message_id":mids()}],
+
+ ["GroupCreate",{"msg_type":"GroupCreate","sender":0,"ids":gids(),"x1":0,"y1":600,"x2":1000,"y2":800,"name":"Group1",type:"group", "message_id":mids()}],
+
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":100,"y":900,"name":"Router5","type":"router","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":300,"y":900,"name":"Switch5","type":"switch","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":500,"y":900,"name":"HostE","type":"host","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":700,"y":900,"name":"Host5","type":"host","message_id":mids()}],
+
+ ["GroupCreate",{"msg_type":"GroupCreate","sender":0,"ids":gids(),"x1":-100,"y1":0,"x2":1100,"y2":1100,"name":"Site1",type:"site", "message_id":mids()}],
+ ["GroupCreate",{"msg_type":"GroupCreate","sender":0,"ids":gids(),"x1":0,"y1":800,"x2":1000,"y2":1000,"name":"Rack1",type:"rack", "message_id":mids()}],
+
+
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":900,"y":100,"name":"Device1","type":"device","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":900,"y":300,"name":"Device2","type":"device","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":900,"y":500,"name":"Device3","type":"device","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":22,"id":1,"name":"eth1","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":23,"id":1,"name":"eth1","message_id":mids()}],
+ ["LinkCreate", {"msg_type":"LinkCreate","id":lids(),"sender":0,"name":"","from_device_id":22,"to_device_id":23,"from_interface_id":1,"to_interface_id":1,"message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":900,"y":700,"name":"Device4","type":"device","message_id":mids()}],
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":900,"y":900,"name":"Device5","type":"device","message_id":mids()}],
+
+ ["DeviceCreate",{"msg_type":"DeviceCreate","sender":0,"id":dids(),"x":100,"y":2900,"name":"Router6","type":"router","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":17,"id":1,"name":"eth1","message_id":mids()}],
+ ["InterfaceCreate", {"msg_type":"InterfaceCreate","sender":0,"device_id":26,"id":1,"name":"eth1","message_id":mids()}],
+ ["LinkCreate", {"msg_type":"LinkCreate","id":lids(),"sender":0,"name":"","from_device_id":17,"to_device_id":26,"from_interface_id":1,"to_interface_id":1,"message_id":mids()}],
+ ["GroupCreate",{"msg_type":"GroupCreate","sender":0,"ids":gids(),"x1":0,"y1":2800,"x2":1000,"y2":3000,"name":"Site2",type:"site", "message_id":mids()}],
+ ];
+
+ var getMouseEventResult = function (mouseEvent) {
+ return "(" + mouseEvent.screenX + ", " + mouseEvent.screenX + ")";
+ };
+
+ $scope.updateScaledXY = function() {
+ $scope.scaledX = ($scope.mouseX - $scope.panX) / $scope.current_scale;
+ $scope.scaledY = ($scope.mouseY - $scope.panY) / $scope.current_scale;
+ $scope.view_port.x = - $scope.panX / $scope.current_scale;
+ $scope.view_port.y = - $scope.panY / $scope.current_scale;
+ $scope.view_port.width = $scope.graph.width / $scope.current_scale;
+ $scope.view_port.height = $scope.graph.height / $scope.current_scale;
+ };
+
+ $scope.updatePanAndScale = function() {
+ var g = document.getElementById('frame_g');
+ g.setAttribute('transform','translate(' + $scope.panX + ',' + $scope.panY + ') scale(' + $scope.current_scale + ')');
+ };
+
+ $scope.clear_selections = function () {
+
+ var i = 0;
+ var j = 0;
+ var devices = $scope.devices;
+ var links = $scope.links;
+ var groups = $scope.groups;
+ $scope.selected_items = [];
+ $scope.selected_devices = [];
+ $scope.selected_links = [];
+ $scope.selected_interfaces = [];
+ $scope.selected_groups = [];
+ for (i = 0; i < devices.length; i++) {
+ for (j = 0; j < devices[i].interfaces.length; j++) {
+ devices[i].interfaces[j].selected = false;
+ }
+ if (devices[i].selected) {
+ $scope.send_control_message(new messages.DeviceUnSelected($scope.client_id, devices[i].id));
+ }
+ devices[i].selected = false;
+ }
+ for (i = 0; i < links.length; i++) {
+ if (links[i].selected) {
+ $scope.send_control_message(new messages.LinkUnSelected($scope.client_id, links[i].id));
+ }
+ links[i].selected = false;
+ }
+ for (i = 0; i < groups.length; i++) {
+ groups[i].selected = false;
+ }
+ };
+
+ $scope.select_items = function (multiple_selection) {
+
+ var i = 0;
+ var j = 0;
+ var devices = $scope.devices;
+ var last_selected_device = null;
+ var last_selected_interface = null;
+ var last_selected_link = null;
+
+ $scope.pressedX = $scope.mouseX;
+ $scope.pressedY = $scope.mouseY;
+ $scope.pressedScaledX = $scope.scaledX;
+ $scope.pressedScaledY = $scope.scaledY;
+
+ if (!multiple_selection) {
+ $scope.clear_selections();
+ }
+
+ for (i = devices.length - 1; i >= 0; i--) {
+ if (devices[i].is_selected($scope.scaledX, $scope.scaledY)) {
+ devices[i].selected = true;
+ $scope.send_control_message(new messages.DeviceSelected($scope.client_id, devices[i].id));
+ last_selected_device = devices[i];
+ if ($scope.selected_items.indexOf($scope.devices[i]) === -1) {
+ $scope.selected_items.push($scope.devices[i]);
+ }
+ if ($scope.selected_devices.indexOf(devices[i]) === -1) {
+ $scope.selected_devices.push(devices[i]);
+ }
+ if (!multiple_selection) {
+ break;
+ }
+ }
+ }
+
+ // Do not select interfaces if a device was selected
+ if (last_selected_device === null && !$scope.hide_interfaces) {
+ for (i = devices.length - 1; i >= 0; i--) {
+ for (j = devices[i].interfaces.length - 1; j >= 0; j--) {
+ if (devices[i].interfaces[j].is_selected($scope.scaledX, $scope.scaledY)) {
+ devices[i].interfaces[j].selected = true;
+ last_selected_interface = devices[i].interfaces[j];
+ if ($scope.selected_interfaces.indexOf($scope.devices[i].interfaces[j]) === -1) {
+ $scope.selected_interfaces.push($scope.devices[i].interfaces[j]);
+ }
+ if ($scope.selected_items.indexOf($scope.devices[i].interfaces[j]) === -1) {
+ $scope.selected_items.push($scope.devices[i].interfaces[j]);
+ }
+ if (!multiple_selection) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Do not select links if a device was selected
+ if (last_selected_device === null && last_selected_interface === null) {
+ for (i = $scope.links.length - 1; i >= 0; i--) {
+ if($scope.links[i].is_selected($scope.scaledX, $scope.scaledY)) {
+ $scope.links[i].selected = true;
+ $scope.send_control_message(new messages.LinkSelected($scope.client_id, $scope.links[i].id));
+ last_selected_link = $scope.links[i];
+ if ($scope.selected_items.indexOf($scope.links[i]) === -1) {
+ $scope.selected_items.push($scope.links[i]);
+ }
+ if ($scope.selected_links.indexOf($scope.links[i]) === -1) {
+ $scope.selected_links.push($scope.links[i]);
+ if (!multiple_selection) {
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return {last_selected_device: last_selected_device,
+ last_selected_link: last_selected_link,
+ last_selected_interface: last_selected_interface,
+ };
+ };
+
+ // Event Handlers
+
+ $scope.onMouseDown = function ($event) {
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.offsetX, $event.offsetY, $event.type));
+ }
+ $scope.last_event = $event;
+ $scope.first_controller.handle_message('MouseDown', $event);
+ $scope.onMouseDownResult = getMouseEventResult($event);
+ $event.preventDefault();
+ };
+
+ $scope.onMouseUp = function ($event) {
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.offsetX, $event.offsetY, $event.type));
+ }
+ $scope.last_event = $event;
+ $scope.first_controller.handle_message('MouseUp', $event);
+ $scope.onMouseUpResult = getMouseEventResult($event);
+ $event.preventDefault();
+ };
+
+ $scope.onMouseLeave = function ($event) {
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.offsetX, $event.offsetY, $event.type));
+ }
+ $scope.onMouseLeaveResult = getMouseEventResult($event);
+ $scope.cursor.hidden = true;
+ $event.preventDefault();
+ };
+
+ $scope.onMouseMove = function ($event) {
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.offsetX, $event.offsetY, $event.type));
+ }
+ //var coords = getCrossBrowserElementCoords($event);
+ $scope.cursor.hidden = false;
+ $scope.cursor.x = $event.offsetX;
+ $scope.cursor.y = $event.offsetY;
+ $scope.mouseX = $event.offsetX;
+ $scope.mouseY = $event.offsetY;
+ $scope.updateScaledXY();
+ $scope.first_controller.handle_message('MouseMove', $event);
+ $scope.onMouseMoveResult = getMouseEventResult($event);
+ $event.preventDefault();
+ };
+
+ $scope.onMouseOver = function ($event) {
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.MouseEvent($scope.client_id, $event.x, $event.offsetY, $event.type));
+ }
+ $scope.onMouseOverResult = getMouseEventResult($event);
+ $scope.cursor.hidden = false;
+ $event.preventDefault();
+ };
+
+ $scope.onMouseEnter = $scope.onMouseOver;
+
+ $scope.onMouseWheel = function ($event, delta, deltaX, deltaY) {
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.MouseWheelEvent($scope.client_id, delta, deltaX, deltaY, $event.type, $event.originalEvent.metaKey));
+ }
+ $scope.last_event = $event;
+ $scope.first_controller.handle_message('MouseWheel', [$event, delta, deltaX, deltaY]);
+ event.preventDefault();
+ };
+
+ $scope.onKeyDown = function ($event) {
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.KeyEvent($scope.client_id,
+ $event.key,
+ $event.keyCode,
+ $event.type,
+ $event.altKey,
+ $event.shiftKey,
+ $event.ctrlKey,
+ $event.metaKey));
+ }
+ $scope.last_event = $event;
+ $scope.last_key = $event.key;
+ $scope.last_key_code = $event.keyCode;
+ $scope.first_controller.handle_message('KeyDown', $event);
+ $scope.$apply();
+ $event.preventDefault();
+ };
+
+ $document.bind("keydown", $scope.onKeyDown);
+
+ // Touch Event Handlers
+ //
+
+ $scope.onTouchStart = function($event) {
+ var touches = [];
+ var i = 0;
+ for (i = 0; i < $event.touches.length; i++) {
+ touches.push({screenX: $event.touches[i].screenX, screenY: $event.touches[i].screenY});
+ }
+ $scope.touches = touches;
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.TouchEvent($scope.client_id, "touchstart", touches));
+ }
+
+ if ($event.touches.length === 1) {
+ $scope.cursor.hidden = false;
+ $scope.cursor.x = $event.touches[0].screenX;
+ $scope.cursor.y = $event.touches[0].screenY;
+ $scope.mouseX = $event.touches[0].screenX;
+ $scope.mouseY = $event.touches[0].screenY;
+ $scope.updateScaledXY();
+ }
+ $scope.first_controller.handle_message('TouchStart', $event);
+ $scope.onTouchStartEvent = $event;
+ $event.preventDefault();
+ };
+
+ $scope.onTouchEnd = function($event) {
+ var touches = [];
+ var i = 0;
+ for (i = 0; i < $event.touches.length; i++) {
+ touches.push({screenX: $event.touches[i].screenX, screenY: $event.touches[i].screenY});
+ }
+ $scope.touches = touches;
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.TouchEvent($scope.client_id, "touchend", touches));
+ }
+ $scope.first_controller.handle_message('TouchEnd', $event);
+ $scope.onTouchEndEvent = $event;
+ $event.preventDefault();
+ };
+
+ $scope.onTouchMove = function($event) {
+ var touches = [];
+ var i = 0;
+ for (i = 0; i < $event.touches.length; i++) {
+ touches.push({screenX: $event.touches[i].screenX, screenY: $event.touches[i].screenY});
+ }
+ $scope.touches = touches;
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.TouchEvent($scope.client_id, "touchmove", touches));
+ }
+
+ if ($event.touches.length === 1) {
+ $scope.cursor.hidden = false;
+ $scope.cursor.x = $event.touches[0].screenX;
+ $scope.cursor.y = $event.touches[0].screenY;
+ $scope.mouseX = $event.touches[0].screenX;
+ $scope.mouseY = $event.touches[0].screenY;
+ $scope.updateScaledXY();
+ }
+
+ $scope.first_controller.handle_message('TouchMove', $event);
+ $scope.onTouchMoveEvent = $event;
+ $event.preventDefault();
+ };
+
+ // Button Event Handlers
+ //
+
+
+ $scope.onDeployButton = function () {
+ $scope.send_control_message(new messages.Deploy($scope.client_id));
+ };
+
+ $scope.onDestroyButton = function () {
+ $scope.resetStatus();
+ $scope.send_control_message(new messages.Destroy($scope.client_id));
+ };
+
+ $scope.onRecordButton = function () {
+ $scope.recording = ! $scope.recording;
+ if ($scope.recording) {
+ $scope.send_control_message(new messages.MultipleMessage($scope.client_id,
+ [new messages.StartRecording($scope.client_id),
+ new messages.ViewPort($scope.client_id,
+ $scope.current_scale,
+ $scope.panX,
+ $scope.panY)]));
+ } else {
+ $scope.send_control_message(new messages.StopRecording($scope.client_id));
+ }
+ };
+
+ $scope.onExportButton = function () {
+ $scope.cursor.hidden = true;
+ $scope.debug.hidden = true;
+ $scope.hide_buttons = true;
+ setTimeout(function () {
+ svg_crowbar.svg_crowbar();
+ $scope.cursor.hidden = false;
+ $scope.hide_buttons = false;
+ $scope.$apply();
+ }, 1000);
+ };
+
+ $scope.onLayoutButton = function () {
+ $scope.send_control_message(new messages.Layout($scope.client_id));
+ };
+
+ $scope.onDiscoverButton = function () {
+ var xhr = new XMLHttpRequest();
+ xhr.open("POST", "http://" + window.location.host + "/api/v1/job_templates/7/launch/", true);
+ xhr.onload = function () {
+ console.log(xhr.readyState);
+ };
+ xhr.onerror = function () {
+ console.error(xhr.statusText);
+ };
+ xhr.send();
+ };
+
+ $scope.onConfigureButton = function () {
+ var xhr = new XMLHttpRequest();
+ xhr.open("POST", "http://" + window.location.host + "/api/v1/job_templates/9/launch/", true);
+ xhr.onload = function () {
+ console.log(xhr.readyState);
+ };
+ xhr.onerror = function () {
+ console.error(xhr.statusText);
+ };
+ xhr.send();
+ };
+
+ $scope.onTogglePhysical = function () {
+ $scope.hide_links = false;
+ };
+
+ $scope.onUnTogglePhysical = function () {
+ $scope.hide_links = true;
+ };
+
+ $scope.onToggleGroup = function () {
+ $scope.hide_groups = false;
+ };
+
+ $scope.onUnToggleGroup = function () {
+ $scope.hide_groups = true;
+ $scope.group_controller.changeState(group.Ready);
+ };
+
+ // Buttons
+
+ $scope.buttons = [
+ new models.Button("BUTTON1", 10, 10, 90, 30, util.noop),
+ new models.Button("BUTTON1", 110, 10, 90, 30, util.noop),
+ ];
+
+ var LAYERS_X = 160;
+
+ $scope.layers = [
+ new models.ToggleButton("TOGGLEBUTTON1", $scope.graph.width - LAYERS_X, 10, 150, 30, util.noop, util.noop, true),
+ new models.ToggleButton("TOGGLEBUTTON2", $scope.graph.width - LAYERS_X, 50, 150, 30, util.noop, util.noop, true),
+ ];
+
+ var STENCIL_X = 10;
+ var STENCIL_Y = 100;
+ var STENCIL_SPACING = 40;
+
+ $scope.stencils = [
+ new models.Button("BUTTON3", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 0, 90, 30, util.noop),
+ new models.Button("BUTTON4", STENCIL_X, STENCIL_Y + STENCIL_SPACING * 1, 90, 30, util.noop),
+ ];
+
+ $scope.all_buttons = [];
+ $scope.all_buttons.extend($scope.buttons);
+ $scope.all_buttons.extend($scope.layers);
+ $scope.all_buttons.extend($scope.stencils);
+
+ $scope.onTaskStatus = function(data) {
+ var i = 0;
+ var j = 0;
+ var found = false;
+ for (i = 0; i < $scope.devices.length; i++) {
+ if ($scope.devices[i].name === data.device_name) {
+ found = false;
+ for (j = 0; j < $scope.devices[i].tasks.length; j++) {
+ if ($scope.devices[i].tasks[j].id === data.task_id) {
+ found = true;
+ }
+ }
+ if (!found) {
+ $scope.devices[i].tasks.push(new models.Task(data.task_id,
+ data.device_name));
+ }
+ for (j = 0; j < $scope.devices[i].tasks.length; j++) {
+ if ($scope.devices[i].tasks[j].id === data.task_id) {
+ if (data.status !== null) {
+ $scope.devices[i].tasks[j].status = data.status === "pass";
+ }
+ if (data.working !== null) {
+ $scope.devices[i].tasks[j].working = data.working;
+ }
+ }
+ }
+ }
+ }
+ };
+
+ $scope.onDeviceStatus = function(data) {
+ var i = 0;
+ for (i = 0; i < $scope.devices.length; i++) {
+ if ($scope.devices[i].name === data.name) {
+ if (data.status !== null) {
+ $scope.devices[i].status = data.status === "pass";
+ }
+ if (data.working !== null) {
+ $scope.devices[i].working = data.working;
+ }
+ }
+ }
+ };
+
+ $scope.onFacts = function(data) {
+ var i = 0;
+ var j = 0;
+ var k = 0;
+ var device = null;
+ var keys = null;
+ var peers = null;
+ var ptm = null;
+ var intf = null;
+ for (i = 0; i < $scope.devices.length; i++) {
+ device = $scope.devices[i];
+ if (device.name === data.key) {
+
+ //Check PTM
+ if (data.value.ansible_local !== undefined &&
+ data.value.ansible_local.ptm !== undefined) {
+ keys = Object.keys(data.value.ansible_local.ptm);
+ for (j = 0; j < keys.length; j++) {
+ ptm = data.value.ansible_local.ptm[keys[j]];
+ for (k = 0; k < device.interfaces.length; k++) {
+ intf = device.interfaces[k];
+ if (intf.name === ptm.port) {
+ intf.link.status = ptm['cbl status'] === 'pass';
+ }
+ }
+ }
+ }
+
+ //Check LLDP
+ if (data.value.ansible_net_neighbors !== undefined) {
+ keys = Object.keys(data.value.ansible_net_neighbors);
+ for (j = 0; j < keys.length; j++) {
+ peers = data.value.ansible_net_neighbors[keys[j]];
+ for (k = 0; k < peers.length; k++) {
+ intf = $scope.getDeviceInterface(device.name, keys[j]);
+ if (intf !== null && intf.link !== null) {
+ if (intf.link.to_interface === intf) {
+ intf.link.status = ($scope.getDeviceInterface(peers[k].host, peers[k].port) === intf.link.from_interface);
+ } else {
+ intf.link.status = ($scope.getDeviceInterface(peers[k].host, peers[k].port) === intf.link.to_interface);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ $scope.$apply();
+ };
+
+ $scope.getDevice = function(name) {
+
+ var i = 0;
+ for (i = 0; i < $scope.devices.length; i++) {
+ if ($scope.devices[i].name === name) {
+ return $scope.devices[i];
+ }
+ }
+
+ return null;
+ };
+
+ $scope.getDeviceInterface = function(device_name, interface_name) {
+
+ var i = 0;
+ var k = 0;
+ for (i = 0; i < $scope.devices.length; i++) {
+ if ($scope.devices[i].name === device_name) {
+ for (k = 0; k < $scope.devices[i].interfaces.length; k++) {
+ if ($scope.devices[i].interfaces[k].name === interface_name) {
+ return $scope.devices[i].interfaces[k];
+ }
+ }
+ }
+ }
+ return null;
+ };
+
+ $scope.onDeviceCreate = function(data) {
+ $scope.create_device(data);
+ };
+
+ $scope.create_device = function(data) {
+ var device = new models.Device(data.id,
+ data.name,
+ data.x,
+ data.y,
+ data.type);
+ $scope.devices.push(device);
+ };
+
+ $scope.onGroupCreate = function(data) {
+ $scope.create_group(data);
+ };
+
+ $scope.create_group = function(data) {
+ var group = new models.Group(data.id,
+ data.name,
+ data.type,
+ data.x1,
+ data.y1,
+ data.x2,
+ data.y2,
+ false);
+ $scope.groups.push(group);
+ };
+
+ $scope.forDevice = function(device_id, data, fn) {
+ var i = 0;
+ for (i = 0; i < $scope.devices.length; i++) {
+ if ($scope.devices[i].id === device_id) {
+ fn($scope.devices[i], data);
+ break;
+ }
+ }
+ };
+
+ $scope.forLink = function(link_id, data, fn) {
+ var i = 0;
+ for (i = 0; i < $scope.links.length; i++) {
+ if ($scope.links[i].id === link_id) {
+ fn($scope.links[i], data);
+ break;
+ }
+ }
+ };
+
+ $scope.forDeviceInterface = function(device_id, interface_id, data, fn) {
+ var i = 0;
+ var j = 0;
+ for (i = 0; i < $scope.devices.length; i++) {
+ if ($scope.devices[i].id === device_id) {
+ for (j = 0; j < $scope.devices[i].interfaces.length; j++) {
+ if ($scope.devices[i].interfaces[j].id === interface_id) {
+ fn($scope.devices[i].interfaces[j], data);
+ break;
+ }
+ }
+ }
+ }
+ };
+
+ $scope.forGroup = function(group_id, data, fn) {
+ var i = 0;
+ for (i = 0; i < $scope.groups.length; i++) {
+ if ($scope.groups[i].id === group_id) {
+ fn($scope.groups[i], data);
+ break;
+ }
+ }
+ };
+
+ $scope.onDeviceLabelEdit = function(data) {
+ $scope.edit_device_label(data);
+ };
+
+ $scope.edit_device_label = function(data) {
+ $scope.forDevice(data.id, data, function(device, data) {
+ device.name = data.name;
+ });
+ };
+
+ $scope.onInterfaceCreate = function(data) {
+ $scope.create_interface(data);
+ };
+
+ $scope.create_interface = function(data) {
+ var i = 0;
+ var new_interface = new models.Interface(data.id, data.name);
+ for (i = 0; i < $scope.devices.length; i++){
+ if ($scope.devices[i].id === data.device_id) {
+ $scope.devices[i].interface_seq = util.natural_numbers(data.id);
+ new_interface.device = $scope.devices[i];
+ $scope.devices[i].interfaces.push(new_interface);
+ }
+ }
+ };
+
+ $scope.onInterfaceLabelEdit = function(data) {
+ $scope.edit_interface_label(data);
+ };
+
+ $scope.edit_interface_label = function(data) {
+ $scope.forDeviceInterface(data.device_id, data.id, data, function(intf, data) {
+ intf.name = data.name;
+ });
+ };
+
+ $scope.onLinkCreate = function(data) {
+ $scope.create_link(data);
+ };
+
+ $scope.create_link = function(data) {
+ var i = 0;
+ var j = 0;
+ var new_link = new models.Link(null, null, null, null);
+ new_link.id = data.id;
+ $scope.link_id_seq = util.natural_numbers(data.id);
+ for (i = 0; i < $scope.devices.length; i++){
+ if ($scope.devices[i].id === data.from_device_id) {
+ new_link.from_device = $scope.devices[i];
+ for (j = 0; j < $scope.devices[i].interfaces.length; j++){
+ if ($scope.devices[i].interfaces[j].id === data.from_interface_id) {
+ new_link.from_interface = $scope.devices[i].interfaces[j];
+ $scope.devices[i].interfaces[j].link = new_link;
+ }
+ }
+ }
+ }
+ for (i = 0; i < $scope.devices.length; i++){
+ if ($scope.devices[i].id === data.to_device_id) {
+ new_link.to_device = $scope.devices[i];
+ for (j = 0; j < $scope.devices[i].interfaces.length; j++){
+ if ($scope.devices[i].interfaces[j].id === data.to_interface_id) {
+ new_link.to_interface = $scope.devices[i].interfaces[j];
+ $scope.devices[i].interfaces[j].link = new_link;
+ }
+ }
+ }
+ }
+ if (new_link.from_interface !== null && new_link.to_interface !== null) {
+ new_link.from_interface.dot();
+ new_link.to_interface.dot();
+ }
+ if (new_link.from_device !== null && new_link.to_device !== null) {
+ $scope.links.push(new_link);
+ }
+ };
+
+ $scope.onLinkDestroy = function(data) {
+ $scope.destroy_link(data);
+ };
+
+ $scope.destroy_link = function(data) {
+ var i = 0;
+ var link = null;
+ var index = -1;
+ for (i = 0; i < $scope.links.length; i++) {
+ link = $scope.links[i];
+ if (link.id === data.id &&
+ link.from_device.id === data.from_device_id &&
+ link.to_device.id === data.to_device_id &&
+ link.to_interface.id === data.to_interface_id &&
+ link.from_interface.id === data.from_interface_id) {
+ link.from_interface.link = null;
+ link.to_interface.link = null;
+ index = $scope.links.indexOf(link);
+ $scope.links.splice(index, 1);
+ }
+ }
+ };
+
+ $scope.onLinkLabelEdit = function(data) {
+ $scope.edit_link_label(data);
+ };
+
+ $scope.edit_link_label = function(data) {
+ $scope.forLink(data.id, data, function(link, data) {
+ link.name = data.name;
+ });
+ };
+
+ $scope.onDeviceMove = function(data) {
+ $scope.move_device(data);
+ };
+
+ $scope.move_device = function(data) {
+ var i = 0;
+ var j = 0;
+ for (i = 0; i < $scope.devices.length; i++) {
+ if ($scope.devices[i].id === data.id) {
+ $scope.devices[i].x = data.x;
+ $scope.devices[i].y = data.y;
+ for (j = 0; j < $scope.devices[i].interfaces.length; j ++) {
+ $scope.devices[i].interfaces[j].dot();
+ if ($scope.devices[i].interfaces[j].link !== null) {
+ $scope.devices[i].interfaces[j].link.to_interface.dot();
+ $scope.devices[i].interfaces[j].link.from_interface.dot();
+ }
+ }
+ break;
+ }
+ }
+ };
+
+ $scope.onDeviceDestroy = function(data) {
+ $scope.destroy_device(data);
+ };
+
+ $scope.destroy_device = function(data) {
+
+ // Delete the device and any links connecting to the device.
+ var i = 0;
+ var j = 0;
+ var dindex = -1;
+ var lindex = -1;
+ var devices = $scope.devices.slice();
+ var all_links = $scope.links.slice();
+ for (i = 0; i < devices.length; i++) {
+ if (devices[i].id === data.id) {
+ dindex = $scope.devices.indexOf(devices[i]);
+ if (dindex !== -1) {
+ $scope.devices.splice(dindex, 1);
+ }
+ lindex = -1;
+ for (j = 0; j < all_links.length; j++) {
+ if (all_links[j].to_device === devices[i] ||
+ all_links[j].from_device === devices[i]) {
+ lindex = $scope.links.indexOf(all_links[j]);
+ if (lindex !== -1) {
+ $scope.links.splice(lindex, 1);
+ }
+ }
+ }
+ }
+ }
+ };
+
+
+ $scope.onGroupLabelEdit = function(data) {
+ $scope.edit_group_label(data);
+ };
+
+ $scope.edit_group_label = function(data) {
+ $scope.forGroup(data.id, data, function(group, data) {
+ group.name = data.name;
+ });
+ };
+
+ $scope.redo = function(type_data) {
+ var type = type_data[0];
+ var data = type_data[1];
+
+ if (type === "DeviceMove") {
+ $scope.move_device(data);
+ }
+
+ if (type === "DeviceCreate") {
+ $scope.create_device(data);
+ }
+
+ if (type === "DeviceDestroy") {
+ $scope.destroy_device(data);
+ }
+
+ if (type === "DeviceLabelEdit") {
+ $scope.edit_device_label(data);
+ }
+
+ if (type === "LinkCreate") {
+ $scope.create_link(data);
+ }
+
+ if (type === "LinkDestroy") {
+ $scope.destroy_link(data);
+ }
+ };
+
+
+ $scope.undo = function(type_data) {
+ var type = type_data[0];
+ var data = type_data[1];
+ var inverted_data;
+
+ if (type === "DeviceMove") {
+ inverted_data = angular.copy(data);
+ inverted_data.x = data.previous_x;
+ inverted_data.y = data.previous_y;
+ $scope.move_device(inverted_data);
+ }
+
+ if (type === "DeviceCreate") {
+ $scope.destroy_device(data);
+ }
+
+ if (type === "DeviceDestroy") {
+ inverted_data = new messages.DeviceCreate(data.sender,
+ data.id,
+ data.previous_x,
+ data.previous_y,
+ data.previous_name,
+ data.previous_type);
+ $scope.create_device(inverted_data);
+ }
+
+ if (type === "DeviceLabelEdit") {
+ inverted_data = angular.copy(data);
+ inverted_data.name = data.previous_name;
+ $scope.edit_device_label(inverted_data);
+ }
+
+ if (type === "LinkCreate") {
+ $scope.destroy_link(data);
+ }
+
+ if (type === "LinkDestroy") {
+ $scope.create_link(data);
+ }
+ };
+
+ $scope.onClientId = function(data) {
+ $scope.client_id = data;
+ };
+
+ $scope.onTopology = function(data) {
+ $scope.topology_id = data.topology_id;
+ $scope.panX = data.panX;
+ $scope.panY = data.panX;
+ $scope.current_scale = data.scale;
+ $scope.link_id_seq = util.natural_numbers(data.link_id_seq);
+ $scope.group_id_seq = util.natural_numbers(data.group_id_seq);
+ $scope.device_id_seq = util.natural_numbers(data.device_id_seq);
+ $location.search({topology_id: data.topology_id});
+ };
+
+ $scope.onDeviceSelected = function(data) {
+ var i = 0;
+ for (i = 0; i < $scope.devices.length; i++) {
+ if ($scope.devices[i].id === data.id) {
+ $scope.devices[i].remote_selected = true;
+ }
+ }
+ };
+
+ $scope.onDeviceUnSelected = function(data) {
+ var i = 0;
+ for (i = 0; i < $scope.devices.length; i++) {
+ if ($scope.devices[i].id === data.id) {
+ $scope.devices[i].remote_selected = false;
+ }
+ }
+ };
+
+ $scope.onHistory = function (data) {
+
+ $scope.history = [];
+ var i = 0;
+ for (i = 0; i < data.length; i++) {
+ $scope.history.push(data[i]);
+ }
+ };
+
+ $scope.onSnapshot = function (data) {
+
+ //Erase the existing state
+ $scope.devices = [];
+ $scope.links = [];
+
+ var device_map = {};
+ var device_interface_map = {};
+ var i = 0;
+ var j = 0;
+ var device = null;
+ var intf = null;
+ var new_device = null;
+ var new_intf = null;
+ var max_device_id = null;
+ var max_link_id = null;
+ var max_group_id = null;
+ var min_x = null;
+ var min_y = null;
+ var max_x = null;
+ var max_y = null;
+ var new_link = null;
+ var new_group = null;
+
+ //Build the devices
+ for (i = 0; i < data.devices.length; i++) {
+ device = data.devices[i];
+ if (max_device_id === null || device.id > max_device_id) {
+ max_device_id = device.id;
+ }
+ if (min_x === null || device.x < min_x) {
+ min_x = device.x;
+ }
+ if (min_y === null || device.y < min_y) {
+ min_y = device.y;
+ }
+ if (max_x === null || device.x > max_x) {
+ max_x = device.x;
+ }
+ if (max_y === null || device.y > max_y) {
+ max_y = device.y;
+ }
+ new_device = new models.Device(device.id,
+ device.name,
+ device.x,
+ device.y,
+ device.type);
+ new_device.interface_seq = util.natural_numbers(device.interface_id_seq);
+ $scope.devices.push(new_device);
+ device_map[device.id] = new_device;
+ device_interface_map[device.id] = {};
+ for (j = 0; j < device.interfaces.length; j++) {
+ intf = device.interfaces[j];
+ new_intf = (new models.Interface(intf.id,
+ intf.name));
+ new_intf.device = new_device;
+ device_interface_map[device.id][intf.id] = new_intf;
+ new_device.interfaces.push(new_intf);
+ }
+ }
+
+ //Build the links
+ var link = null;
+ for (i = 0; i < data.links.length; i++) {
+ link = data.links[i];
+ if (max_link_id === null || link.id > max_link_id) {
+ max_link_id = link.id;
+ }
+ new_link = new models.Link(link.id,
+ device_map[link.from_device_id],
+ device_map[link.to_device_id],
+ device_interface_map[link.from_device_id][link.from_interface_id],
+ device_interface_map[link.to_device_id][link.to_interface_id]);
+ new_link.name = link.name;
+ $scope.links.push(new_link);
+ device_interface_map[link.from_device_id][link.from_interface_id].link = new_link;
+ device_interface_map[link.to_device_id][link.to_interface_id].link = new_link;
+ }
+
+ //Build the groups
+ var group = null;
+ for (i = 0; i < data.groups.length; i++) {
+ group = data.groups[i];
+ if (max_group_id === null || group.id > max_group_id) {
+ max_group_id = group.id;
+ }
+ new_group = new models.Group(group.id,
+ group.name,
+ group.type,
+ group.x1,
+ group.y1,
+ group.x2,
+ group.y2,
+ false);
+ if (group.members !== undefined) {
+ for (j=0; j < group.members.length; j++) {
+ new_group.devices.push(device_map[group.members[j]]);
+ }
+ }
+ $scope.groups.push(new_group);
+ }
+
+ var diff_x;
+ var diff_y;
+
+ // Calculate the new scale to show the entire diagram
+ if (min_x !== null && min_y !== null && max_x !== null && max_y !== null) {
+ diff_x = max_x - min_x;
+ diff_y = max_y - min_y;
+
+ $scope.current_scale = Math.min(2, Math.max(0.10, Math.min((window.innerWidth-200)/diff_x, (window.innerHeight-300)/diff_y)));
+ $scope.updateScaledXY();
+ $scope.updatePanAndScale();
+ }
+ // Calculate the new panX and panY to show the entire diagram
+ if (min_x !== null && min_y !== null) {
+ diff_x = max_x - min_x;
+ diff_y = max_y - min_y;
+ $scope.panX = $scope.current_scale * (-min_x - diff_x/2) + window.innerWidth/2;
+ $scope.panY = $scope.current_scale * (-min_y - diff_y/2) + window.innerHeight/2;
+ $scope.updateScaledXY();
+ $scope.updatePanAndScale();
+ }
+
+ //Update the device_id_seq to be greater than all device ids to prevent duplicate ids.
+ if (max_device_id !== null) {
+ $scope.device_id_seq = util.natural_numbers(max_device_id);
+ }
+ //
+ //Update the link_id_seq to be greater than all link ids to prevent duplicate ids.
+ if (max_link_id !== null) {
+ $scope.link_id_seq = util.natural_numbers(max_link_id);
+ }
+ //Update the group_id_seq to be greater than all group ids to prevent duplicate ids.
+ if (max_group_id !== null) {
+ $scope.group_id_seq = util.natural_numbers(max_group_id);
+ }
+
+ $scope.updateInterfaceDots();
+ };
+
+ $scope.updateInterfaceDots = function() {
+ var i = 0;
+ var j = 0;
+ var devices = $scope.devices;
+ for (i = devices.length - 1; i >= 0; i--) {
+ for (j = devices[i].interfaces.length - 1; j >= 0; j--) {
+ devices[i].interfaces[j].dot();
+ }
+ }
+ };
+
+ $scope.resetStatus = function() {
+ var i = 0;
+ var j = 0;
+ var devices = $scope.devices;
+ var links = $scope.links;
+ for (i = 0; i < devices.length; i++) {
+ devices[i].status = null;
+ devices[i].working = false;
+ devices[i].tasks = [];
+ for (j = devices[i].interfaces.length - 1; j >= 0; j--) {
+ devices[i].interfaces[j].status = null;
+ }
+ }
+ for (i = 0; i < links.length; i++) {
+ links[i].status = null;
+ }
+ };
+
+ $scope.send_coverage = function () {
+ if (typeof(window.__coverage__) !== "undefined" && window.__coverage__ !== null) {
+ $scope.send_control_message(new messages.Coverage($scope.client_id, window.__coverage__));
+ }
+ };
+
+
+ $scope.control_socket.onmessage = function(message) {
+ $scope.first_controller.handle_message('Message', message);
+ $scope.$apply();
+ };
+
+ $scope.control_socket.onopen = function() {
+ //Ignore
+ };
+
+ // Call onopen directly if $scope.control_socket is already open
+ if ($scope.control_socket.readyState === WebSocket.OPEN) {
+ $scope.control_socket.onopen();
+ }
+
+ $scope.send_control_message = function (message) {
+ var i = 0;
+ message.sender = $scope.client_id;
+ message.message_id = $scope.message_id_seq();
+ if (message.constructor.name === "MultipleMessage") {
+ for (i=0; i < message.messages.length; i++) {
+ message.messages[i].message_id = $scope.message_id_seq();
+ }
+ }
+ //var data = messages.serialize(message);
+ //console.log(data);
+ };
+
+
+ // End web socket
+ //
+
+ angular.element($window).bind('resize', function(){
+
+ $scope.graph.width = $window.innerWidth;
+ $scope.graph.right_column = $window.innerWidth - 300;
+ $scope.graph.height = $window.innerHeight;
+
+ $scope.update_size();
+
+ // manuall $digest required as resize event
+ // is outside of angular
+ $scope.$digest();
+ });
+
+ //60fps ~ 17ms delay
+ setInterval( function () {
+ $scope.frame = Math.floor(window.performance.now());
+ $scope.$apply();
+ }, 17);
+
+ console.log("Network Widgets started");
+
+ $scope.$on('$destroy', function () {
+ console.log("Network Widgets stopping");
+ $document.unbind('keydown', $scope.onKeyDown);
+ });
+
+ $scope.update_size = function () {
+ var i = 0;
+ for (i = 0; i < $scope.layers.length; i++) {
+ $scope.layers[i].x = $scope.graph.width - 140;
+ }
+ };
+
+ for (i =0; i < $scope.initial_messages.length; i++) {
+ console.log(['Inital message', $scope.initial_messages[i]]);
+ $scope.first_controller.handle_message($scope.initial_messages[i][0], $scope.initial_messages[i][1]);
+ }
+
+ $scope.updateScaledXY();
+ $scope.updatePanAndScale();
+
+ for (i=0; i < $scope.groups.length; i++) {
+ $scope.groups[i].update_membership($scope.devices, $scope.groups);
+ }
+
+ $scope.update_offsets = function () {
+
+ var i = 0;
+ var streams = $scope.streams;
+ var map = new Map();
+ var stream = null;
+ var key = null;
+ for (i = 0; i < streams.length; i++) {
+ stream = streams[i];
+ key = "" + stream.from_device.id + "_" + stream.to_device.id;
+ map.set(key, 0);
+ }
+ for (i = 0; i < streams.length; i++) {
+ stream = streams[i];
+ key = "" + stream.from_device.id + "_" + stream.to_device.id;
+ stream.offset = map.get(key);
+ map.set(key, stream.offset + 1);
+ }
+ };
+};
+
+exports.NetworkWidgetsController = NetworkWidgetsController;
+console.log("Network Widgets loaded");
diff --git a/awx/network_ui/static/network_ui/src/network.widgets.directive.js b/awx/network_ui/static/network_ui/src/network.widgets.directive.js
new file mode 100644
index 0000000000..5fda827cd1
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/network.widgets.directive.js
@@ -0,0 +1,5 @@
+
+function awxNetworkWidgets () {
+ return { restrict: 'E', templateUrl: '/static/network_ui/widgets/network_widgets.html' };
+}
+exports.awxNetworkWidgets = awxNetworkWidgets;
diff --git a/awx/network_ui/static/network_ui/src/process.directive.js b/awx/network_ui/static/network_ui/src/process.directive.js
new file mode 100644
index 0000000000..6738c21a96
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/process.directive.js
@@ -0,0 +1,5 @@
+
+function process () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/process.html' };
+}
+exports.process = process;
diff --git a/awx/network_ui/static/network_ui/src/rack.fsm.js b/awx/network_ui/static/network_ui/src/rack.fsm.js
new file mode 100644
index 0000000000..948410b8de
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/rack.fsm.js
@@ -0,0 +1,487 @@
+var inherits = require('inherits');
+var fsm = require('./fsm.js');
+var models = require('./models.js');
+var messages = require('./messages.js');
+
+function _State () {
+}
+inherits(_State, fsm._State);
+
+
+function _Ready () {
+ this.name = 'Ready';
+}
+inherits(_Ready, _State);
+var Ready = new _Ready();
+exports.Ready = Ready;
+
+function _Disable () {
+ this.name = 'Disable';
+}
+inherits(_Disable, _State);
+var Disable = new _Disable();
+exports.Disable = Disable;
+
+function _Start () {
+ this.name = 'Start';
+}
+inherits(_Start, _State);
+var Start = new _Start();
+exports.Start = Start;
+
+
+function _Selected1 () {
+ this.name = 'Selected1';
+}
+inherits(_Selected1, _State);
+var Selected1 = new _Selected1();
+exports.Selected1 = Selected1;
+
+function _Selected2 () {
+ this.name = 'Selected2';
+}
+inherits(_Selected2, _State);
+var Selected2 = new _Selected2();
+exports.Selected2 = Selected2;
+
+function _Selected3 () {
+ this.name = 'Selected3';
+}
+inherits(_Selected3, _State);
+var Selected3 = new _Selected3();
+exports.Selected3 = Selected3;
+
+function _EditLabel () {
+ this.name = 'EditLabel';
+}
+inherits(_EditLabel, _State);
+var EditLabel = new _EditLabel();
+exports.EditLabel = EditLabel;
+
+
+function _Move () {
+ this.name = 'Move';
+}
+inherits(_Move, _State);
+var Move = new _Move();
+exports.Move = Move;
+
+
+
+
+_Start.prototype.start = function (controller) {
+
+ controller.changeState(Ready);
+
+};
+_Start.prototype.start.transitions = ['Ready'];
+
+
+_Ready.prototype.onPasteRack = function (controller, msg_type, message) {
+
+ var scope = controller.scope;
+ var device = null;
+ var intf = null;
+ var process = null;
+ var link = null;
+ var i = 0;
+ var j = 0;
+ var top_left_x, top_left_y;
+ var device_map = {};
+ scope.hide_groups = false;
+
+ scope.pressedX = scope.mouseX;
+ scope.pressedY = scope.mouseY;
+ scope.pressedScaledX = scope.scaledX;
+ scope.pressedScaledY = scope.scaledY;
+ top_left_x = scope.scaledX - message.group.x2/2;
+ top_left_y = scope.scaledY - message.group.y2/2;
+
+ var group = new models.Group(controller.scope.group_id_seq(),
+ message.group.name,
+ message.group.type,
+ top_left_x,
+ top_left_y,
+ top_left_x + message.group.x2,
+ top_left_y + message.group.y2,
+ false);
+
+ scope.send_control_message(new messages.GroupCreate(scope.client_id,
+ group.id,
+ group.x1,
+ group.y1,
+ group.x2,
+ group.y2,
+ group.name,
+ group.type));
+
+ scope.groups.push(group);
+
+ for(i=0; i= 48 && $event.keyCode <=90) { //Alphanumeric
+ item.name += $event.key;
+ } else if ($event.keyCode >= 186 && $event.keyCode <=222) { //Punctuation
+ item.name += $event.key;
+ } else if ($event.keyCode === 13) { //Enter
+ controller.changeState(Selected2);
+ } else if ($event.keyCode === 32) { //Space
+ item.name += " ";
+ } else {
+ console.log($event.keyCode);
+ }
+ controller.scope.send_control_message(new messages.GroupLabelEdit(controller.scope.client_id,
+ item.id,
+ item.name,
+ previous_name));
+};
+_EditLabel.prototype.onKeyDown.transitions = ['Selected2'];
+
+
+_Ready.prototype.onMouseDown = function (controller, msg_type, $event) {
+
+ controller.scope.pressedScaledX = controller.scope.scaledX;
+ controller.scope.pressedScaledY = controller.scope.scaledY;
+
+ var groups = controller.scope.groups;
+ var i = 0;
+ var selected = false;
+ controller.scope.clear_selections();
+
+ for (i = 0; i < groups.length; i++) {
+ if (groups[i].type !== "rack") {
+ continue;
+ }
+ if (groups[i].is_icon_selected(controller.scope.scaledX, controller.scope.scaledY)) {
+ groups[i].selected = true;
+ selected = true;
+ controller.scope.selected_groups.push(groups[i]);
+ }
+ }
+
+ if (selected) {
+ controller.changeState(Selected1);
+ } else {
+ controller.next_controller.handle_message(msg_type, $event);
+ }
+};
+_Ready.prototype.onMouseDown.transitions = ['Selected1'];
+
+_Move.prototype.start = function (controller) {
+
+ var groups = controller.scope.selected_groups;
+
+ var i = 0;
+ for (i = 0; i < groups.length; i++) {
+ groups[i].moving = true;
+ }
+};
+
+_Move.prototype.end = function (controller) {
+
+ var groups = controller.scope.selected_groups;
+
+ var i = 0;
+ var j = 0;
+ for (i = 0; i < groups.length; i++) {
+ for(j = 0; j < groups[i].devices.length; j++) {
+ groups[i].devices[j].selected = false;
+ }
+ }
+
+ for (i = 0; i < groups.length; i++) {
+ groups[i].moving = false;
+ }
+};
+
+_Move.prototype.onMouseUp = function (controller) {
+
+ controller.changeState(Selected2);
+
+};
+_Move.prototype.onMouseUp.transitions = ['Selected2'];
+
+
+_Move.prototype.onMouseMove = function (controller) {
+
+ var groups = controller.scope.selected_groups;
+ var devices = null;
+
+ var diffX = controller.scope.scaledX - controller.scope.pressedScaledX;
+ var diffY = controller.scope.scaledY - controller.scope.pressedScaledY;
+ var i = 0;
+ var j = 0;
+ var k = 0;
+ var previous_x1, previous_y1, previous_x2, previous_y2, previous_x, previous_y;
+ for (i = 0; i < groups.length; i++) {
+ previous_x1 = groups[i].x1;
+ previous_y1 = groups[i].y1;
+ previous_x2 = groups[i].x2;
+ previous_y2 = groups[i].y2;
+ groups[i].x1 = groups[i].x1 + diffX;
+ groups[i].y1 = groups[i].y1 + diffY;
+ groups[i].x2 = groups[i].x2 + diffX;
+ groups[i].y2 = groups[i].y2 + diffY;
+
+ controller.scope.send_control_message(new messages.GroupMove(controller.scope.client_id,
+ groups[i].id,
+ groups[i].x1,
+ groups[i].y1,
+ groups[i].x2,
+ groups[i].y2,
+ previous_x1,
+ previous_y1,
+ previous_x2,
+ previous_y2));
+
+
+ devices = groups[i].devices;
+ for (j = 0; j < devices.length; j++) {
+ previous_x = devices[j].x;
+ previous_y = devices[j].y;
+ devices[j].x = devices[j].x + diffX;
+ devices[j].y = devices[j].y + diffY;
+ for (k = 0; k < devices[j].interfaces.length; k++) {
+ devices[j].interfaces[k].dot();
+ if (devices[j].interfaces[k].link !== null) {
+ devices[j].interfaces[k].link.to_interface.dot();
+ devices[j].interfaces[k].link.from_interface.dot();
+ }
+ }
+ controller.scope.send_control_message(new messages.DeviceMove(controller.scope.client_id,
+ devices[j].id,
+ devices[j].x,
+ devices[j].y,
+ previous_x,
+ previous_y));
+ }
+ }
+ controller.scope.pressedScaledX = controller.scope.scaledX;
+ controller.scope.pressedScaledY = controller.scope.scaledY;
+
+};
+
+_Move.prototype.onTouchMove = _Move.prototype.onMouseMove;
diff --git a/awx/network_ui/static/network_ui/src/rack.icon.directive.js b/awx/network_ui/static/network_ui/src/rack.icon.directive.js
new file mode 100644
index 0000000000..1fcca0992c
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/rack.icon.directive.js
@@ -0,0 +1,5 @@
+
+function rackIcon () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/rack_icon.html' };
+}
+exports.rackIcon = rackIcon;
diff --git a/awx/network_ui/static/network_ui/src/site.directive.js b/awx/network_ui/static/network_ui/src/site.directive.js
new file mode 100644
index 0000000000..b910d0ff92
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/site.directive.js
@@ -0,0 +1,5 @@
+
+function site () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/site.html' };
+}
+exports.site = site;
diff --git a/awx/network_ui/static/network_ui/src/site.fsm.js b/awx/network_ui/static/network_ui/src/site.fsm.js
new file mode 100644
index 0000000000..59d407fc28
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/site.fsm.js
@@ -0,0 +1,567 @@
+var inherits = require('inherits');
+var fsm = require('./fsm.js');
+var models = require('./models.js');
+var messages = require('./messages.js');
+
+function _State () {
+}
+inherits(_State, fsm._State);
+
+
+function _Ready () {
+ this.name = 'Ready';
+}
+inherits(_Ready, _State);
+var Ready = new _Ready();
+exports.Ready = Ready;
+
+function _Disable () {
+ this.name = 'Disable';
+}
+inherits(_Disable, _State);
+var Disable = new _Disable();
+exports.Disable = Disable;
+
+function _Start () {
+ this.name = 'Start';
+}
+inherits(_Start, _State);
+var Start = new _Start();
+exports.Start = Start;
+
+
+function _Selected1 () {
+ this.name = 'Selected1';
+}
+inherits(_Selected1, _State);
+var Selected1 = new _Selected1();
+exports.Selected1 = Selected1;
+
+function _Selected2 () {
+ this.name = 'Selected2';
+}
+inherits(_Selected2, _State);
+var Selected2 = new _Selected2();
+exports.Selected2 = Selected2;
+
+function _Selected3 () {
+ this.name = 'Selected3';
+}
+inherits(_Selected3, _State);
+var Selected3 = new _Selected3();
+exports.Selected3 = Selected3;
+
+function _EditLabel () {
+ this.name = 'EditLabel';
+}
+inherits(_EditLabel, _State);
+var EditLabel = new _EditLabel();
+exports.EditLabel = EditLabel;
+
+
+function _Move () {
+ this.name = 'Move';
+}
+inherits(_Move, _State);
+var Move = new _Move();
+exports.Move = Move;
+
+
+
+
+_Start.prototype.start = function (controller) {
+
+ controller.changeState(Ready);
+
+};
+_Start.prototype.start.transitions = ['Ready'];
+
+
+_Ready.prototype.onPasteSite = function (controller, msg_type, message) {
+
+ var scope = controller.scope;
+ var device = null;
+ var intf = null;
+ var process = null;
+ var link = null;
+ var stream = null;
+ var i = 0;
+ var j = 0;
+ var top_left_x, top_left_y;
+ var device_map = {};
+ var inner_group = null;
+ scope.hide_groups = false;
+
+ scope.pressedX = scope.mouseX;
+ scope.pressedY = scope.mouseY;
+ scope.pressedScaledX = scope.scaledX;
+ scope.pressedScaledY = scope.scaledY;
+ top_left_x = scope.scaledX - message.group.x2/2;
+ top_left_y = scope.scaledY - message.group.y2/2;
+
+ var group = new models.Group(controller.scope.group_id_seq(),
+ message.group.name,
+ message.group.type,
+ top_left_x,
+ top_left_y,
+ top_left_x + message.group.x2,
+ top_left_y + message.group.y2,
+ false);
+
+ scope.send_control_message(new messages.GroupCreate(scope.client_id,
+ group.id,
+ group.x1,
+ group.y1,
+ group.x2,
+ group.y2,
+ group.name,
+ group.type));
+
+ scope.groups.push(group);
+
+ for(i=0; i= 48 && $event.keyCode <=90) { //Alphanumeric
+ item.name += $event.key;
+ } else if ($event.keyCode >= 186 && $event.keyCode <=222) { //Punctuation
+ item.name += $event.key;
+ } else if ($event.keyCode === 13) { //Enter
+ controller.changeState(Selected2);
+ } else if ($event.keyCode === 32) { //Space
+ item.name += " ";
+ } else {
+ console.log($event.keyCode);
+ }
+ controller.scope.send_control_message(new messages.GroupLabelEdit(controller.scope.client_id,
+ item.id,
+ item.name,
+ previous_name));
+};
+_EditLabel.prototype.onKeyDown.transitions = ['Selected2'];
+
+
+_Ready.prototype.onMouseDown = function (controller, msg_type, $event) {
+
+ controller.scope.pressedScaledX = controller.scope.scaledX;
+ controller.scope.pressedScaledY = controller.scope.scaledY;
+
+ var groups = controller.scope.groups;
+ var i = 0;
+ var selected = false;
+ controller.scope.clear_selections();
+
+ for (i = 0; i < groups.length; i++) {
+ if (groups[i].type !== "site") {
+ continue;
+ }
+ if (groups[i].is_icon_selected(controller.scope.scaledX, controller.scope.scaledY)) {
+ groups[i].selected = true;
+ selected = true;
+ controller.scope.selected_groups.push(groups[i]);
+ }
+ }
+
+ if (selected) {
+ controller.changeState(Selected1);
+ } else {
+ controller.next_controller.handle_message(msg_type, $event);
+ }
+};
+_Ready.prototype.onMouseDown.transitions = ['Selected1'];
+
+_Move.prototype.start = function (controller) {
+
+ var groups = controller.scope.selected_groups;
+
+ var i = 0;
+ for (i = 0; i < groups.length; i++) {
+ groups[i].moving = true;
+ }
+};
+
+_Move.prototype.end = function (controller) {
+
+ var groups = controller.scope.selected_groups;
+
+ var i = 0;
+ var j = 0;
+ for (i = 0; i < groups.length; i++) {
+ for(j = 0; j < groups[i].devices.length; j++) {
+ groups[i].devices[j].selected = false;
+ }
+ }
+
+ for (i = 0; i < groups.length; i++) {
+ groups[i].moving = false;
+ }
+};
+
+_Move.prototype.onMouseUp = function (controller) {
+
+ controller.changeState(Selected2);
+
+};
+_Move.prototype.onMouseUp.transitions = ['Selected2'];
+
+
+_Move.prototype.onMouseMove = function (controller) {
+
+ var groups = controller.scope.selected_groups;
+ var devices = null;
+
+ var diffX = controller.scope.scaledX - controller.scope.pressedScaledX;
+ var diffY = controller.scope.scaledY - controller.scope.pressedScaledY;
+ var i = 0;
+ var j = 0;
+ var k = 0;
+ var previous_x1, previous_y1, previous_x2, previous_y2, previous_x, previous_y;
+ for (i = 0; i < groups.length; i++) {
+ previous_x1 = groups[i].x1;
+ previous_y1 = groups[i].y1;
+ previous_x2 = groups[i].x2;
+ previous_y2 = groups[i].y2;
+ groups[i].x1 = groups[i].x1 + diffX;
+ groups[i].y1 = groups[i].y1 + diffY;
+ groups[i].x2 = groups[i].x2 + diffX;
+ groups[i].y2 = groups[i].y2 + diffY;
+
+ controller.scope.send_control_message(new messages.GroupMove(controller.scope.client_id,
+ groups[i].id,
+ groups[i].x1,
+ groups[i].y1,
+ groups[i].x2,
+ groups[i].y2,
+ previous_x1,
+ previous_y1,
+ previous_x2,
+ previous_y2));
+
+
+ devices = groups[i].devices;
+ for (j = 0; j < devices.length; j++) {
+ previous_x = devices[j].x;
+ previous_y = devices[j].y;
+ devices[j].x = devices[j].x + diffX;
+ devices[j].y = devices[j].y + diffY;
+ for (k = 0; k < devices[j].interfaces.length; k++) {
+ devices[j].interfaces[k].dot();
+ if (devices[j].interfaces[k].link !== null) {
+ devices[j].interfaces[k].link.to_interface.dot();
+ devices[j].interfaces[k].link.from_interface.dot();
+ }
+ }
+ controller.scope.send_control_message(new messages.DeviceMove(controller.scope.client_id,
+ devices[j].id,
+ devices[j].x,
+ devices[j].y,
+ previous_x,
+ previous_y));
+ }
+ for (j = 0; j < groups[i].groups.length; j++) {
+ previous_x1 = groups[i].groups[j].x1;
+ previous_y1 = groups[i].groups[j].y1;
+ previous_x2 = groups[i].groups[j].x2;
+ previous_y2 = groups[i].groups[j].y2;
+ groups[i].groups[j].x1 = groups[i].groups[j].x1 + diffX;
+ groups[i].groups[j].y1 = groups[i].groups[j].y1 + diffY;
+ groups[i].groups[j].x2 = groups[i].groups[j].x2 + diffX;
+ groups[i].groups[j].y2 = groups[i].groups[j].y2 + diffY;
+
+ controller.scope.send_control_message(new messages.GroupMove(controller.scope.client_id,
+ groups[i].groups[j].id,
+ groups[i].groups[j].x1,
+ groups[i].groups[j].y1,
+ groups[i].groups[j].x2,
+ groups[i].groups[j].y2,
+ previous_x1,
+ previous_y1,
+ previous_x2,
+ previous_y2));
+ }
+ }
+ controller.scope.pressedScaledX = controller.scope.scaledX;
+ controller.scope.pressedScaledY = controller.scope.scaledY;
+
+};
+
+_Move.prototype.onTouchMove = _Move.prototype.onMouseMove;
diff --git a/awx/network_ui/static/network_ui/src/site.icon.directive.js b/awx/network_ui/static/network_ui/src/site.icon.directive.js
new file mode 100644
index 0000000000..ffa4245f33
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/site.icon.directive.js
@@ -0,0 +1,5 @@
+
+function siteIcon () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/site_icon.html' };
+}
+exports.siteIcon = siteIcon;
diff --git a/awx/network_ui/static/network_ui/src/stream.directive.js b/awx/network_ui/static/network_ui/src/stream.directive.js
new file mode 100644
index 0000000000..a8974f2419
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/stream.directive.js
@@ -0,0 +1,5 @@
+
+function stream () {
+ return { restrict: 'A', templateUrl: '/static/network_ui/widgets/stream.html' };
+}
+exports.stream = stream;
diff --git a/awx/network_ui/static/network_ui/src/stream.fsm.js b/awx/network_ui/static/network_ui/src/stream.fsm.js
new file mode 100644
index 0000000000..24dbe3eb8a
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/stream.fsm.js
@@ -0,0 +1,115 @@
+var inherits = require('inherits');
+var fsm = require('./fsm.js');
+var models = require('./models.js');
+var messages = require('./messages.js');
+
+function _State () {
+}
+inherits(_State, fsm._State);
+
+
+function _Ready () {
+ this.name = 'Ready';
+}
+inherits(_Ready, _State);
+var Ready = new _Ready();
+exports.Ready = Ready;
+
+function _Start () {
+ this.name = 'Start';
+}
+inherits(_Start, _State);
+var Start = new _Start();
+exports.Start = Start;
+
+function _Connected () {
+ this.name = 'Connected';
+}
+inherits(_Connected, _State);
+var Connected = new _Connected();
+exports.Connected = Connected;
+
+function _Connecting () {
+ this.name = 'Connecting';
+}
+inherits(_Connecting, _State);
+var Connecting = new _Connecting();
+exports.Connecting = Connecting;
+
+function _Selecting () {
+ this.name = 'Selecting';
+}
+inherits(_Selecting, _State);
+var Selecting = new _Selecting();
+exports.Selecting = Selecting;
+
+
+
+
+_Ready.prototype.onNewStream = function (controller) {
+
+ controller.scope.clear_selections();
+ controller.changeState(Selecting);
+};
+_Ready.prototype.onNewStream.transitions = ['Selecting'];
+
+
+_Start.prototype.start = function (controller) {
+
+ controller.changeState(Ready);
+
+};
+_Start.prototype.start.transitions = ['Ready'];
+
+
+
+_Connected.prototype.start = function (controller) {
+
+ controller.scope.clear_selections();
+ controller.changeState(Ready);
+};
+_Connected.prototype.start.transitions = ['Ready'];
+
+
+_Connecting.prototype.onMouseDown = function () {
+};
+
+_Connecting.prototype.onMouseUp = function (controller) {
+
+ var selected = controller.scope.select_items(false);
+ if (selected.last_selected_device !== null) {
+ controller.scope.new_stream.to_device = selected.last_selected_device;
+ controller.scope.send_control_message(new messages.StreamCreate(controller.scope.client_id,
+ controller.scope.new_stream.id,
+ controller.scope.new_stream.from_device.id,
+ controller.scope.new_stream.to_device.id),
+ '');
+ controller.scope.new_stream = null;
+ controller.scope.update_offsets();
+ controller.changeState(Connected);
+ } else {
+ var index = controller.scope.streams.indexOf(controller.scope.new_stream);
+ if (index !== -1) {
+ controller.scope.streams.splice(index, 1);
+ }
+ controller.scope.new_stream = null;
+ controller.changeState(Ready);
+ }
+};
+_Connecting.prototype.onMouseUp.transitions = ['Ready', 'Connected'];
+
+
+_Selecting.prototype.onMouseDown = function () {
+};
+
+_Selecting.prototype.onMouseUp = function (controller) {
+
+ var selected = controller.scope.select_items(false);
+ if (selected.last_selected_device !== null) {
+ controller.scope.new_stream = new models.Stream(controller.scope.stream_id_seq(), selected.last_selected_device, null, '');
+ controller.scope.streams.push(controller.scope.new_stream);
+ controller.changeState(Connecting);
+ }
+};
+_Selecting.prototype.onMouseUp.transitions = ['Connecting'];
+
diff --git a/awx/network_ui/static/network_ui/src/style.less b/awx/network_ui/static/network_ui/src/style.less
index ff11fd4bc3..beecb91902 100644
--- a/awx/network_ui/static/network_ui/src/style.less
+++ b/awx/network_ui/static/network_ui/src/style.less
@@ -31,6 +31,7 @@
@button-text-pressed: #ffffff;
@green: #5CB85C;
@red: #D9534F;
+@light-toolbox-background: #f6f6f6;
.NetworkUI {
background-color: @light-background;
@@ -53,6 +54,12 @@
stroke-width: 1;
}
+.NetworkUI--construction {
+ fill-opacity: 0;
+ stroke: @debug-copynot;
+ stroke-width: 1;
+}
+
.NetworkUI__link--selected {
stroke: @selected-blue;
@@ -227,6 +234,72 @@
stroke: none;
}
+
+.NetworkUI__rack-text {
+ fill: @button-text;
+ font-family: 'Open Sans';
+}
+
+.NetworkUI__rack-text--selected {
+ font-family: 'Open Sans';
+}
+
+.NetworkUI__site {
+ fill: @widget-body;
+ stroke: @dark-widget-detail;
+ stroke-width: 2;
+}
+
+.NetworkUI__site--network {
+ fill: @dark-widget-detail;
+ stroke: @dark-widget-detail;
+ stroke-width: 2;
+}
+
+.NetworkUI__site-background {
+ fill: @light-background;
+ stroke: @light-background;
+ stroke-width: 2;
+}
+
+.NetworkUI__site--selected {
+ fill: @selected-blue;
+ stroke: @selected-blue;
+ stroke-width: 10;
+}
+
+.NetworkUI__site--remote-selected {
+ fill: @selected-mango;
+ stroke: @selected-mango;
+ stroke-width: 10;
+}
+
+.NetworkUI__site--selected-conflict {
+ fill: @selected-red;
+ stroke: @selected-red;
+ stroke-width: 10;
+}
+
+.NetworkUI__site line {
+ stroke: @dark-widget-detail;
+ stroke-width: 10;
+}
+
+.NetworkUI__site circle {
+ fill: @light-widget-detail;
+ stroke: none;
+}
+
+
+.NetworkUI__site-text {
+ fill: @button-text;
+ font-family: 'Open Sans';
+}
+
+.NetworkUI__site-text--selected {
+ font-family: 'Open Sans';
+}
+
.NetworkUI__button {
fill: @button-body;
stroke: @button-outline;
@@ -386,6 +459,52 @@
font-family: 'Open Sans';
}
+.NetworkUI__device {
+ fill: @widget-body;
+ stroke: @dark-widget-detail;
+ stroke-width: 2;
+}
+
+.NetworkUI__device-background {
+ fill: @light-background;
+ stroke: @light-background;
+ stroke-width: 2;
+}
+
+.NetworkUI__device--selected {
+ fill: @selected-blue;
+ stroke: @selected-blue;
+ stroke-width: 10;
+}
+
+.NetworkUI__device--remote-selected {
+ fill: @selected-mango;
+ stroke: @selected-mango;
+ stroke-width: 10;
+}
+
+.NetworkUI__device--selected-conflict {
+ fill: @selected-red;
+ stroke: @selected-red;
+ stroke-width: 10;
+}
+
+.NetworkUI__device line {
+ stroke: @light-widget-detail;
+ stroke-width: 20;
+}
+
+
+.NetworkUI__device-text {
+ fill: @button-text;
+ font-family: 'Open Sans';
+}
+
+
+.NetworkUI__device-text--selected {
+ font-family: 'Open Sans';
+}
+
.NetworkUI__status {
fill: @widget-body;
stroke: @dark-widget-detail;
@@ -487,3 +606,92 @@
.NetworkUI__group-text--selected {
font-family: 'Open Sans';
}
+
+.NetworkUI__location-text {
+ fill: @button-text;
+ font-family: 'Open Sans';
+}
+
+
+.NetworkUI__toolbox {
+ stroke: none;
+ fill: @light-toolbox-background;
+}
+
+.NetworkUI__toolbox-bezel {
+ stroke: @group;
+ stroke-width: 2;
+ fill: none;
+}
+
+.NetworkUI__process {
+ fill: @widget-body;
+ stroke: @dark-widget-detail;
+ stroke-width: 2;
+}
+
+.NetworkUI__process-background {
+ fill: @light-background;
+ stroke: @light-background;
+ stroke-width: 2;
+}
+
+.NetworkUI__process--selected {
+ fill: @selected-blue;
+ stroke: @selected-blue;
+ stroke-width: 10;
+}
+
+.NetworkUI__process--remote-selected {
+ fill: @selected-mango;
+ stroke: @selected-mango;
+ stroke-width: 10;
+}
+
+.NetworkUI__process--selected-conflict {
+ fill: @selected-red;
+ stroke: @selected-red;
+ stroke-width: 10;
+}
+
+.NetworkUI__process path {
+ fill: @widget-body;
+ stroke: @dark-widget-detail;
+ stroke-width: 2;
+}
+
+.NetworkUI__process-text {
+ fill: @button-text;
+ font-family: 'Open Sans';
+}
+
+
+.NetworkUI__process-text--selected {
+ font-family: 'Open Sans';
+}
+
+.NetworkUI__stream {
+ fill: none;
+ stroke: @dark-widget-detail;
+}
+
+.NetworkUI__stream-arrow {
+ fill: @dark-widget-detail;
+ stroke: @dark-widget-detail;
+}
+
+.NetworkUI__stream--selected {
+ fill: none;
+ stroke: @selected-blue;
+ stroke-width: 6;
+}
+.NetworkUI__stream-arrow--selected {
+ fill: @selected-blue;
+ stroke: @selected-blue;
+}
+
+.NetworkUI__stream-text {
+ fill: @button-text;
+ font-size: 8px;
+ font-family: 'Open Sans';
+}
diff --git a/awx/network_ui/static/network_ui/src/time.js b/awx/network_ui/static/network_ui/src/time.js
index 6b731acefc..c90745a221 100644
--- a/awx/network_ui/static/network_ui/src/time.js
+++ b/awx/network_ui/static/network_ui/src/time.js
@@ -46,6 +46,7 @@ _Past.prototype.onMessage = function(controller, msg_type, message) {
'DeviceMove',
'DeviceLabelEdit',
'GroupLabelEdit',
+ 'GroupCreate',
'LinkLabelEdit',
'InterfaceLabelEdit',
'InterfaceCreate',
@@ -274,6 +275,7 @@ _Present.prototype.onMessage = function(controller, msg_type, message) {
'DeviceMove',
'DeviceLabelEdit',
'GroupLabelEdit',
+ 'GroupCreate',
'InterfaceCreate',
'InterfaceLabelEdit',
'LinkCreate',
@@ -314,6 +316,11 @@ _Present.prototype.onDeviceCreate = function(controller, msg_type, message) {
controller.scope.onDeviceCreate(message);
}
};
+_Present.prototype.onGroupCreate = function(controller, msg_type, message) {
+ if (message.sender !== controller.scope.client_id) {
+ controller.scope.onGroupCreate(message);
+ }
+};
_Present.prototype.onInterfaceCreate = function(controller, msg_type, message) {
if (message.sender !== controller.scope.client_id) {
controller.scope.onInterfaceCreate(message);
diff --git a/awx/network_ui/static/network_ui/src/toolbox.fsm.js b/awx/network_ui/static/network_ui/src/toolbox.fsm.js
new file mode 100644
index 0000000000..89d8f22ff4
--- /dev/null
+++ b/awx/network_ui/static/network_ui/src/toolbox.fsm.js
@@ -0,0 +1,216 @@
+var inherits = require('inherits');
+var fsm = require('./fsm.js');
+
+function _State () {
+}
+inherits(_State, fsm._State);
+
+
+function _Dropping () {
+ this.name = 'Dropping';
+}
+inherits(_Dropping, _State);
+var Dropping = new _Dropping();
+exports.Dropping = Dropping;
+
+function _Selecting () {
+ this.name = 'Selecting';
+}
+inherits(_Selecting, _State);
+var Selecting = new _Selecting();
+exports.Selecting = Selecting;
+
+function _Selected () {
+ this.name = 'Selected';
+}
+inherits(_Selected, _State);
+var Selected = new _Selected();
+exports.Selected = Selected;
+
+function _Ready () {
+ this.name = 'Ready';
+}
+inherits(_Ready, _State);
+var Ready = new _Ready();
+exports.Ready = Ready;
+
+function _Scrolling () {
+ this.name = 'Scrolling';
+}
+inherits(_Scrolling, _State);
+var Scrolling = new _Scrolling();
+exports.Scrolling = Scrolling;
+
+function _Start () {
+ this.name = 'Start';
+}
+inherits(_Start, _State);
+var Start = new _Start();
+exports.Start = Start;
+
+function _Move () {
+ this.name = 'Move';
+}
+inherits(_Move, _State);
+var Move = new _Move();
+exports.Move = Move;
+
+
+
+
+_Dropping.prototype.start = function (controller) {
+
+
+ var i = 0;
+ var toolbox = controller.toolbox;
+ console.log(["Dropping", toolbox.selected_item]);
+ for(i = 0; i < toolbox.items.length; i++) {
+ toolbox.items[i].selected = false;
+ }
+
+ controller.dropped_action(toolbox.selected_item);
+
+ if (controller.remove_on_drop) {
+ var dindex = toolbox.items.indexOf(toolbox.selected_item);
+ if (dindex !== -1) {
+ toolbox.items.splice(dindex, 1);
+ }
+ }
+
+ toolbox.selected_item = null;
+ controller.changeState(Ready);
+};
+_Dropping.prototype.start.transitions = ['Ready'];
+
+
+
+_Selected.prototype.onMouseMove = function (controller) {
+
+ controller.changeState(Move);
+
+};
+_Selected.prototype.onMouseMove.transitions = ['Move'];
+
+_Selected.prototype.onMouseUp = function (controller) {
+
+ var i = 0;
+ var toolbox = controller.toolbox;
+ for(i = 0; i < toolbox.items.length; i++) {
+ toolbox.items[i].selected = false;
+ }
+ toolbox.selected_item = null;
+ controller.changeState(Ready);
+};
+_Selected.prototype.onMouseUp.transitions = ['Move'];
+
+
+_Selecting.prototype.onMouseDown = function (controller) {
+
+ var i = 0;
+
+ var toolbox = controller.toolbox;
+ var scope = controller.scope;
+ var selected_item = Math.floor((controller.scope.mouseY - toolbox.y - toolbox.scroll_offset) / toolbox.spacing);
+
+ for(i = 0; i < toolbox.items.length; i++) {
+ toolbox.items[i].selected = false;
+ }
+ if (selected_item >= 0 && selected_item < toolbox.items.length) {
+ toolbox.items[selected_item].selected = true;
+ toolbox.selected_item = toolbox.items[selected_item];
+ scope.pressedX = scope.mouseX;
+ scope.pressedY = scope.mouseY;
+ scope.pressedScaledX = scope.scaledX;
+ scope.pressedScaledY = scope.scaledY;
+ toolbox.selected_item.x = toolbox.x + toolbox.width/2;
+ toolbox.selected_item.y = selected_item * toolbox.spacing + toolbox.y + toolbox.scroll_offset + toolbox.spacing/2;
+ controller.scope.clear_selections();
+ controller.scope.first_controller.handle_message("UnselectAll", {});
+ controller.changeState(Selected);
+ } else {
+ toolbox.selected_item = null;
+ controller.changeState(Ready);
+ }
+
+};
+_Selecting.prototype.onMouseDown.transitions = ['Selected'];
+
+_Ready.prototype.onMouseDown = function (controller, msg_type, $event) {
+
+ if(controller.toolbox.enabled &&
+ controller.scope.mouseX > controller.toolbox.x &&
+ controller.scope.mouseY > controller.toolbox.y &&
+ controller.scope.mouseX < controller.toolbox.x + controller.toolbox.width &&
+ controller.scope.mouseY < controller.toolbox.y + controller.toolbox.height) {
+
+ controller.changeState(Selecting);
+ controller.handle_message(msg_type, $event);
+
+ } else {
+ controller.next_controller.handle_message(msg_type, $event);
+ }
+};
+_Ready.prototype.onMouseDown.transitions = ['Selecting'];
+
+_Ready.prototype.onMouseWheel = function (controller, msg_type, $event) {
+
+ if(controller.toolbox.enabled &&
+ controller.scope.mouseX > controller.toolbox.x &&
+ controller.scope.mouseY > controller.toolbox.y &&
+ controller.scope.mouseX < controller.toolbox.x + controller.toolbox.width &&
+ controller.scope.mouseY < controller.toolbox.y + controller.toolbox.height) {
+
+ controller.changeState(Scrolling);
+ controller.handle_message(msg_type, $event);
+
+ } else {
+ controller.next_controller.handle_message(msg_type, $event);
+ }
+};
+_Ready.prototype.onMouseWheel.transitions = ['Scrolling'];
+
+
+
+_Scrolling.prototype.onMouseWheel = function (controller, msg_type, $event) {
+
+ var delta = $event[1];
+ controller.toolbox.scroll_offset += -1 * delta;
+ controller.toolbox.scroll_offset = Math.min(controller.toolbox.scroll_offset, 0);
+ controller.toolbox.scroll_offset = Math.max(controller.toolbox.scroll_offset, -1 * controller.toolbox.spacing * controller.toolbox.items.length + controller.toolbox.height);
+
+
+ controller.changeState(Ready);
+
+};
+_Scrolling.prototype.start.transitions = ['Ready'];
+
+
+
+_Start.prototype.start = function (controller) {
+
+ controller.changeState(Ready);
+
+};
+_Start.prototype.start.transitions = ['Ready'];
+
+
+
+_Move.prototype.onMouseUp = function (controller) {
+
+ controller.changeState(Dropping);
+
+};
+_Move.prototype.onMouseUp.transitions = ['Dropping'];
+
+
+_Move.prototype.onMouseMove = function (controller) {
+
+ var diffX = controller.scope.mouseX - controller.scope.pressedX;
+ var diffY = controller.scope.mouseY - controller.scope.pressedY;
+
+ controller.toolbox.selected_item.x += diffX;
+ controller.toolbox.selected_item.y += diffY;
+
+ controller.scope.pressedX = controller.scope.mouseX;
+ controller.scope.pressedY = controller.scope.mouseY;
+};
diff --git a/awx/network_ui/static/network_ui/src/view.js b/awx/network_ui/static/network_ui/src/view.js
index 4f55d57ade..09814c79e2 100644
--- a/awx/network_ui/static/network_ui/src/view.js
+++ b/awx/network_ui/static/network_ui/src/view.js
@@ -95,7 +95,7 @@ _Start.prototype.start = function (controller) {
_Scale.prototype.onMouseWheel = function (controller, msg_type, message) {
var delta = message[1];
- var new_scale = Math.max(0.1, Math.min(10, (controller.scope.current_scale + delta / 100)));
+ var new_scale = Math.max(0.001, Math.min(100, (controller.scope.current_scale + delta / (100 / controller.scope.current_scale))));
var new_panX = controller.scope.mouseX - new_scale * ((controller.scope.mouseX - controller.scope.panX) / controller.scope.current_scale);
var new_panY = controller.scope.mouseY - new_scale * ((controller.scope.mouseY - controller.scope.panY) / controller.scope.current_scale);
controller.scope.updateScaledXY();
diff --git a/awx/network_ui/static/network_ui/widgets.html b/awx/network_ui/static/network_ui/widgets.html
new file mode 100644
index 0000000000..fd7984b38d
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/configuration.html b/awx/network_ui/static/network_ui/widgets/configuration.html
new file mode 100644
index 0000000000..8cb52c028e
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/configuration.html
@@ -0,0 +1,3 @@
+
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/debug.html b/awx/network_ui/static/network_ui/widgets/debug.html
index 2257c390d9..57efb2ec62 100644
--- a/awx/network_ui/static/network_ui/widgets/debug.html
+++ b/awx/network_ui/static/network_ui/widgets/debug.html
@@ -1,6 +1,10 @@
+ view_port.x: {{view_port.x}}
+ view_port.y: {{view_port.y}}
+ view_port.width: {{view_port.width}}
+ view_port.height: {{view_port.height}}
width: {{graph.width}}
height: {{graph.height}}
rc: {{graph.right_column}}
@@ -10,7 +14,7 @@
Mouse over: {{onMouseOverResult}}
Mouse enter: {{onMouseEnterResult}}
Mouse leave: {{onMouseLeaveResult}}
- Current scale: {{current_scale.toFixed(2)}}
+ Current scale: {{current_scale.toFixed(4)}}
Pan X: {{panX.toFixed(2)}}
Pan Y: {{panY.toFixed(2)}}
View State: {{view_controller.state.name}}
@@ -32,4 +36,10 @@
Group State: {{group_controller.state.name}}
Selected groups: {{selected_groups.length}}
Hotkeys State: {{hotkeys_controller.state.name}}
+ Mode State: {{mode_controller.state.name}}
+ Device Detail State: {{device_detail_controller.state.name}}
+ Site State: {{site_controller.state.name}}
+ Rack State: {{rack_controller.state.name}}
+ Stream State: {{stream_controller.state.name}}
+
diff --git a/awx/network_ui/static/network_ui/widgets/default.html b/awx/network_ui/static/network_ui/widgets/default.html
index 519df77101..26b4992974 100644
--- a/awx/network_ui/static/network_ui/widgets/default.html
+++ b/awx/network_ui/static/network_ui/widgets/default.html
@@ -1,36 +1,53 @@
-
+
+
+
+
+
+
+
+ class="NetworkUI--debug">
+ class="NetworkUI--debug">
+ class="NetworkUI--debug">
+
+
+ ng-attr-class="{{item.selected || item.remote_selected ? item.selected && item.remote_selected ? 'NetworkUI__device--selected-conflict' : item.selected ? 'NetworkUI__device--selected' : 'NetworkUI__device--remote-selected' : 'NetworkUI--hidden'}}">
-
-
+
+ {{device.name}}
- {{device.name}}{{device.edit_label?'_':''}}
+ y="0"> {{item.name}}
+ {{item.name}}{{item.edit_label?'_':''}}
diff --git a/awx/network_ui/static/network_ui/widgets/device_detail.html b/awx/network_ui/static/network_ui/widgets/device_detail.html
new file mode 100644
index 0000000000..7471a5b0db
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/device_detail.html
@@ -0,0 +1,109 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{interface.name}}
+{{interface.name}}{{interface.edit_label?'_':''}}
+
+
+
+
+
+
+
+
+{{interface.remote_interface().name}}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/group.html b/awx/network_ui/static/network_ui/widgets/group.html
index a3804843b8..fb8bc2b296 100644
--- a/awx/network_ui/static/network_ui/widgets/group.html
+++ b/awx/network_ui/static/network_ui/widgets/group.html
@@ -1,70 +1,131 @@
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ng-attr-x="{{item.left_extent(scaledX)}}"
+ ng-attr-y="{{item.top_extent(scaledY)}}"
+ ng-attr-class="{{item.selected && 'NetworkUI__group--selected' || 'NetworkUI--hidden'}}"/>
+ ng-attr-x="{{item.right_extent(scaledX) - 10}}"
+ ng-attr-y="{{item.top_extent(scaledY)}}"
+ ng-attr-class="{{item.selected && 'NetworkUI__group--selected' || 'NetworkUI--hidden'}}"/>
+ ng-attr-x="{{item.right_extent(scaledX) - 10}}"
+ ng-attr-y="{{item.bottom_extent(scaledY) - 10}}"
+ ng-attr-class="{{item.selected && 'NetworkUI__group--selected' || 'NetworkUI--hidden'}}"/>
+ ng-attr-x="{{item.left_extent(scaledX)}}"
+ ng-attr-y="{{item.bottom_extent(scaledY) - 10}}"
+ ng-attr-class="{{item.selected && 'NetworkUI__group--selected' || 'NetworkUI--hidden'}}"/>
-
+
-
-
+
+ {{group.name}}
-{{group.name}}{{group.edit_label?'_':''}}
+ x="20"
+ y="32"> {{item.name}}
+{{item.name}}{{item.edit_label?'_':''}}
+
+
+
+
+
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/host.html b/awx/network_ui/static/network_ui/widgets/host.html
index 2d065df54d..db6424c522 100644
--- a/awx/network_ui/static/network_ui/widgets/host.html
+++ b/awx/network_ui/static/network_ui/widgets/host.html
@@ -1,5 +1,18 @@
+
+
+
+
+
-
-
+ {{device.name}}
- {{device.name}}{{device.edit_label?'_':''}}
+ y="5"> {{item.name}}
+ {{item.name}}{{item.edit_label?'_':''}}
diff --git a/awx/network_ui/static/network_ui/widgets/inventory_toolbox.html b/awx/network_ui/static/network_ui/widgets/inventory_toolbox.html
new file mode 100644
index 0000000000..ec1cd2f904
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/inventory_toolbox.html
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/inventory_toolbox_clip_path.html b/awx/network_ui/static/network_ui/widgets/inventory_toolbox_clip_path.html
new file mode 100644
index 0000000000..82f94f1329
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/inventory_toolbox_clip_path.html
@@ -0,0 +1,6 @@
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/map.html b/awx/network_ui/static/network_ui/widgets/map.html
new file mode 100644
index 0000000000..a17ba4fe5f
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/map.html
@@ -0,0 +1,2661 @@
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/network_ui.html b/awx/network_ui/static/network_ui/widgets/network_ui.html
index 8cbc64678f..e902d52638 100644
--- a/awx/network_ui/static/network_ui/widgets/network_ui.html
+++ b/awx/network_ui/static/network_ui/widgets/network_ui.html
@@ -22,21 +22,38 @@
+
+
+
+
+
-
-
+
+
+
-
-
+
+
+
+
+
+
+
+
+
@@ -49,17 +66,21 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -69,6 +90,9 @@
+
+
+
+
+ {{l}}
+
diff --git a/awx/network_ui/static/network_ui/widgets/network_widgets.html b/awx/network_ui/static/network_ui/widgets/network_widgets.html
new file mode 100644
index 0000000000..2c9c9e1d2b
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/network_widgets.html
@@ -0,0 +1,126 @@
+
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/process.html b/awx/network_ui/static/network_ui/widgets/process.html
new file mode 100644
index 0000000000..0105997e06
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/process.html
@@ -0,0 +1,11 @@
+
+
+
+
+ {{item.name}}
+{{item.name}}{{item.edit_label?'_':''}}
diff --git a/awx/network_ui/static/network_ui/widgets/quadrants.html b/awx/network_ui/static/network_ui/widgets/quadrants.html
index d1c3310812..551a64519c 100644
--- a/awx/network_ui/static/network_ui/widgets/quadrants.html
+++ b/awx/network_ui/static/network_ui/widgets/quadrants.html
@@ -1,10 +1,16 @@
-
-
+
diff --git a/awx/network_ui/static/network_ui/widgets/rack.html b/awx/network_ui/static/network_ui/widgets/rack.html
index 89fcf4742e..2387b92738 100644
--- a/awx/network_ui/static/network_ui/widgets/rack.html
+++ b/awx/network_ui/static/network_ui/widgets/rack.html
@@ -1,4 +1,19 @@
+
+
+
+
+
+
+
@@ -60,12 +75,13 @@
-
- {{device.name}}
- {{device.name}}{{device.edit_label?'_':''}}
-
-
+
+
+ {{item.name}}
+{{item.name}}{{item.edit_label?'_':''}}
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/rack_icon.html b/awx/network_ui/static/network_ui/widgets/rack_icon.html
new file mode 100644
index 0000000000..e436db1de1
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/rack_icon.html
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+ {{item.name}}{{item.edit_label?'_':''}}
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/router.html b/awx/network_ui/static/network_ui/widgets/router.html
index 54795afef1..01dda00bb0 100644
--- a/awx/network_ui/static/network_ui/widgets/router.html
+++ b/awx/network_ui/static/network_ui/widgets/router.html
@@ -1,5 +1,19 @@
+
+
+
+
+
+
+ ng-attr-class="{{item.selected || item.remote_selected ? item.selected && item.remote_selected ? 'NetworkUI__router--selected-conflict' : item.selected ? 'NetworkUI__router--selected' : 'NetworkUI__router--remote-selected' : 'NetworkUI--hidden'}}">
-
-
+ {{device.name}}
- {{device.name}}{{device.edit_label?'_':''}}
+ y="0"> {{item.name}}
+ {{item.name}}{{item.edit_label?'_':''}}
diff --git a/awx/network_ui/static/network_ui/widgets/site.html b/awx/network_ui/static/network_ui/widgets/site.html
new file mode 100644
index 0000000000..31e674794a
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/site.html
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+{{item.name}}{{item.edit_label?'_':''}}
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/site_icon.html b/awx/network_ui/static/network_ui/widgets/site_icon.html
new file mode 100644
index 0000000000..6d165a243e
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/site_icon.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{item.name}}
+{{item.name}}{{item.edit_label?'_':''}}
diff --git a/awx/network_ui/static/network_ui/widgets/status_light.html b/awx/network_ui/static/network_ui/widgets/status_light.html
index 354964fb6a..357ddd02dd 100644
--- a/awx/network_ui/static/network_ui/widgets/status_light.html
+++ b/awx/network_ui/static/network_ui/widgets/status_light.html
@@ -1,10 +1,10 @@
-
-
+
+
-
-
+
+ ng-attr-class="{{item.status === null ? 'NetworkUI--hidden' : item.status ? 'NetworkUI__status--pass': 'NetworkUI__status--fail'}}">
diff --git a/awx/network_ui/static/network_ui/widgets/stream.html b/awx/network_ui/static/network_ui/widgets/stream.html
new file mode 100644
index 0000000000..5f46537ba6
--- /dev/null
+++ b/awx/network_ui/static/network_ui/widgets/stream.html
@@ -0,0 +1,133 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{stream.label}}
+{{stream.label}}{{stream.edit_label?'_':''}}
+
+
+
diff --git a/awx/network_ui/static/network_ui/widgets/switch.html b/awx/network_ui/static/network_ui/widgets/switch.html
index 5d0ab6ac9f..99300ac2e6 100644
--- a/awx/network_ui/static/network_ui/widgets/switch.html
+++ b/awx/network_ui/static/network_ui/widgets/switch.html
@@ -1,5 +1,19 @@
+
+
+
+
+
+
@@ -54,11 +68,11 @@
ng-attr-y2="-14"/>
-
-
+ {{device.name}}
- {{device.name}}{{device.edit_label?'_':''}}
+ y="0"> {{item.name}}
+ {{item.name}}{{item.edit_label?'_':''}}
diff --git a/awx/network_ui/static/network_ui/widgets/task_status.html b/awx/network_ui/static/network_ui/widgets/task_status.html
index b850a238ec..2b348d994f 100644
--- a/awx/network_ui/static/network_ui/widgets/task_status.html
+++ b/awx/network_ui/static/network_ui/widgets/task_status.html
@@ -1,5 +1,5 @@
-
-
+
+