From 050f43e3bf8cd26c34a9c147e298a928db9ba4be Mon Sep 17 00:00:00 2001 From: Jared Tabor Date: Wed, 3 Jan 2018 17:43:44 -0800 Subject: [PATCH] Improves host details panel UI * Hooks up the first two context menu buttons * Makes the rename and details menu show up wherever the user's cursor's location * Adds TopologyInventory and DeviceHost tables * Adds design for host_id on the Device table * Adds migrations for TopologyInventory * Adds host_id to Device table * Adds inventory_id and host_id tracking * Auto-closes the right hand panel if focus is directed to the canvas. * Retrieves the host details on inventory load. * Adds back support for inventory and host_id tracking * Adds host icon * Changes rack icon to new icon * Site icon replacement * Fixes host icon "hitbox", and adding debug and construction * Adds construction and debug lines for switch, router, rack, and site * Adds some error handling for REST calls, as well as alert on host detail panel. --- awx/network_ui/admin.py | 12 +- awx/network_ui/consumers.py | 53 +++-- awx/network_ui/designs/models.yml | 26 ++- .../0025_devicehost_topologyinventory.py | 30 +++ .../migrations/0026_auto_20180105_1403.py | 26 +++ awx/network_ui/models.py | 9 +- .../networking/networking.controller.js | 16 +- .../features/networking/networking.view.html | 131 ++++++------ awx/ui/client/src/network-ui/host.partial.svg | 139 ++++++++----- awx/ui/client/src/network-ui/messages.js | 6 +- awx/ui/client/src/network-ui/models.js | 9 +- awx/ui/client/src/network-ui/move.js | 54 ++++- .../src/network-ui/network.ui.controller.js | 115 +++++----- awx/ui/client/src/network-ui/rack.fsm.js | 3 +- awx/ui/client/src/network-ui/rack.partial.svg | 196 ++++++++++-------- .../src/network-ui/rack_icon.partial.svg | 183 ++++++++++------ .../client/src/network-ui/router.partial.svg | 147 ++++++------- awx/ui/client/src/network-ui/site.fsm.js | 3 +- awx/ui/client/src/network-ui/site.partial.svg | 184 ++++++++-------- .../src/network-ui/site_icon.partial.svg | 166 +++++++++------ awx/ui/client/src/network-ui/style.less | 79 +++---- .../client/src/network-ui/switch.partial.svg | 150 +++++++------- awx/ui/client/src/network-ui/view.js | 1 + 23 files changed, 1034 insertions(+), 704 deletions(-) create mode 100644 awx/network_ui/migrations/0025_devicehost_topologyinventory.py create mode 100644 awx/network_ui/migrations/0026_auto_20180105_1403.py diff --git a/awx/network_ui/admin.py b/awx/network_ui/admin.py index b79cbe2ecb..3154699382 100644 --- a/awx/network_ui/admin.py +++ b/awx/network_ui/admin.py @@ -34,9 +34,11 @@ from awx.network_ui.models import ToolboxItem from awx.network_ui.models import FSMTrace +from awx.network_ui.models import TopologyInventory + class DeviceAdmin(admin.ModelAdmin): - fields = ('topology', 'name', 'x', 'y', 'id', 'type', 'interface_id_seq', 'process_id_seq',) + fields = ('topology', 'name', 'x', 'y', 'id', 'type', 'interface_id_seq', 'process_id_seq', 'host_id',) raw_id_fields = ('topology',) @@ -169,3 +171,11 @@ class FSMTraceAdmin(admin.ModelAdmin): admin.site.register(FSMTrace, FSMTraceAdmin) + + +class TopologyInventoryAdmin(admin.ModelAdmin): + fields = ('topology', 'inventory_id',) + raw_id_fields = ('topology',) + + +admin.site.register(TopologyInventory, TopologyInventoryAdmin) diff --git a/awx/network_ui/consumers.py b/awx/network_ui/consumers.py index 51151be65c..de5a0c262b 100644 --- a/awx/network_ui/consumers.py +++ b/awx/network_ui/consumers.py @@ -9,13 +9,12 @@ from awx.network_ui.models import DataSheet, DataBinding, DataType from awx.network_ui.models import Process, Stream from awx.network_ui.models import Toolbox, ToolboxItem from awx.network_ui.models import FSMTrace -from awx.network_ui.serializers import yaml_serialize_topology +from awx.network_ui.models import TopologyInventory from awx.network_ui.messages import MultipleMessage, InterfaceCreate, LinkCreate, to_dict import urlparse from django.core.exceptions import ObjectDoesNotExist from django.db.models import Q from collections import defaultdict -from django.conf import settings import math import random import logging @@ -249,8 +248,19 @@ def parse_topology_id(data): return topology_id +def parse_inventory_id(data): + inventory_id = data.get('inventory_id', ['null']) + try: + inventory_id = int(inventory_id[0]) + except ValueError: + inventory_id = None + if not inventory_id: + inventory_id = None + return inventory_id + # Persistence + class _Persistence(object): def handle(self, message): @@ -270,7 +280,7 @@ class _Persistence(object): message_value = data[1] try: message_type_id = MessageType.objects.get(name=message_type).pk - except ObjectDoesNotExist, e: + except ObjectDoesNotExist: logger.warning("Unsupported message %s", message_type) return TopologyHistory(topology_id=topology_id, @@ -292,11 +302,15 @@ class _Persistence(object): y='y', name='name', type='type', - id='id'), device) + id='id', + host_id='host_id'), device) + logger.info("Device %s", device) + print ("Device %s" % device) d, _ = Device.objects.get_or_create(topology_id=topology_id, id=device['id'], defaults=device) d.x = device['x'] d.y = device['y'] d.type = device['type'] + d.host_id = device['host_id'] d.save() (Topology.objects .filter(topology_id=topology_id, device_id_seq__lt=device['id']) @@ -516,13 +530,13 @@ class _Persistence(object): GroupDeviceMap.objects.bulk_create(new_entries) def onFSMTrace(self, message_value, diagram_id, client_id): - FSMTrace(trace_session_id=message_value['trace_id'], - fsm_name=message_value['fsm_name'], - from_state=message_value['from_state'], - to_state=message_value['to_state'], - order=message_value['order'], - client_id=client_id, - message_type=message_value['recv_message_type'] or "none").save() + FSMTrace(trace_session_id=message_value['trace_id'], + fsm_name=message_value['fsm_name'], + from_state=message_value['from_state'], + to_state=message_value['to_state'], + order=message_value['order'], + client_id=client_id, + message_type=message_value['recv_message_type'] or "none").save() persistence = _Persistence() @@ -777,9 +791,19 @@ def ansible_disconnect(message): def ws_connect(message): # Accept connection data = urlparse.parse_qs(message.content['query_string']) - topology_id = parse_topology_id(data) - topology, created = Topology.objects.get_or_create( - topology_id=topology_id, defaults=dict(name="topology", scale=1.0, panX=0, panY=0)) + inventory_id = parse_inventory_id(data) + topology_ids = list(TopologyInventory.objects.filter(inventory_id=inventory_id).values_list('topology_id', flat=True)) + print ("topology_ids", topology_ids) + topology_id = 0 + if len(topology_ids) > 0: + topology_id = topology_ids[0] + print ("topology_id", topology_id) + if topology_id: + topology = Topology.objects.get(topology_id=topology_id) + else: + topology = Topology(name="topology", scale=1.0, panX=0, panY=0) + topology.save() + TopologyInventory(inventory_id=inventory_id, topology_id=topology.topology_id).save() topology_id = topology.topology_id message.channel_session['topology_id'] = topology_id Group("topology-%s" % topology_id).add(message.reply_channel) @@ -903,6 +927,7 @@ def console_printer(message): # Tester channel events + @channel_session def tester_connect(message): data = urlparse.parse_qs(message.content['query_string']) diff --git a/awx/network_ui/designs/models.yml b/awx/network_ui/designs/models.yml index e0d6303b50..d1384fc837 100644 --- a/awx/network_ui/designs/models.yml +++ b/awx/network_ui/designs/models.yml @@ -28,6 +28,9 @@ models: - default: 0 name: process_id_seq type: IntegerField + - default: 0 + name: host_id + type: IntegerField name: Device x: 348 y: 124 @@ -153,8 +156,8 @@ models: - name: id type: IntegerField name: Interface - x: 600 - y: 243 + x: 1157 + y: 337 - fields: - name: group_id pk: true @@ -349,8 +352,21 @@ models: name: FSMTrace x: -872 y: 507 +- fields: + - name: topology_inventory_id + pk: true + type: AutoField + - name: topology + ref: Topology + ref_field: topology_id + type: ForeignKey + - name: inventory_id + type: IntegerField + name: TopologyInventory + x: -226 + y: -19 modules: [] view: - panX: 213.72955551921206 - panY: 189.44695909464298 - scaleXY: 0.6900000000000002 + panX: 213.729555519212 + panY: 189.446959094643 + scaleXY: 0.69 diff --git a/awx/network_ui/migrations/0025_devicehost_topologyinventory.py b/awx/network_ui/migrations/0025_devicehost_topologyinventory.py new file mode 100644 index 0000000000..ba167af327 --- /dev/null +++ b/awx/network_ui/migrations/0025_devicehost_topologyinventory.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('network_ui', '0024_auto_20171213_1949'), + ] + + operations = [ + migrations.CreateModel( + name='DeviceHost', + fields=[ + ('device_host_id', models.AutoField(serialize=False, primary_key=True)), + ('host_id', models.IntegerField()), + ('device', models.ForeignKey(to='network_ui.Device')), + ], + ), + migrations.CreateModel( + name='TopologyInventory', + fields=[ + ('topology_inventory_id', models.AutoField(serialize=False, primary_key=True)), + ('inventory_id', models.IntegerField()), + ('topology', models.ForeignKey(to='network_ui.Topology')), + ], + ), + ] diff --git a/awx/network_ui/migrations/0026_auto_20180105_1403.py b/awx/network_ui/migrations/0026_auto_20180105_1403.py new file mode 100644 index 0000000000..052f021c1c --- /dev/null +++ b/awx/network_ui/migrations/0026_auto_20180105_1403.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('network_ui', '0025_devicehost_topologyinventory'), + ] + + operations = [ + migrations.RemoveField( + model_name='devicehost', + name='device', + ), + migrations.AddField( + model_name='device', + name='host_id', + field=models.IntegerField(default=0), + ), + migrations.DeleteModel( + name='DeviceHost', + ), + ] diff --git a/awx/network_ui/models.py b/awx/network_ui/models.py index e454c88a3d..7c3cee39dd 100644 --- a/awx/network_ui/models.py +++ b/awx/network_ui/models.py @@ -1,4 +1,3 @@ -# Copyright (c) 2017 Red Hat, Inc from django.db import models @@ -13,6 +12,7 @@ class Device(models.Model): type = models.CharField(max_length=200,) interface_id_seq = models.IntegerField(default=0) process_id_seq = models.IntegerField(default=0) + host_id = models.IntegerField(default=0) def __unicode__(self): return self.name @@ -168,3 +168,10 @@ class FSMTrace(models.Model): client = models.ForeignKey('Client',) trace_session_id = models.IntegerField(default=0) order = models.IntegerField(default=0) + + +class TopologyInventory(models.Model): + + topology_inventory_id = models.AutoField(primary_key=True,) + topology = models.ForeignKey('Topology',) + inventory_id = models.IntegerField() diff --git a/awx/ui/client/features/networking/networking.controller.js b/awx/ui/client/features/networking/networking.controller.js index cd33106bed..10bb7f40e3 100644 --- a/awx/ui/client/features/networking/networking.controller.js +++ b/awx/ui/client/features/networking/networking.controller.js @@ -7,7 +7,7 @@ function NetworkingController (models, $state, $scope, strings) { vm.strings = strings; vm.panelTitle = `${strings.get('state.BREADCRUMB_LABEL')} | ${inventory.name}`; - vm.hostDetail = {}; + vm.hostDetail = false; vm.panelIsExpanded = false; @@ -19,11 +19,19 @@ function NetworkingController (models, $state, $scope, strings) { $state.go('inventories'); }; - $scope.$on('retrievedHostData', (e, hostData) => { - if (!vm.panelIsExpanded) { + $scope.$on('closeDetailsPanel', () => { + vm.panelIsExpanded = false; + }); + + $scope.$on('retrievedHostData', (e, hostData, expand) => { + if (expand) { vm.panelIsExpanded = true; } - $scope.hostDetail = hostData; + if (_.isEmpty(hostData)) { + $scope.hostDetail = false; + } else { + $scope.hostDetail = hostData; + } }); } diff --git a/awx/ui/client/features/networking/networking.view.html b/awx/ui/client/features/networking/networking.view.html index 418e1da972..9153809aad 100644 --- a/awx/ui/client/features/networking/networking.view.html +++ b/awx/ui/client/features/networking/networking.view.html @@ -26,73 +26,84 @@ + +
+ +
- - -
-
DETAILS
- - - - - - - - - - - - +
+ NO HOST DETAIL
- - -
- -
- {{hostDetail.name}} + + +
+ +
+
+ DETAILS +
+
+ + + +
+ +
+ {{hostDetail.name}} +
+ + + +
+ + +
+
- - - -
- - -
- - -
- - +
+
+ + + + + diff --git a/awx/ui/client/src/network-ui/host.partial.svg b/awx/ui/client/src/network-ui/host.partial.svg index 4b93d2a586..192be94dee 100644 --- a/awx/ui/client/src/network-ui/host.partial.svg +++ b/awx/ui/client/src/network-ui/host.partial.svg @@ -1,60 +1,87 @@ + + + + + - - - - + + + + + - - - - - - - - - - - - - - - {{item.name}} - {{item.name}}{{item.edit_label?'_':''}} - + + + + + + + + + + + + + + + + + + + + + + + + + + + {{item.name}} + + {{item.name}}{{item.edit_label?'_':''}} + diff --git a/awx/ui/client/src/network-ui/messages.js b/awx/ui/client/src/network-ui/messages.js index ef80dd1511..9ab0f0c11e 100644 --- a/awx/ui/client/src/network-ui/messages.js +++ b/awx/ui/client/src/network-ui/messages.js @@ -17,7 +17,7 @@ function DeviceMove(sender, id, x, y, previous_x, previous_y) { } exports.DeviceMove = DeviceMove; -function DeviceCreate(sender, id, x, y, name, type) { +function DeviceCreate(sender, id, x, y, name, type, host_id) { this.msg_type = "DeviceCreate"; this.sender = sender; this.id = id; @@ -25,10 +25,11 @@ function DeviceCreate(sender, id, x, y, name, type) { this.y = y; this.name = name; this.type = type; + this.host_id = host_id; } exports.DeviceCreate = DeviceCreate; -function DeviceDestroy(sender, id, previous_x, previous_y, previous_name, previous_type) { +function DeviceDestroy(sender, id, previous_x, previous_y, previous_name, previous_type, previous_host_id) { this.msg_type = "DeviceDestroy"; this.sender = sender; this.id = id; @@ -36,6 +37,7 @@ function DeviceDestroy(sender, id, previous_x, previous_y, previous_name, previo this.previous_y = previous_y; this.previous_name = previous_name; this.previous_type = previous_type; + this.previous_host_id = previous_host_id; } exports.DeviceDestroy = DeviceDestroy; diff --git a/awx/ui/client/src/network-ui/models.js b/awx/ui/client/src/network-ui/models.js index f57b207339..edb9405012 100644 --- a/awx/ui/client/src/network-ui/models.js +++ b/awx/ui/client/src/network-ui/models.js @@ -4,12 +4,13 @@ var button = require('./button.js'); var util = require('./util.js'); var inherits = require('inherits'); -function Device(id, name, x, y, type) { +function Device(id, name, x, y, type, host_id) { this.id = id; + this.host_id = host_id ? host_id: 0; this.name = name; this.x = x; this.y = y; - this.height = type === "host" ? 15 : 50; + this.height = type === "host" ? 30 : 50; this.width = 50; this.size = 50; this.type = type; @@ -374,9 +375,9 @@ function ContextMenu(name, x, y, width, height, callback, enabled, buttons, trac this.callback = callback; this.is_pressed = false; this.mouse_over = false; - this.enabled = enabled; + this.enabled = false; this.buttons = buttons; - this.fsm = new fsm.FSMController(this, "button_fsm", button.Start, tracer); + this.fsm = new fsm.FSMController(this, "button_fsm", enabled ? button.Start : button.Disabled, tracer); } exports.ContextMenu = ContextMenu; diff --git a/awx/ui/client/src/network-ui/move.js b/awx/ui/client/src/network-ui/move.js index 3f1fbb70cf..a7e0c85591 100644 --- a/awx/ui/client/src/network-ui/move.js +++ b/awx/ui/client/src/network-ui/move.js @@ -76,6 +76,14 @@ var Placing = new _Placing(); exports.Placing = Placing; +function _ContextMenu () { + this.name = 'ContextMenu'; +} +inherits(_ContextMenu, _State); +var ContextMenu = new _ContextMenu(); +exports.ContextMenu = ContextMenu; + + _State.prototype.onUnselectAll = function (controller, msg_type, $event) { controller.changeState(Ready); @@ -135,7 +143,8 @@ _Ready.prototype.onNewDevice = function (controller, msg_type, message) { device.x, device.y, device.name, - device.type)); + device.type, + device.host_id)); scope.selected_devices.push(device); device.selected = true; controller.changeState(Placing); @@ -161,14 +170,16 @@ _Ready.prototype.onPasteDevice = function (controller, msg_type, message) { message.device.name, scope.scaledX, scope.scaledY, - message.device.type); + message.device.type, + message.device.host_id); scope.devices.push(device); c_messages.push(new messages.DeviceCreate(scope.client_id, device.id, device.x, device.y, device.name, - device.type)); + device.type, + device.host_id)); 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); @@ -331,7 +342,8 @@ _Selected2.prototype.onKeyDown = function (controller, msg_type, $event) { devices[i].x, devices[i].y, devices[i].name, - devices[i].type)); + devices[i].type, + devices[i].host_id)); } for (j = 0; j < all_links.length; j++) { if (all_links[j].to_device === devices[i] || @@ -457,10 +469,20 @@ _Move.prototype.onMouseDown = function (controller) { }; _Move.prototype.onMouseDown.transitions = ['Selected1']; -_Selected3.prototype.onMouseUp = function (controller) { - controller.changeState(EditLabel); +_Selected3.prototype.onMouseUp = function (controller, msg_type, $event) { + let context_menu = controller.scope.context_menus[0]; + context_menu.enabled = true; + context_menu.x = $event.x; + context_menu.y = $event.y; + context_menu.buttons.forEach(function(button, index){ + button.x = $event.x; + let menuPaddingTop = 5; + button.y = $event.y + menuPaddingTop + (button.height * index); + }); + + controller.changeState(ContextMenu); }; -_Selected3.prototype.onMouseUp.transitions = ['EditLabel']; +_Selected3.prototype.onMouseUp.transitions = ['ContextMenu']; _Selected3.prototype.onTouchEnd = function (controller) { controller.changeState(Selected2); @@ -545,3 +567,21 @@ _Placing.prototype.onMouseMove = function (controller) { _Placing.prototype.onMouseMove.transitions = ['Move']; + + + +_ContextMenu.prototype.onLabelEdit = function (controller) { + + controller.changeState(EditLabel); + +}; +_ContextMenu.prototype.onLabelEdit.transitions = ['EditLabel']; + +_ContextMenu.prototype.onMouseDown = function (controller) { + + var item = controller.scope.context_menus[0]; + item.enabled = false; + controller.changeState(Ready); + +}; +_ContextMenu.prototype.onMouseDown.transitions = ['Ready']; 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 06fafe8669..93931b0fed 100644 --- a/awx/ui/client/src/network-ui/network.ui.controller.js +++ b/awx/ui/client/src/network-ui/network.ui.controller.js @@ -21,7 +21,8 @@ var messages = require('./messages.js'); var svg_crowbar = require('./svg-crowbar.js'); var ReconnectingWebSocket = require('reconnectingwebsocket'); -var NetworkUIController = function($scope, $document, $location, $window, $http, $q) { +var NetworkUIController = function($scope, $document, $location, $window, $http, + $q, $state, ProcessErrors) { window.scope = $scope; var i = 0; @@ -31,16 +32,16 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $scope.api_token = ''; $scope.disconnected = false; - $scope.topology_id = $location.search().topology_id || 0; + $scope.topology_id = 0; // Create a web socket to connect to the backend server - // - $scope.inventory_id = $location.search().inventory_id || 1; + + $scope.inventory_id = $state.params.inventory_id; $scope.initial_messages = []; if (!$scope.disconnected) { - $scope.control_socket = new ReconnectingWebSocket("wss://" + window.location.host + "/network_ui/topology?topology_id=" + $scope.topology_id, - null, - {debug: false, reconnectInterval: 300}); + $scope.control_socket = new ReconnectingWebSocket("wss://" + window.location.host + "/network_ui/topology?inventory_id=" + $scope.inventory_id, + null, + {debug: false, reconnectInterval: 300}); } else { $scope.control_socket = { on_message: util.noop @@ -170,42 +171,27 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, } $scope.inventory_toolbox_controller = new fsm.FSMController($scope, "toolbox_fsm", toolbox_fsm.Start, $scope); - function add_host (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); - } + //Inventory Toolbox Setup $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); - $http.get('/api/v2/inventories/' + $scope.inventory_id + '/hosts/?format=json') - .then(function(inventory) { - console.log(inventory); - console.log(inventory.headers()); - - var host = null; - var i = 0; - var httpGets = []; - for (i=0; i < inventory.data.results.length;i++) { - host = inventory.data.results[i]; - console.log($location.protocol() + "://" + $location.host() + ':' + $location.port()); - console.log($scope.my_location); - httpGets.push($http.get('/api/v2/hosts/'+ host.id + '/variable_data/?format=json')); + $http.get('/api/v2/inventories/' + $scope.inventory_id + '/hosts/') + .then(function(response) { + let hosts = response.data.results; + for(var i = 0; i { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get host data: ' + status }); }); } $scope.inventory_toolbox.spacing = 150; @@ -429,7 +415,7 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, // 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)) { + 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]; @@ -638,27 +624,40 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $event.preventDefault(); }; - // Conext Menu - $scope.onDetailsContextButton = function (button) { - console.log(button.name); + $scope.$watchCollection('selected_items', function(){ + $scope.onDetailsContextButton(false); + }); + + // Conext Menu Button Handlers + $scope.onDetailsContextButton = function (panelBoolean) { 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); - - }); + if ($scope.selected_items.length === 1){ + if ($scope.selected_items[0].host_id === 0){ + $scope.$emit('retrievedHostData', {}, panelBoolean !== null ? panelBoolean: true); + } + if ($scope.selected_items[0].host_id !== 0){ + let host_id = $scope.selected_items[0].host_id; + let url = `/api/v2/hosts/${host_id}/`; + $http.get(url) + .then(function(response) { + let host = response.data; + $scope.$emit('retrievedHostData', host, panelBoolean !== null ? panelBoolean: true); + $scope.context_menus[0].enabled = false; + }) + .catch(({data, status}) => { + ProcessErrors($scope, data, status, null, { hdr: 'Error!', msg: 'Failed to get host data: ' + status }); + }); + } + } } + }; + $scope.onRenameContextButton = function (button) { + $scope.context_menus[0].enabled = false; + $scope.first_channel.send("LabelEdit", {}); }; // Button Event Handlers - // $scope.onToggleToolboxButtonLeft = function (button) { console.log(button.name); $scope.first_channel.send("ToggleToolbox", {}); @@ -771,13 +770,13 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, // Context Menu Buttons $scope.context_menu_buttons = [ - new models.ContextMenuButton("Edit", 210, 200, 160, 26, $scope.onDetailsContextButton, $scope), + new models.ContextMenuButton("Rename", 210, 200, 160, 26, $scope.onRenameContextButton, $scope), new models.ContextMenuButton("Details", 236, 231, 160, 26, $scope.onDetailsContextButton, $scope) ]; // Context Menus $scope.context_menus = [ - new models.ContextMenu('HOST', 210, 200, 160, 64, $scope.contextMenuCallback, true, $scope.context_menu_buttons, $scope) + new models.ContextMenu('HOST', 210, 200, 160, 64, $scope.contextMenuCallback, false, $scope.context_menu_buttons, $scope) ]; // Icons @@ -976,7 +975,8 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, data.name, data.x, data.y, - data.type); + data.type, + data.host_id); $scope.device_id_seq = util.natural_numbers(data.id); $scope.devices.push(device); }; @@ -1274,7 +1274,8 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, data.previous_x, data.previous_y, data.previous_name, - data.previous_type); + data.previous_type, + data.previous_host_id); $scope.create_device(inverted_data); } @@ -1306,7 +1307,6 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, $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, inventory_id: $scope.inventory_id}); }; $scope.onDeviceSelected = function(data) { @@ -1474,7 +1474,8 @@ var NetworkUIController = function($scope, $document, $location, $window, $http, device.name, device.x, device.y, - device.type); + device.type, + device.host_id); new_device.interface_seq = util.natural_numbers(device.interface_id_seq); new_device.process_id_seq = util.natural_numbers(device.process_id_seq); $scope.devices.push(new_device); diff --git a/awx/ui/client/src/network-ui/rack.fsm.js b/awx/ui/client/src/network-ui/rack.fsm.js index af6216329a..de010c51e7 100644 --- a/awx/ui/client/src/network-ui/rack.fsm.js +++ b/awx/ui/client/src/network-ui/rack.fsm.js @@ -135,7 +135,8 @@ _Ready.prototype.onPasteRack = function (controller, msg_type, message) { device.x, device.y, device.name, - device.type)); + device.type, + device.host_id)); for (j=0; j < message.group.devices[i].interfaces.length; j++) { intf = new models.Interface(message.group.devices[i].interfaces[j].id, message.group.devices[i].interfaces[j].name); intf.device = device; diff --git a/awx/ui/client/src/network-ui/rack.partial.svg b/awx/ui/client/src/network-ui/rack.partial.svg index 6297494107..e86debee66 100644 --- a/awx/ui/client/src/network-ui/rack.partial.svg +++ b/awx/ui/client/src/network-ui/rack.partial.svg @@ -1,88 +1,118 @@ - - + + + + + + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - {{item.name}} -{{item.name}}{{item.edit_label?'_':''}} - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{item.name}} + + {{item.name}}{{item.edit_label?'_':''}} + diff --git a/awx/ui/client/src/network-ui/rack_icon.partial.svg b/awx/ui/client/src/network-ui/rack_icon.partial.svg index 233d146114..f3666ee240 100644 --- a/awx/ui/client/src/network-ui/rack_icon.partial.svg +++ b/awx/ui/client/src/network-ui/rack_icon.partial.svg @@ -1,71 +1,116 @@ - - - - - - - - - - - - - - - - - - - - - - - {{item.name}} - {{item.name}}{{item.edit_label?'_':''}} - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{item.name}} + + {{item.name}}{{item.edit_label?'_':''}} + diff --git a/awx/ui/client/src/network-ui/router.partial.svg b/awx/ui/client/src/network-ui/router.partial.svg index c523912ba1..fd6835ba97 100644 --- a/awx/ui/client/src/network-ui/router.partial.svg +++ b/awx/ui/client/src/network-ui/router.partial.svg @@ -1,78 +1,79 @@ + + + + + + + + + + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - {{item.name}} - {{item.name}}{{item.edit_label?'_':''}} - - + + + + + + + + + + + + + + + + + + + {{item.name}} + {{item.name}}{{item.edit_label?'_':''}} + diff --git a/awx/ui/client/src/network-ui/site.fsm.js b/awx/ui/client/src/network-ui/site.fsm.js index b8a120c5ee..7ea69a9f39 100644 --- a/awx/ui/client/src/network-ui/site.fsm.js +++ b/awx/ui/client/src/network-ui/site.fsm.js @@ -138,7 +138,8 @@ _Ready.prototype.onPasteSite = function (controller, msg_type, message) { device.x, device.y, device.name, - device.type)); + device.type, + device.host_id)); for (j=0; j < message.group.devices[i].interfaces.length; j++) { intf = new models.Interface(message.group.devices[i].interfaces[j].id, message.group.devices[i].interfaces[j].name); intf.device = device; diff --git a/awx/ui/client/src/network-ui/site.partial.svg b/awx/ui/client/src/network-ui/site.partial.svg index 2934190778..b6a11ffb7d 100644 --- a/awx/ui/client/src/network-ui/site.partial.svg +++ b/awx/ui/client/src/network-ui/site.partial.svg @@ -1,91 +1,103 @@ - - + + + + + + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - {{item.name}} -{{item.name}}{{item.edit_label?'_':''}} - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{item.name}} + {{item.name}}{{item.edit_label?'_':''}} + diff --git a/awx/ui/client/src/network-ui/site_icon.partial.svg b/awx/ui/client/src/network-ui/site_icon.partial.svg index cfa980057d..4b49b20fd2 100644 --- a/awx/ui/client/src/network-ui/site_icon.partial.svg +++ b/awx/ui/client/src/network-ui/site_icon.partial.svg @@ -1,72 +1,100 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{item.name}} + + {{item.name}}{{item.edit_label?'_':''}} - {{item.name}} -{{item.name}}{{item.edit_label?'_':''}} diff --git a/awx/ui/client/src/network-ui/style.less b/awx/ui/client/src/network-ui/style.less index 8981631bb8..9d2589ccc5 100644 --- a/awx/ui/client/src/network-ui/style.less +++ b/awx/ui/client/src/network-ui/style.less @@ -31,9 +31,13 @@ @button-body-pressed: #848992; @button-text-pressed: #ffffff; @green: #5CB85C; +@host-green: #449D44; @red: #D9534F; +@blue: #337AB7; @light-toolbox-background: #f6f6f6; -@icon-background-hover:#337AB7; +@rack-orange: #F0AD4E; +@site-orange: #EC971F; +@icon-background-hover:@blue; .NetworkUI { background-color: @light-toolbox-background; @@ -114,14 +118,17 @@ } .NetworkUI__router { - fill: @widget-body; - stroke: @dark-widget-detail; - stroke-width: 2; + fill: @green; +} + +.NetworkUI__router--background{ + fill: @light-background; } .NetworkUI__router--selected { stroke: @selected-blue; stroke-width: 4; + fill:@light-background; } .NetworkUI__router--remote-selected { @@ -134,16 +141,6 @@ stroke-width: 4; } -.NetworkUI__router line { - stroke: @light-widget-detail; - stroke-width: 20; -} - -.NetworkUI__router polygon { - fill: @light-widget-detail; - stroke: none; -} - .NetworkUI__router-text { fill: @button-text; font-family: 'Open Sans'; @@ -156,14 +153,17 @@ .NetworkUI__switch { - fill: @widget-body; - stroke: @dark-widget-detail; - stroke-width: 2; + fill: @blue; +} + +.NetworkUI__switch--background{ + fill: @light-background; } .NetworkUI__switch--selected { stroke: @selected-blue; stroke-width: 10; + fill:@light-background; } .NetworkUI__switch--remote-selected { @@ -197,19 +197,15 @@ } .NetworkUI__rack { - fill: @widget-body; - stroke: @dark-widget-detail; - stroke-width: 2; + fill: @rack-orange; } -.NetworkUI__rack-background { +.NetworkUI__rack--background { fill: @light-background; - stroke: @light-background; - stroke-width: 2; } .NetworkUI__rack--selected { - fill: @selected-blue; + fill: @light-background; stroke: @selected-blue; stroke-width: 10; } @@ -252,20 +248,33 @@ stroke-width: 2; } +.NetworkUI__site--fill0{ + fill:@site-orange; +} + +.NetworkUI__site--fill1{ + fill:none; + stroke:@light-background; + stroke-width:2; + stroke-miterlimit:10; +} + +.NetworkUI__site--fill2{ + fill:@light-background; +} + .NetworkUI__site--network { fill: @dark-widget-detail; stroke: @dark-widget-detail; stroke-width: 2; } -.NetworkUI__site-background { +.NetworkUI__site--background { fill: @light-background; - stroke: @light-background; - stroke-width: 2; } .NetworkUI__site--selected { - fill: @selected-blue; + fill: @light-background; stroke: @selected-blue; stroke-width: 10; } @@ -411,19 +420,15 @@ } .NetworkUI__host { - fill: @widget-body; - stroke: @dark-widget-detail; - stroke-width: 2; + fill: @host-green; } -.NetworkUI__host-background { +.NetworkUI__host--background { fill: @light-background; - stroke: @light-background; - stroke-width: 2; } .NetworkUI__host--selected { - fill: @selected-blue; + fill: @light-background; stroke: @selected-blue; stroke-width: 10; } @@ -746,13 +751,13 @@ } .NetworkUI__contextMenuButtonText{ - fill: @button-text; + fill: #333; //@button-text; font-family: 'Open Sans'; font-size: 14px; } .NetworkUI__contextMenuButtonText-hover{ - fill: @button-text; + fill: #333; //@button-text; font-family: 'Open Sans'; font-size: 14px; } diff --git a/awx/ui/client/src/network-ui/switch.partial.svg b/awx/ui/client/src/network-ui/switch.partial.svg index 3017c66d82..3b7ed184f2 100644 --- a/awx/ui/client/src/network-ui/switch.partial.svg +++ b/awx/ui/client/src/network-ui/switch.partial.svg @@ -1,79 +1,81 @@ + + + + + + + + + + - - - - + + + + + - - - - - - - - - - - - - - - - - - - - - {{item.name}} - {{item.name}}{{item.edit_label?'_':''}} - + + + + + + + + + + + + + + + + + + + + {{item.name}} + {{item.name}}{{item.edit_label?'_':''}} + diff --git a/awx/ui/client/src/network-ui/view.js b/awx/ui/client/src/network-ui/view.js index b984a3030c..c2cb2fd235 100644 --- a/awx/ui/client/src/network-ui/view.js +++ b/awx/ui/client/src/network-ui/view.js @@ -50,6 +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.changeState(Pressed); };