blob: ff8a0502891c062df6da3441a51c4ff2b3f53e03 [file] [log] [blame]
Sean Condonf4f54a12018-10-10 23:25:46 +01001/*
Sean Condon91481822019-01-01 13:56:14 +00002 * Copyright 2019-present Open Networking Foundation
Sean Condonf4f54a12018-10-10 23:25:46 +01003 *
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 Condon0c577f62018-11-18 22:40:05 +000016import {
17 Component,
18 OnDestroy,
Sean Condon021f0fa2018-12-06 23:31:11 -080019 OnInit, SimpleChange,
Sean Condon0c577f62018-11-18 22:40:05 +000020 ViewChild
21} from '@angular/core';
Sean Condon55c30532018-10-29 12:26:57 +000022import * as d3 from 'd3';
Sean Condonf4f54a12018-10-10 23:25:46 +010023import {
Sean Condon91481822019-01-01 13:56:14 +000024 FnService, IconService,
Sean Condon0c577f62018-11-18 22:40:05 +000025 KeysService,
Sean Condon91481822019-01-01 13:56:14 +000026 KeysToken, LionService,
Sean Condon0c577f62018-11-18 22:40:05 +000027 LogService,
28 PrefsService,
29 SvgUtilService,
30 WebSocketService,
Sean Condon0c577f62018-11-18 22:40:05 +000031 ZoomService
Sean Condonf4f54a12018-10-10 23:25:46 +010032} from 'gui2-fw-lib';
Sean Condon0c577f62018-11-18 22:40:05 +000033import {InstanceComponent} from '../panel/instance/instance.component';
Sean Condon0c577f62018-11-18 22:40:05 +000034import {DetailsComponent} from '../panel/details/details.component';
35import {BackgroundSvgComponent} from '../layer/backgroundsvg/backgroundsvg.component';
36import {ForceSvgComponent} from '../layer/forcesvg/forcesvg.component';
37import {TopologyService} from '../topology.service';
Sean Condon91481822019-01-01 13:56:14 +000038import {
39 HostLabelToggle,
40 LabelToggle,
41 UiElement
42} from '../layer/forcesvg/models';
Sean Condonb2c483c2019-01-16 20:28:55 +000043import {
44 INSTANCE_TOGGLE, SUMMARY_TOGGLE, DETAILS_TOGGLE,
45 HOSTS_TOGGLE, OFFLINE_TOGGLE, PORTS_TOGGLE,
46 BKGRND_TOGGLE, CYCLELABELS_BTN, CYCLEHOSTLABEL_BTN,
47 RESETZOOM_BTN, EQMASTER_BTN,
48 CANCEL_TRAFFIC, ALL_TRAFFIC, QUICKHELP_BTN
49} from '../panel/toolbar/toolbar.component';
Sean Condon50855cf2018-12-23 15:37:42 +000050import {TrafficService} from '../traffic.service';
Sean Condon91481822019-01-01 13:56:14 +000051import {ZoomableDirective} from '../layer/zoomable.directive';
Sean Condonf4f54a12018-10-10 23:25:46 +010052
Sean Condonb2c483c2019-01-16 20:28:55 +000053const TOPO2_PREFS = 'topo2_prefs';
54const PREF_BG = 'bg';
55const PREF_DETAIL = 'detail';
56const PREF_DLBLS = 'dlbls';
57const PREF_HLBLS = 'hlbls';
58const PREF_HOSTS = 'hosts';
59const PREF_INSTS = 'insts';
60const PREF_OFFDEV = 'offdev';
61const PREF_PORTHL = 'porthl';
62const PREF_SUMMARY = 'summary';
63const PREF_TOOLBAR = 'toolbar';
64
65/**
66 * model of the topo2_prefs object - this is a subset of the overall Prefs returned
67 * by the server
68 */
69export interface Topo2Prefs {
70 bg: number;
71 detail: number;
72 dlbls: number;
73 hlbls: number;
74 hosts: number;
75 insts: number;
76 offdev: number;
77 porthl: number;
78 spr: number;
79 ovid: string;
80 summary: number;
81 toolbar: number;
82}
83
Sean Condonf4f54a12018-10-10 23:25:46 +010084/**
85 * ONOS GUI Topology View
86 *
87 * This Topology View component is the top level component in a hierarchy that
88 * comprises the whole Topology View
89 *
90 * There are three main parts (panels, graphical and breadcrumbs)
91 * The panel hierarchy
92 * |-- Instances Panel (shows ONOS instances)
93 * |-- Summary Panel (summary of ONOS)
94 * |-- Toolbar Panel (the toolbar)
95 * |-- Details Panel (when a node is selected in the Force graphical view (see below))
96 *
97 * The graphical hierarchy contains
98 * Topology (this)
99 * |-- No Devices Connected (only of there are no nodes to show)
100 * |-- Zoom Layer (everything beneath this can be zoomed and panned)
101 * |-- Background (container for any backgrounds - can be toggled on and off)
102 * |-- Map
103 * |-- Forces (all of the nodes and links laid out by a d3.force simulation)
104 *
105 * The breadcrumbs
106 * |-- Breadcrumb (in region view a way of navigating back up through regions)
107 */
108@Component({
109 selector: 'onos-topology',
110 templateUrl: './topology.component.html',
111 styleUrls: ['./topology.component.css']
112})
Sean Condonaa4366d2018-11-02 14:29:01 +0000113export class TopologyComponent implements OnInit, OnDestroy {
114 // These are references to the components inserted in the template
Sean Condonf4f54a12018-10-10 23:25:46 +0100115 @ViewChild(InstanceComponent) instance: InstanceComponent;
Sean Condonf4f54a12018-10-10 23:25:46 +0100116 @ViewChild(DetailsComponent) details: DetailsComponent;
Sean Condonaa4366d2018-11-02 14:29:01 +0000117 @ViewChild(BackgroundSvgComponent) background: BackgroundSvgComponent;
118 @ViewChild(ForceSvgComponent) force: ForceSvgComponent;
Sean Condon91481822019-01-01 13:56:14 +0000119 @ViewChild(ZoomableDirective) zoomDirective: ZoomableDirective;
Sean Condonf4f54a12018-10-10 23:25:46 +0100120
121 flashMsg: string = '';
Sean Condonb2c483c2019-01-16 20:28:55 +0000122 // These are used as defaults if nothing is set on the server
123 prefsState: Topo2Prefs = <Topo2Prefs>{
124 bg: 0,
125 detail: 1,
126 dlbls: 0,
127 hlbls: 2,
128 hosts: 0,
129 insts: 1,
130 offdev: 1,
131 ovid: 'traffic', // default to traffic overlay
132 porthl: 1,
133 spr: 0,
134 summary: 1,
135 toolbar: 0,
136 };
Sean Condon91481822019-01-01 13:56:14 +0000137 lionFn; // Function
Sean Condon55c30532018-10-29 12:26:57 +0000138
Sean Condonf4f54a12018-10-10 23:25:46 +0100139 constructor(
140 protected log: LogService,
141 protected fs: FnService,
142 protected ks: KeysService,
143 protected sus: SvgUtilService,
144 protected ps: PrefsService,
Sean Condon55c30532018-10-29 12:26:57 +0000145 protected wss: WebSocketService,
Sean Condonaa4366d2018-11-02 14:29:01 +0000146 protected ts: TopologyService,
Sean Condon91481822019-01-01 13:56:14 +0000147 protected trs: TrafficService,
148 protected is: IconService,
149 private lion: LionService,
Sean Condonf4f54a12018-10-10 23:25:46 +0100150 ) {
Sean Condon91481822019-01-01 13:56:14 +0000151 if (this.lion.ubercache.length === 0) {
152 this.lionFn = this.dummyLion;
153 this.lion.loadCbs.set('topo-toolbar', () => this.doLion());
154 } else {
155 this.doLion();
156 }
Sean Condonf4f54a12018-10-10 23:25:46 +0100157
Sean Condon91481822019-01-01 13:56:14 +0000158 this.is.loadIconDef('bird');
159 this.is.loadIconDef('active');
160 this.is.loadIconDef('uiAttached');
161 this.is.loadIconDef('m_switch');
162 this.is.loadIconDef('m_roadm');
163 this.is.loadIconDef('m_router');
164 this.is.loadIconDef('m_uiAttached');
165 this.is.loadIconDef('m_endstation');
166 this.is.loadIconDef('m_ports');
167 this.is.loadIconDef('m_summary');
168 this.is.loadIconDef('m_details');
169 this.is.loadIconDef('m_map');
170 this.is.loadIconDef('m_cycleLabels');
171 this.is.loadIconDef('m_resetZoom');
172 this.is.loadIconDef('m_eqMaster');
173 this.is.loadIconDef('m_unknown');
174 this.is.loadIconDef('m_allTraffic');
175 this.is.loadIconDef('deviceTable');
176 this.is.loadIconDef('flowTable');
177 this.is.loadIconDef('portTable');
178 this.is.loadIconDef('groupTable');
179 this.is.loadIconDef('meterTable');
180 this.is.loadIconDef('triangleUp');
Sean Condonf4f54a12018-10-10 23:25:46 +0100181 this.log.debug('Topology component constructed');
182 }
183
Sean Condon91481822019-01-01 13:56:14 +0000184 /**
185 * Static functions must come before member variables
186 * @param index
187 */
Sean Condon021f0fa2018-12-06 23:31:11 -0800188 private static deviceLabelFlashMessage(index: number): string {
189 switch (index) {
Sean Condon91481822019-01-01 13:56:14 +0000190 case 0: return 'fl_device_labels_hide';
191 case 1: return 'fl_device_labels_show_friendly';
192 case 2: return 'fl_device_labels_show_id';
Sean Condon021f0fa2018-12-06 23:31:11 -0800193 }
194 }
195
196 private static hostLabelFlashMessage(index: number): string {
197 switch (index) {
Sean Condon91481822019-01-01 13:56:14 +0000198 case 0: return 'fl_host_labels_hide';
199 case 1: return 'fl_host_labels_show_friendly';
200 case 2: return 'fl_host_labels_show_ip';
201 case 3: return 'fl_host_labels_show_mac';
Sean Condon021f0fa2018-12-06 23:31:11 -0800202 }
203 }
204
Sean Condon91481822019-01-01 13:56:14 +0000205 /**
206 * Pass the list of Key Commands to the KeyService, and initialize the Topology
207 * Service - which communicates with through the WebSocket to the ONOS server
208 * to get the nodes and links.
209 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100210 ngOnInit() {
211 this.bindCommands();
Sean Condonaa4366d2018-11-02 14:29:01 +0000212 // The components from the template are handed over to TopologyService here
213 // so that WebSocket responses can be passed back in to them
214 // The handling of the WebSocket call is delegated out to the Topology
215 // Service just to compartmentalize things a bit
216 this.ts.init(this.instance, this.background, this.force);
Sean Condonb2c483c2019-01-16 20:28:55 +0000217
218 this.ps.addListener((data) => this.prefsUpdateHandler(data));
219 this.prefsState = this.ps.getPrefs(TOPO2_PREFS, this.prefsState);
Sean Condonf4f54a12018-10-10 23:25:46 +0100220 this.log.debug('Topology component initialized');
221 }
222
Sean Condon91481822019-01-01 13:56:14 +0000223 /**
Sean Condonb2c483c2019-01-16 20:28:55 +0000224 * Callback function that's called whenever new Prefs are received from WebSocket
225 *
226 * Note: At present the backend server does not filter updated by logged in user,
227 * so you might get updates pertaining to a different user
228 */
229 prefsUpdateHandler(data: any): void {
230 // Extract the TOPO2 prefs from it
231 this.prefsState = data[TOPO2_PREFS];
232 this.log.debug('Updated topo2 prefs', this.prefsState);
233 }
234
235 /**
Sean Condon91481822019-01-01 13:56:14 +0000236 * When this component is being stopped, disconnect the TopologyService from
237 * the WebSocket
238 */
Sean Condonaa4366d2018-11-02 14:29:01 +0000239 ngOnDestroy() {
240 this.ts.destroy();
Sean Condonb2c483c2019-01-16 20:28:55 +0000241 this.ps.removeListener((data) => this.prefsUpdateHandler(data));
Sean Condonaa4366d2018-11-02 14:29:01 +0000242 this.log.debug('Topology component destroyed');
243 }
244
Sean Condon91481822019-01-01 13:56:14 +0000245 /**
246 * When ever a toolbar button is clicked, an event is sent up from toolbar
247 * component which is caught and passed on to here.
248 * @param name The name of the button that was clicked
249 */
250 toolbarButtonClicked(name: string) {
251 switch (name) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000252 case INSTANCE_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000253 this.toggleInstancePanel();
254 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000255 case SUMMARY_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000256 this.toggleSummary();
257 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000258 case DETAILS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000259 this.toggleDetails();
260 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000261 case HOSTS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000262 this.toggleHosts();
263 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000264 case OFFLINE_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000265 this.toggleOfflineDevices();
266 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000267 case PORTS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000268 this.togglePorts();
269 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000270 case BKGRND_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000271 this.toggleBackground();
272 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000273 case CYCLELABELS_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000274 this.cycleDeviceLabels();
275 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000276 case CYCLEHOSTLABEL_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000277 this.cycleHostLabels();
278 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000279 case RESETZOOM_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000280 this.resetZoom();
281 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000282 case EQMASTER_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000283 this.equalizeMasters();
284 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000285 case CANCEL_TRAFFIC:
Sean Condon91481822019-01-01 13:56:14 +0000286 this.cancelTraffic();
287 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000288 case ALL_TRAFFIC:
Sean Condon91481822019-01-01 13:56:14 +0000289 this.monitorAllTraffic();
290 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000291 case QUICKHELP_BTN:
292 this.ks.quickHelpShown = true;
293 break;
Sean Condon91481822019-01-01 13:56:14 +0000294 default:
295 this.log.warn('Unhandled Toolbar action', name);
296 }
297 }
298
299 /**
300 * The list of key strokes that will be active in the Topology View.
301 *
302 * This action map is passed to the KeyService through the bindCommands()
303 * when this component is being initialized
304 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100305 actionMap() {
306 return {
Sean Condon50855cf2018-12-23 15:37:42 +0000307 A: [() => {this.monitorAllTraffic(); }, 'Monitor all traffic'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100308 L: [() => {this.cycleDeviceLabels(); }, 'Cycle device labels'],
309 B: [(token) => {this.toggleBackground(token); }, 'Toggle background'],
310 D: [(token) => {this.toggleDetails(token); }, 'Toggle details panel'],
311 I: [(token) => {this.toggleInstancePanel(token); }, 'Toggle ONOS Instance Panel'],
312 O: [() => {this.toggleSummary(); }, 'Toggle the Summary Panel'],
313 R: [() => {this.resetZoom(); }, 'Reset pan / zoom'],
314 P: [(token) => {this.togglePorts(token); }, 'Toggle Port Highlighting'],
315 E: [() => {this.equalizeMasters(); }, 'Equalize mastership roles'],
316 X: [() => {this.resetNodeLocation(); }, 'Reset Node Location'],
317 U: [() => {this.unpinNode(); }, 'Unpin node (mouse over)'],
318 H: [() => {this.toggleHosts(); }, 'Toggle host visibility'],
319 M: [() => {this.toggleOfflineDevices(); }, 'Toggle offline visibility'],
320 dot: [() => {this.toggleToolbar(); }, 'Toggle Toolbar'],
Sean Condon50855cf2018-12-23 15:37:42 +0000321 0: [() => {this.cancelTraffic(); }, 'Cancel traffic monitoring'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100322 'shift-L': [() => {this.cycleHostLabels(); }, 'Cycle host labels'],
323
324 // -- instance color palette debug
Sean Condon55c30532018-10-29 12:26:57 +0000325 9: () => {
326 this.sus.cat7().testCard(d3.select('svg#topo2'));
Sean Condonf4f54a12018-10-10 23:25:46 +0100327 },
328
Sean Condonb2c483c2019-01-16 20:28:55 +0000329 esc: [() => {this.handleEscape(); }, 'Cancel commands'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100330
331 // TODO update after adding in Background Service
332 // topology overlay selections
333 // F1: function () { t2tbs.fnKey(0); },
334 // F2: function () { t2tbs.fnKey(1); },
335 // F3: function () { t2tbs.fnKey(2); },
336 // F4: function () { t2tbs.fnKey(3); },
337 // F5: function () { t2tbs.fnKey(4); },
338 //
339 // _keyListener: t2tbs.keyListener.bind(t2tbs),
340
341 _helpFormat: [
342 ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B'],
343 ['X', 'Z', 'N', 'L', 'shift-L', 'U', 'R', 'E', 'dot'],
344 [], // this column reserved for overlay actions
345 ],
346 };
347 }
348
349
350 bindCommands(additional?: any) {
351
352 const am = this.actionMap();
353 const add = this.fs.isO(additional);
354
Sean Condonf4f54a12018-10-10 23:25:46 +0100355 this.ks.keyBindings(am);
356
357 this.ks.gestureNotes([
358 ['click', 'Select the item and show details'],
359 ['shift-click', 'Toggle selection state'],
360 ['drag', 'Reposition (and pin) device / host'],
361 ['cmd-scroll', 'Zoom in / out'],
362 ['cmd-drag', 'Pan'],
363 ]);
364 }
365
366 handleEscape() {
367
368 if (false) {
369 // TODO: Cancel show mastership
370 // TODO: Cancel Active overlay
371 // TODO: Reinstate with components
372 } else {
Sean Condonb2c483c2019-01-16 20:28:55 +0000373 this.nodeSelected(undefined);
Sean Condonf4f54a12018-10-10 23:25:46 +0100374 this.log.debug('Handling escape');
375 // } else if (t2rs.deselectAllNodes()) {
376 // // else if we have node selections, deselect them all
377 // // (work already done)
378 // } else if (t2rs.deselectLink()) {
379 // // else if we have a link selection, deselect it
380 // // (work already done)
381 // } else if (t2is.isVisible()) {
382 // // If the instance panel is visible, close it
383 // t2is.toggle();
384 // } else if (t2sp.isVisible()) {
385 // // If the summary panel is visible, close it
386 // t2sp.toggle();
387 }
388 }
389
Sean Condonb2c483c2019-01-16 20:28:55 +0000390 /**
391 * Updates the cache of preferences locally and onwards to the PrefsService
392 * @param what The attribute of the local topo2-prefs cache to update
393 * @param b the value to update it with
394 */
395 updatePrefsState(what: string, b: number) {
396 this.prefsState[what] = b;
397 this.ps.setPrefs(TOPO2_PREFS, this.prefsState);
Sean Condonf4f54a12018-10-10 23:25:46 +0100398 }
399
Sean Condonb2c483c2019-01-16 20:28:55 +0000400 /**
401 * When the button is clicked on the toolbar or the L key is pressed
402 * 1) cycle through options
403 * 2) flash up a message
404 * 3a) Update the local prefs cache
405 * 3b) And passes on to the global prefs service which sends back to the server
406 * 3c) It also has a knock on effect of passing it on to ForceSvgComponent
407 * because prefsState.dlbls is given as an input to it
408 * 3d) This will in turn pass it down to the DeviceSvgComponent which
409 * displays the label
410 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100411 protected cycleDeviceLabels() {
Sean Condonb2c483c2019-01-16 20:28:55 +0000412 const old: LabelToggle = this.prefsState.dlbls;
Sean Condon021f0fa2018-12-06 23:31:11 -0800413 const next = LabelToggle.next(old);
Sean Condon91481822019-01-01 13:56:14 +0000414 this.flashMsg = this.lionFn(TopologyComponent.deviceLabelFlashMessage(next));
Sean Condonb2c483c2019-01-16 20:28:55 +0000415 this.updatePrefsState(PREF_DLBLS, next);
Sean Condon021f0fa2018-12-06 23:31:11 -0800416 this.log.debug('Cycling device labels', old, next);
Sean Condonf4f54a12018-10-10 23:25:46 +0100417 }
418
419 protected cycleHostLabels() {
Sean Condonb2c483c2019-01-16 20:28:55 +0000420 const old: HostLabelToggle = this.prefsState.hlbls;
Sean Condon021f0fa2018-12-06 23:31:11 -0800421 const next = HostLabelToggle.next(old);
Sean Condon91481822019-01-01 13:56:14 +0000422 this.flashMsg = this.lionFn(TopologyComponent.hostLabelFlashMessage(next));
Sean Condonb2c483c2019-01-16 20:28:55 +0000423 this.updatePrefsState(PREF_HLBLS, next);
Sean Condon021f0fa2018-12-06 23:31:11 -0800424 this.log.debug('Cycling host labels', old, next);
Sean Condonf4f54a12018-10-10 23:25:46 +0100425 }
426
Sean Condonb2c483c2019-01-16 20:28:55 +0000427 /**
428 * When the button is clicked on the toolbar or the B key is pressed
429 * 1) Find the inverse of the current state (held as 1 or 0)
430 * 2) Flash up a message on screen
431 * 3b) And passes on to the global prefs service which sends back to the server
432 * 3c) It also has a knock on effect of passing it on to ToolbarComponent
433 * because prefsState.bg is given as an input to it
434 * @param token
435 */
Sean Condon91481822019-01-01 13:56:14 +0000436 protected toggleBackground(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000437 const bg: boolean = !Boolean(this.prefsState.bg);
438 this.flashMsg = this.lionFn(bg ? 'show' : 'hide') +
Sean Condon91481822019-01-01 13:56:14 +0000439 ' ' + this.lionFn('fl_background_map');
Sean Condonb2c483c2019-01-16 20:28:55 +0000440 this.updatePrefsState(PREF_BG, bg ? 1 : 0);
441 this.log.debug('Toggling background', token, bg ? 'shown' : 'hidden');
Sean Condonf4f54a12018-10-10 23:25:46 +0100442 }
443
Sean Condon91481822019-01-01 13:56:14 +0000444 protected toggleDetails(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000445 const on: boolean = !Boolean(this.prefsState.detail);
446 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
447 ' ' + this.lionFn('fl_panel_details');
448 this.updatePrefsState(PREF_DETAIL, on ? 1 : 0);
449 this.log.debug('Toggling details', token);
Sean Condonf4f54a12018-10-10 23:25:46 +0100450 }
451
Sean Condon91481822019-01-01 13:56:14 +0000452 protected toggleInstancePanel(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000453 const on: boolean = !Boolean(this.prefsState.insts);
Sean Condon91481822019-01-01 13:56:14 +0000454 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
455 ' ' + this.lionFn('fl_panel_instances');
Sean Condonb2c483c2019-01-16 20:28:55 +0000456 this.updatePrefsState(PREF_INSTS, on ? 1 : 0);
Sean Condon91481822019-01-01 13:56:14 +0000457 this.log.debug('Toggling instances', token, on);
Sean Condonf4f54a12018-10-10 23:25:46 +0100458 }
459
460 protected toggleSummary() {
Sean Condonb2c483c2019-01-16 20:28:55 +0000461 const on: boolean = !Boolean(this.prefsState.summary);
Sean Condon91481822019-01-01 13:56:14 +0000462 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
463 ' ' + this.lionFn('fl_panel_summary');
Sean Condonb2c483c2019-01-16 20:28:55 +0000464 this.updatePrefsState(PREF_SUMMARY, on ? 1 : 0);
465 }
466
467 protected togglePorts(token?: KeysToken) {
468 const current: boolean = !Boolean(this.prefsState.porthl);
469 this.flashMsg = this.lionFn(current ? 'enable' : 'disable') +
470 ' ' + this.lionFn('fl_port_highlighting');
471 this.updatePrefsState(PREF_PORTHL, current ? 1 : 0);
472 this.log.debug(current ? 'Enable' : 'Disable', 'port highlighting');
473 }
474
475 protected toggleToolbar() {
476 const on: boolean = !Boolean(this.prefsState.toolbar);
477 this.updatePrefsState(PREF_TOOLBAR, on ? 1 : 0);
478 this.log.debug('toggling toolbar', on ? 'shown' : 'hidden');
479 }
480
481 protected toggleHosts() {
482 const current: boolean = !Boolean(this.prefsState.hosts);
483 this.flashMsg = this.lionFn('hosts') + ' ' +
484 this.lionFn(this.force.showHosts ? 'visible' : 'hidden');
485 this.updatePrefsState(PREF_HOSTS, current ? 1 : 0);
486 this.log.debug('toggling hosts: ', this.prefsState.hosts ? 'Show' : 'Hide');
487 }
488
489 protected toggleOfflineDevices() {
490 const on: boolean = !Boolean(this.prefsState.offdev);
491 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
492 ' ' + this.lionFn('fl_offline_devices');
493 this.updatePrefsState(PREF_OFFDEV, on ? 1 : 0);
494 this.log.debug('toggling offline devices', this.prefsState.offdev);
Sean Condonf4f54a12018-10-10 23:25:46 +0100495 }
496
497 protected resetZoom() {
Sean Condon91481822019-01-01 13:56:14 +0000498 this.zoomDirective.resetZoom();
499 this.flashMsg = this.lionFn('fl_pan_zoom_reset');
Sean Condonf4f54a12018-10-10 23:25:46 +0100500 }
501
Sean Condonf4f54a12018-10-10 23:25:46 +0100502 protected equalizeMasters() {
503 this.wss.sendEvent('equalizeMasters', null);
Sean Condon91481822019-01-01 13:56:14 +0000504 this.flashMsg = this.lionFn('fl_eq_masters');
Sean Condonf4f54a12018-10-10 23:25:46 +0100505 this.log.debug('equalizing masters');
Sean Condonf4f54a12018-10-10 23:25:46 +0100506 }
507
508 protected resetNodeLocation() {
Sean Condon91481822019-01-01 13:56:14 +0000509 // TODO: Implement reset locations
510 this.flashMsg = this.lionFn('fl_reset_node_locations');
Sean Condonf4f54a12018-10-10 23:25:46 +0100511 this.log.debug('resetting node location');
Sean Condonf4f54a12018-10-10 23:25:46 +0100512 }
513
514 protected unpinNode() {
Sean Condon91481822019-01-01 13:56:14 +0000515 // TODO: Implement this
Sean Condonf4f54a12018-10-10 23:25:46 +0100516 this.log.debug('unpinning node');
Sean Condonf4f54a12018-10-10 23:25:46 +0100517 }
518
Sean Condon91481822019-01-01 13:56:14 +0000519 /**
520 * Check to see if this is needed anymore
521 * @param what
522 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100523 protected notValid(what) {
524 this.log.warn('topo.js getActionEntry(): Not a valid ' + what);
525 }
526
Sean Condon91481822019-01-01 13:56:14 +0000527 /**
528 * Check to see if this is needed anymore
529 * @param what
530 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100531 getActionEntry(key) {
532 let entry;
533
534 if (!key) {
535 this.notValid('key');
536 return null;
537 }
538
539 entry = this.actionMap()[key];
540
541 if (!entry) {
542 this.notValid('actionMap (' + key + ') entry');
543 return null;
544 }
545 return this.fs.isA(entry) || [entry, ''];
546 }
547
Sean Condon91481822019-01-01 13:56:14 +0000548 /**
549 * An event handler that updates the details panel as items are
550 * selected in the forcesvg layer
551 * @param nodeOrLink the item to display details of
552 */
553 nodeSelected(nodeOrLink: UiElement) {
554 this.details.ngOnChanges({'selectedNode':
555 new SimpleChange(undefined, nodeOrLink, true)});
Sean Condon0c577f62018-11-18 22:40:05 +0000556 }
557
Sean Condon50855cf2018-12-23 15:37:42 +0000558 /**
559 * Enable traffic monitoring
560 */
561 monitorAllTraffic() {
Sean Condon91481822019-01-01 13:56:14 +0000562 // TODO: Implement support for toggling between bits, packets and octets
563 this.flashMsg = this.lionFn('tr_fl_pstats_bits');
Sean Condon50855cf2018-12-23 15:37:42 +0000564 this.trs.init(this.force);
565 }
566
567 /**
568 * Cancel traffic monitoring
569 */
570 cancelTraffic() {
Sean Condon91481822019-01-01 13:56:14 +0000571 this.flashMsg = this.lionFn('fl_monitoring_canceled');
Sean Condon50855cf2018-12-23 15:37:42 +0000572 this.trs.destroy();
573 }
Sean Condon91481822019-01-01 13:56:14 +0000574
575 /**
576 * Read the LION bundle for Toolbar and set up the lionFn
577 */
578 doLion() {
579 this.lionFn = this.lion.bundle('core.view.Topo');
580 }
581
582 /**
583 * A dummy implementation of the lionFn until the response is received and the LION
584 * bundle is received from the WebSocket
585 */
586 dummyLion(key: string): string {
587 return '%' + key + '%';
588 }
Sean Condonf4f54a12018-10-10 23:25:46 +0100589}