diff --git a/awx/network_ui/designs/animation_fsm.yml b/awx/network_ui/designs/animation_fsm.yml new file mode 100644 index 0000000000..c99b99dd1c --- /dev/null +++ b/awx/network_ui/designs/animation_fsm.yml @@ -0,0 +1,29 @@ +diagram_id: 58 +name: animation_fsm +states: +- id: 4 + label: Cancelled + x: 590 + y: 602 +- id: 3 + label: Completed + x: 225 + y: 604 +- id: 2 + label: Running + x: 418 + y: 362 +- id: 1 + label: Start + x: 454 + y: 158 +transitions: +- from_state: Running + label: onAnimationCancelled + to_state: Cancelled +- from_state: Running + label: onAnimationCompleted + to_state: Completed +- from_state: Start + label: start + to_state: Running diff --git a/awx/network_ui/designs/keybindings.png b/awx/network_ui/designs/keybindings.png new file mode 100644 index 0000000000..e54b652211 Binary files /dev/null and b/awx/network_ui/designs/keybindings.png differ diff --git a/awx/network_ui/designs/keybindings.yml b/awx/network_ui/designs/keybindings.yml new file mode 100644 index 0000000000..11ce6fa212 --- /dev/null +++ b/awx/network_ui/designs/keybindings.yml @@ -0,0 +1,25 @@ +diagram_id: 60 +name: diagram +states: +- id: 3 + label: Enabled + x: 842 + y: 533 +- id: 2 + label: Start + x: 839 + y: 270 +- id: 6 + label: Disabled + x: 1231 + y: 532 +transitions: +- from_state: Start + label: start + to_state: Enabled +- from_state: Disabled + label: onBindDocument + to_state: Enabled +- from_state: Enabled + label: onUnbindDocument + to_state: Disabled diff --git a/awx/network_ui/static/network_ui/extract.js b/awx/network_ui/static/network_ui/extract.js index 40c14c7462..79edb17f60 100755 --- a/awx/network_ui/static/network_ui/extract.js +++ b/awx/network_ui/static/network_ui/extract.js @@ -26,7 +26,7 @@ var transition = null; var i = 0; while(next_state !== undefined) { state = implementation[next_state]; - transition_iter = Iterator(state.constructor.prototype) + transition_iter = Iterator(state.constructor.prototype); next_transition = transition_iter.next(); while (next_transition !== undefined) { transition = state.constructor.prototype[next_transition]; diff --git a/awx/network_ui/static/network_ui/extract_messages.js b/awx/network_ui/static/network_ui/extract_messages.js index 914e5c4cb0..aee32413de 100755 --- a/awx/network_ui/static/network_ui/extract_messages.js +++ b/awx/network_ui/static/network_ui/extract_messages.js @@ -20,19 +20,19 @@ var next_message = message_iter.next(); var next_field = null; var message = null; var message_instance = null; -var field = null; var fields = null; -var i = 0; +// var field = null; +// var i = 0; while(next_message !== undefined) { message = implementation[next_message]; try { - message_instance = new message() + message_instance = new message(); } catch(err) { next_message = message_iter.next(); continue; } fields = []; - field_iter = Iterator(message_instance) + field_iter = Iterator(message_instance); next_field = field_iter.next(); while (next_field !== undefined) { fields.push(next_field); diff --git a/awx/ui/client/features/_index.less b/awx/ui/client/features/_index.less index 053f270ddd..e2339dc9e4 100644 --- a/awx/ui/client/features/_index.less +++ b/awx/ui/client/features/_index.less @@ -1,3 +1,2 @@ @import 'credentials/_index'; @import 'users/tokens/_index'; -@import 'networking/_index'; diff --git a/awx/ui/client/features/index.js b/awx/ui/client/features/index.js index 5eb1cd96b2..01216e575f 100644 --- a/awx/ui/client/features/index.js +++ b/awx/ui/client/features/index.js @@ -6,7 +6,6 @@ import atFeaturesApplications from '~features/applications'; import atFeaturesCredentials from '~features/credentials'; import atFeaturesTemplates from '~features/templates'; import atFeaturesUsers from '~features/users'; -import atFeaturesNetworking from '~features/networking'; const MODULE_NAME = 'at.features'; @@ -17,8 +16,7 @@ angular.module(MODULE_NAME, [ atFeaturesApplications, atFeaturesCredentials, atFeaturesTemplates, - atFeaturesUsers, - atFeaturesNetworking + atFeaturesUsers ]); export default MODULE_NAME; diff --git a/awx/ui/client/features/networking/networking.controller.js b/awx/ui/client/features/networking/networking.controller.js deleted file mode 100644 index f330d30ac1..0000000000 --- a/awx/ui/client/features/networking/networking.controller.js +++ /dev/null @@ -1,66 +0,0 @@ -function NetworkingController (models, $state, $scope, strings) { - const vm = this || {}; - - const { - inventory - } = models; - - vm.strings = strings; - vm.panelTitle = `${strings.get('state.BREADCRUMB_LABEL')} | ${inventory.name}`; - vm.hostDetail = {}; - - vm.rightPanelIsExpanded = false; - vm.leftPanelIsExpanded = true; - vm.jumpToPanelExpanded = false; - vm.keyPanelExpanded = false; - vm.close = () => { - $state.go('inventories'); - }; - - vm.redirectButtonHandler = (string) => { - $scope.$broadcast('toolbarButtonEvent', string); - }; - - vm.jumpTo = (string) => { - vm.jumpToPanelExpanded = !vm.jumpToPanelExpanded; - vm.keyPanelExpanded = false; - if (string) { - $scope.$broadcast('jumpTo', string); - } - }; - - vm.key = () => { - vm.keyPanelExpanded = !vm.keyPanelExpanded; - vm.jumpToPanelExpanded = false; - }; - - $scope.$on('overall_toolbox_collapsed', () => { - vm.leftPanelIsExpanded = !vm.leftPanelIsExpanded; - }); - - $scope.$on('closeDetailsPanel', () => { - vm.rightPanelIsExpanded = false; - vm.jumpToPanelExpanded = false; - vm.keyPanelExpanded = false; - }); - - $scope.$on('showDetails', (e, data, expand) => { - if (expand) { - vm.rightPanelIsExpanded = true; - } - if (!_.has(data, 'host_id')) { - $scope.item = data; - } else { - $scope.item = data; - } - }); -} - -NetworkingController.$inject = [ - 'resolvedModels', - '$state', - '$scope', - 'NetworkingStrings' -]; - -export default NetworkingController; diff --git a/awx/ui/client/src/network-ui/animation.fsm.js b/awx/ui/client/src/network-ui/animation.fsm.js new file mode 100644 index 0000000000..19fe58c731 --- /dev/null +++ b/awx/ui/client/src/network-ui/animation.fsm.js @@ -0,0 +1,81 @@ +/* Copyright (c) 2018 Benjamin Thomasson */ +/* Copyright (c) 2018 Red Hat, Inc. */ + +var inherits = require('inherits'); +var fsm = require('./fsm.js'); + + +function _Start () { + this.name = 'Start'; +} +inherits(_Start, fsm._State); +var Start = new _Start(); +exports.Start = Start; + +function _Completed () { + this.name = 'Completed'; +} +inherits(_Completed, fsm._State); +var Completed = new _Completed(); +exports.Completed = Completed; + +function _Cancelled () { + this.name = 'Cancelled'; +} +inherits(_Cancelled, fsm._State); +var Cancelled = new _Cancelled(); +exports.Cancelled = Cancelled; + +function _Running () { + this.name = 'Running'; +} +inherits(_Running, fsm._State); +var Running = new _Running(); +exports.Running = Running; + + +_Start.prototype.start = function (controller) { + + controller.changeState(Running); +}; +_Start.prototype.start.transitions = ['Running']; + +_Running.prototype.start = function (controller) { + + controller.scope.interval = setInterval(function () { + controller.scope.frame_number = controller.scope.frame_number_seq(); + if (!controller.scope.active) { + return; + } + if (controller.scope.frame_number > controller.scope.steps) { + controller.scope.fsm.handle_message('AnimationCompleted'); + return; + } + controller.scope.callback(controller.scope); + controller.scope.scope.$apply(); + }, 17); +}; + +_Running.prototype.onAnimationCancelled = function (controller) { + + controller.changeState(Cancelled); + +}; +_Running.prototype.onAnimationCancelled.transitions = ['Cancelled']; + +_Running.prototype.onAnimationCompleted = function (controller) { + + controller.changeState(Completed); + +}; +_Running.prototype.onAnimationCompleted.transitions = ['Completed']; + +_Completed.prototype.start = function (controller) { + controller.scope.active = false; + clearInterval(controller.scope.interval); +}; + +_Cancelled.prototype.start = function (controller) { + controller.scope.active = false; + clearInterval(controller.scope.interval); +}; diff --git a/awx/ui/client/src/network-ui/animations.js b/awx/ui/client/src/network-ui/animations.js new file mode 100644 index 0000000000..b5caee6b3d --- /dev/null +++ b/awx/ui/client/src/network-ui/animations.js @@ -0,0 +1,51 @@ + +/* + * Uses y = cx^2 * cdx to calculate the height of the camera + * Uses scale = 1 / (height + 1) to calculate the scale of the virtual canvas + */ + +function scale_animation (scope) { + + var d = scope.steps; + var c = scope.data.c; + var x = scope.frame_number; + var initial_height = ((1 / scope.data.current_scale) - 1); + var a = -1 * initial_height / (c * d); + var height = 0; + if(scope.data.distance > 0) { + height = (x + a) * (x - d) * c + scope.data.end_height; + } else { + height = (scope.data.end_height - initial_height) * (scope.frame_number / scope.steps) + initial_height + } + //console.log({x: x, + // c: c, + // d: d, + // a: a, + // h: height, + // i: initial_height}); + scope.data.scope.current_scale = 1 / (1 + height); + //console.log(scope.data.scope.current_scale); + //scope.data.scope.current_scale = 1.0; + scope.data.scope.first_channel.send("ScaleChanged", {}); + scope.data.scope.first_channel.send("ScaleChanged", {}); + scope.data.scope.updatePanAndScale(); +} +exports.scale_animation = scale_animation; + +function pan_animation (scope) { + var incr_x = (scope.data.x2 - scope.data.x1) / scope.steps; + var incr_y = (scope.data.y2 - scope.data.y1) / scope.steps; + //console.log({incr_x: incr_x, incr_y: incr_y}); + var v_x = incr_x * scope.frame_number + scope.data.x1; + var v_y = incr_y * scope.frame_number + scope.data.y1; + var p = scope.data.scope.to_pan(v_x, v_y); + //console.log({v_x: v_x, v_y: v_y}); + //console.log({p_x: p.x, p_y: p.y}); + //scope.data.scope.panX = scope.data.scope.graph.width/2 - scope.data.scope.current_scale * p.x / 1.0; + //scope.data.scope.panY = scope.data.scope.graph.height/2 - scope.data.scope.current_scale * p.y / 1.0; + scope.data.scope.panX = p.x + scope.data.scope.graph.width/2; + scope.data.scope.panY = p.y + scope.data.scope.graph.height/2; + scope.data.scope.first_channel.send("PanChanged", {}); + scope.data.scope.updatePanAndScale(); +} +exports.pan_animation = pan_animation; diff --git a/awx/ui/client/src/network-ui/debug.partial.svg b/awx/ui/client/src/network-ui/debug.partial.svg index 60ee70aa85..f9816f49a7 100644 --- a/awx/ui/client/src/network-ui/debug.partial.svg +++ b/awx/ui/client/src/network-ui/debug.partial.svg @@ -1,7 +1,8 @@ - + + view_port.x: {{view_port.x}} view_port.y: {{view_port.y}} view_port.width: {{view_port.width}} @@ -45,5 +46,16 @@ Inventory Toolbox State: {{inventory_toolbox_controller.state.name}} Rack Toolbox State: {{rack_toolbox_controller.state.name}} Site Toolbox State: {{site_toolbox_controller.state.name}} - - + + + + + diff --git a/awx/ui/client/src/network-ui/hotkeys.fsm.js b/awx/ui/client/src/network-ui/hotkeys.fsm.js index 17556054c8..2c310380c6 100644 --- a/awx/ui/client/src/network-ui/hotkeys.fsm.js +++ b/awx/ui/client/src/network-ui/hotkeys.fsm.js @@ -77,8 +77,13 @@ _Enabled.prototype.onKeyDown = function(controller, msg_type, $event) { scope.hide_interfaces = !scope.hide_interfaces; return; } + if($event.keyCode === 27){ + // 27 is the escape key + scope.reset_fsm_state(); + return; + } - if ($event.key === 'r') { + if ($event.key === 'r' && !($event.ctrlKey || $event.metaKey)) { scope.first_channel.send("NewDevice", new messages.NewDevice("router")); return; } @@ -103,11 +108,7 @@ _Enabled.prototype.onKeyDown = function(controller, msg_type, $event) { return; } else if ($event.key === '0') { - scope.panX = 0; - scope.panY = 0; - scope.current_scale = 1.0; - scope.updateScaledXY(); - scope.updatePanAndScale(); + scope.jump_to_animation(0, 0, 1.0); } controller.delegate_channel.send(msg_type, $event); diff --git a/awx/ui/client/src/network-ui/keybindings.fsm.js b/awx/ui/client/src/network-ui/keybindings.fsm.js new file mode 100644 index 0000000000..5087b1c5b5 --- /dev/null +++ b/awx/ui/client/src/network-ui/keybindings.fsm.js @@ -0,0 +1,59 @@ +var inherits = require('inherits'); +var fsm = require('./fsm.js'); + +function _State () { +} +inherits(_State, fsm._State); + + +function _Disabled () { + this.name = 'Disabled'; +} +inherits(_Disabled, _State); +var Disabled = new _Disabled(); +exports.Disabled = Disabled; + +function _Start () { + this.name = 'Start'; +} +inherits(_Start, _State); +var Start = new _Start(); +exports.Start = Start; + +function _Enabled () { + this.name = 'Enabled'; +} +inherits(_Enabled, _State); +var Enabled = new _Enabled(); +exports.Enabled = Enabled; + + + + +_Disabled.prototype.onBindDocument = function (controller) { + + $(document).bind("keydown", controller.scope.onKeyDown); + controller.changeState(Enabled); + +}; +_Disabled.prototype.onBindDocument.transitions = ['Enabled']; + + + +_Start.prototype.start = function (controller) { + + $(document).bind("keydown", controller.scope.onKeyDown); + controller.changeState(Enabled); + +}; +_Start.prototype.start.transitions = ['Enabled']; + + + +_Enabled.prototype.onUnbindDocument = function (controller) { + + $(document).unbind("keydown", controller.scope.onKeyDown); + controller.changeState(Disabled); + +}; +_Enabled.prototype.onUnbindDocument.transitions = ['Disabled']; diff --git a/awx/ui/client/src/network-ui/mode.fsm.js b/awx/ui/client/src/network-ui/mode.fsm.js index bf657dd82d..85bfbab285 100644 --- a/awx/ui/client/src/network-ui/mode.fsm.js +++ b/awx/ui/client/src/network-ui/mode.fsm.js @@ -88,6 +88,8 @@ _Interface.prototype.onMouseWheel = function (controller, msg_type, $event) { }; _Interface.prototype.onMouseWheel.transitions = ['Device']; +_Interface.prototype.onScaleChanged = _Interface.prototype.onMouseWheel; + _Site.prototype.start = function (controller) { controller.scope.current_mode = controller.state.name; controller.scope.rack_toolbox_controller.handle_message('Enable', {}); @@ -115,6 +117,7 @@ _Site.prototype.onMouseWheel = function (controller, msg_type, $event) { }; _Site.prototype.onMouseWheel.transitions = ['MultiSite', 'Rack']; +_Site.prototype.onScaleChanged = _Site.prototype.onMouseWheel; _Process.prototype.onMouseWheel = function (controller, msg_type, $event) { @@ -126,6 +129,8 @@ _Process.prototype.onMouseWheel = function (controller, msg_type, $event) { }; _Process.prototype.onMouseWheel.transitions = ['Device']; +_Process.prototype.onScaleChanged = _Process.prototype.onMouseWheel; + _MultiSite.prototype.start = function (controller) { controller.scope.current_mode = controller.state.name; controller.scope.site_toolbox_controller.handle_message('Enable', {}); @@ -149,6 +154,8 @@ _MultiSite.prototype.onMouseWheel = function (controller, msg_type, $event) { }; _MultiSite.prototype.onMouseWheel.transitions = ['Site']; +_MultiSite.prototype.onScaleChanged = _MultiSite.prototype.onMouseWheel; + _Device.prototype.start = function (controller) { controller.scope.current_mode = controller.state.name; controller.scope.app_toolbox_controller.handle_message('Enable', {}); @@ -175,6 +182,7 @@ _Device.prototype.onMouseWheel = function (controller, msg_type, $event) { }; _Device.prototype.onMouseWheel.transitions = ['Process', 'Interface', 'Rack']; +_Device.prototype.onScaleChanged = _Device.prototype.onMouseWheel; _Rack.prototype.start = function (controller) { controller.scope.current_mode = controller.state.name; @@ -203,3 +211,5 @@ _Rack.prototype.onMouseWheel = function (controller, msg_type, $event) { controller.delegate_channel.send(msg_type, $event); }; _Rack.prototype.onMouseWheel.transitions = ['Site', 'Device']; + +_Rack.prototype.onScaleChanged = _Rack.prototype.onMouseWheel; diff --git a/awx/ui/client/src/network-ui/models.js b/awx/ui/client/src/network-ui/models.js index be2fd5dd54..df25cc5880 100644 --- a/awx/ui/client/src/network-ui/models.js +++ b/awx/ui/client/src/network-ui/models.js @@ -1,8 +1,9 @@ -/* Copyright (c) 2017 Red Hat, Inc. */ +/* Copyright (c) 2017-2018 Red Hat, Inc. */ var fsm = require('./fsm.js'); var button = require('./button.js'); var util = require('./util.js'); var inherits = require('inherits'); +var animation_fsm = require('./animation.fsm.js'); function Device(id, name, x, y, type, host_id) { this.id = id; @@ -908,3 +909,18 @@ function TestResult(id, name, result, date, code_under_test) { this.code_under_test = code_under_test; } exports.TestResult = TestResult; + +function Animation(id, steps, data, scope, tracer, callback) { + + this.id = id; + this.steps = steps; + this.active = true; + this.frame_number_seq = util.natural_numbers(-1); + this.frame_number = 0; + this.data = data; + this.callback = callback; + this.scope = scope; + this.interval = null; + this.fsm = new fsm.FSMController(this, "animation_fsm", animation_fsm.Start, tracer); +} +exports.Animation = Animation; diff --git a/awx/ui/client/src/network-ui/move.js b/awx/ui/client/src/network-ui/move.js index d3070d3d9b..41c721289b 100644 --- a/awx/ui/client/src/network-ui/move.js +++ b/awx/ui/client/src/network-ui/move.js @@ -139,6 +139,7 @@ _Ready.prototype.onNewDevice = function (controller, msg_type, message) { device.host_id)); scope.selected_devices.push(device); device.selected = true; + scope.$emit('addSearchOption', device); controller.changeState(Placing); } }; @@ -451,6 +452,7 @@ _EditLabel.prototype.onKeyDown = function (controller, msg_type, $event) { } else if ($event.keyCode >= 186 && $event.keyCode <=222) { //Punctuation item.name += $event.key; } else if ($event.keyCode === 13) { //Enter + controller.scope.$emit('editSearchOption', item); controller.changeState(Selected2); } if (item.constructor.name === "Device") { diff --git a/awx/ui/client/features/networking/_index.less b/awx/ui/client/src/network-ui/network-nav/_index.less similarity index 97% rename from awx/ui/client/features/networking/_index.less rename to awx/ui/client/src/network-ui/network-nav/_index.less index a7a1dabf3c..a12cddfd9d 100644 --- a/awx/ui/client/features/networking/_index.less +++ b/awx/ui/client/src/network-ui/network-nav/_index.less @@ -190,7 +190,14 @@ } .Networking-searchBarContainer{ - height: 30px + height: 30px; + flex: 1 0 auto; + display: flex; + margin-top:-5px; +} + +.Networking-dropDown{ + left:-2px!important; } .Networking-searchButton{ diff --git a/awx/ui/client/features/networking/index.js b/awx/ui/client/src/network-ui/network-nav/index.js similarity index 82% rename from awx/ui/client/features/networking/index.js rename to awx/ui/client/src/network-ui/network-nav/index.js index 71c20257e9..1a05acfefd 100644 --- a/awx/ui/client/features/networking/index.js +++ b/awx/ui/client/src/network-ui/network-nav/index.js @@ -1,9 +1,9 @@ -import NetworkingController from './networking.controller'; -import NetworkingStrings from './networking.strings'; +import NetworkingController from './network.nav.controller'; +import NetworkingStrings from './network.nav.strings'; const MODULE_NAME = 'at.features.networking'; -const networkingTemplate = require('~features/networking/networking.view.html'); +const networkNavTemplate = require('~network-ui/network-nav/network.nav.view.html'); function NetworkingResolve ($stateParams, resourceData) { const resolve = { @@ -31,7 +31,7 @@ function NetworkingRun ($stateExtender, strings) { }, views: { 'networking@': { - templateUrl: networkingTemplate, + templateUrl: networkNavTemplate, controller: NetworkingController, controllerAs: 'vm' } diff --git a/awx/ui/client/src/network-ui/network-nav/network.nav.controller.js b/awx/ui/client/src/network-ui/network-nav/network.nav.controller.js new file mode 100644 index 0000000000..88bbc5824e --- /dev/null +++ b/awx/ui/client/src/network-ui/network-nav/network.nav.controller.js @@ -0,0 +1,136 @@ +/* eslint-disable */ +function NetworkingController (models, $state, $scope, strings, CreateSelect2) { + const vm = this || {}; + + const { + inventory + } = models; + + vm.strings = strings; + vm.panelTitle = `${strings.get('state.BREADCRUMB_LABEL')} | ${inventory.name}`; + vm.hostDetail = {}; + + vm.rightPanelIsExpanded = false; + vm.leftPanelIsExpanded = true; + vm.jumpToPanelExpanded = false; + vm.keyPanelExpanded = false; + $scope.devices = []; + // $scope.device = null; + vm.close = () => { + $state.go('inventories'); + }; + + vm.redirectButtonHandler = (string) => { + $scope.$broadcast('toolbarButtonEvent', string); + }; + + vm.jumpTo = (thing) => { + vm.jumpToPanelExpanded = !vm.jumpToPanelExpanded; + vm.keyPanelExpanded = false; + if (thing && typeof thing === 'string') { + $scope.$broadcast('jumpTo', thing); + } + if (thing && typeof thing === 'object') { + $scope.$broadcast('search', thing); + } + }; + + vm.key = () => { + vm.keyPanelExpanded = !vm.keyPanelExpanded; + vm.jumpToPanelExpanded = false; + }; + + $scope.$on('overall_toolbox_collapsed', () => { + vm.leftPanelIsExpanded = !vm.leftPanelIsExpanded; + }); + + $scope.$on('closeDetailsPanel', () => { + vm.rightPanelIsExpanded = false; + vm.jumpToPanelExpanded = false; + vm.keyPanelExpanded = false; + }); + + $scope.$on('showDetails', (e, data, expand) => { + if (expand) { + vm.rightPanelIsExpanded = true; + } + if (!_.has(data, 'host_id')) { + $scope.item = data; + } else { + $scope.item = data; + } + }); + + $scope.$on('instatiateSelect', (e, devices) => { + for(var i = 0; i < devices.length; i++){ + let device = devices[i]; + $scope.devices.push({ + value: device.id, + text: device.name, + label: device.name, + id: device.id + }); + } + + $("#networking-search").select2({ + width:'100%', + containerCssClass: 'Form-dropDown', + placeholder: 'SEARCH' + }); + }); + + $scope.$on('addSearchOption', (e, device) => { + $scope.devices.push({ + value: device.id, + text: device.name, + label: device.name, + id: device.id + }); + }); + + $scope.$on('editSearchOption', (e, device) => { + for(var i = 0; i < $scope.devices.length; i++){ + if(device.id === $scope.devices[i].id){ + $scope.devices[i].text = device.name; + $scope.devices[i].label = device.name; + } + } + }); + + $scope.$on('removeSearchOption', (e, device) => { + for (var i = 0; i < $scope.devices.length; i++) { + if ($scope.devices[i].id === device.id) { + $scope.devices.splice(i, 1); + } + } + }); + + $('#networking-search').on('select2:select', (e) => { + $scope.$broadcast('search', e.params.data); + }); + + $('#networking-search').on('select2:open', () => { + $('.select2-dropdown').addClass('Networking-dropDown'); + $scope.$broadcast('unbind'); + }); + + $('#networking-search').on('select2:close', () => { + setTimeout(function() { + $('.select2-container-active').removeClass('select2-container-active'); + $(':focus').blur(); + }, 1); + $scope.$broadcast('bind'); + }); + +} + +NetworkingController.$inject = [ + 'resolvedModels', + '$state', + '$scope', + 'NetworkingStrings', + 'CreateSelect2' +]; + +export default NetworkingController; +/* eslint-disable */ diff --git a/awx/ui/client/features/networking/networking.strings.js b/awx/ui/client/src/network-ui/network-nav/network.nav.strings.js similarity index 100% rename from awx/ui/client/features/networking/networking.strings.js rename to awx/ui/client/src/network-ui/network-nav/network.nav.strings.js diff --git a/awx/ui/client/features/networking/networking.view.html b/awx/ui/client/src/network-ui/network-nav/network.nav.view.html similarity index 90% rename from awx/ui/client/features/networking/networking.view.html rename to awx/ui/client/src/network-ui/network-nav/network.nav.view.html index 6d225101c4..4e90642869 100644 --- a/awx/ui/client/features/networking/networking.view.html +++ b/awx/ui/client/src/network-ui/network-nav/network.nav.view.html @@ -22,14 +22,13 @@
-
- -
- -
-
- -
+
+ + + +
-
foo-bar
+
- +
@@ -144,6 +143,17 @@ + +
+ + + + +
+ +
{{item.type}} DETAILS NOT AVAILABLE
diff --git a/awx/ui/client/src/network-ui/network.ui.app.js b/awx/ui/client/src/network-ui/network.ui.app.js index b1caa34156..6590dee7ed 100644 --- a/awx/ui/client/src/network-ui/network.ui.app.js +++ b/awx/ui/client/src/network-ui/network.ui.app.js @@ -1,5 +1,7 @@ /* Copyright (c) 2017 Red Hat, Inc. */ +import atFeaturesNetworking from './network-nav/index'; + //console.log = function () { }; var angular = require('angular'); var NetworkUIController = require('./network.ui.controller.js'); @@ -31,6 +33,7 @@ var awxNetworkUI = require('./network.ui.directive.js'); var networkUI = angular.module('networkUI', [ 'monospaced.mousewheel', + atFeaturesNetworking ]) .controller('NetworkUIController', NetworkUIController.NetworkUIController) .directive('awxNetCursor', cursor.cursor) diff --git a/awx/ui/client/src/network-ui/network.ui.controller.js b/awx/ui/client/src/network-ui/network.ui.controller.js index b27ce65587..206a8863f9 100644 --- a/awx/ui/client/src/network-ui/network.ui.controller.js +++ b/awx/ui/client/src/network-ui/network.ui.controller.js @@ -19,6 +19,8 @@ var test_fsm = require('./test.fsm.js'); var util = require('./util.js'); var models = require('./models.js'); var messages = require('./messages.js'); +var animations = require('./animations.js'); +var keybindings = require('./keybindings.fsm.js'); var svg_crowbar = require('./svg-crowbar.js'); var ReconnectingWebSocket = require('reconnectingwebsocket'); @@ -106,6 +108,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.message_id_seq = util.natural_numbers(0); $scope.stream_id_seq = util.natural_numbers(0); $scope.test_result_id_seq = util.natural_numbers(0); + $scope.animation_id_seq = util.natural_numbers(0); $scope.overall_toolbox_collapsed = false; $scope.time_pointer = -1; $scope.frame = 0; @@ -124,6 +127,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.test_results = []; $scope.test_errors = []; $scope.streams = []; + $scope.animations = []; $scope.view_port = {'x': 0, 'y': 0, 'width': 0, @@ -131,6 +135,10 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.trace_id_seq = util.natural_numbers(0); $scope.trace_order_seq = util.natural_numbers(0); $scope.trace_id = $scope.trace_id_seq(); + $scope.jump = {from_x: 0, + from_y: 0, + to_x: 0, + to_y: 0}; $scope.send_trace_message = function (message) { if (!$scope.recording) { @@ -150,9 +158,30 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, } }; + $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.trace_id)); + } + $scope.last_event = $event; + $scope.last_key = $event.key; + $scope.last_key_code = $event.keyCode; + $scope.first_channel.send('KeyDown', $event); + $scope.$apply(); + $event.preventDefault(); + }; + //Define the FSMs $scope.null_controller = new fsm.FSMController($scope, "null_fsm", null_fsm.Start, $scope); $scope.hotkeys_controller = new fsm.FSMController($scope, "hotkeys_fsm", hotkeys.Start, $scope); + $scope.keybindings_controller = new fsm.FSMController($scope, "keybindings_fsm", keybindings.Start, $scope); $scope.view_controller = new fsm.FSMController($scope, "view_fsm", view.Start, $scope); $scope.device_detail_controller = new fsm.FSMController($scope, "device_detail_fsm", device_detail_fsm.Start, $scope); $scope.move_controller = new fsm.FSMController($scope, "move_fsm", move.Start, $scope); @@ -202,21 +231,28 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, .then(function(response) { let hosts = response.data.results; for(var i = 0; i { + console.log([data, status]); ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get host data: ' + status }); }); } @@ -269,9 +305,13 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.mode_controller = new fsm.FSMController($scope, "mode_fsm", mode_fsm.Start, $scope); //Wire up the FSMs - $scope.view_controller.delegate_channel = new fsm.Channel($scope.view_controller, + $scope.keybindings_controller.delegate_channel = new fsm.Channel($scope.keybindings_controller, $scope.hotkeys_controller, $scope); + + $scope.view_controller.delegate_channel = new fsm.Channel($scope.view_controller, + $scope.keybindings_controller, + $scope); $scope.device_detail_controller.delegate_channel = new fsm.Channel($scope.device_detail_controller, $scope.view_controller, $scope); @@ -354,6 +394,24 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, g.setAttribute('transform','translate(' + $scope.panX + ',' + $scope.panY + ') scale(' + $scope.current_scale + ')'); }; + $scope.to_virtual_coordinates = function (b_x, b_y) { + var v_x = (b_x - $scope.panX) / $scope.current_scale; + var v_y = (b_y - $scope.panY) / $scope.current_scale; + return {x: v_x, y: v_y}; + }; + + $scope.to_browser_coordinates = function (v_x, v_y) { + var b_x = (v_x * $scope.current_scale) + $scope.panX; + var b_y = (v_y * $scope.current_scale) + $scope.panY; + return {x: b_x, y: b_y}; + }; + + $scope.to_pan = function (v_x, v_y) { + var p_x = v_x * $scope.current_scale * -1; + var p_y = v_y * $scope.current_scale * -1; + return {x: p_x, y: p_y}; + }; + $scope.clear_selections = function () { var i = 0; @@ -565,41 +623,22 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $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.trace_id)); - } - $scope.last_event = $event; - $scope.last_key = $event.key; - $scope.last_key_code = $event.keyCode; - $scope.first_channel.send('KeyDown', $event); - $scope.$apply(); - $event.preventDefault(); - }; - - $document.bind("keydown", $scope.onKeyDown); - // Conext Menu Button Handlers - $scope.removeContextMenu = function(){ let context_menu = $scope.context_menus[0]; context_menu.enabled = false; context_menu.x = -100000; context_menu.y = -100000; - context_menu.buttons.forEach(function(button, index){ + context_menu.buttons.forEach(function(button){ button.enabled = false; button.x = -100000; button.y = -100000; }); - } + }; + + $scope.closeDetailsPanel = function () { + $scope.$emit('closeDetailsPanel'); + }; $scope.onDetailsContextButton = function (panelBoolean) { if (!$scope.disconnected) { @@ -689,6 +728,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, index = $scope.devices.indexOf(devices[i]); if (index !== -1) { $scope.devices.splice(index, 1); + $scope.$emit('removeSearchOption', devices[i]); $scope.send_control_message(new messages.DeviceDestroy($scope.client_id, devices[i].id, devices[i].x, @@ -790,29 +830,85 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope[`on${functionName}Button`](); }); - $scope.$on('jumpTo', function(e, zoomLevel){ + $scope.$on('unbind', function(){ + $scope.first_channel.send('UnbindDocument', {}); + }); + + $scope.$on('bind', function(){ + $scope.first_channel.send('BindDocument', {}); + }); + + $scope.jump_to_animation = function(jump_to_x, jump_to_y, jump_to_scale) { + $scope.cancel_animations(); + var v_center = $scope.to_virtual_coordinates($scope.graph.width/2, $scope.graph.height/2); + //console.log({v_center: v_center}); + $scope.jump.from_x = v_center.x; + $scope.jump.from_y = v_center.y; + $scope.jump.to_x = jump_to_x; + $scope.jump.to_y = jump_to_y; + var distance = util.distance(v_center.x, v_center.y, jump_to_x, jump_to_y); + //console.log({distance: distance}); + var num_frames = 30 * Math.floor((1 + 4 * distance / (distance + 3000))); + //console.log({num_frames: num_frames}); + var scale_animation = new models.Animation($scope.animation_id_seq(), + num_frames, + { + c: -0.1, + distance: distance, + end_height: (1.0/jump_to_scale) - 1, + current_scale: $scope.current_scale, + scope: $scope + }, + $scope, + $scope, + animations.scale_animation); + $scope.animations.push(scale_animation); + var pan_animation = new models.Animation($scope.animation_id_seq(), + num_frames, + { + x2: jump_to_x, + y2: jump_to_y, + x1: v_center.x, + y1: v_center.y, + scope: $scope + }, + $scope, + $scope, + animations.pan_animation); + $scope.animations.push(pan_animation); + }; + + $scope.$on('search', function(e, device){ + + var num_frames = 30; + var searched; + for(var i = 0; i < $scope.devices.length; i++){ + if(Number(device.id) === $scope.devices[i].id){ + searched = $scope.devices[i]; + } + } + searched.selected = true; + $scope.selected_devices.push(searched); + //console.log(searched); + $scope.jump_to_animation(searched.x, searched.y, 1.0); + }); + + $scope.$on('jumpTo', function(e, zoomLevel) { + var v_center = $scope.to_virtual_coordinates($scope.graph.width/2, $scope.graph.height/2); switch (zoomLevel){ case 'site': - $scope.current_scale = 0.051; + $scope.jump_to_animation(v_center.x, v_center.y, 0.051); break; case 'rack': - $scope.current_scale = 0.11; + $scope.jump_to_animation(v_center.x, v_center.y, 0.11); break; case 'inventory': - $scope.current_scale = 0.51; + $scope.jump_to_animation(v_center.x, v_center.y, 0.51); break; case 'process': - $scope.current_scale = 1.1; + $scope.jump_to_animation(v_center.x, v_center.y, 5.1); break; } - // var new_panX = controller.scope.{{somethinghere}} - 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(); - // // controller.scope.current_scale = new_scale; - // controller.scope.panX = new_panX; - // controller.scope.panY = new_panY; - $scope.updateScaledXY(); - $scope.updatePanAndScale(); }); $scope.onDeployButton = function (button) { @@ -1691,6 +1787,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, } $scope.updateInterfaceDots(); + $scope.$emit('instatiateSelect', $scope.devices); }; $scope.updateInterfaceDots = function() { @@ -1774,7 +1871,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.$on('$destroy', function () { console.log("Network UI stopping"); - $document.unbind('keydown', $scope.onKeyDown); + $scope.first_channel.send('UnbindDocument', {}); }); $scope.update_toolbox_heights = function(){ @@ -1877,6 +1974,8 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.null_controller.state.start($scope.null_controller); $scope.hotkeys_controller.state = hotkeys.Start; $scope.hotkeys_controller.state.start($scope.hotkeys_controller); + $scope.keybindings_controller.state = keybindings.Start; + $scope.keybindings_controller.state.start($scope.keybindings_controller); $scope.view_controller.state = view.Start; $scope.view_controller.state.start($scope.view_controller); $scope.device_detail_controller.state = device_detail_fsm.Start; @@ -1927,6 +2026,15 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.rack_toolbox.items = []; $scope.site_toolbox.items = []; }; + + $scope.cancel_animations = function () { + + var i = 0; + for (i = 0; i < $scope.animations.length; i++) { + this.animations[i].fsm.handle_message('AnimationCancelled'); + } + $scope.animations = []; + }; }; exports.NetworkUIController = NetworkUIController; diff --git a/awx/ui/client/src/network-ui/network_ui.partial.svg b/awx/ui/client/src/network-ui/network_ui.partial.svg index 5c1e03981e..b102480a10 100644 --- a/awx/ui/client/src/network-ui/network_ui.partial.svg +++ b/awx/ui/client/src/network-ui/network_ui.partial.svg @@ -85,7 +85,7 @@ - + diff --git a/awx/ui/client/src/network-ui/quadrants.partial.svg b/awx/ui/client/src/network-ui/quadrants.partial.svg index e5160bf169..142b733d42 100644 --- a/awx/ui/client/src/network-ui/quadrants.partial.svg +++ b/awx/ui/client/src/network-ui/quadrants.partial.svg @@ -1,17 +1,27 @@ - - - + + + + + + + + diff --git a/awx/ui/client/src/network-ui/style.less b/awx/ui/client/src/network-ui/style.less index 9db36896ef..5b4a599df8 100644 --- a/awx/ui/client/src/network-ui/style.less +++ b/awx/ui/client/src/network-ui/style.less @@ -1,5 +1,5 @@ /* Copyright (c) 2017 Red Hat, Inc. */ - +@import 'network-nav/_index'; @font-face { font-family: 'Open Sans'; font-style: normal; diff --git a/awx/ui/client/src/network-ui/view.js b/awx/ui/client/src/network-ui/view.js index 24cfdd7bab..4c39e8754b 100644 --- a/awx/ui/client/src/network-ui/view.js +++ b/awx/ui/client/src/network-ui/view.js @@ -50,7 +50,7 @@ _Ready.prototype.onMouseDown = function (controller) { controller.scope.pressedY = controller.scope.mouseY; controller.scope.lastPanX = controller.scope.panX; controller.scope.lastPanY = controller.scope.panY; - controller.scope.$emit('closeDetailsPanel'); + controller.scope.closeDetailsPanel(); controller.changeState(Pressed); };