blob: 441bbc646b147e2539fad93c8a4e88b2fa7a3874 [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 Condon1ae15802019-03-02 09:07:18 +000031 TopoZoomPrefs
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 {
Sean Condon71910542019-02-16 18:16:42 +000039 GridDisplayToggle,
Sean Condon91481822019-01-01 13:56:14 +000040 HostLabelToggle,
41 LabelToggle,
42 UiElement
43} from '../layer/forcesvg/models';
Sean Condonb2c483c2019-01-16 20:28:55 +000044import {
45 INSTANCE_TOGGLE, SUMMARY_TOGGLE, DETAILS_TOGGLE,
46 HOSTS_TOGGLE, OFFLINE_TOGGLE, PORTS_TOGGLE,
47 BKGRND_TOGGLE, CYCLELABELS_BTN, CYCLEHOSTLABEL_BTN,
Sean Condon71910542019-02-16 18:16:42 +000048 CYCLEGRIDDISPLAY_BTN, RESETZOOM_BTN, EQMASTER_BTN,
Sean Condon0d064ec2019-02-04 21:53:53 +000049 CANCEL_TRAFFIC, ALL_TRAFFIC, QUICKHELP_BTN, BKGRND_SELECT
Sean Condonb2c483c2019-01-16 20:28:55 +000050} from '../panel/toolbar/toolbar.component';
Sean Condon50855cf2018-12-23 15:37:42 +000051import {TrafficService} from '../traffic.service';
Sean Condon91481822019-01-01 13:56:14 +000052import {ZoomableDirective} from '../layer/zoomable.directive';
Sean Condon0d064ec2019-02-04 21:53:53 +000053import {MapObject} from '../layer/maputils';
Sean Condonf4f54a12018-10-10 23:25:46 +010054
Sean Condonb2c483c2019-01-16 20:28:55 +000055const TOPO2_PREFS = 'topo2_prefs';
Sean Condon0d064ec2019-02-04 21:53:53 +000056const TOPO_MAPID_PREFS = 'topo_mapid';
57
Sean Condonb2c483c2019-01-16 20:28:55 +000058const PREF_BG = 'bg';
59const PREF_DETAIL = 'detail';
60const PREF_DLBLS = 'dlbls';
61const PREF_HLBLS = 'hlbls';
Sean Condon71910542019-02-16 18:16:42 +000062const PREF_GRID = 'grid';
Sean Condonb2c483c2019-01-16 20:28:55 +000063const PREF_HOSTS = 'hosts';
64const PREF_INSTS = 'insts';
65const PREF_OFFDEV = 'offdev';
66const PREF_PORTHL = 'porthl';
67const PREF_SUMMARY = 'summary';
68const PREF_TOOLBAR = 'toolbar';
69
70/**
Sean Condon0d064ec2019-02-04 21:53:53 +000071 * Model of the topo2_prefs object - this is a subset of the overall Prefs returned
Sean Condonb2c483c2019-01-16 20:28:55 +000072 * by the server
73 */
74export interface Topo2Prefs {
75 bg: number;
76 detail: number;
77 dlbls: number;
78 hlbls: number;
79 hosts: number;
80 insts: number;
81 offdev: number;
82 porthl: number;
83 spr: number;
84 ovid: string;
85 summary: number;
86 toolbar: number;
Sean Condon71910542019-02-16 18:16:42 +000087 grid: number;
Sean Condonb2c483c2019-01-16 20:28:55 +000088}
89
Sean Condonf4f54a12018-10-10 23:25:46 +010090/**
91 * ONOS GUI Topology View
92 *
93 * This Topology View component is the top level component in a hierarchy that
94 * comprises the whole Topology View
95 *
96 * There are three main parts (panels, graphical and breadcrumbs)
97 * The panel hierarchy
98 * |-- Instances Panel (shows ONOS instances)
99 * |-- Summary Panel (summary of ONOS)
100 * |-- Toolbar Panel (the toolbar)
101 * |-- Details Panel (when a node is selected in the Force graphical view (see below))
102 *
103 * The graphical hierarchy contains
104 * Topology (this)
105 * |-- No Devices Connected (only of there are no nodes to show)
106 * |-- Zoom Layer (everything beneath this can be zoomed and panned)
107 * |-- Background (container for any backgrounds - can be toggled on and off)
108 * |-- Map
109 * |-- Forces (all of the nodes and links laid out by a d3.force simulation)
110 *
111 * The breadcrumbs
112 * |-- Breadcrumb (in region view a way of navigating back up through regions)
113 */
114@Component({
115 selector: 'onos-topology',
116 templateUrl: './topology.component.html',
117 styleUrls: ['./topology.component.css']
118})
Sean Condonaa4366d2018-11-02 14:29:01 +0000119export class TopologyComponent implements OnInit, OnDestroy {
120 // These are references to the components inserted in the template
Sean Condonf4f54a12018-10-10 23:25:46 +0100121 @ViewChild(InstanceComponent) instance: InstanceComponent;
Sean Condonf4f54a12018-10-10 23:25:46 +0100122 @ViewChild(DetailsComponent) details: DetailsComponent;
Sean Condonaa4366d2018-11-02 14:29:01 +0000123 @ViewChild(BackgroundSvgComponent) background: BackgroundSvgComponent;
124 @ViewChild(ForceSvgComponent) force: ForceSvgComponent;
Sean Condon91481822019-01-01 13:56:14 +0000125 @ViewChild(ZoomableDirective) zoomDirective: ZoomableDirective;
Sean Condonf4f54a12018-10-10 23:25:46 +0100126
127 flashMsg: string = '';
Sean Condonb2c483c2019-01-16 20:28:55 +0000128 // These are used as defaults if nothing is set on the server
129 prefsState: Topo2Prefs = <Topo2Prefs>{
130 bg: 0,
131 detail: 1,
132 dlbls: 0,
133 hlbls: 2,
134 hosts: 0,
135 insts: 1,
136 offdev: 1,
137 ovid: 'traffic', // default to traffic overlay
138 porthl: 1,
139 spr: 0,
140 summary: 1,
141 toolbar: 0,
Sean Condon71910542019-02-16 18:16:42 +0000142 grid: 0
Sean Condonb2c483c2019-01-16 20:28:55 +0000143 };
Sean Condon0d064ec2019-02-04 21:53:53 +0000144
145 mapIdState: MapObject = <MapObject>{
146 id: undefined,
147 scale: 1.0
148 };
149 mapSelShown: boolean = false;
Sean Condon91481822019-01-01 13:56:14 +0000150 lionFn; // Function
Sean Condon55c30532018-10-29 12:26:57 +0000151
Sean Condon71910542019-02-16 18:16:42 +0000152 gridShown: boolean = true;
153 geoGridShown: boolean = true;
154
Sean Condonf4f54a12018-10-10 23:25:46 +0100155 constructor(
156 protected log: LogService,
157 protected fs: FnService,
158 protected ks: KeysService,
159 protected sus: SvgUtilService,
160 protected ps: PrefsService,
Sean Condon55c30532018-10-29 12:26:57 +0000161 protected wss: WebSocketService,
Sean Condonaa4366d2018-11-02 14:29:01 +0000162 protected ts: TopologyService,
Sean Condon91481822019-01-01 13:56:14 +0000163 protected trs: TrafficService,
164 protected is: IconService,
165 private lion: LionService,
Sean Condonf4f54a12018-10-10 23:25:46 +0100166 ) {
Sean Condon91481822019-01-01 13:56:14 +0000167 if (this.lion.ubercache.length === 0) {
168 this.lionFn = this.dummyLion;
169 this.lion.loadCbs.set('topo-toolbar', () => this.doLion());
170 } else {
171 this.doLion();
172 }
Sean Condonf4f54a12018-10-10 23:25:46 +0100173
Sean Condon91481822019-01-01 13:56:14 +0000174 this.is.loadIconDef('bird');
175 this.is.loadIconDef('active');
176 this.is.loadIconDef('uiAttached');
177 this.is.loadIconDef('m_switch');
178 this.is.loadIconDef('m_roadm');
179 this.is.loadIconDef('m_router');
180 this.is.loadIconDef('m_uiAttached');
181 this.is.loadIconDef('m_endstation');
182 this.is.loadIconDef('m_ports');
183 this.is.loadIconDef('m_summary');
184 this.is.loadIconDef('m_details');
185 this.is.loadIconDef('m_map');
Sean Condon0d064ec2019-02-04 21:53:53 +0000186 this.is.loadIconDef('m_selectMap');
Sean Condon91481822019-01-01 13:56:14 +0000187 this.is.loadIconDef('m_cycleLabels');
Sean Condon71910542019-02-16 18:16:42 +0000188 this.is.loadIconDef('m_cycleGridDisplay');
Sean Condon91481822019-01-01 13:56:14 +0000189 this.is.loadIconDef('m_resetZoom');
190 this.is.loadIconDef('m_eqMaster');
191 this.is.loadIconDef('m_unknown');
192 this.is.loadIconDef('m_allTraffic');
193 this.is.loadIconDef('deviceTable');
194 this.is.loadIconDef('flowTable');
195 this.is.loadIconDef('portTable');
196 this.is.loadIconDef('groupTable');
197 this.is.loadIconDef('meterTable');
198 this.is.loadIconDef('triangleUp');
Sean Condonf4f54a12018-10-10 23:25:46 +0100199 this.log.debug('Topology component constructed');
200 }
201
Sean Condon91481822019-01-01 13:56:14 +0000202 /**
203 * Static functions must come before member variables
204 * @param index
205 */
Sean Condon021f0fa2018-12-06 23:31:11 -0800206 private static deviceLabelFlashMessage(index: number): string {
207 switch (index) {
Sean Condon91481822019-01-01 13:56:14 +0000208 case 0: return 'fl_device_labels_hide';
209 case 1: return 'fl_device_labels_show_friendly';
210 case 2: return 'fl_device_labels_show_id';
Sean Condon021f0fa2018-12-06 23:31:11 -0800211 }
212 }
213
214 private static hostLabelFlashMessage(index: number): string {
215 switch (index) {
Sean Condon91481822019-01-01 13:56:14 +0000216 case 0: return 'fl_host_labels_hide';
217 case 1: return 'fl_host_labels_show_friendly';
218 case 2: return 'fl_host_labels_show_ip';
219 case 3: return 'fl_host_labels_show_mac';
Sean Condon021f0fa2018-12-06 23:31:11 -0800220 }
221 }
222
Sean Condon71910542019-02-16 18:16:42 +0000223 private static gridDisplayFlashMessage(index: number): string {
224 switch (index) {
225 case 0: return 'fl_grid_display_hide';
226 case 1: return 'fl_grid_display_1000';
227 case 2: return 'fl_grid_display_geo';
228 case 3: return 'fl_grid_display_both';
229 }
230 }
231
Sean Condon91481822019-01-01 13:56:14 +0000232 /**
233 * Pass the list of Key Commands to the KeyService, and initialize the Topology
234 * Service - which communicates with through the WebSocket to the ONOS server
235 * to get the nodes and links.
236 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100237 ngOnInit() {
238 this.bindCommands();
Sean Condonaa4366d2018-11-02 14:29:01 +0000239 // The components from the template are handed over to TopologyService here
240 // so that WebSocket responses can be passed back in to them
241 // The handling of the WebSocket call is delegated out to the Topology
242 // Service just to compartmentalize things a bit
243 this.ts.init(this.instance, this.background, this.force);
Sean Condonb2c483c2019-01-16 20:28:55 +0000244
245 this.ps.addListener((data) => this.prefsUpdateHandler(data));
246 this.prefsState = this.ps.getPrefs(TOPO2_PREFS, this.prefsState);
Sean Condon0d064ec2019-02-04 21:53:53 +0000247 this.mapIdState = this.ps.getPrefs(TOPO_MAPID_PREFS, this.mapIdState);
Sean Condonf4f54a12018-10-10 23:25:46 +0100248 this.log.debug('Topology component initialized');
249 }
250
Sean Condon91481822019-01-01 13:56:14 +0000251 /**
Sean Condonb2c483c2019-01-16 20:28:55 +0000252 * Callback function that's called whenever new Prefs are received from WebSocket
253 *
254 * Note: At present the backend server does not filter updated by logged in user,
255 * so you might get updates pertaining to a different user
256 */
257 prefsUpdateHandler(data: any): void {
258 // Extract the TOPO2 prefs from it
Sean Condon0d064ec2019-02-04 21:53:53 +0000259 if (data[TOPO2_PREFS]) {
260 this.prefsState = data[TOPO2_PREFS];
261 }
Sean Condon0d064ec2019-02-04 21:53:53 +0000262 this.log.debug('Updated topo2 prefs', this.prefsState, this.mapIdState);
Sean Condonb2c483c2019-01-16 20:28:55 +0000263 }
264
265 /**
Sean Condon91481822019-01-01 13:56:14 +0000266 * When this component is being stopped, disconnect the TopologyService from
267 * the WebSocket
268 */
Sean Condonaa4366d2018-11-02 14:29:01 +0000269 ngOnDestroy() {
270 this.ts.destroy();
Sean Condonb2c483c2019-01-16 20:28:55 +0000271 this.ps.removeListener((data) => this.prefsUpdateHandler(data));
Sean Condonaa4366d2018-11-02 14:29:01 +0000272 this.log.debug('Topology component destroyed');
273 }
274
Sean Condon91481822019-01-01 13:56:14 +0000275 /**
276 * When ever a toolbar button is clicked, an event is sent up from toolbar
277 * component which is caught and passed on to here.
278 * @param name The name of the button that was clicked
279 */
280 toolbarButtonClicked(name: string) {
281 switch (name) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000282 case INSTANCE_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000283 this.toggleInstancePanel();
284 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000285 case SUMMARY_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000286 this.toggleSummary();
287 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000288 case DETAILS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000289 this.toggleDetails();
290 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000291 case HOSTS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000292 this.toggleHosts();
293 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000294 case OFFLINE_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000295 this.toggleOfflineDevices();
296 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000297 case PORTS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000298 this.togglePorts();
299 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000300 case BKGRND_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000301 this.toggleBackground();
302 break;
Sean Condon0d064ec2019-02-04 21:53:53 +0000303 case BKGRND_SELECT:
304 this.mapSelShown = !this.mapSelShown;
305 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000306 case CYCLELABELS_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000307 this.cycleDeviceLabels();
308 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000309 case CYCLEHOSTLABEL_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000310 this.cycleHostLabels();
311 break;
Sean Condon71910542019-02-16 18:16:42 +0000312 case CYCLEGRIDDISPLAY_BTN:
313 this.cycleGridDisplay();
314 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000315 case RESETZOOM_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000316 this.resetZoom();
317 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000318 case EQMASTER_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000319 this.equalizeMasters();
320 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000321 case CANCEL_TRAFFIC:
Sean Condon91481822019-01-01 13:56:14 +0000322 this.cancelTraffic();
323 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000324 case ALL_TRAFFIC:
Sean Condon91481822019-01-01 13:56:14 +0000325 this.monitorAllTraffic();
326 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000327 case QUICKHELP_BTN:
328 this.ks.quickHelpShown = true;
329 break;
Sean Condon91481822019-01-01 13:56:14 +0000330 default:
331 this.log.warn('Unhandled Toolbar action', name);
332 }
333 }
334
335 /**
336 * The list of key strokes that will be active in the Topology View.
337 *
338 * This action map is passed to the KeyService through the bindCommands()
339 * when this component is being initialized
340 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100341 actionMap() {
342 return {
Sean Condon50855cf2018-12-23 15:37:42 +0000343 A: [() => {this.monitorAllTraffic(); }, 'Monitor all traffic'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100344 B: [(token) => {this.toggleBackground(token); }, 'Toggle background'],
345 D: [(token) => {this.toggleDetails(token); }, 'Toggle details panel'],
Sean Condon71910542019-02-16 18:16:42 +0000346 E: [() => {this.equalizeMasters(); }, 'Equalize mastership roles'],
347 H: [() => {this.toggleHosts(); }, 'Toggle host visibility'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100348 I: [(token) => {this.toggleInstancePanel(token); }, 'Toggle ONOS Instance Panel'],
Sean Condon0d064ec2019-02-04 21:53:53 +0000349 G: [() => {this.mapSelShown = !this.mapSelShown; }, 'Show map selection dialog'],
Sean Condon71910542019-02-16 18:16:42 +0000350 L: [() => {this.cycleDeviceLabels(); }, 'Cycle device labels'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100351 M: [() => {this.toggleOfflineDevices(); }, 'Toggle offline visibility'],
Sean Condon71910542019-02-16 18:16:42 +0000352 O: [() => {this.toggleSummary(); }, 'Toggle the Summary Panel'],
353 P: [(token) => {this.togglePorts(token); }, 'Toggle Port Highlighting'],
354 Q: [() => {this.cycleGridDisplay(); }, 'Cycle grid display'],
355 R: [() => {this.resetZoom(); }, 'Reset pan / zoom'],
356 U: [() => {this.unpinNode(); }, 'Unpin node (mouse over)'],
357 X: [() => {this.resetNodeLocation(); }, 'Reset Node Location'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100358 dot: [() => {this.toggleToolbar(); }, 'Toggle Toolbar'],
Sean Condon50855cf2018-12-23 15:37:42 +0000359 0: [() => {this.cancelTraffic(); }, 'Cancel traffic monitoring'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100360 'shift-L': [() => {this.cycleHostLabels(); }, 'Cycle host labels'],
361
362 // -- instance color palette debug
Sean Condon55c30532018-10-29 12:26:57 +0000363 9: () => {
364 this.sus.cat7().testCard(d3.select('svg#topo2'));
Sean Condonf4f54a12018-10-10 23:25:46 +0100365 },
366
Sean Condonb2c483c2019-01-16 20:28:55 +0000367 esc: [() => {this.handleEscape(); }, 'Cancel commands'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100368
369 // TODO update after adding in Background Service
370 // topology overlay selections
371 // F1: function () { t2tbs.fnKey(0); },
372 // F2: function () { t2tbs.fnKey(1); },
373 // F3: function () { t2tbs.fnKey(2); },
374 // F4: function () { t2tbs.fnKey(3); },
375 // F5: function () { t2tbs.fnKey(4); },
376 //
377 // _keyListener: t2tbs.keyListener.bind(t2tbs),
378
379 _helpFormat: [
380 ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B'],
381 ['X', 'Z', 'N', 'L', 'shift-L', 'U', 'R', 'E', 'dot'],
382 [], // this column reserved for overlay actions
383 ],
384 };
385 }
386
387
388 bindCommands(additional?: any) {
389
390 const am = this.actionMap();
391 const add = this.fs.isO(additional);
392
Sean Condonf4f54a12018-10-10 23:25:46 +0100393 this.ks.keyBindings(am);
394
395 this.ks.gestureNotes([
396 ['click', 'Select the item and show details'],
397 ['shift-click', 'Toggle selection state'],
398 ['drag', 'Reposition (and pin) device / host'],
399 ['cmd-scroll', 'Zoom in / out'],
400 ['cmd-drag', 'Pan'],
401 ]);
402 }
403
404 handleEscape() {
405
406 if (false) {
407 // TODO: Cancel show mastership
408 // TODO: Cancel Active overlay
409 // TODO: Reinstate with components
410 } else {
Sean Condonb2c483c2019-01-16 20:28:55 +0000411 this.nodeSelected(undefined);
Sean Condonf4f54a12018-10-10 23:25:46 +0100412 this.log.debug('Handling escape');
413 // } else if (t2rs.deselectAllNodes()) {
414 // // else if we have node selections, deselect them all
415 // // (work already done)
416 // } else if (t2rs.deselectLink()) {
417 // // else if we have a link selection, deselect it
418 // // (work already done)
419 // } else if (t2is.isVisible()) {
420 // // If the instance panel is visible, close it
421 // t2is.toggle();
422 // } else if (t2sp.isVisible()) {
423 // // If the summary panel is visible, close it
424 // t2sp.toggle();
425 }
426 }
427
Sean Condonb2c483c2019-01-16 20:28:55 +0000428 /**
429 * Updates the cache of preferences locally and onwards to the PrefsService
430 * @param what The attribute of the local topo2-prefs cache to update
431 * @param b the value to update it with
432 */
433 updatePrefsState(what: string, b: number) {
434 this.prefsState[what] = b;
435 this.ps.setPrefs(TOPO2_PREFS, this.prefsState);
Sean Condonf4f54a12018-10-10 23:25:46 +0100436 }
437
Sean Condonb2c483c2019-01-16 20:28:55 +0000438 /**
439 * When the button is clicked on the toolbar or the L key is pressed
440 * 1) cycle through options
441 * 2) flash up a message
442 * 3a) Update the local prefs cache
443 * 3b) And passes on to the global prefs service which sends back to the server
444 * 3c) It also has a knock on effect of passing it on to ForceSvgComponent
445 * because prefsState.dlbls is given as an input to it
446 * 3d) This will in turn pass it down to the DeviceSvgComponent which
447 * displays the label
448 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100449 protected cycleDeviceLabels() {
Sean Condonb2c483c2019-01-16 20:28:55 +0000450 const old: LabelToggle = this.prefsState.dlbls;
Sean Condon021f0fa2018-12-06 23:31:11 -0800451 const next = LabelToggle.next(old);
Sean Condon91481822019-01-01 13:56:14 +0000452 this.flashMsg = this.lionFn(TopologyComponent.deviceLabelFlashMessage(next));
Sean Condonb2c483c2019-01-16 20:28:55 +0000453 this.updatePrefsState(PREF_DLBLS, next);
Sean Condon021f0fa2018-12-06 23:31:11 -0800454 this.log.debug('Cycling device labels', old, next);
Sean Condonf4f54a12018-10-10 23:25:46 +0100455 }
456
457 protected cycleHostLabels() {
Sean Condonb2c483c2019-01-16 20:28:55 +0000458 const old: HostLabelToggle = this.prefsState.hlbls;
Sean Condon021f0fa2018-12-06 23:31:11 -0800459 const next = HostLabelToggle.next(old);
Sean Condon91481822019-01-01 13:56:14 +0000460 this.flashMsg = this.lionFn(TopologyComponent.hostLabelFlashMessage(next));
Sean Condonb2c483c2019-01-16 20:28:55 +0000461 this.updatePrefsState(PREF_HLBLS, next);
Sean Condon021f0fa2018-12-06 23:31:11 -0800462 this.log.debug('Cycling host labels', old, next);
Sean Condonf4f54a12018-10-10 23:25:46 +0100463 }
464
Sean Condon71910542019-02-16 18:16:42 +0000465 protected cycleGridDisplay() {
466 const old: GridDisplayToggle = this.prefsState.grid;
467 const next = GridDisplayToggle.next(old);
468 this.flashMsg = this.lionFn(TopologyComponent.gridDisplayFlashMessage(next));
469 this.updatePrefsState(PREF_GRID, next);
470 this.log.debug('Cycling grid display', old, next);
471 }
472
Sean Condonb2c483c2019-01-16 20:28:55 +0000473 /**
474 * When the button is clicked on the toolbar or the B key is pressed
475 * 1) Find the inverse of the current state (held as 1 or 0)
476 * 2) Flash up a message on screen
477 * 3b) And passes on to the global prefs service which sends back to the server
478 * 3c) It also has a knock on effect of passing it on to ToolbarComponent
479 * because prefsState.bg is given as an input to it
480 * @param token
481 */
Sean Condon91481822019-01-01 13:56:14 +0000482 protected toggleBackground(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000483 const bg: boolean = !Boolean(this.prefsState.bg);
484 this.flashMsg = this.lionFn(bg ? 'show' : 'hide') +
Sean Condon91481822019-01-01 13:56:14 +0000485 ' ' + this.lionFn('fl_background_map');
Sean Condonb2c483c2019-01-16 20:28:55 +0000486 this.updatePrefsState(PREF_BG, bg ? 1 : 0);
487 this.log.debug('Toggling background', token, bg ? 'shown' : 'hidden');
Sean Condonf4f54a12018-10-10 23:25:46 +0100488 }
489
Sean Condon91481822019-01-01 13:56:14 +0000490 protected toggleDetails(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000491 const on: boolean = !Boolean(this.prefsState.detail);
492 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
493 ' ' + this.lionFn('fl_panel_details');
494 this.updatePrefsState(PREF_DETAIL, on ? 1 : 0);
495 this.log.debug('Toggling details', token);
Sean Condonf4f54a12018-10-10 23:25:46 +0100496 }
497
Sean Condon91481822019-01-01 13:56:14 +0000498 protected toggleInstancePanel(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000499 const on: boolean = !Boolean(this.prefsState.insts);
Sean Condon91481822019-01-01 13:56:14 +0000500 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
501 ' ' + this.lionFn('fl_panel_instances');
Sean Condonb2c483c2019-01-16 20:28:55 +0000502 this.updatePrefsState(PREF_INSTS, on ? 1 : 0);
Sean Condon91481822019-01-01 13:56:14 +0000503 this.log.debug('Toggling instances', token, on);
Sean Condonf4f54a12018-10-10 23:25:46 +0100504 }
505
506 protected toggleSummary() {
Sean Condonb2c483c2019-01-16 20:28:55 +0000507 const on: boolean = !Boolean(this.prefsState.summary);
Sean Condon91481822019-01-01 13:56:14 +0000508 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
509 ' ' + this.lionFn('fl_panel_summary');
Sean Condonb2c483c2019-01-16 20:28:55 +0000510 this.updatePrefsState(PREF_SUMMARY, on ? 1 : 0);
511 }
512
513 protected togglePorts(token?: KeysToken) {
514 const current: boolean = !Boolean(this.prefsState.porthl);
515 this.flashMsg = this.lionFn(current ? 'enable' : 'disable') +
516 ' ' + this.lionFn('fl_port_highlighting');
517 this.updatePrefsState(PREF_PORTHL, current ? 1 : 0);
518 this.log.debug(current ? 'Enable' : 'Disable', 'port highlighting');
519 }
520
521 protected toggleToolbar() {
522 const on: boolean = !Boolean(this.prefsState.toolbar);
523 this.updatePrefsState(PREF_TOOLBAR, on ? 1 : 0);
524 this.log.debug('toggling toolbar', on ? 'shown' : 'hidden');
525 }
526
527 protected toggleHosts() {
528 const current: boolean = !Boolean(this.prefsState.hosts);
529 this.flashMsg = this.lionFn('hosts') + ' ' +
530 this.lionFn(this.force.showHosts ? 'visible' : 'hidden');
531 this.updatePrefsState(PREF_HOSTS, current ? 1 : 0);
532 this.log.debug('toggling hosts: ', this.prefsState.hosts ? 'Show' : 'Hide');
533 }
534
535 protected toggleOfflineDevices() {
536 const on: boolean = !Boolean(this.prefsState.offdev);
537 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
538 ' ' + this.lionFn('fl_offline_devices');
539 this.updatePrefsState(PREF_OFFDEV, on ? 1 : 0);
540 this.log.debug('toggling offline devices', this.prefsState.offdev);
Sean Condonf4f54a12018-10-10 23:25:46 +0100541 }
542
543 protected resetZoom() {
Sean Condon91481822019-01-01 13:56:14 +0000544 this.zoomDirective.resetZoom();
545 this.flashMsg = this.lionFn('fl_pan_zoom_reset');
Sean Condonf4f54a12018-10-10 23:25:46 +0100546 }
547
Sean Condonf4f54a12018-10-10 23:25:46 +0100548 protected equalizeMasters() {
549 this.wss.sendEvent('equalizeMasters', null);
Sean Condon91481822019-01-01 13:56:14 +0000550 this.flashMsg = this.lionFn('fl_eq_masters');
Sean Condonf4f54a12018-10-10 23:25:46 +0100551 this.log.debug('equalizing masters');
Sean Condonf4f54a12018-10-10 23:25:46 +0100552 }
553
554 protected resetNodeLocation() {
Sean Condon91481822019-01-01 13:56:14 +0000555 // TODO: Implement reset locations
Sean Condon1ae15802019-03-02 09:07:18 +0000556 this.force.resetNodeLocations();
Sean Condon91481822019-01-01 13:56:14 +0000557 this.flashMsg = this.lionFn('fl_reset_node_locations');
Sean Condonf4f54a12018-10-10 23:25:46 +0100558 this.log.debug('resetting node location');
Sean Condonf4f54a12018-10-10 23:25:46 +0100559 }
560
561 protected unpinNode() {
Sean Condon91481822019-01-01 13:56:14 +0000562 // TODO: Implement this
Sean Condonf4f54a12018-10-10 23:25:46 +0100563 this.log.debug('unpinning node');
Sean Condonf4f54a12018-10-10 23:25:46 +0100564 }
565
Sean Condon91481822019-01-01 13:56:14 +0000566 /**
567 * Check to see if this is needed anymore
568 * @param what
569 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100570 protected notValid(what) {
571 this.log.warn('topo.js getActionEntry(): Not a valid ' + what);
572 }
573
Sean Condon91481822019-01-01 13:56:14 +0000574 /**
575 * Check to see if this is needed anymore
576 * @param what
577 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100578 getActionEntry(key) {
579 let entry;
580
581 if (!key) {
582 this.notValid('key');
583 return null;
584 }
585
586 entry = this.actionMap()[key];
587
588 if (!entry) {
589 this.notValid('actionMap (' + key + ') entry');
590 return null;
591 }
592 return this.fs.isA(entry) || [entry, ''];
593 }
594
Sean Condon91481822019-01-01 13:56:14 +0000595 /**
596 * An event handler that updates the details panel as items are
597 * selected in the forcesvg layer
598 * @param nodeOrLink the item to display details of
599 */
600 nodeSelected(nodeOrLink: UiElement) {
601 this.details.ngOnChanges({'selectedNode':
602 new SimpleChange(undefined, nodeOrLink, true)});
Sean Condon0c577f62018-11-18 22:40:05 +0000603 }
604
Sean Condon50855cf2018-12-23 15:37:42 +0000605 /**
606 * Enable traffic monitoring
607 */
608 monitorAllTraffic() {
Sean Condon91481822019-01-01 13:56:14 +0000609 // TODO: Implement support for toggling between bits, packets and octets
610 this.flashMsg = this.lionFn('tr_fl_pstats_bits');
Sean Condon50855cf2018-12-23 15:37:42 +0000611 this.trs.init(this.force);
612 }
613
614 /**
615 * Cancel traffic monitoring
616 */
617 cancelTraffic() {
Sean Condon91481822019-01-01 13:56:14 +0000618 this.flashMsg = this.lionFn('fl_monitoring_canceled');
Sean Condon50855cf2018-12-23 15:37:42 +0000619 this.trs.destroy();
620 }
Sean Condon91481822019-01-01 13:56:14 +0000621
Sean Condon0d064ec2019-02-04 21:53:53 +0000622 changeMap(map: MapObject) {
623 this.mapSelShown = false; // Hide the MapSelector component
624 this.mapIdState = map;
625 this.ps.setPrefs(TOPO_MAPID_PREFS, this.mapIdState);
626 this.log.debug('Map has been changed to ', map);
627 }
628
Sean Condon1ae15802019-03-02 09:07:18 +0000629 mapExtentsZoom(zoomMapExtents: TopoZoomPrefs) {
630 // this.zoomDirective.updateZoomState(zoomPrefs.tx, zoomPrefs.ty, zoomPrefs.sc);
631 this.zoomDirective.changeZoomLevel(zoomMapExtents);
632 this.log.debug('Map zoom prefs updated', zoomMapExtents);
633 }
634
Sean Condon91481822019-01-01 13:56:14 +0000635 /**
636 * Read the LION bundle for Toolbar and set up the lionFn
637 */
638 doLion() {
639 this.lionFn = this.lion.bundle('core.view.Topo');
640 }
641
642 /**
643 * A dummy implementation of the lionFn until the response is received and the LION
644 * bundle is received from the WebSocket
645 */
646 dummyLion(key: string): string {
647 return '%' + key + '%';
648 }
Sean Condonf4f54a12018-10-10 23:25:46 +0100649}