From 9dc4e22fe670a8baa3f8a3eb478a5f9fc0401331 Mon Sep 17 00:00:00 2001 From: Ben Thomasson Date: Fri, 11 Aug 2017 09:51:40 -0400 Subject: [PATCH] Adds support for multiple view modes Adds mulitple view modes based on zoom-level. This allows for easy drilling into a device for more detail or zooming-out for a overview. * Adds support for multi-site and device modes * Adds icons to remote device in device detail * Adds site widget * Adds link between sites * Adds toolboxes for inventory, site, and applications * Adds rack mode * Adds UI for adding processes to devices * Adds copy and paste support * Adds streams --- awx/network_ui/static/network_ui/Makefile | 4 +- .../network_ui/designs/device_detail.yml | 19 + .../static/network_ui/designs/mode.yml | 65 + .../static/network_ui/designs/rack.yml | 72 + .../static/network_ui/designs/site.yml | 72 + .../static/network_ui/designs/stream.yml | 42 + .../static/network_ui/designs/toolbox.yml | 49 + awx/network_ui/static/network_ui/index.html | 2 +- awx/network_ui/static/network_ui/package.json | 3 +- .../network_ui/src/configuration.directive.js | 5 + .../network_ui/src/device.detail.directive.js | 5 + .../network_ui/src/device.detail.fsm.js | 72 + awx/network_ui/static/network_ui/src/group.js | 96 +- .../static/network_ui/src/hotkeys.fsm.js | 25 +- .../inventory.toolbox.clip.path.directive.js | 5 + .../src/inventory.toolbox.directive.js | 5 + awx/network_ui/static/network_ui/src/main.js | 7 +- .../static/network_ui/src/map.directive.js | 5 + .../static/network_ui/src/messages.js | 78 +- .../static/network_ui/src/mode.fsm.js | 201 ++ .../static/network_ui/src/models.js | 321 +- awx/network_ui/static/network_ui/src/move.js | 108 +- .../static/network_ui/src/network.ui.app.js | 20 + .../network_ui/src/network.ui.controller.js | 172 +- .../network_ui/src/network.widgets.app.js | 66 + .../src/network.widgets.controller.js | 1426 +++++++++ .../src/network.widgets.directive.js | 5 + .../network_ui/src/process.directive.js | 5 + .../static/network_ui/src/rack.fsm.js | 487 +++ .../network_ui/src/rack.icon.directive.js | 5 + .../static/network_ui/src/site.directive.js | 5 + .../static/network_ui/src/site.fsm.js | 567 ++++ .../network_ui/src/site.icon.directive.js | 5 + .../static/network_ui/src/stream.directive.js | 5 + .../static/network_ui/src/stream.fsm.js | 115 + .../static/network_ui/src/style.less | 208 ++ awx/network_ui/static/network_ui/src/time.js | 7 + .../static/network_ui/src/toolbox.fsm.js | 216 ++ awx/network_ui/static/network_ui/src/view.js | 2 +- awx/network_ui/static/network_ui/widgets.html | 12 + .../network_ui/widgets/configuration.html | 3 + .../static/network_ui/widgets/debug.html | 12 +- .../static/network_ui/widgets/default.html | 35 +- .../network_ui/widgets/device_detail.html | 109 + .../static/network_ui/widgets/group.html | 131 +- .../static/network_ui/widgets/host.html | 23 +- .../network_ui/widgets/inventory_toolbox.html | 96 + .../widgets/inventory_toolbox_clip_path.html | 6 + .../static/network_ui/widgets/map.html | 2661 +++++++++++++++++ .../static/network_ui/widgets/network_ui.html | 51 +- .../network_ui/widgets/network_widgets.html | 126 + .../static/network_ui/widgets/process.html | 11 + .../static/network_ui/widgets/quadrants.html | 22 +- .../static/network_ui/widgets/rack.html | 36 +- .../static/network_ui/widgets/rack_icon.html | 70 + .../static/network_ui/widgets/router.html | 24 +- .../static/network_ui/widgets/site.html | 90 + .../static/network_ui/widgets/site_icon.html | 71 + .../network_ui/widgets/status_light.html | 12 +- .../static/network_ui/widgets/stream.html | 133 + .../static/network_ui/widgets/switch.html | 24 +- .../network_ui/widgets/task_status.html | 4 +- 62 files changed, 8207 insertions(+), 132 deletions(-) create mode 100644 awx/network_ui/static/network_ui/designs/device_detail.yml create mode 100644 awx/network_ui/static/network_ui/designs/mode.yml create mode 100644 awx/network_ui/static/network_ui/designs/rack.yml create mode 100644 awx/network_ui/static/network_ui/designs/site.yml create mode 100644 awx/network_ui/static/network_ui/designs/stream.yml create mode 100644 awx/network_ui/static/network_ui/designs/toolbox.yml create mode 100644 awx/network_ui/static/network_ui/src/configuration.directive.js create mode 100644 awx/network_ui/static/network_ui/src/device.detail.directive.js create mode 100644 awx/network_ui/static/network_ui/src/device.detail.fsm.js create mode 100644 awx/network_ui/static/network_ui/src/inventory.toolbox.clip.path.directive.js create mode 100644 awx/network_ui/static/network_ui/src/inventory.toolbox.directive.js create mode 100644 awx/network_ui/static/network_ui/src/map.directive.js create mode 100644 awx/network_ui/static/network_ui/src/mode.fsm.js create mode 100644 awx/network_ui/static/network_ui/src/network.widgets.app.js create mode 100644 awx/network_ui/static/network_ui/src/network.widgets.controller.js create mode 100644 awx/network_ui/static/network_ui/src/network.widgets.directive.js create mode 100644 awx/network_ui/static/network_ui/src/process.directive.js create mode 100644 awx/network_ui/static/network_ui/src/rack.fsm.js create mode 100644 awx/network_ui/static/network_ui/src/rack.icon.directive.js create mode 100644 awx/network_ui/static/network_ui/src/site.directive.js create mode 100644 awx/network_ui/static/network_ui/src/site.fsm.js create mode 100644 awx/network_ui/static/network_ui/src/site.icon.directive.js create mode 100644 awx/network_ui/static/network_ui/src/stream.directive.js create mode 100644 awx/network_ui/static/network_ui/src/stream.fsm.js create mode 100644 awx/network_ui/static/network_ui/src/toolbox.fsm.js create mode 100644 awx/network_ui/static/network_ui/widgets.html create mode 100644 awx/network_ui/static/network_ui/widgets/configuration.html create mode 100644 awx/network_ui/static/network_ui/widgets/device_detail.html create mode 100644 awx/network_ui/static/network_ui/widgets/inventory_toolbox.html create mode 100644 awx/network_ui/static/network_ui/widgets/inventory_toolbox_clip_path.html create mode 100644 awx/network_ui/static/network_ui/widgets/map.html create mode 100644 awx/network_ui/static/network_ui/widgets/network_widgets.html create mode 100644 awx/network_ui/static/network_ui/widgets/process.html create mode 100644 awx/network_ui/static/network_ui/widgets/rack_icon.html create mode 100644 awx/network_ui/static/network_ui/widgets/site.html create mode 100644 awx/network_ui/static/network_ui/widgets/site_icon.html create mode 100644 awx/network_ui/static/network_ui/widgets/stream.html 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 @@ + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ - - + +