From a1f639bc8f261081232bab854da2829a09c97353 Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Tue, 21 Nov 2017 11:51:43 -0800 Subject: [PATCH] Adds host detail panel UI and improves toolbox UI * Changes Layers' panel's default setting to not expanded * Adds OffScreen2 state to handle the case where a toolbox is both offscreen and disabled * Adds a collapsed view of the toolbox, as well as a model for ActionIcons which is a model whose purpose is to connect the button FSM with the chevron icons that are used on the toolbox. * Adds action-icon directive * Enables/disables the icons if they're not shown * Fixes initial state of the toolboxes * Creates context menu and context menu buttons in the network UI * Adds extra vars to details panel on left hand side --- .../static/network_ui/designs/toolbox.yml | 52 ++++++- .../static/network_ui/src/button.js | 36 ++++- .../static/network_ui/src/buttons.js | 1 - .../network_ui/src/chevron.left.directive.js | 12 ++ .../network_ui/src/chevron.right.directive.js | 12 ++ .../src/context.menu.button.directive.js | 13 ++ .../network_ui/src/context.menu.directive.js | 12 ++ awx/network_ui/static/network_ui/src/fsm.js | 6 +- .../static/network_ui/src/mode.fsm.js | 23 +-- .../static/network_ui/src/models.js | 75 +++++++++- .../static/network_ui/src/network.ui.app.js | 8 + .../network_ui/src/network.ui.controller.js | 137 +++++++++++++----- .../static/network_ui/src/style.less | 73 +++++++++- .../static/network_ui/src/toolbox.fsm.js | 115 +++++++++++++++ .../network_ui/widgets/chevron_left.svg | 8 + .../network_ui/widgets/chevron_right.svg | 7 + .../network_ui/widgets/context_menu.svg | 23 +++ .../widgets/context_menu_button.svg | 13 ++ .../static/network_ui/widgets/debug.html | 4 + .../network_ui/widgets/inventory_toolbox.html | 27 +++- .../widgets/inventory_toolbox_clip_path.html | 3 +- .../static/network_ui/widgets/network_ui.html | 6 + awx/ui/client/features/networking/_index.less | 32 +++- .../networking/networking.controller.js | 10 +- .../features/networking/networking.view.html | 66 ++++++++- awx/ui/client/src/app.js | 2 +- 26 files changed, 703 insertions(+), 73 deletions(-) create mode 100644 awx/network_ui/static/network_ui/src/chevron.left.directive.js create mode 100644 awx/network_ui/static/network_ui/src/chevron.right.directive.js create mode 100644 awx/network_ui/static/network_ui/src/context.menu.button.directive.js create mode 100644 awx/network_ui/static/network_ui/src/context.menu.directive.js create mode 100644 awx/network_ui/static/network_ui/widgets/chevron_left.svg create mode 100644 awx/network_ui/static/network_ui/widgets/chevron_right.svg create mode 100644 awx/network_ui/static/network_ui/widgets/context_menu.svg create mode 100644 awx/network_ui/static/network_ui/widgets/context_menu_button.svg diff --git a/awx/network_ui/static/network_ui/designs/toolbox.yml b/awx/network_ui/static/network_ui/designs/toolbox.yml index 16233fa9fe..e62e5f502d 100644 --- a/awx/network_ui/static/network_ui/designs/toolbox.yml +++ b/awx/network_ui/static/network_ui/designs/toolbox.yml @@ -1,11 +1,19 @@ -finite_state_machine_id: 14 +finite_state_machine_id: 24 name: toolbox states: -- id: 2 +- id: 9 + label: Disabled + x: 885 + y: 141 +- id: 7 + label: OffScreen + x: 1140 + y: 217 +- id: 1 label: Selected x: 1180 y: 959 -- id: 6 +- id: 2 label: Move x: 1409 y: 741 @@ -18,18 +26,34 @@ states: x: 567 y: 431 - id: 5 - label: Start - x: 892 - y: 216 -- id: 7 label: Selecting x: 888 y: 710 -- id: 1 +- id: 6 label: Dropping x: 1358 y: 431 +- id: 8 + label: Start + x: 672 + y: 196 +- id: 10 + label: OffScreen2 + x: 1115 + y: -12 transitions: +- from_state: Ready + label: onDisable + to_state: Disabled +- from_state: OffScreen2 + label: onToggleToolbox + to_state: Disabled +- from_state: OffScreen2 + label: onEnable + to_state: OffScreen +- from_state: Ready + label: onToggleToolbox + to_state: OffScreen - from_state: Selecting label: onMouseDown to_state: Selected @@ -51,6 +75,12 @@ transitions: - from_state: Scrolling label: onMouseWheel to_state: Ready +- from_state: OffScreen + label: onToggleToolbox + to_state: Ready +- from_state: Disabled + label: onEnable + to_state: Ready - from_state: Ready label: onMouseWheel to_state: Scrolling @@ -60,3 +90,9 @@ transitions: - from_state: Move label: onMouseUp to_state: Dropping +- from_state: OffScreen + label: onDisable + to_state: OffScreen2 +- from_state: Disabled + label: onToggleToolbox + to_state: OffScreen2 diff --git a/awx/network_ui/static/network_ui/src/button.js b/awx/network_ui/static/network_ui/src/button.js index 3c7ab7cf78..d00d9eb50a 100644 --- a/awx/network_ui/static/network_ui/src/button.js +++ b/awx/network_ui/static/network_ui/src/button.js @@ -33,9 +33,16 @@ function _Pressed () { inherits(_Pressed, _State); var Pressed = new _Pressed(); exports.Pressed = Pressed; +function _Disabled () { + this.name = 'Disabled'; +} +inherits(_Disabled, _State); +var Disabled = new _Disabled(); +exports.Disabled = Disabled; +// Begin ready state _Ready.prototype.onMouseDown = function (controller) { controller.changeState(Pressed); @@ -45,6 +52,20 @@ _Ready.prototype.onMouseDown.transitions = ['Pressed']; _Ready.prototype.onTouchStart = _Ready.prototype.onMouseDown; +_Ready.prototype.start = function (controller) { + + controller.scope.enabled = true; + +}; + +_Ready.prototype.onDisable = function (controller) { + + controller.changeState(Disabled); + +}; +_Ready.prototype.onDisable.transitions = ['Disabled']; +// end ready state + _Start.prototype.start = function (controller) { @@ -57,8 +78,8 @@ _Start.prototype.start.transitions = ['Ready']; _Clicked.prototype.start = function (controller) { controller.scope.is_pressed = false; - controller.scope.callback(controller.scope); controller.changeState(Ready); + controller.scope.callback(controller.scope); }; _Clicked.prototype.start.transitions = ['Ready']; @@ -75,3 +96,16 @@ _Pressed.prototype.onMouseUp = function (controller) { _Pressed.prototype.onMouseUp.transitions = ['Clicked']; _Pressed.prototype.onTouchEnd = _Pressed.prototype.onMouseUp; + +_Disabled.prototype.onEnable = function (controller) { + + controller.changeState(Ready); + +}; +_Disabled.prototype.onEnable.transitions = ['Ready']; + +_Disabled.prototype.start = function (controller) { + + controller.scope.enabled = false; + +}; diff --git a/awx/network_ui/static/network_ui/src/buttons.js b/awx/network_ui/static/network_ui/src/buttons.js index 85bdf3a9f3..fc0f4e5a50 100644 --- a/awx/network_ui/static/network_ui/src/buttons.js +++ b/awx/network_ui/static/network_ui/src/buttons.js @@ -98,4 +98,3 @@ _ButtonPressed.prototype.onMouseUp = function (controller, msg_type, $event) { _ButtonPressed.prototype.onMouseUp.transitions = ['Ready']; _ButtonPressed.prototype.onTouchEnd = _ButtonPressed.prototype.onMouseUp; - diff --git a/awx/network_ui/static/network_ui/src/chevron.left.directive.js b/awx/network_ui/static/network_ui/src/chevron.left.directive.js new file mode 100644 index 0000000000..fd349619ed --- /dev/null +++ b/awx/network_ui/static/network_ui/src/chevron.left.directive.js @@ -0,0 +1,12 @@ +/* Copyright (c) 2017 Red Hat, Inc. */ + +function chevronLeft () { + return { + restrict: 'A', + templateUrl: '/static/network_ui/widgets/chevron_left.svg', + scope: { + actionIcon: '=' + } + }; +} +exports.chevronLeft = chevronLeft; diff --git a/awx/network_ui/static/network_ui/src/chevron.right.directive.js b/awx/network_ui/static/network_ui/src/chevron.right.directive.js new file mode 100644 index 0000000000..f24aa46923 --- /dev/null +++ b/awx/network_ui/static/network_ui/src/chevron.right.directive.js @@ -0,0 +1,12 @@ +/* Copyright (c) 2017 Red Hat, Inc. */ + +function chevronRight () { + return { + restrict: 'A', + templateUrl: '/static/network_ui/widgets/chevron_right.svg', + scope: { + actionIcon: '=' + } + }; +} +exports.chevronRight = chevronRight; diff --git a/awx/network_ui/static/network_ui/src/context.menu.button.directive.js b/awx/network_ui/static/network_ui/src/context.menu.button.directive.js new file mode 100644 index 0000000000..29a7949b6d --- /dev/null +++ b/awx/network_ui/static/network_ui/src/context.menu.button.directive.js @@ -0,0 +1,13 @@ +/* Copyright (c) 2017 Red Hat, Inc. */ + +function contextMenuButton () { + return { + restrict: 'A', + templateUrl: '/static/network_ui/widgets/context_menu_button.svg', + scope: { + contextMenuButton: '=', + contextMenu: '=' + } + }; +} +exports.contextMenuButton = contextMenuButton; diff --git a/awx/network_ui/static/network_ui/src/context.menu.directive.js b/awx/network_ui/static/network_ui/src/context.menu.directive.js new file mode 100644 index 0000000000..4f817372b1 --- /dev/null +++ b/awx/network_ui/static/network_ui/src/context.menu.directive.js @@ -0,0 +1,12 @@ +/* Copyright (c) 2017 Red Hat, Inc. */ + +function contextMenu () { + return { + restrict: 'A', + templateUrl: '/static/network_ui/widgets/context_menu.svg', + scope: { + contextMenu: '=' + } + }; +} +exports.contextMenu = contextMenu; diff --git a/awx/network_ui/static/network_ui/src/fsm.js b/awx/network_ui/static/network_ui/src/fsm.js index 3a15a6ccf2..e7692e1a80 100644 --- a/awx/network_ui/static/network_ui/src/fsm.js +++ b/awx/network_ui/static/network_ui/src/fsm.js @@ -1,9 +1,11 @@ /* Copyright (c) 2017 Red Hat, Inc. */ -function FSMController (scope, initial_state, next_controller) { +function FSMController (scope, initial_state, next_controller, name) { this.scope = scope; this.state = initial_state; - this.state.start(this); this.next_controller = next_controller; + this.name = name; + this.debug = false; + this.state.start(this); } exports.FSMController = FSMController; diff --git a/awx/network_ui/static/network_ui/src/mode.fsm.js b/awx/network_ui/static/network_ui/src/mode.fsm.js index c75b3d1a7d..4749892d8e 100644 --- a/awx/network_ui/static/network_ui/src/mode.fsm.js +++ b/awx/network_ui/static/network_ui/src/mode.fsm.js @@ -68,8 +68,12 @@ _State.prototype.start = function (controller) { _Start.prototype.start = function (controller) { - controller.changeState(Rack); + controller.scope.app_toolbox_controller.handle_message('Disable', {}); + controller.scope.inventory_toolbox_controller.handle_message('Disable', {}); + controller.scope.rack_toolbox_controller.handle_message('Disable', {}); + controller.scope.site_toolbox_controller.handle_message('Disable', {}); + controller.changeState(Rack); }; _Start.prototype.start.transitions = ['MultiSite']; @@ -86,13 +90,13 @@ _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_toolbox_controller.handle_message('Enable', {}); controller.scope.rack_controller.changeState(rack_fsm.Ready); }; _Site.prototype.end = function (controller) { - controller.scope.rack_toolbox.enabled = false; + controller.scope.rack_toolbox_controller.handle_message('Disable', {}); controller.scope.rack_controller.changeState(rack_fsm.Disable); }; @@ -124,13 +128,13 @@ _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_toolbox_controller.handle_message('Enable', {}); controller.scope.site_controller.changeState(site_fsm.Ready); }; _MultiSite.prototype.end = function (controller) { - controller.scope.site_toolbox.enabled = false; + controller.scope.site_toolbox_controller.handle_message('Disable', {}); controller.scope.site_controller.changeState(site_fsm.Disable); }; @@ -147,12 +151,12 @@ _MultiSite.prototype.onMouseWheel.transitions = ['Site']; _Device.prototype.start = function (controller) { controller.scope.current_mode = controller.state.name; - controller.scope.app_toolbox.enabled = true; + controller.scope.app_toolbox_controller.handle_message('Enable', {}); }; _Device.prototype.end = function (controller) { - controller.scope.app_toolbox.enabled = false; + controller.scope.app_toolbox_controller.handle_message('Disable', {}); }; _Device.prototype.onMouseWheel = function (controller, msg_type, $event) { @@ -174,14 +178,14 @@ _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.inventory_toolbox_controller.handle_message('Enable', {}); 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.inventory_toolbox_controller.handle_message('Disable', {}); controller.scope.move_controller.changeState(move.Disable); controller.scope.group_controller.changeState(group.Disable); }; @@ -199,4 +203,3 @@ _Rack.prototype.onMouseWheel = function (controller, msg_type, $event) { 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 1734dc66ec..47efc02fd0 100644 --- a/awx/network_ui/static/network_ui/src/models.js +++ b/awx/network_ui/static/network_ui/src/models.js @@ -289,6 +289,27 @@ Link.prototype.plength = function (x, y) { return util.pDistance(x, y, x1, y1, x2, y2); }; +function ActionIcon(name, x, y, r, callback, enabled) { + this.name = name; + this.x = x; + this.y = y; + this.r = r; + this.callback = callback; + this.is_pressed = false; + this.mouse_over = false; + this.enabled = enabled; + this.fsm = new fsm.FSMController(this, enabled ? button.Start : button.Disabled, null, name+'button_fsm'); +} +exports.ActionIcon = ActionIcon; + +ActionIcon.prototype.is_selected = function (x, y) { + + return (x > this.x - this.r && + x < this.x + this.r && + y > this.y - this.r && + y < this.y + this.r); + +}; function Button(name, x, y, width, height, callback) { this.name = name; @@ -299,7 +320,8 @@ function Button(name, x, y, width, height, callback) { this.callback = callback; this.is_pressed = false; this.mouse_over = false; - this.fsm = new fsm.FSMController(this, button.Start, null); + this.enabled = true; + this.fsm = new fsm.FSMController(this, button.Start, null, name+'button_fsm'); } exports.Button = Button; @@ -326,7 +348,8 @@ function ToggleButton(name, x, y, width, height, toggle_callback, untoggle_callb this.toggle_callback = toggle_callback; this.untoggle_callback = untoggle_callback; this.mouse_over = false; - this.fsm = new fsm.FSMController(this, button.Start, null); + this.enabled = true; + this.fsm = new fsm.FSMController(this, button.Start, null, name+'toggle_button_fsm'); } inherits(ToggleButton, Button); exports.ToggleButton = ToggleButton; @@ -342,6 +365,54 @@ ToggleButton.prototype.toggle = function () { } }; +function ContextMenu(name, x, y, width, height, callback, enabled, buttons) { + this.name = name; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.callback = callback; + this.is_pressed = false; + this.mouse_over = false; + this.enabled = enabled; + this.buttons = buttons; + this.fsm = new fsm.FSMController(this, button.Start, null, name+'button_fsm'); +} +exports.ContextMenu = ContextMenu; + + +ContextMenu.prototype.is_selected = function (x, y) { + + return (x > this.x && + x < this.x + this.width && + y > this.y && + y < this.y + this.height); + +}; + +function ContextMenuButton(name, x, y, width, height, callback) { + this.name = name; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.callback = callback; + this.is_pressed = false; + this.mouse_over = false; + this.enabled = true; + this.fsm = new fsm.FSMController(this, button.Start, null, name+'button_fsm'); +} +exports.ContextMenuButton = ContextMenuButton; + + +ContextMenuButton.prototype.is_selected = function (x, y) { + + return (x > this.x && + x < this.x + this.width && + y > this.y && + y < this.y + this.height); + +}; function Task(id, name) { this.id = id; 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 23bd9a84e2..da11b56090 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 @@ -15,6 +15,10 @@ 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 chevronRight = require('./chevron.right.directive.js'); +var chevronLeft = require('./chevron.left.directive.js'); +var contextMenu = require('./context.menu.directive.js'); +var contextMenuButton = require('./context.menu.button.directive.js'); var process = require('./process.directive.js'); var configuration = require('./configuration.directive.js'); var map = require('./map.directive.js'); @@ -49,6 +53,10 @@ var networkUI = angular.module('networkUI', [ .directive('awxNetSite', site.site) .directive('awxNetSiteIcon', siteIcon.siteIcon) .directive('awxNetRackIcon', rackIcon.rackIcon) + .directive('awxNetChevronRightIcon', chevronRight.chevronRight) + .directive('awxNetChevronLeftIcon', chevronLeft.chevronLeft) + .directive('awxNetContextMenu', contextMenu.contextMenu) + .directive('awxNetContextMenuButton', contextMenuButton.contextMenuButton) .directive('awxNetProcess', process.process) .directive('awxNetConfiguration', configuration.configuration) .directive('awxNetMap', map.map) 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 6151847486..d5ad0b59f3 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,5 +1,5 @@ /* Copyright (c) 2017 Red Hat, Inc. */ -var _ = require('lodash'); +// var _ = require('lodash'); var angular = require('angular'); var fsm = require('./fsm.js'); var null_fsm = require('./null.fsm.js'); @@ -30,7 +30,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.http = $http; $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 @@ -82,7 +82,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.last_event = null; $scope.cursor = {'x':100, 'y': 100, 'hidden': false}; - $scope.debug = {'hidden': false}; + $scope.debug = {'hidden': true}; $scope.hide_buttons = false; $scope.hide_links = false; $scope.hide_interfaces = false; @@ -95,6 +95,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $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.overall_toolbox_collapsed = false; $scope.time_pointer = -1; $scope.frame = 0; $scope.recording = false; @@ -112,27 +113,29 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, '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); + $scope.null_controller = new fsm.FSMController($scope, null_fsm.Start, null, 'null_fsm'); + $scope.hotkeys_controller = new fsm.FSMController($scope, hotkeys.Start, $scope.null_controller, 'hotkeys_fsm'); + $scope.view_controller = new fsm.FSMController($scope, view.Start, $scope.hotkeys_controller, 'null_fsm'); + $scope.device_detail_controller = new fsm.FSMController($scope, device_detail_fsm.Start, $scope.view_controller, 'device_detail_fsm'); + $scope.move_controller = new fsm.FSMController($scope, move.Start, $scope.device_detail_controller, 'move_fsm'); + $scope.link_controller = new fsm.FSMController($scope, link.Start, $scope.move_controller, 'link_fsm'); + $scope.stream_controller = new fsm.FSMController($scope, stream_fsm.Start, $scope.link_controller, 'stream_fsm'); + $scope.group_controller = new fsm.FSMController($scope, group.Start, $scope.stream_controller, 'group_fsm'); + $scope.rack_controller = new fsm.FSMController($scope, rack_fsm.Disable, $scope.group_controller, 'rack_fsm'); + $scope.site_controller = new fsm.FSMController($scope, site_fsm.Disable, $scope.rack_controller, 'site_fsm'); + $scope.time_controller = new fsm.FSMController($scope, time.Start, $scope.site_controller, 'time_fsm'); + $scope.app_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Disabled, $scope.time_controller, 'toolbox_fsm'); //App Toolbox Setup - $scope.app_toolbox = new models.ToolBox(0, 'Process', 'app', 10, 200, 150, $scope.graph.height - 200 - 100); + $scope.app_toolbox = new models.ToolBox(0, 'Process', 'app', 0, 40, 200, $scope.graph.height - 40); + $scope.app_toolbox.title_coordinates = {x: 70, y: 70}; $scope.app_toolbox.spacing = 150; $scope.app_toolbox.enabled = false; $scope.app_toolbox_controller.toolbox = $scope.app_toolbox; + $scope.app_toolbox_controller.debug = true; $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.Process(0, 'BGP', 'process', 0, 0)); $scope.app_toolbox.items.push(new models.Process(0, 'OSPF', 'process', 0, 0)); $scope.app_toolbox.items.push(new models.Process(0, 'STP', 'process', 0, 0)); @@ -142,19 +145,19 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.app_toolbox.items[i].icon = true; } - $scope.inventory_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.app_toolbox_controller); + $scope.inventory_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.app_toolbox_controller, 'inventory_toolbox_fsm'); //Inventory Toolbox Setup - $scope.inventory_toolbox = new models.ToolBox(0, 'Inventory', 'device', 10, 200, 150, $scope.graph.height - 200 - 100); + $scope.inventory_toolbox = new models.ToolBox(0, 'Inventory', 'device', 0, 40, 200, $scope.graph.height - 40); if (!$scope.disconnected) { console.log($location.protocol() + "://" + $location.host() + ':' + $location.port()); console.log($scope.my_location); - function add_host (host) { + var add_host = function(host) { console.log(host); var device = new models.Device(0, host.data.name, 0, 0, host.data.type); device.icon = true; $scope.inventory_toolbox.items.push(device); - } + }; $http.get('/api/v2/inventories/' + $scope.inventory_id + '/hosts/?format=json') .then(function(inventory) { console.log(inventory); @@ -178,26 +181,29 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, for (i=0; i < results.length; i++) { add_host(results[i]); } - console.log(['done', x]); }); }); } $scope.inventory_toolbox.spacing = 150; $scope.inventory_toolbox.enabled = true; + $scope.inventory_toolbox.title_coordinates = {x: 60, y: 70}; $scope.inventory_toolbox_controller.toolbox = $scope.inventory_toolbox; $scope.inventory_toolbox_controller.remove_on_drop = true; + $scope.inventory_toolbox_controller.debug = true; $scope.inventory_toolbox_controller.dropped_action = function (selected_item) { $scope.first_controller.handle_message("PasteDevice", new messages.PasteDevice(selected_item)); }; //End Inventory Toolbox Setup - $scope.rack_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.inventory_toolbox_controller); + $scope.rack_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.inventory_toolbox_controller, 'rack_toolbox_fsm'); //Rack Toolbox Setup - $scope.rack_toolbox = new models.ToolBox(0, 'Rack', 'rack', 10, 200, 150, $scope.graph.height - 200 - 100); + $scope.rack_toolbox = new models.ToolBox(0, 'Rack', 'rack', 0, 40, 200, $scope.graph.height - 40); + $scope.rack_toolbox.title_coordinates = {x: 80, y: 70}; $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.debug = true; $scope.rack_toolbox_controller.dropped_action = function (selected_item) { $scope.first_controller.handle_message("PasteRack", new messages.PasteRack(selected_item)); }; @@ -206,13 +212,15 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $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); + $scope.site_toolbox_controller = new fsm.FSMController($scope, toolbox_fsm.Start, $scope.rack_toolbox_controller, 'site_toolbox_fsm'); //Site Toolbox Setup - $scope.site_toolbox = new models.ToolBox(0, 'Sites', 'sites', 10, 200, 150, $scope.graph.height - 200 - 100); + $scope.site_toolbox = new models.ToolBox(0, 'Sites', 'sites', 0, 40, 200, $scope.graph.height - 40); + $scope.site_toolbox.title_coordinates = {x: 80, y: 70}; $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.debug = true; $scope.site_toolbox_controller.dropped_action = function (selected_item) { $scope.first_controller.handle_message("PasteSite", new messages.PasteSite(selected_item)); }; @@ -221,8 +229,8 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $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.buttons_controller = new fsm.FSMController($scope, buttons.Start, $scope.site_toolbox_controller, 'buttons_fsm'); + $scope.mode_controller = new fsm.FSMController($scope, mode_fsm.Start, $scope.buttons_controller, 'mode_fsm'); $scope.first_controller = $scope.mode_controller; var getMouseEventResult = function (mouseEvent) { return "(" + mouseEvent.x + ", " + mouseEvent.y + ")"; @@ -458,7 +466,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, var delta = $event.delta; var deltaX = $event.deltaX; var deltaY = $event.deltaY; - console.log([$event, delta, deltaX, deltaY]); + // console.log([$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)); } @@ -555,8 +563,42 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $event.preventDefault(); }; + // Conext Menu + $scope.onDetailsContextButton = function (button) { + console.log(button.name); + if (!$scope.disconnected) { + // this will end up being the id of the host the user clicked on + let host_id = 1; + let url = `/api/v2/hosts/${host_id}/?format=json`; + $http.get(url) + .then(function(host) { + $scope.$emit('retrievedHostData', host.data); + }) + .catch(function(httpGets) { + console.log(httpGets); + + }); + } + + }; + // Button Event Handlers // + $scope.onToggleToolboxButtonLeft = function (button) { + console.log(button.name); + $scope.first_controller.handle_message("ToggleToolbox", {}); + $scope.action_icons[0].fsm.handle_message("Disable", {}); + $scope.action_icons[1].fsm.handle_message("Enable", {}); + $scope.overall_toolbox_collapsed = !$scope.overall_toolbox_collapsed; + }; + + $scope.onToggleToolboxButtonRight = function (button) { + console.log(button.name); + $scope.first_controller.handle_message("ToggleToolbox", {}); + $scope.action_icons[0].fsm.handle_message("Enable", {}); + $scope.action_icons[1].fsm.handle_message("Disable", {}); + $scope.overall_toolbox_collapsed = !$scope.overall_toolbox_collapsed; + }; $scope.onDeployButton = function (button) { @@ -646,22 +688,41 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.group_controller.changeState(group.Ready); }; + $scope.onExportYamlButton = function (button) { console.log(button); $window.open('/network_ui/topology.yaml?topology_id=' + $scope.topology_id , '_blank'); }; + // Context Menu Buttons + $scope.context_menu_buttons = [ + new models.ContextMenuButton("Edit", 210, 200, 160, 26, $scope.onDetailsContextButton), + new models.ContextMenuButton("Details", 236, 231, 160, 26, $scope.onDetailsContextButton) + ]; + + // Context Menus + $scope.context_menus = [ + new models.ContextMenu('HOST', 210, 200, 160, 64, $scope.contextMenuCallback, true, $scope.context_menu_buttons) + ]; + + // Icons + $scope.action_icons = [ + new models.ActionIcon("chevron-left", 170, $scope.graph.height/2, 16, $scope.onToggleToolboxButtonLeft, true), + new models.ActionIcon("chevron-right", 15, $scope.graph.height/2, 16, $scope.onToggleToolboxButtonRight, false) + ]; + // Buttons + var button_offset = 200; $scope.buttons = [ - new models.Button("DEPLOY", 10, 48, 70, 30, $scope.onDeployButton), - new models.Button("DESTROY", 90, 48, 80, 30, $scope.onDestroyButton), - new models.Button("RECORD", 180, 48, 80, 30, $scope.onRecordButton), - new models.Button("EXPORT", 270, 48, 70, 30, $scope.onExportButton), - new models.Button("DISCOVER", 350, 48, 80, 30, $scope.onDiscoverButton), - new models.Button("LAYOUT", 440, 48, 70, 30, $scope.onLayoutButton), - new models.Button("CONFIGURE", 520, 48, 90, 30, $scope.onConfigureButton), - new models.Button("EXPORT YAML", 620, 48, 120, 30, $scope.onExportYamlButton), + new models.Button("DEPLOY", button_offset + 10, 48, 70, 30, $scope.onDeployButton), + new models.Button("DESTROY", button_offset + 90, 48, 80, 30, $scope.onDestroyButton), + new models.Button("RECORD", button_offset + 180, 48, 80, 30, $scope.onRecordButton), + new models.Button("EXPORT", button_offset + 270, 48, 70, 30, $scope.onExportButton), + new models.Button("DISCOVER", button_offset + 350, 48, 80, 30, $scope.onDiscoverButton), + new models.Button("LAYOUT", button_offset + 440, 48, 70, 30, $scope.onLayoutButton), + new models.Button("CONFIGURE", button_offset + 520, 48, 90, 30, $scope.onConfigureButton), + new models.Button("EXPORT YAML", button_offset + 620, 48, 120, 30, $scope.onExportYamlButton), ]; var LAYERS_X = 160; @@ -688,6 +749,8 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.layers = []; $scope.all_buttons = []; + $scope.all_buttons.extend($scope.context_menu_buttons); + $scope.all_buttons.extend($scope.action_icons); $scope.all_buttons.extend($scope.buttons); $scope.all_buttons.extend($scope.layers); diff --git a/awx/network_ui/static/network_ui/src/style.less b/awx/network_ui/static/network_ui/src/style.less index c380c2f01e..8981631bb8 100644 --- a/awx/network_ui/static/network_ui/src/style.less +++ b/awx/network_ui/static/network_ui/src/style.less @@ -33,9 +33,10 @@ @green: #5CB85C; @red: #D9534F; @light-toolbox-background: #f6f6f6; +@icon-background-hover:#337AB7; .NetworkUI { - background-color: @light-background; + background-color: @light-toolbox-background; cursor: none; } @@ -616,13 +617,25 @@ .NetworkUI__toolbox { stroke: none; - fill: @light-toolbox-background; + fill: @light-background; +} + +.NetworkUI__toolbox-collapsed{ + fill: @light-background; + stroke: @button-outline; + stroke-width: 1; + rx: 0; + stroke-dasharray: calc(~"100vh - 40px"); + stroke-dashoffset: -45; } .NetworkUI__toolbox-bezel { - stroke: @group; - stroke-width: 2; + stroke: @button-outline; + stroke-width: 1; fill: none; + rx: 0; + stroke-dasharray: calc(~"100vh - 40px"); + stroke-dashoffset: -200; } .NetworkUI__process { @@ -696,3 +709,55 @@ font-size: 8px; font-family: 'Open Sans'; } + +.NetworkUI_chevron{ + fill: @button-body-pressed; +} + +.NetworkUI_chevron--hover{ + cursor: pointer; + fill: white; +} + +.NetworkUI_iconBackground{ + fill:@button-body; +} + +.NetworkUI_iconBackground--hover{ + fill:@icon-background-hover; +} + +.NetworkUI__toolbox--title{ + fill: @dark-widget-detail; + text-transform: uppercase; + font-size: 14px; + font-weight: bold; +} + +.NetworkUI__contextMenu{ + fill: @light-background; + stroke: @button-outline; + stroke-width: 1; + +} + +.NetworkUI__contextMenuButton{ + fill: @light-background; +} + +.NetworkUI__contextMenuButtonText{ + fill: @button-text; + font-family: 'Open Sans'; + font-size: 14px; +} + +.NetworkUI__contextMenuButtonText-hover{ + fill: @button-text; + font-family: 'Open Sans'; + font-size: 14px; +} + +.NetworkUI__contextMenuButton-hover, +.NetworkUI__contextMenuButton-pressed{ + fill:@button-body-hover; +} diff --git a/awx/network_ui/static/network_ui/src/toolbox.fsm.js b/awx/network_ui/static/network_ui/src/toolbox.fsm.js index fd69ce317c..2fc2bed471 100644 --- a/awx/network_ui/static/network_ui/src/toolbox.fsm.js +++ b/awx/network_ui/static/network_ui/src/toolbox.fsm.js @@ -56,7 +56,26 @@ inherits(_Move, _State); var Move = new _Move(); exports.Move = Move; +function _OffScreen () { + this.name = 'OffScreen'; +} +inherits(_OffScreen, _State); +var OffScreen = new _OffScreen(); +exports.OffScreen = OffScreen; +function _OffScreen2 () { + this.name = 'OffScreen2'; +} +inherits(_OffScreen2, _State); +var OffScreen2 = new _OffScreen2(); +exports.OffScreen2 = OffScreen2; + +function _Disabled () { + this.name = 'Disabled'; +} +inherits(_Disabled, _State); +var Disabled = new _Disabled(); +exports.Disabled = Disabled; _Dropping.prototype.start = function (controller) { @@ -136,6 +155,10 @@ _Selecting.prototype.onMouseDown = function (controller) { }; _Selecting.prototype.onMouseDown.transitions = ['Selected', 'Ready']; +_Ready.prototype.onEnable = function () { + +}; + _Ready.prototype.onMouseDown = function (controller, msg_type, $event) { if(controller.toolbox.enabled && @@ -170,7 +193,20 @@ _Ready.prototype.onMouseWheel = function (controller, msg_type, $event) { }; _Ready.prototype.onMouseWheel.transitions = ['Scrolling']; +_Ready.prototype.onToggleToolbox = function (controller, msg_type, message) { + controller.changeState(OffScreen); + controller.next_controller.handle_message(msg_type, message); + +}; +_Ready.prototype.onToggleToolbox.transitions = ['OffScreen']; + +_Ready.prototype.onDisable = function (controller) { + + controller.changeState(Disabled); + +}; +_Ready.prototype.onDisable.transitions = ['Disabled']; _Scrolling.prototype.onMouseWheel = function (controller, msg_type, $event) { @@ -215,3 +251,82 @@ _Move.prototype.onMouseMove = function (controller) { controller.scope.pressedX = controller.scope.mouseX; controller.scope.pressedY = controller.scope.mouseY; }; + + +_OffScreen.prototype.onToggleToolbox = function (controller, msg_type, message) { + + controller.changeState(Ready); + controller.next_controller.handle_message(msg_type, message); + +}; +_OffScreen.prototype.onToggleToolbox.transitions = ['Ready']; + + +_OffScreen.prototype.start = function (controller) { + + controller.toolbox.enabled = false; + +}; + +_OffScreen.prototype.end = function (controller) { + + controller.toolbox.enabled = true; + +}; + +_OffScreen.prototype.onDisable = function (controller) { + + controller.changeState(OffScreen2); +}; +_OffScreen.prototype.onDisable.transitions = ['OffScreen2']; + +_OffScreen2.prototype.onEnable = function (controller) { + + controller.changeState(OffScreen); +}; +_OffScreen2.prototype.onEnable.transitions = ['OffScreen']; + +_OffScreen2.prototype.onDisable = function () { + +}; + +_OffScreen2.prototype.start = function (controller) { + + controller.toolbox.enabled = false; +}; + +_OffScreen2.prototype.onToggleToolbox = function (controller, msg_type, message) { + + controller.changeState(Disabled); + controller.next_controller.handle_message(msg_type, message); +}; +_OffScreen2.prototype.onToggleToolbox.transitions = ['Disabled']; + +_Disabled.prototype.onDisable = function () { + +}; + +_Disabled.prototype.onEnable = function (controller) { + + controller.changeState(Ready); +}; +_Disabled.prototype.onEnable.transitions = ['Ready']; + +_Disabled.prototype.start = function (controller) { + if(controller.toolbox !== undefined){ + controller.toolbox.enabled = false; + } +}; + +_Disabled.prototype.end = function (controller) { + + controller.toolbox.enabled = true; + +}; + +_Disabled.prototype.onToggleToolbox = function (controller, msg_type, message) { + + controller.changeState(OffScreen2); + controller.next_controller.handle_message(msg_type, message); +}; +_Disabled.prototype.onToggleToolbox.transitions = ['OffScreen2']; diff --git a/awx/network_ui/static/network_ui/widgets/chevron_left.svg b/awx/network_ui/static/network_ui/widgets/chevron_left.svg new file mode 100644 index 0000000000..bc61bf9aa0 --- /dev/null +++ b/awx/network_ui/static/network_ui/widgets/chevron_left.svg @@ -0,0 +1,8 @@ + + diff --git a/awx/network_ui/static/network_ui/widgets/chevron_right.svg b/awx/network_ui/static/network_ui/widgets/chevron_right.svg new file mode 100644 index 0000000000..47c151c6be --- /dev/null +++ b/awx/network_ui/static/network_ui/widgets/chevron_right.svg @@ -0,0 +1,7 @@ + + diff --git a/awx/network_ui/static/network_ui/widgets/context_menu.svg b/awx/network_ui/static/network_ui/widgets/context_menu.svg new file mode 100644 index 0000000000..883b532c04 --- /dev/null +++ b/awx/network_ui/static/network_ui/widgets/context_menu.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + diff --git a/awx/network_ui/static/network_ui/widgets/context_menu_button.svg b/awx/network_ui/static/network_ui/widgets/context_menu_button.svg new file mode 100644 index 0000000000..270a6287ec --- /dev/null +++ b/awx/network_ui/static/network_ui/widgets/context_menu_button.svg @@ -0,0 +1,13 @@ + + + +{{contextMenuButton.name}} + diff --git a/awx/network_ui/static/network_ui/widgets/debug.html b/awx/network_ui/static/network_ui/widgets/debug.html index e5ebf99f8a..ef362d5d77 100644 --- a/awx/network_ui/static/network_ui/widgets/debug.html +++ b/awx/network_ui/static/network_ui/widgets/debug.html @@ -42,5 +42,9 @@ Site State: {{site_controller.state.name}} Rack State: {{rack_controller.state.name}} Stream State: {{stream_controller.state.name}} + App Toolbox State: {{app_toolbox_controller.state.name}} + 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/network_ui/static/network_ui/widgets/inventory_toolbox.html b/awx/network_ui/static/network_ui/widgets/inventory_toolbox.html index 35a004f4c8..abcf0d5d88 100644 --- a/awx/network_ui/static/network_ui/widgets/inventory_toolbox.html +++ b/awx/network_ui/static/network_ui/widgets/inventory_toolbox.html @@ -1,5 +1,20 @@ + + + + + + + + + + {{toolbox.name}} + + + - + + ng-attr-height="{{toolbox.height}}"> 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 4e23e97ed0..848977db7d 100644 --- a/awx/network_ui/static/network_ui/widgets/network_ui.html +++ b/awx/network_ui/static/network_ui/widgets/network_ui.html @@ -94,6 +94,7 @@ + @@ -109,6 +110,11 @@ + + diff --git a/awx/ui/client/features/networking/_index.less b/awx/ui/client/features/networking/_index.less index 4abeb3f996..2e9b1fbc91 100644 --- a/awx/ui/client/features/networking/_index.less +++ b/awx/ui/client/features/networking/_index.less @@ -58,7 +58,6 @@ .Networking-rightPanel{ border-left: 1px solid @at-color-panel-border; - display:flex; width:400px; height: calc(~"100vh - 40px"); padding: 20px; @@ -70,3 +69,34 @@ right: 0px; background-color: @default-bg; } + + +.Networking-panelHeader { + display: flex; + height: 30px; + width:100%; +} + +.Networking-panelHeaderText { + color: @default-interface-txt; + flex: 1 0 auto; + font-size: 14px; + font-weight: bold; + margin-right: 10px; + text-transform: uppercase; +} + +.Networking-resultRow { + width: 100%; + display: flex; + padding-bottom: 10px; + flex-wrap: wrap; +} + +.Networking-resultRow--variables { + flex-direction: column; + + #cm-variables-container { + width: 100%; + } +} diff --git a/awx/ui/client/features/networking/networking.controller.js b/awx/ui/client/features/networking/networking.controller.js index b1d76f815a..cd33106bed 100644 --- a/awx/ui/client/features/networking/networking.controller.js +++ b/awx/ui/client/features/networking/networking.controller.js @@ -7,8 +7,9 @@ function NetworkingController (models, $state, $scope, strings) { vm.strings = strings; vm.panelTitle = `${strings.get('state.BREADCRUMB_LABEL')} | ${inventory.name}`; + vm.hostDetail = {}; - vm.panelIsExpanded = true; + vm.panelIsExpanded = false; vm.togglePanel = () => { vm.panelIsExpanded = !vm.panelIsExpanded; @@ -17,6 +18,13 @@ function NetworkingController (models, $state, $scope, strings) { vm.close = () => { $state.go('inventories'); }; + + $scope.$on('retrievedHostData', (e, hostData) => { + if (!vm.panelIsExpanded) { + vm.panelIsExpanded = true; + } + $scope.hostDetail = hostData; + }); } NetworkingController.$inject = [ diff --git a/awx/ui/client/features/networking/networking.view.html b/awx/ui/client/features/networking/networking.view.html index 32c74c738c..418e1da972 100644 --- a/awx/ui/client/features/networking/networking.view.html +++ b/awx/ui/client/features/networking/networking.view.html @@ -31,6 +31,68 @@
- VIEW LAYERS -
+ + + +
+
DETAILS
+ + + + + + + + + + + + +
+ + +
+ +
+ {{hostDetail.name}} +
+
+ + + +
+ + +
+ + + + + diff --git a/awx/ui/client/src/app.js b/awx/ui/client/src/app.js index 519809e584..d2374041a9 100644 --- a/awx/ui/client/src/app.js +++ b/awx/ui/client/src/app.js @@ -10,7 +10,7 @@ if ($basePath) { } import start from './app.start'; - +// import networkUI from './../network_ui/static/network_ui/src/main.js'; import portalMode from './portal-mode/main'; import systemTracking from './system-tracking/main'; import inventoriesHosts from './inventories-hosts/main';