diff --git a/awx/network_ui/admin.py b/awx/network_ui/admin.py index 57aa688909..1a99798f06 100644 --- a/awx/network_ui/admin.py +++ b/awx/network_ui/admin.py @@ -28,6 +28,10 @@ from awx.network_ui.models import Stream from awx.network_ui.models import Process +from awx.network_ui.models import Toolbox + +from awx.network_ui.models import ToolboxItem + class DeviceAdmin(admin.ModelAdmin): fields = ('topology', 'name', 'x', 'y', 'id', 'type', 'interface_id_seq', 'process_id_seq',) @@ -139,3 +143,19 @@ class ProcessAdmin(admin.ModelAdmin): admin.site.register(Process, ProcessAdmin) + + +class ToolboxAdmin(admin.ModelAdmin): + fields = ('name',) + raw_id_fields = () + + +admin.site.register(Toolbox, ToolboxAdmin) + + +class ToolboxItemAdmin(admin.ModelAdmin): + fields = ('toolbox', 'data',) + raw_id_fields = ('toolbox',) + + +admin.site.register(ToolboxItem, ToolboxItemAdmin) diff --git a/awx/network_ui/consumers.py b/awx/network_ui/consumers.py index d98d06b3cf..cb1e1ed949 100644 --- a/awx/network_ui/consumers.py +++ b/awx/network_ui/consumers.py @@ -6,6 +6,7 @@ from awx.network_ui.models import Group as DeviceGroup from awx.network_ui.models import GroupDevice as GroupDeviceMap 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.serializers import yaml_serialize_topology import urlparse from django.db.models import Q @@ -382,14 +383,19 @@ class _Persistence(object): device_map = dict(Device.objects .filter(topology_id=topology_id, id__in=[stream['from_id'], stream['to_id']]) .values_list('id', 'pk')) + logger.info("onStreamCreate %s", stream) Stream.objects.get_or_create(id=stream['id'], - label=stream['label'], + label='', from_device_id=device_map[stream['from_id']], to_device_id=device_map[stream['to_id']]) (Topology.objects .filter(topology_id=topology_id, stream_id_seq__lt=stream['id']) .update(stream_id_seq=stream['id'])) + def onCopySite(self, site, topology_id, client_id): + site_toolbox, _ = Toolbox.objects.get_or_create(name="Site") + ToolboxItem(toolbox=site_toolbox, data=json.dumps(site['site'])).save() + def onDeviceSelected(self, message_value, topology_id, client_id): 'Ignore DeviceSelected messages' pass @@ -460,6 +466,7 @@ class _Persistence(object): onKeyEvent = write_event def onGroupCreate(self, group, topology_id, client_id): + logger.info("GroupCreate %s %s %s", group['id'], group['name'], group['type']) group = transform_dict(dict(x1='x1', y1='y1', x2='x2', @@ -775,6 +782,14 @@ def ws_connect(message): message.reply_channel.send({"text": json.dumps(["Topology", topology_data])}) send_snapshot(message.reply_channel, topology_id) send_history(message.reply_channel, topology_id) + send_toolboxes(message.reply_channel) + + +def send_toolboxes(channel): + for toolbox_item in ToolboxItem.objects.filter(toolbox__name__in=['Process', 'Device', 'Rack', 'Site']).values('toolbox__name', 'data'): + item = dict(toolbox_name=toolbox_item['toolbox__name'], + data=toolbox_item['data']) + channel.send({"text": json.dumps(["ToolboxItem", item])}) def send_snapshot(channel, topology_id): @@ -921,7 +936,10 @@ def make_sheet(data, column_headers=[]): sheet = [] - n_columns = max([len(x) for x in data]) - 1 + if len(data): + n_columns = max([len(x) for x in data]) - 1 + else: + n_columns = 0 row_i = 0 sheet.append([dict(value=x, editable=False) for x in list("ABCDEFGHIJKLMNOPQRSTUVWXYZ")[0:n_columns]]) diff --git a/awx/network_ui/designs/models.yml b/awx/network_ui/designs/models.yml index 01e5362fe4..aefebe8483 100644 --- a/awx/network_ui/designs/models.yml +++ b/awx/network_ui/designs/models.yml @@ -297,6 +297,29 @@ models: name: Process x: 654 y: 778 +- fields: + - name: toolbox_id + pk: true + type: AutoField + - len: 200 + name: name + type: CharField + name: Toolbox + x: -222 + y: 627 +- fields: + - name: toolbox_item_id + pk: true + type: AutoField + - name: toolbox + ref: Toolbox + ref_field: toolbox_id + type: ForeignKey + - name: data + type: TextField + name: ToolboxItem + x: 54 + y: 664 modules: [] view: panX: 213.72955551921206 diff --git a/awx/network_ui/migrations/0021_toolbox_toolboxitem.py b/awx/network_ui/migrations/0021_toolbox_toolboxitem.py new file mode 100644 index 0000000000..201d511ab5 --- /dev/null +++ b/awx/network_ui/migrations/0021_toolbox_toolboxitem.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('network_ui', '0020_device_process_id_seq'), + ] + + operations = [ + migrations.CreateModel( + name='Toolbox', + fields=[ + ('toolbox_id', models.AutoField(serialize=False, primary_key=True)), + ('name', models.CharField(max_length=200)), + ], + ), + migrations.CreateModel( + name='ToolboxItem', + fields=[ + ('toolbox_item_id', models.AutoField(serialize=False, primary_key=True)), + ('data', models.TextField()), + ('toolbox', models.ForeignKey(to='network_ui.Toolbox')), + ], + ), + ] diff --git a/awx/network_ui/models.py b/awx/network_ui/models.py index e870a3c81c..8023944424 100644 --- a/awx/network_ui/models.py +++ b/awx/network_ui/models.py @@ -142,3 +142,16 @@ class Process(models.Model): name = models.CharField(max_length=200,) type = models.CharField(max_length=200,) id = models.IntegerField(default=0) + + +class Toolbox(models.Model): + + toolbox_id = models.AutoField(primary_key=True,) + name = models.CharField(max_length=200,) + + +class ToolboxItem(models.Model): + + toolbox_item_id = models.AutoField(primary_key=True,) + toolbox = models.ForeignKey('Toolbox',) + data = models.TextField() diff --git a/awx/network_ui/static/network_ui/src/messages.js b/awx/network_ui/static/network_ui/src/messages.js index 4862b36c9e..6b6e697cbc 100644 --- a/awx/network_ui/static/network_ui/src/messages.js +++ b/awx/network_ui/static/network_ui/src/messages.js @@ -278,6 +278,12 @@ function PasteSite(group) { } exports.PasteSite = PasteSite; +function CopySite(site) { + this.msg_type = "CopySite"; + this.site = site; +} +exports.CopySite = CopySite; + function GroupMove(sender, id, x1, y1, x2, y2, previous_x1, previous_y1, previous_x2, previous_y2) { this.msg_type = "GroupMove"; diff --git a/awx/network_ui/static/network_ui/src/models.js b/awx/network_ui/static/network_ui/src/models.js index 76f297df25..4d65328ada 100644 --- a/awx/network_ui/static/network_ui/src/models.js +++ b/awx/network_ui/static/network_ui/src/models.js @@ -28,6 +28,16 @@ function Device(id, name, x, y, type) { } exports.Device = Device; +Device.prototype.toJSON = function () { + return {id: this.id, + name: this.name, + x: this.x, + y: this.y, + type: this.type, + interfaces: this.interfaces, + processes: this.processes}; +}; + Device.prototype.is_selected = function (x, y) { return (x > this.x - this.width && @@ -51,6 +61,12 @@ function Interface(id, name) { } exports.Interface = Interface; +Interface.prototype.toJSON = function () { + + return {id: this.id, + name: this.name}; +}; + Interface.prototype.remote_interface = function () { if (this.link === null) { @@ -192,6 +208,15 @@ function Link(id, from_device, to_device, from_interface, to_interface) { } exports.Link = Link; +Link.prototype.toJSON = function () { + + return {from_device_id: this.from_device.id, + to_device_id: this.to_device.id, + from_interface_id: this.from_interface.id, + to_interface_id: this.to_interface.id, + name: this.name}; +}; + Link.prototype.is_selected = function (x, y) { // Is the distance to the mouse location less than 25 if on the label side // or 5 on the other from the shortest line to the link? @@ -349,6 +374,22 @@ function Group(id, name, type, x1, y1, x2, y2, selected) { } exports.Group = Group; +Group.prototype.toJSON = function () { + + return {id: this.id, + name: this.name, + type: this.type, + x1: this.x1, + y1: this.y1, + x2: this.x2, + y2: this.y2, + devices: this.devices, + links: this.links, + streams: this.streams, + groups: this.groups}; +}; + + Group.prototype.update_hightlighted = function (x, y) { this.highlighted = this.is_highlighted(x, y); 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 314cb394a1..960c060c91 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 @@ -20,7 +20,7 @@ var messages = require('./messages.js'); var svg_crowbar = require('../vendor/svg-crowbar.js'); var ReconnectingWebSocket = require('reconnectingwebsocket'); -var NetworkUIController = function($scope, $document, $location, $window) { +var NetworkUIController = function($scope, $document, $location, $window, $http) { window.scope = $scope; var i = 0; @@ -30,6 +30,8 @@ var NetworkUIController = function($scope, $document, $location, $window) { $scope.topology_id = $location.search().topology_id || 0; // Create a web socket to connect to the backend server + // + $scope.inventory_id = $location.search().inventory_id || 0; if (!$scope.disconnected) { $scope.control_socket = new ReconnectingWebSocket("ws://" + window.location.host + "/network_ui/topology?topology_id=" + $scope.topology_id, @@ -139,19 +141,26 @@ var NetworkUIController = function($scope, $document, $location, $window) { //Inventory Toolbox Setup $scope.inventory_toolbox = new models.ToolBox(0, 'Inventory', 'device', 10, 200, 150, $scope.graph.height - 200 - 100); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router6', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Switch6', 0, 0, 'switch')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Host6', 0, 0, 'host')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router7', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router8', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router9', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router10', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router11', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router12', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router13', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router14', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router15', 0, 0, 'router')); - $scope.inventory_toolbox.items.push(new models.Device(0, 'Router16', 0, 0, 'router')); + if (!$scope.disconnected) { + $http.get('/api/v2/inventories/' + $scope.inventory_id + '/hosts/?format=json') + .then(function(response) { + console.log(response); + + var host = null; + var i = 0; + function add_host (response) { + console.log(response); + var device = new models.Device(0, response.data.name, 0, 0, response.data.type); + device.icon = true; + $scope.inventory_toolbox.items.push(device); + } + for (i=0; i