class ServicesModal { constructor(coreRest, coreNetwork) { this.coreRest = coreRest; this.coreNetwork = coreNetwork; this.$servicesModal = $('#services-modal'); this.$servicesForm = this.$servicesModal.find('form'); this.$serviceGroup = $('#service-group'); this.$servicesList = $('#services-list'); this.$servicesButton = $('#services-button'); this.defaultServices = { mdr: new Set(["zebra", "OSPFv3MDR", "IPForward"]), PC: new Set(["DefaultRoute"]), prouter: new Set(["zebra", "OSPFv2", "OSPFv3", "IPForward"]), router: new Set(["zebra", "OSPFv2", "OSPFv3", "IPForward"]), host: new Set(["DefaultRoute", "SSH"]) }; this.node = null; this.nodeDefaults = null; this.serviceGroups = null; this.serviceOptions = new Map(); this.$currentGroup = null; this.groupChange(); this.saveClicked(); } async show(nodeId) { this.node = this.coreNetwork.getCoreNode(nodeId); if (this.node.services.length) { this.nodeDefaults = new Set(this.node.services); } else { this.nodeDefaults = this.defaultServices[this.node.model] || new Set(); } this.serviceGroups = await coreRest.getServices(nodeId); // clear data this.$serviceGroup.html(''); this.$servicesList.html(''); this.serviceOptions.clear(); this.$servicesModal.find('.modal-title').text(`Services: ${this.node.name}`); for (let group in this.serviceGroups) { const $option = $('<option>', {value: group, text: group}); this.$serviceGroup.append($option); const services = this.serviceGroups[group]; console.log('services: ', services); const $formGroup = $('<div>', {class: 'form-group d-none'}); this.serviceOptions.set(group, $formGroup); this.$servicesList.append($formGroup); for (let service of services) { const checked = this.nodeDefaults.has(service); const $formCheck = $('<div>', {class: 'form-check'}); const $input = $('<input>', { class: 'form-check-input', type: 'checkbox', value: service, name: service, checked }); const $label = $('<label>', {class: 'form-check-label', text: service}); $formCheck.append($input); $formCheck.append($label); $formGroup.append($formCheck); } } this.$serviceGroup.change(); this.$servicesModal.modal('show'); } groupChange() { const self = this; this.$serviceGroup.on('change', function () { const group = $(this).val(); if (self.$currentGroup) { self.$currentGroup.addClass('d-none'); } self.$currentGroup = self.serviceOptions.get(group); self.$currentGroup.removeClass('d-none'); }); } saveClicked() { const self = this; this.$servicesButton.click(function () { let services = self.$servicesForm.serializeArray(); services = services.map(x => x.value); console.log('services save clicked: ', services); self.node.services = services; self.$servicesModal.modal('hide'); }); } } class SessionsModal { constructor(coreRest, coreNetwork, onJoin) { this.coreRest = coreRest; this.coreNetwork = coreNetwork; this.onJoin = onJoin; this.$sessionsModal = $('#sessions-modal'); this.$sessionsTable = $('#sessions-table'); this.onShow(); this.onClick(); } onClick() { const self = this; this.$sessionsTable.on('click', 'td', function (event) { const sessionId = $(this).parent('tr').data('session'); console.log('clicked session to join: ', sessionId); if (sessionId === self.coreRest.currentSession) { console.log('same session, not changing'); } else { self.coreNetwork.joinSession(sessionId) .then(function (session) { self.onJoin(session); self.$sessionsModal.modal('hide'); }) .catch(function (err) { console.log('join session error: ', err); }); } }); } onShow() { const self = this; this.$sessionsModal.on('shown.bs.modal', function () { console.log('show sessions'); self.$sessionsTable.find('tbody tr').remove(); self.coreRest.getSessions() .then(function (response) { const sessions = response.sessions; for (let session of sessions) { console.log('show sessions: ', session); const $idCell = $('<td>', {text: session.id}); const $nodeCell = $('<td>', {text: session.nodes}); const stateName = self.coreRest.getStateName(session.state); const $stateCell = $('<td>', {text: stateName}); const $row = $('<tr>', {class: 'session-join', 'data-session': session.id}); $row.append([$idCell, $nodeCell, $stateCell]); self.$sessionsTable.find('tbody').append($row); } }) .catch(function (err) { console.log('error getting sessions: ', err); }); }); } } class NodeContext { constructor(coreNetwork, coreRest, nodeEditModal, servicesModal) { this.coreNetwork = coreNetwork; this.coreRest = coreRest; this.nodeEditModal = nodeEditModal; this.servicesModal = servicesModal; this.$nodeContext = $('#node-context'); this.$linkRfButton = $('#node-linkrf-button'); this.$deleteButton = $('#node-delete-button'); this.onClick(); } show(nodeId, x, y) { const node = this.coreNetwork.getCoreNode(nodeId); console.log('context node: ', node); this.coreRest.isRunning() .then(isRunning => { if (isRunning) { this.$deleteButton.attr('disabled', 'disabled'); } else { this.$deleteButton.removeAttr('disabled'); } console.log('node type: ', node.type); if (node.type === CoreNodeHelper.wlanNode) { this.$linkRfButton.removeClass('d-none'); } else { this.$linkRfButton.addClass('d-none'); } this.$nodeContext.data('node', nodeId); this.$nodeContext.css({ position: 'absolute', left: x, top: y }); this.$nodeContext.removeClass('d-none'); }) .catch(function(err) { console.log('error checking is session is running: ', err); }); } hide() { this.$nodeContext.addClass('d-none'); } onClick() { const self = this; this.$nodeContext.click(function (event) { self.$nodeContext.addClass('d-none'); console.log('node context click: ', event); const nodeId = self.$nodeContext.data('node'); const $target = $(event.target); const option = $target.data('option'); console.log('node context: ', nodeId, option); switch (option) { case 'edit': self.nodeEditModal.show(nodeId); break; case 'services': self.servicesModal.show(nodeId) .catch(function (err) { console.log('error showing services modal: ', err); }); break; case 'linkrf': console.log('linking all routers'); self.coreNetwork.linkAllRouters(nodeId); break; case 'delete': self.coreNetwork.deleteNode(nodeId); break; } }); } } class NodeEditModal { constructor(coreNetwork) { this.coreNetwork = coreNetwork; this.$nodeEditModal = $('#nodeedit-modal'); this.$nodeEditButton = $('#nodeedit-button'); this.onClick(); } show(nodeId) { const node = this.coreNetwork.getCoreNode(nodeId); this.$nodeEditModal.data('node', nodeId); this.$nodeEditModal.find('.modal-title').text(`Edit Node: ${node.name}`); this.$nodeEditModal.find('#node-name').val(node.name); this.$nodeEditModal.modal('show'); } onClick() { const self = this; this.$nodeEditButton.click(function () { const $form = self.$nodeEditModal.find('form'); const formData = formToJson($form); console.log('node edit data: ', formData); const nodeId = self.$nodeEditModal.data('node'); const node = self.coreNetwork.nodes.get(nodeId); if (formData.name) { node.label = formData.name; node.coreNode.name = formData.name; self.coreNetwork.nodes.update(node); } self.$nodeEditModal.modal('hide'); }); } } class EdgeContext { constructor(coreNetwork, edgeEditModal) { this.coreNetwork = coreNetwork; this.edgeEditModal = edgeEditModal; this.$edgeContext = $('#edge-context'); this.onClick(); } show(edgeId, x, y) { const edge = this.coreNetwork.edges.get(edgeId); console.log('context edge: ', edge); this.$edgeContext.data('edge', edgeId); this.$edgeContext.css({ position: 'absolute', left: x, top: y }); this.$edgeContext.removeClass('d-none'); } hide() { this.$edgeContext.addClass('d-none'); } onClick() { const self = this; this.$edgeContext.click(function (event) { self.$edgeContext.addClass('d-none'); console.log('edge context click: ', event); const edgeId = self.$edgeContext.data('edge'); const $target = $(event.target); const option = $target.data('option'); console.log('edge context: ', edgeId, option); if (option === 'edit') { self.edgeEditModal.show(edgeId); } }); } } class EdgeEditModal { constructor(coreNetwork, coreRest) { this.coreNetwork = coreNetwork; this.coreRest = coreRest; this.$linkEditButton = $('#linkedit-button'); this.$linkEditModal = $('#linkedit-modal'); this.onClick(); } show(edgeId) { // populate form with current link data const edge = this.coreNetwork.edges.get(edgeId); const link = edge.link; this.$linkEditModal.data('link', edgeId); this.$linkEditModal.find('#link-bandwidth').val(link.bandwidth); this.$linkEditModal.find('#link-delay').val(link.delay); this.$linkEditModal.find('#link-per').val(link.loss); this.$linkEditModal.find('#link-dup').val(link.duplicate); this.$linkEditModal.find('#link-jitter').val(link.jitter); // set modal name and show this.$linkEditModal.find('.modal-title').text('Edit Edge'); this.$linkEditModal.modal('show'); } onClick() { const self = this; this.$linkEditButton.click(function () { const $form = self.$linkEditModal.find('form'); const formData = {}; $form.serializeArray().map(function (x) { let value = x.value; if (value === '') { value = null; } else if (!isNaN(value)) { value = parseInt(value); } formData[x.name] = value; }); console.log('link edit data: ', formData); const edgeId = self.$linkEditModal.data('link'); const edge = self.coreNetwork.edges.get(edgeId); const link = edge.link; link.bandwidth = formData.bandwidth; link.delay = formData.delay; link.duplicate = formData.duplicate; link.loss = formData.loss; link.jitter = formData.jitter; coreRest.isRunning() .then(function (isRunning) { if (isRunning) { const linkEdit = link.json(); linkEdit.interface_one = linkEdit.interface_one.id; linkEdit.interface_two = linkEdit.interface_two.id; return self.coreRest.editLink(linkEdit); } }) .then(function (response) { console.log('link edit success'); }) .catch(function (err) { console.log('error editing link: ', err); }); self.$linkEditModal.modal('hide'); }); } } class InfoPanel { constructor(coreNetwork) { this.coreNetwork = coreNetwork; this.$infoCard = $('#info-card'); this.$infoCardTable = $('#info-card-table'); this.$infoCardHeader = $('#info-card-header'); } addInfoTable(name, value) { const $nameCell = $('<td>', {text: name}); const $valueCell = $('<td>', {text: value}); const $row = $('<tr>').append([$nameCell, $valueCell]); this.$infoCardTable.find('tbody').append($row); } show() { this.$infoCard.removeClass('visible invisible'); this.$infoCard.addClass('visible'); } hide() { this.$infoCard.removeClass('visible invisible'); this.$infoCard.addClass('invisible'); } addInterfaceInfo(nodeInterface) { this.addInfoTable('Interface', `eth${nodeInterface.id}`); if (nodeInterface.ip4) { this.addInfoTable('IP4', `${nodeInterface.ip4}/${nodeInterface.ip4mask}`); } if (nodeInterface.ip6) { this.addInfoTable('IP6', `${nodeInterface.ip6}/${nodeInterface.ip6mask}`); } } showNode(nodeId) { const node = coreNetwork.getCoreNode(nodeId); this.$infoCardHeader.text(node.name); this.$infoCardTable.find('tbody tr').remove(); this.addInfoTable('Model', node.model); this.addInfoTable('X', node.x); this.addInfoTable('Y', node.y); for (let interfaceId in node.interfaces) { const nodeInterface = node.interfaces[interfaceId]; console.log('node interface: ', nodeInterface); this.addInterfaceInfo(nodeInterface); } this.show(); } showEdge(edgeId) { const edge = coreNetwork.edges.get(edgeId); const link = edge.link; const nodeOne = coreNetwork.getCoreNode(link.nodeOne); const nodeTwo = coreNetwork.getCoreNode(link.nodeTwo); console.log('clicked edge: ', link); this.$infoCard.addClass('visible'); this.$infoCardHeader.text('Edge'); this.$infoCardTable.find('tbody tr').remove(); const interfaceOne = link.interfaceOne; if (interfaceOne) { this.addInfoTable(nodeOne.name, null); this.addInterfaceInfo(interfaceOne); } const interfaceTwo = link.interfaceTwo; if (interfaceTwo) { this.addInfoTable(nodeTwo.name, null); this.addInterfaceInfo(interfaceTwo); } this.addInfoTable('Bandwidth', edge.link.bandwidth); this.addInfoTable('Delay', edge.link.delay); this.addInfoTable('Duplicate', edge.link.duplicate); this.addInfoTable('Loss', edge.link.loss); this.addInfoTable('Jitter', edge.link.jitter); this.show(); } }