Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 1 | /* |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 2 | * Copyright 2019-present Open Networking Foundation |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the 'License'); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an 'AS IS' BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 16 | import { |
| 17 | Component, |
| 18 | OnDestroy, |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 19 | OnInit, SimpleChange, |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 20 | ViewChild |
| 21 | } from '@angular/core'; |
Sean Condon | 55c3053 | 2018-10-29 12:26:57 +0000 | [diff] [blame] | 22 | import * as d3 from 'd3'; |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 23 | import { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 24 | FnService, IconService, |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 25 | KeysService, |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 26 | KeysToken, LionService, |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 27 | LogService, |
| 28 | PrefsService, |
| 29 | SvgUtilService, |
| 30 | WebSocketService, |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 31 | ZoomService |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 32 | } from 'gui2-fw-lib'; |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 33 | import {InstanceComponent} from '../panel/instance/instance.component'; |
| 34 | import {SummaryComponent} from '../panel/summary/summary.component'; |
| 35 | import {DetailsComponent} from '../panel/details/details.component'; |
| 36 | import {BackgroundSvgComponent} from '../layer/backgroundsvg/backgroundsvg.component'; |
| 37 | import {ForceSvgComponent} from '../layer/forcesvg/forcesvg.component'; |
| 38 | import {TopologyService} from '../topology.service'; |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 39 | import { |
| 40 | HostLabelToggle, |
| 41 | LabelToggle, |
| 42 | UiElement |
| 43 | } from '../layer/forcesvg/models'; |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 44 | import {ToolbarComponent} from '../panel/toolbar/toolbar.component'; |
| 45 | import {TrafficService} from '../traffic.service'; |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 46 | import {ZoomableDirective} from '../layer/zoomable.directive'; |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 47 | |
| 48 | /** |
| 49 | * ONOS GUI Topology View |
| 50 | * |
| 51 | * This Topology View component is the top level component in a hierarchy that |
| 52 | * comprises the whole Topology View |
| 53 | * |
| 54 | * There are three main parts (panels, graphical and breadcrumbs) |
| 55 | * The panel hierarchy |
| 56 | * |-- Instances Panel (shows ONOS instances) |
| 57 | * |-- Summary Panel (summary of ONOS) |
| 58 | * |-- Toolbar Panel (the toolbar) |
| 59 | * |-- Details Panel (when a node is selected in the Force graphical view (see below)) |
| 60 | * |
| 61 | * The graphical hierarchy contains |
| 62 | * Topology (this) |
| 63 | * |-- No Devices Connected (only of there are no nodes to show) |
| 64 | * |-- Zoom Layer (everything beneath this can be zoomed and panned) |
| 65 | * |-- Background (container for any backgrounds - can be toggled on and off) |
| 66 | * |-- Map |
| 67 | * |-- Forces (all of the nodes and links laid out by a d3.force simulation) |
| 68 | * |
| 69 | * The breadcrumbs |
| 70 | * |-- Breadcrumb (in region view a way of navigating back up through regions) |
| 71 | */ |
| 72 | @Component({ |
| 73 | selector: 'onos-topology', |
| 74 | templateUrl: './topology.component.html', |
| 75 | styleUrls: ['./topology.component.css'] |
| 76 | }) |
Sean Condon | aa4366d | 2018-11-02 14:29:01 +0000 | [diff] [blame] | 77 | export class TopologyComponent implements OnInit, OnDestroy { |
| 78 | // These are references to the components inserted in the template |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 79 | @ViewChild(InstanceComponent) instance: InstanceComponent; |
| 80 | @ViewChild(SummaryComponent) summary: SummaryComponent; |
| 81 | @ViewChild(DetailsComponent) details: DetailsComponent; |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 82 | @ViewChild(ToolbarComponent) toolbar: ToolbarComponent; |
Sean Condon | aa4366d | 2018-11-02 14:29:01 +0000 | [diff] [blame] | 83 | @ViewChild(BackgroundSvgComponent) background: BackgroundSvgComponent; |
| 84 | @ViewChild(ForceSvgComponent) force: ForceSvgComponent; |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 85 | @ViewChild(ZoomableDirective) zoomDirective: ZoomableDirective; |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 86 | |
| 87 | flashMsg: string = ''; |
| 88 | prefsState = {}; |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 89 | hostLabelIdx: number = 1; |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 90 | showBackground: boolean = false; |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 91 | lionFn; // Function |
Sean Condon | 55c3053 | 2018-10-29 12:26:57 +0000 | [diff] [blame] | 92 | |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 93 | constructor( |
| 94 | protected log: LogService, |
| 95 | protected fs: FnService, |
| 96 | protected ks: KeysService, |
| 97 | protected sus: SvgUtilService, |
| 98 | protected ps: PrefsService, |
Sean Condon | 55c3053 | 2018-10-29 12:26:57 +0000 | [diff] [blame] | 99 | protected wss: WebSocketService, |
Sean Condon | aa4366d | 2018-11-02 14:29:01 +0000 | [diff] [blame] | 100 | protected zs: ZoomService, |
| 101 | protected ts: TopologyService, |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 102 | protected trs: TrafficService, |
| 103 | protected is: IconService, |
| 104 | private lion: LionService, |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 105 | ) { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 106 | if (this.lion.ubercache.length === 0) { |
| 107 | this.lionFn = this.dummyLion; |
| 108 | this.lion.loadCbs.set('topo-toolbar', () => this.doLion()); |
| 109 | } else { |
| 110 | this.doLion(); |
| 111 | } |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 112 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 113 | this.is.loadIconDef('bird'); |
| 114 | this.is.loadIconDef('active'); |
| 115 | this.is.loadIconDef('uiAttached'); |
| 116 | this.is.loadIconDef('m_switch'); |
| 117 | this.is.loadIconDef('m_roadm'); |
| 118 | this.is.loadIconDef('m_router'); |
| 119 | this.is.loadIconDef('m_uiAttached'); |
| 120 | this.is.loadIconDef('m_endstation'); |
| 121 | this.is.loadIconDef('m_ports'); |
| 122 | this.is.loadIconDef('m_summary'); |
| 123 | this.is.loadIconDef('m_details'); |
| 124 | this.is.loadIconDef('m_map'); |
| 125 | this.is.loadIconDef('m_cycleLabels'); |
| 126 | this.is.loadIconDef('m_resetZoom'); |
| 127 | this.is.loadIconDef('m_eqMaster'); |
| 128 | this.is.loadIconDef('m_unknown'); |
| 129 | this.is.loadIconDef('m_allTraffic'); |
| 130 | this.is.loadIconDef('deviceTable'); |
| 131 | this.is.loadIconDef('flowTable'); |
| 132 | this.is.loadIconDef('portTable'); |
| 133 | this.is.loadIconDef('groupTable'); |
| 134 | this.is.loadIconDef('meterTable'); |
| 135 | this.is.loadIconDef('triangleUp'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 136 | this.log.debug('Topology component constructed'); |
| 137 | } |
| 138 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 139 | /** |
| 140 | * Static functions must come before member variables |
| 141 | * @param index |
| 142 | */ |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 143 | private static deviceLabelFlashMessage(index: number): string { |
| 144 | switch (index) { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 145 | case 0: return 'fl_device_labels_hide'; |
| 146 | case 1: return 'fl_device_labels_show_friendly'; |
| 147 | case 2: return 'fl_device_labels_show_id'; |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 148 | } |
| 149 | } |
| 150 | |
| 151 | private static hostLabelFlashMessage(index: number): string { |
| 152 | switch (index) { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 153 | case 0: return 'fl_host_labels_hide'; |
| 154 | case 1: return 'fl_host_labels_show_friendly'; |
| 155 | case 2: return 'fl_host_labels_show_ip'; |
| 156 | case 3: return 'fl_host_labels_show_mac'; |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 157 | } |
| 158 | } |
| 159 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 160 | /** |
| 161 | * Pass the list of Key Commands to the KeyService, and initialize the Topology |
| 162 | * Service - which communicates with through the WebSocket to the ONOS server |
| 163 | * to get the nodes and links. |
| 164 | */ |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 165 | ngOnInit() { |
| 166 | this.bindCommands(); |
Sean Condon | aa4366d | 2018-11-02 14:29:01 +0000 | [diff] [blame] | 167 | // The components from the template are handed over to TopologyService here |
| 168 | // so that WebSocket responses can be passed back in to them |
| 169 | // The handling of the WebSocket call is delegated out to the Topology |
| 170 | // Service just to compartmentalize things a bit |
| 171 | this.ts.init(this.instance, this.background, this.force); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 172 | this.log.debug('Topology component initialized'); |
| 173 | } |
| 174 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 175 | /** |
| 176 | * When this component is being stopped, disconnect the TopologyService from |
| 177 | * the WebSocket |
| 178 | */ |
Sean Condon | aa4366d | 2018-11-02 14:29:01 +0000 | [diff] [blame] | 179 | ngOnDestroy() { |
| 180 | this.ts.destroy(); |
| 181 | this.log.debug('Topology component destroyed'); |
| 182 | } |
| 183 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 184 | /** |
| 185 | * When ever a toolbar button is clicked, an event is sent up from toolbar |
| 186 | * component which is caught and passed on to here. |
| 187 | * @param name The name of the button that was clicked |
| 188 | */ |
| 189 | toolbarButtonClicked(name: string) { |
| 190 | switch (name) { |
| 191 | case 'instance-tog': |
| 192 | this.toggleInstancePanel(); |
| 193 | break; |
| 194 | case 'summary-tog': |
| 195 | this.toggleSummary(); |
| 196 | break; |
| 197 | case 'details-tog': |
| 198 | this.toggleDetails(); |
| 199 | break; |
| 200 | case 'hosts-tog': |
| 201 | this.toggleHosts(); |
| 202 | break; |
| 203 | case 'offline-tog': |
| 204 | this.toggleOfflineDevices(); |
| 205 | break; |
| 206 | case 'ports-tog': |
| 207 | this.togglePorts(); |
| 208 | break; |
| 209 | case 'bkgrnd-tog': |
| 210 | this.toggleBackground(); |
| 211 | break; |
| 212 | case 'cycleLabels-btn': |
| 213 | this.cycleDeviceLabels(); |
| 214 | break; |
| 215 | case 'cycleHostLabel-btn': |
| 216 | this.cycleHostLabels(); |
| 217 | break; |
| 218 | case 'resetZoom-btn': |
| 219 | this.resetZoom(); |
| 220 | break; |
| 221 | case 'eqMaster-btn': |
| 222 | this.equalizeMasters(); |
| 223 | break; |
| 224 | case 'cancel-traffic': |
| 225 | this.cancelTraffic(); |
| 226 | break; |
| 227 | case 'all-traffic': |
| 228 | this.monitorAllTraffic(); |
| 229 | break; |
| 230 | default: |
| 231 | this.log.warn('Unhandled Toolbar action', name); |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | /** |
| 236 | * The list of key strokes that will be active in the Topology View. |
| 237 | * |
| 238 | * This action map is passed to the KeyService through the bindCommands() |
| 239 | * when this component is being initialized |
| 240 | */ |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 241 | actionMap() { |
| 242 | return { |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 243 | A: [() => {this.monitorAllTraffic(); }, 'Monitor all traffic'], |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 244 | L: [() => {this.cycleDeviceLabels(); }, 'Cycle device labels'], |
| 245 | B: [(token) => {this.toggleBackground(token); }, 'Toggle background'], |
| 246 | D: [(token) => {this.toggleDetails(token); }, 'Toggle details panel'], |
| 247 | I: [(token) => {this.toggleInstancePanel(token); }, 'Toggle ONOS Instance Panel'], |
| 248 | O: [() => {this.toggleSummary(); }, 'Toggle the Summary Panel'], |
| 249 | R: [() => {this.resetZoom(); }, 'Reset pan / zoom'], |
| 250 | P: [(token) => {this.togglePorts(token); }, 'Toggle Port Highlighting'], |
| 251 | E: [() => {this.equalizeMasters(); }, 'Equalize mastership roles'], |
| 252 | X: [() => {this.resetNodeLocation(); }, 'Reset Node Location'], |
| 253 | U: [() => {this.unpinNode(); }, 'Unpin node (mouse over)'], |
| 254 | H: [() => {this.toggleHosts(); }, 'Toggle host visibility'], |
| 255 | M: [() => {this.toggleOfflineDevices(); }, 'Toggle offline visibility'], |
| 256 | dot: [() => {this.toggleToolbar(); }, 'Toggle Toolbar'], |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 257 | 0: [() => {this.cancelTraffic(); }, 'Cancel traffic monitoring'], |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 258 | 'shift-L': [() => {this.cycleHostLabels(); }, 'Cycle host labels'], |
| 259 | |
| 260 | // -- instance color palette debug |
Sean Condon | 55c3053 | 2018-10-29 12:26:57 +0000 | [diff] [blame] | 261 | 9: () => { |
| 262 | this.sus.cat7().testCard(d3.select('svg#topo2')); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 263 | }, |
| 264 | |
| 265 | esc: this.handleEscape, |
| 266 | |
| 267 | // TODO update after adding in Background Service |
| 268 | // topology overlay selections |
| 269 | // F1: function () { t2tbs.fnKey(0); }, |
| 270 | // F2: function () { t2tbs.fnKey(1); }, |
| 271 | // F3: function () { t2tbs.fnKey(2); }, |
| 272 | // F4: function () { t2tbs.fnKey(3); }, |
| 273 | // F5: function () { t2tbs.fnKey(4); }, |
| 274 | // |
| 275 | // _keyListener: t2tbs.keyListener.bind(t2tbs), |
| 276 | |
| 277 | _helpFormat: [ |
| 278 | ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B'], |
| 279 | ['X', 'Z', 'N', 'L', 'shift-L', 'U', 'R', 'E', 'dot'], |
| 280 | [], // this column reserved for overlay actions |
| 281 | ], |
| 282 | }; |
| 283 | } |
| 284 | |
| 285 | |
| 286 | bindCommands(additional?: any) { |
| 287 | |
| 288 | const am = this.actionMap(); |
| 289 | const add = this.fs.isO(additional); |
| 290 | |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 291 | this.ks.keyBindings(am); |
| 292 | |
| 293 | this.ks.gestureNotes([ |
| 294 | ['click', 'Select the item and show details'], |
| 295 | ['shift-click', 'Toggle selection state'], |
| 296 | ['drag', 'Reposition (and pin) device / host'], |
| 297 | ['cmd-scroll', 'Zoom in / out'], |
| 298 | ['cmd-drag', 'Pan'], |
| 299 | ]); |
| 300 | } |
| 301 | |
| 302 | handleEscape() { |
| 303 | |
| 304 | if (false) { |
| 305 | // TODO: Cancel show mastership |
| 306 | // TODO: Cancel Active overlay |
| 307 | // TODO: Reinstate with components |
| 308 | } else { |
| 309 | this.log.debug('Handling escape'); |
| 310 | // } else if (t2rs.deselectAllNodes()) { |
| 311 | // // else if we have node selections, deselect them all |
| 312 | // // (work already done) |
| 313 | // } else if (t2rs.deselectLink()) { |
| 314 | // // else if we have a link selection, deselect it |
| 315 | // // (work already done) |
| 316 | // } else if (t2is.isVisible()) { |
| 317 | // // If the instance panel is visible, close it |
| 318 | // t2is.toggle(); |
| 319 | // } else if (t2sp.isVisible()) { |
| 320 | // // If the summary panel is visible, close it |
| 321 | // t2sp.toggle(); |
| 322 | } |
| 323 | } |
| 324 | |
| 325 | |
| 326 | |
| 327 | updatePrefsState(what, b) { |
| 328 | this.prefsState[what] = b ? 1 : 0; |
| 329 | this.ps.setPrefs('topo2_prefs', this.prefsState); |
| 330 | } |
| 331 | |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 332 | protected cycleDeviceLabels() { |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 333 | const old: LabelToggle = this.force.deviceLabelToggle; |
| 334 | const next = LabelToggle.next(old); |
| 335 | this.force.ngOnChanges({'deviceLabelToggle': |
| 336 | new SimpleChange(old, next, false)}); |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 337 | this.flashMsg = this.lionFn(TopologyComponent.deviceLabelFlashMessage(next)); |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 338 | this.log.debug('Cycling device labels', old, next); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 339 | } |
| 340 | |
| 341 | protected cycleHostLabels() { |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 342 | const old: HostLabelToggle = this.force.hostLabelToggle; |
| 343 | const next = HostLabelToggle.next(old); |
| 344 | this.force.ngOnChanges({'hostLabelToggle': |
| 345 | new SimpleChange(old, next, false)}); |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 346 | this.flashMsg = this.lionFn(TopologyComponent.hostLabelFlashMessage(next)); |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 347 | this.log.debug('Cycling host labels', old, next); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 348 | } |
| 349 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 350 | protected toggleBackground(token?: KeysToken) { |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 351 | this.showBackground = !this.showBackground; |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 352 | this.flashMsg = this.lionFn(this.showBackground ? 'show' : 'hide') + |
| 353 | ' ' + this.lionFn('fl_background_map'); |
| 354 | this.toolbar.backgroundVisible = this.showBackground; |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 355 | this.log.debug('Toggling background', token); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 356 | } |
| 357 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 358 | protected toggleDetails(token?: KeysToken) { |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 359 | if (this.details.selectedNode) { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 360 | const on: boolean = this.details.togglePanel(() => { |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 361 | }); |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 362 | this.flashMsg = this.lionFn(on ? 'show' : 'hide') + |
| 363 | ' ' + this.lionFn('fl_panel_details'); |
| 364 | this.toolbar.detailsVisible = on; |
| 365 | |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 366 | this.log.debug('Toggling details', token); |
| 367 | } |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 368 | } |
| 369 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 370 | protected toggleInstancePanel(token?: KeysToken) { |
| 371 | const on: boolean = this.instance.togglePanel(() => {}); |
| 372 | this.flashMsg = this.lionFn(on ? 'show' : 'hide') + |
| 373 | ' ' + this.lionFn('fl_panel_instances'); |
| 374 | this.toolbar.instancesVisible = on; |
| 375 | this.log.debug('Toggling instances', token, on); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 376 | } |
| 377 | |
| 378 | protected toggleSummary() { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 379 | const on: boolean = this.summary.togglePanel(() => {}); |
| 380 | this.flashMsg = this.lionFn(on ? 'show' : 'hide') + |
| 381 | ' ' + this.lionFn('fl_panel_summary'); |
| 382 | this.toolbar.summaryVisible = on; |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 383 | } |
| 384 | |
| 385 | protected resetZoom() { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 386 | this.zoomDirective.resetZoom(); |
| 387 | this.flashMsg = this.lionFn('fl_pan_zoom_reset'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 388 | } |
| 389 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 390 | protected togglePorts(token?: KeysToken) { |
| 391 | const old: boolean = this.force.highlightPorts; |
| 392 | const current: boolean = !this.force.highlightPorts; |
| 393 | this.force.ngOnChanges({'highlightPorts': new SimpleChange(old, current, false)}); |
| 394 | this.flashMsg = this.lionFn(current ? 'enable' : 'disable') + |
| 395 | ' ' + this.lionFn('fl_port_highlighting'); |
| 396 | this.toolbar.portsVisible = current; |
| 397 | this.log.debug(current ? 'Enable' : 'Disable', 'port highlighting'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 398 | } |
| 399 | |
| 400 | protected equalizeMasters() { |
| 401 | this.wss.sendEvent('equalizeMasters', null); |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 402 | this.flashMsg = this.lionFn('fl_eq_masters'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 403 | this.log.debug('equalizing masters'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 404 | } |
| 405 | |
| 406 | protected resetNodeLocation() { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 407 | // TODO: Implement reset locations |
| 408 | this.flashMsg = this.lionFn('fl_reset_node_locations'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 409 | this.log.debug('resetting node location'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 410 | } |
| 411 | |
| 412 | protected unpinNode() { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 413 | // TODO: Implement this |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 414 | this.log.debug('unpinning node'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 415 | } |
| 416 | |
| 417 | protected toggleToolbar() { |
| 418 | this.log.debug('toggling toolbar'); |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 419 | this.toolbar.on = !this.toolbar.on; |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 420 | } |
| 421 | |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 422 | protected toggleHosts() { |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 423 | const old: boolean = this.force.showHosts; |
| 424 | const current = !this.force.showHosts; |
| 425 | this.force.ngOnChanges({'showHosts': new SimpleChange(old, current, false)}); |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 426 | this.flashMsg = this.lionFn('hosts') + ' ' + |
| 427 | this.lionFn(this.force.showHosts ? 'visible' : 'hidden'); |
| 428 | this.toolbar.hostsVisible = current; |
Sean Condon | 021f0fa | 2018-12-06 23:31:11 -0800 | [diff] [blame] | 429 | this.log.debug('toggling hosts: ', this.force.showHosts ? 'Show' : 'Hide'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 430 | } |
| 431 | |
| 432 | protected toggleOfflineDevices() { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 433 | // TODO: Implement toggle offline visibility |
| 434 | const on: boolean = true; |
| 435 | this.flashMsg = this.lionFn(on ? 'show' : 'hide') + |
| 436 | ' ' + this.lionFn('fl_offline_devices'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 437 | this.log.debug('toggling offline devices'); |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 438 | } |
| 439 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 440 | /** |
| 441 | * Check to see if this is needed anymore |
| 442 | * @param what |
| 443 | */ |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 444 | protected notValid(what) { |
| 445 | this.log.warn('topo.js getActionEntry(): Not a valid ' + what); |
| 446 | } |
| 447 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 448 | /** |
| 449 | * Check to see if this is needed anymore |
| 450 | * @param what |
| 451 | */ |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 452 | getActionEntry(key) { |
| 453 | let entry; |
| 454 | |
| 455 | if (!key) { |
| 456 | this.notValid('key'); |
| 457 | return null; |
| 458 | } |
| 459 | |
| 460 | entry = this.actionMap()[key]; |
| 461 | |
| 462 | if (!entry) { |
| 463 | this.notValid('actionMap (' + key + ') entry'); |
| 464 | return null; |
| 465 | } |
| 466 | return this.fs.isA(entry) || [entry, '']; |
| 467 | } |
| 468 | |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 469 | /** |
| 470 | * An event handler that updates the details panel as items are |
| 471 | * selected in the forcesvg layer |
| 472 | * @param nodeOrLink the item to display details of |
| 473 | */ |
| 474 | nodeSelected(nodeOrLink: UiElement) { |
| 475 | this.details.ngOnChanges({'selectedNode': |
| 476 | new SimpleChange(undefined, nodeOrLink, true)}); |
| 477 | this.details.on = Boolean(nodeOrLink); |
Sean Condon | 0c577f6 | 2018-11-18 22:40:05 +0000 | [diff] [blame] | 478 | } |
| 479 | |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 480 | /** |
| 481 | * Enable traffic monitoring |
| 482 | */ |
| 483 | monitorAllTraffic() { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 484 | // TODO: Implement support for toggling between bits, packets and octets |
| 485 | this.flashMsg = this.lionFn('tr_fl_pstats_bits'); |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 486 | this.trs.init(this.force); |
| 487 | } |
| 488 | |
| 489 | /** |
| 490 | * Cancel traffic monitoring |
| 491 | */ |
| 492 | cancelTraffic() { |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 493 | this.flashMsg = this.lionFn('fl_monitoring_canceled'); |
Sean Condon | 50855cf | 2018-12-23 15:37:42 +0000 | [diff] [blame] | 494 | this.trs.destroy(); |
| 495 | } |
Sean Condon | 9148182 | 2019-01-01 13:56:14 +0000 | [diff] [blame^] | 496 | |
| 497 | /** |
| 498 | * Read the LION bundle for Toolbar and set up the lionFn |
| 499 | */ |
| 500 | doLion() { |
| 501 | this.lionFn = this.lion.bundle('core.view.Topo'); |
| 502 | } |
| 503 | |
| 504 | /** |
| 505 | * A dummy implementation of the lionFn until the response is received and the LION |
| 506 | * bundle is received from the WebSocket |
| 507 | */ |
| 508 | dummyLion(key: string): string { |
| 509 | return '%' + key + '%'; |
| 510 | } |
Sean Condon | f4f54a1 | 2018-10-10 23:25:46 +0100 | [diff] [blame] | 511 | } |