blob: 9f2a08b8c50f90f65e83ab075ab69161cda8660d [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 {
Sean Condonff85fbe2019-03-16 14:28:46 +000017 AfterContentInit,
18 Component, HostListener, Inject, Input,
Sean Condon0c577f62018-11-18 22:40:05 +000019 OnDestroy,
Sean Condon021f0fa2018-12-06 23:31:11 -080020 OnInit, SimpleChange,
Sean Condon0c577f62018-11-18 22:40:05 +000021 ViewChild
22} from '@angular/core';
Sean Condon55c30532018-10-29 12:26:57 +000023import * as d3 from 'd3';
Sean Condonf4f54a12018-10-10 23:25:46 +010024import {
Sean Condon28884332019-03-21 14:07:00 +000025 FnService,
26 IconService,
Sean Condon0c577f62018-11-18 22:40:05 +000027 KeysService,
Sean Condon28884332019-03-21 14:07:00 +000028 KeysToken,
29 LionService,
Sean Condon0c577f62018-11-18 22:40:05 +000030 LogService,
31 PrefsService,
32 SvgUtilService,
Sean Condon28884332019-03-21 14:07:00 +000033 TopoZoomPrefs,
Sean Condon0c577f62018-11-18 22:40:05 +000034 WebSocketService,
Sean Condon28884332019-03-21 14:07:00 +000035 ZoomUtils
Sean Condonf4f54a12018-10-10 23:25:46 +010036} from 'gui2-fw-lib';
Sean Condon0c577f62018-11-18 22:40:05 +000037import {InstanceComponent} from '../panel/instance/instance.component';
Sean Condon0c577f62018-11-18 22:40:05 +000038import {DetailsComponent} from '../panel/details/details.component';
39import {BackgroundSvgComponent} from '../layer/backgroundsvg/backgroundsvg.component';
40import {ForceSvgComponent} from '../layer/forcesvg/forcesvg.component';
41import {TopologyService} from '../topology.service';
Sean Condon91481822019-01-01 13:56:14 +000042import {
Sean Condon71910542019-02-16 18:16:42 +000043 GridDisplayToggle,
Sean Condon91481822019-01-01 13:56:14 +000044 HostLabelToggle,
45 LabelToggle,
46 UiElement
47} from '../layer/forcesvg/models';
Sean Condonb2c483c2019-01-16 20:28:55 +000048import {
Sean Condon28884332019-03-21 14:07:00 +000049 ALL_TRAFFIC,
50 BKGRND_SELECT,
51 BKGRND_TOGGLE,
52 CANCEL_TRAFFIC,
53 CYCLEGRIDDISPLAY_BTN,
54 CYCLEHOSTLABEL_BTN,
55 CYCLELABELS_BTN,
56 DETAILS_TOGGLE,
57 EQMASTER_BTN,
58 HOSTS_TOGGLE,
59 INSTANCE_TOGGLE,
60 LAYOUT_ACCESS_BTN,
61 LAYOUT_DEFAULT_BTN,
62 OFFLINE_TOGGLE,
63 PORTS_TOGGLE,
64 QUICKHELP_BTN,
65 RESETZOOM_BTN,
66 SUMMARY_TOGGLE
Sean Condonb2c483c2019-01-16 20:28:55 +000067} from '../panel/toolbar/toolbar.component';
Sean Condon50855cf2018-12-23 15:37:42 +000068import {TrafficService} from '../traffic.service';
Sean Condon91481822019-01-01 13:56:14 +000069import {ZoomableDirective} from '../layer/zoomable.directive';
Sean Condon0d064ec2019-02-04 21:53:53 +000070import {MapObject} from '../layer/maputils';
Sean Condon28884332019-03-21 14:07:00 +000071import {LayoutService, LayoutType} from '../layout.service';
Sean Condonf4f54a12018-10-10 23:25:46 +010072
Sean Condonb2c483c2019-01-16 20:28:55 +000073const TOPO2_PREFS = 'topo2_prefs';
Sean Condon0d064ec2019-02-04 21:53:53 +000074const TOPO_MAPID_PREFS = 'topo_mapid';
75
Sean Condonb2c483c2019-01-16 20:28:55 +000076const PREF_BG = 'bg';
77const PREF_DETAIL = 'detail';
78const PREF_DLBLS = 'dlbls';
79const PREF_HLBLS = 'hlbls';
Sean Condon71910542019-02-16 18:16:42 +000080const PREF_GRID = 'grid';
Sean Condonb2c483c2019-01-16 20:28:55 +000081const PREF_HOSTS = 'hosts';
82const PREF_INSTS = 'insts';
83const PREF_OFFDEV = 'offdev';
84const PREF_PORTHL = 'porthl';
85const PREF_SUMMARY = 'summary';
86const PREF_TOOLBAR = 'toolbar';
87
88/**
Sean Condon0d064ec2019-02-04 21:53:53 +000089 * Model of the topo2_prefs object - this is a subset of the overall Prefs returned
Sean Condonb2c483c2019-01-16 20:28:55 +000090 * by the server
91 */
92export interface Topo2Prefs {
93 bg: number;
94 detail: number;
95 dlbls: number;
96 hlbls: number;
97 hosts: number;
98 insts: number;
99 offdev: number;
100 porthl: number;
101 spr: number;
102 ovid: string;
103 summary: number;
104 toolbar: number;
Sean Condon71910542019-02-16 18:16:42 +0000105 grid: number;
Sean Condonb2c483c2019-01-16 20:28:55 +0000106}
107
Sean Condonf4f54a12018-10-10 23:25:46 +0100108/**
109 * ONOS GUI Topology View
110 *
111 * This Topology View component is the top level component in a hierarchy that
112 * comprises the whole Topology View
113 *
114 * There are three main parts (panels, graphical and breadcrumbs)
115 * The panel hierarchy
116 * |-- Instances Panel (shows ONOS instances)
117 * |-- Summary Panel (summary of ONOS)
118 * |-- Toolbar Panel (the toolbar)
119 * |-- Details Panel (when a node is selected in the Force graphical view (see below))
120 *
121 * The graphical hierarchy contains
122 * Topology (this)
123 * |-- No Devices Connected (only of there are no nodes to show)
124 * |-- Zoom Layer (everything beneath this can be zoomed and panned)
125 * |-- Background (container for any backgrounds - can be toggled on and off)
126 * |-- Map
127 * |-- Forces (all of the nodes and links laid out by a d3.force simulation)
128 *
129 * The breadcrumbs
130 * |-- Breadcrumb (in region view a way of navigating back up through regions)
131 */
132@Component({
133 selector: 'onos-topology',
134 templateUrl: './topology.component.html',
135 styleUrls: ['./topology.component.css']
136})
Sean Condonff85fbe2019-03-16 14:28:46 +0000137export class TopologyComponent implements AfterContentInit, OnInit, OnDestroy {
138 @Input() bannerHeight: number = 48;
Sean Condonaa4366d2018-11-02 14:29:01 +0000139 // These are references to the components inserted in the template
Sean Condonf4f54a12018-10-10 23:25:46 +0100140 @ViewChild(InstanceComponent) instance: InstanceComponent;
Sean Condonf4f54a12018-10-10 23:25:46 +0100141 @ViewChild(DetailsComponent) details: DetailsComponent;
Sean Condonaa4366d2018-11-02 14:29:01 +0000142 @ViewChild(BackgroundSvgComponent) background: BackgroundSvgComponent;
143 @ViewChild(ForceSvgComponent) force: ForceSvgComponent;
Sean Condon91481822019-01-01 13:56:14 +0000144 @ViewChild(ZoomableDirective) zoomDirective: ZoomableDirective;
Sean Condonf4f54a12018-10-10 23:25:46 +0100145
146 flashMsg: string = '';
Sean Condonb2c483c2019-01-16 20:28:55 +0000147 // These are used as defaults if nothing is set on the server
148 prefsState: Topo2Prefs = <Topo2Prefs>{
149 bg: 0,
150 detail: 1,
151 dlbls: 0,
152 hlbls: 2,
153 hosts: 0,
154 insts: 1,
155 offdev: 1,
156 ovid: 'traffic', // default to traffic overlay
157 porthl: 1,
158 spr: 0,
159 summary: 1,
160 toolbar: 0,
Sean Condon71910542019-02-16 18:16:42 +0000161 grid: 0
Sean Condonb2c483c2019-01-16 20:28:55 +0000162 };
Sean Condon0d064ec2019-02-04 21:53:53 +0000163
164 mapIdState: MapObject = <MapObject>{
165 id: undefined,
166 scale: 1.0
167 };
168 mapSelShown: boolean = false;
Sean Condon91481822019-01-01 13:56:14 +0000169 lionFn; // Function
Sean Condon55c30532018-10-29 12:26:57 +0000170
Sean Condon71910542019-02-16 18:16:42 +0000171 gridShown: boolean = true;
172 geoGridShown: boolean = true;
173
Sean Condonf4f54a12018-10-10 23:25:46 +0100174 constructor(
175 protected log: LogService,
176 protected fs: FnService,
177 protected ks: KeysService,
178 protected sus: SvgUtilService,
179 protected ps: PrefsService,
Sean Condon55c30532018-10-29 12:26:57 +0000180 protected wss: WebSocketService,
Sean Condonaa4366d2018-11-02 14:29:01 +0000181 protected ts: TopologyService,
Sean Condon91481822019-01-01 13:56:14 +0000182 protected trs: TrafficService,
183 protected is: IconService,
184 private lion: LionService,
Sean Condon28884332019-03-21 14:07:00 +0000185 private layout: LayoutService,
Sean Condonff85fbe2019-03-16 14:28:46 +0000186 @Inject('Window') public window: any,
Sean Condonf4f54a12018-10-10 23:25:46 +0100187 ) {
Sean Condon91481822019-01-01 13:56:14 +0000188 if (this.lion.ubercache.length === 0) {
189 this.lionFn = this.dummyLion;
190 this.lion.loadCbs.set('topo-toolbar', () => this.doLion());
191 } else {
192 this.doLion();
193 }
Sean Condonf4f54a12018-10-10 23:25:46 +0100194
Sean Condon91481822019-01-01 13:56:14 +0000195 this.is.loadIconDef('bird');
196 this.is.loadIconDef('active');
197 this.is.loadIconDef('uiAttached');
198 this.is.loadIconDef('m_switch');
199 this.is.loadIconDef('m_roadm');
200 this.is.loadIconDef('m_router');
201 this.is.loadIconDef('m_uiAttached');
202 this.is.loadIconDef('m_endstation');
203 this.is.loadIconDef('m_ports');
204 this.is.loadIconDef('m_summary');
205 this.is.loadIconDef('m_details');
206 this.is.loadIconDef('m_map');
Sean Condon0d064ec2019-02-04 21:53:53 +0000207 this.is.loadIconDef('m_selectMap');
Sean Condon91481822019-01-01 13:56:14 +0000208 this.is.loadIconDef('m_cycleLabels');
Sean Condon71910542019-02-16 18:16:42 +0000209 this.is.loadIconDef('m_cycleGridDisplay');
Sean Condon91481822019-01-01 13:56:14 +0000210 this.is.loadIconDef('m_resetZoom');
211 this.is.loadIconDef('m_eqMaster');
212 this.is.loadIconDef('m_unknown');
213 this.is.loadIconDef('m_allTraffic');
214 this.is.loadIconDef('deviceTable');
215 this.is.loadIconDef('flowTable');
216 this.is.loadIconDef('portTable');
217 this.is.loadIconDef('groupTable');
218 this.is.loadIconDef('meterTable');
219 this.is.loadIconDef('triangleUp');
Sean Condon28884332019-03-21 14:07:00 +0000220 this.is.loadIconDef('m_disjointPaths');
221 this.is.loadIconDef('m_fiberSwitch');
Sean Condonf4f54a12018-10-10 23:25:46 +0100222 this.log.debug('Topology component constructed');
223 }
224
Sean Condon91481822019-01-01 13:56:14 +0000225 /**
226 * Static functions must come before member variables
Sean Condonff85fbe2019-03-16 14:28:46 +0000227 * @param index Corresponds to LabelToggle.Enum index
Sean Condon91481822019-01-01 13:56:14 +0000228 */
Sean Condon021f0fa2018-12-06 23:31:11 -0800229 private static deviceLabelFlashMessage(index: number): string {
230 switch (index) {
Sean Condon91481822019-01-01 13:56:14 +0000231 case 0: return 'fl_device_labels_hide';
232 case 1: return 'fl_device_labels_show_friendly';
233 case 2: return 'fl_device_labels_show_id';
Sean Condon021f0fa2018-12-06 23:31:11 -0800234 }
235 }
236
237 private static hostLabelFlashMessage(index: number): string {
238 switch (index) {
Sean Condon91481822019-01-01 13:56:14 +0000239 case 0: return 'fl_host_labels_hide';
240 case 1: return 'fl_host_labels_show_friendly';
241 case 2: return 'fl_host_labels_show_ip';
242 case 3: return 'fl_host_labels_show_mac';
Sean Condon021f0fa2018-12-06 23:31:11 -0800243 }
244 }
245
Sean Condon71910542019-02-16 18:16:42 +0000246 private static gridDisplayFlashMessage(index: number): string {
247 switch (index) {
248 case 0: return 'fl_grid_display_hide';
249 case 1: return 'fl_grid_display_1000';
250 case 2: return 'fl_grid_display_geo';
251 case 3: return 'fl_grid_display_both';
252 }
253 }
254
Sean Condon91481822019-01-01 13:56:14 +0000255 /**
256 * Pass the list of Key Commands to the KeyService, and initialize the Topology
257 * Service - which communicates with through the WebSocket to the ONOS server
258 * to get the nodes and links.
259 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100260 ngOnInit() {
261 this.bindCommands();
Sean Condonaa4366d2018-11-02 14:29:01 +0000262 // The components from the template are handed over to TopologyService here
263 // so that WebSocket responses can be passed back in to them
264 // The handling of the WebSocket call is delegated out to the Topology
265 // Service just to compartmentalize things a bit
266 this.ts.init(this.instance, this.background, this.force);
Sean Condonb2c483c2019-01-16 20:28:55 +0000267
268 this.ps.addListener((data) => this.prefsUpdateHandler(data));
269 this.prefsState = this.ps.getPrefs(TOPO2_PREFS, this.prefsState);
Sean Condon0d064ec2019-02-04 21:53:53 +0000270 this.mapIdState = this.ps.getPrefs(TOPO_MAPID_PREFS, this.mapIdState);
Sean Condonff85fbe2019-03-16 14:28:46 +0000271
Sean Condonf4f54a12018-10-10 23:25:46 +0100272 this.log.debug('Topology component initialized');
273 }
274
Sean Condonff85fbe2019-03-16 14:28:46 +0000275 ngAfterContentInit(): void {
276 // Scale the window initially - then after resize
277 const zoomMapExtents = ZoomUtils.zoomToWindowSize(
278 this.bannerHeight, this.window.innerWidth, this.window.innerHeight);
279 this.zoomDirective.changeZoomLevel(zoomMapExtents, true);
280 this.log.debug('Topology zoom initialized',
281 this.bannerHeight, this.window.innerWidth, this.window.innerHeight,
282 zoomMapExtents);
283 }
284
Sean Condon91481822019-01-01 13:56:14 +0000285 /**
Sean Condonb2c483c2019-01-16 20:28:55 +0000286 * Callback function that's called whenever new Prefs are received from WebSocket
287 *
288 * Note: At present the backend server does not filter updated by logged in user,
289 * so you might get updates pertaining to a different user
290 */
291 prefsUpdateHandler(data: any): void {
292 // Extract the TOPO2 prefs from it
Sean Condon0d064ec2019-02-04 21:53:53 +0000293 if (data[TOPO2_PREFS]) {
294 this.prefsState = data[TOPO2_PREFS];
295 }
Sean Condon0d064ec2019-02-04 21:53:53 +0000296 this.log.debug('Updated topo2 prefs', this.prefsState, this.mapIdState);
Sean Condonb2c483c2019-01-16 20:28:55 +0000297 }
298
299 /**
Sean Condon91481822019-01-01 13:56:14 +0000300 * When this component is being stopped, disconnect the TopologyService from
301 * the WebSocket
302 */
Sean Condonaa4366d2018-11-02 14:29:01 +0000303 ngOnDestroy() {
304 this.ts.destroy();
Sean Condonb2c483c2019-01-16 20:28:55 +0000305 this.ps.removeListener((data) => this.prefsUpdateHandler(data));
Sean Condonaa4366d2018-11-02 14:29:01 +0000306 this.log.debug('Topology component destroyed');
307 }
308
Sean Condonff85fbe2019-03-16 14:28:46 +0000309 @HostListener('window:resize', ['$event'])
310 onResize(event) {
311 const zoomMapExtents = ZoomUtils.zoomToWindowSize(
312 this.bannerHeight, event.target.innerWidth, event.target.innerHeight);
313 this.zoomDirective.changeZoomLevel(zoomMapExtents, true);
314 this.log.debug('Topology window resize',
315 event.target.innerWidth, event.target.innerHeight, this.bannerHeight, zoomMapExtents);
316 }
317
Sean Condon91481822019-01-01 13:56:14 +0000318 /**
319 * When ever a toolbar button is clicked, an event is sent up from toolbar
320 * component which is caught and passed on to here.
321 * @param name The name of the button that was clicked
322 */
323 toolbarButtonClicked(name: string) {
324 switch (name) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000325 case INSTANCE_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000326 this.toggleInstancePanel();
327 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000328 case SUMMARY_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000329 this.toggleSummary();
330 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000331 case DETAILS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000332 this.toggleDetails();
333 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000334 case HOSTS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000335 this.toggleHosts();
336 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000337 case OFFLINE_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000338 this.toggleOfflineDevices();
339 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000340 case PORTS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000341 this.togglePorts();
342 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000343 case BKGRND_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000344 this.toggleBackground();
345 break;
Sean Condon0d064ec2019-02-04 21:53:53 +0000346 case BKGRND_SELECT:
347 this.mapSelShown = !this.mapSelShown;
348 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000349 case CYCLELABELS_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000350 this.cycleDeviceLabels();
351 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000352 case CYCLEHOSTLABEL_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000353 this.cycleHostLabels();
354 break;
Sean Condon71910542019-02-16 18:16:42 +0000355 case CYCLEGRIDDISPLAY_BTN:
356 this.cycleGridDisplay();
357 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000358 case RESETZOOM_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000359 this.resetZoom();
360 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000361 case EQMASTER_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000362 this.equalizeMasters();
363 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000364 case CANCEL_TRAFFIC:
Sean Condon91481822019-01-01 13:56:14 +0000365 this.cancelTraffic();
366 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000367 case ALL_TRAFFIC:
Sean Condon91481822019-01-01 13:56:14 +0000368 this.monitorAllTraffic();
369 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000370 case QUICKHELP_BTN:
371 this.ks.quickHelpShown = true;
372 break;
Sean Condon28884332019-03-21 14:07:00 +0000373 case LAYOUT_DEFAULT_BTN:
374 this.layout.changeLayout(LayoutType.LAYOUT_DEFAULT);
375 break;
376 case LAYOUT_ACCESS_BTN:
377 this.layout.changeLayout(LayoutType.LAYOUT_ACCESS);
378 break;
Sean Condon91481822019-01-01 13:56:14 +0000379 default:
380 this.log.warn('Unhandled Toolbar action', name);
381 }
382 }
383
384 /**
385 * The list of key strokes that will be active in the Topology View.
386 *
387 * This action map is passed to the KeyService through the bindCommands()
388 * when this component is being initialized
389 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100390 actionMap() {
391 return {
Sean Condon50855cf2018-12-23 15:37:42 +0000392 A: [() => {this.monitorAllTraffic(); }, 'Monitor all traffic'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100393 B: [(token) => {this.toggleBackground(token); }, 'Toggle background'],
394 D: [(token) => {this.toggleDetails(token); }, 'Toggle details panel'],
Sean Condon71910542019-02-16 18:16:42 +0000395 E: [() => {this.equalizeMasters(); }, 'Equalize mastership roles'],
396 H: [() => {this.toggleHosts(); }, 'Toggle host visibility'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100397 I: [(token) => {this.toggleInstancePanel(token); }, 'Toggle ONOS Instance Panel'],
Sean Condon0d064ec2019-02-04 21:53:53 +0000398 G: [() => {this.mapSelShown = !this.mapSelShown; }, 'Show map selection dialog'],
Sean Condon71910542019-02-16 18:16:42 +0000399 L: [() => {this.cycleDeviceLabels(); }, 'Cycle device labels'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100400 M: [() => {this.toggleOfflineDevices(); }, 'Toggle offline visibility'],
Sean Condon71910542019-02-16 18:16:42 +0000401 O: [() => {this.toggleSummary(); }, 'Toggle the Summary Panel'],
402 P: [(token) => {this.togglePorts(token); }, 'Toggle Port Highlighting'],
403 Q: [() => {this.cycleGridDisplay(); }, 'Cycle grid display'],
404 R: [() => {this.resetZoom(); }, 'Reset pan / zoom'],
405 U: [() => {this.unpinNode(); }, 'Unpin node (mouse over)'],
406 X: [() => {this.resetNodeLocation(); }, 'Reset Node Location'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100407 dot: [() => {this.toggleToolbar(); }, 'Toggle Toolbar'],
Sean Condon50855cf2018-12-23 15:37:42 +0000408 0: [() => {this.cancelTraffic(); }, 'Cancel traffic monitoring'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100409 'shift-L': [() => {this.cycleHostLabels(); }, 'Cycle host labels'],
410
411 // -- instance color palette debug
Sean Condon55c30532018-10-29 12:26:57 +0000412 9: () => {
413 this.sus.cat7().testCard(d3.select('svg#topo2'));
Sean Condonf4f54a12018-10-10 23:25:46 +0100414 },
415
Sean Condonb2c483c2019-01-16 20:28:55 +0000416 esc: [() => {this.handleEscape(); }, 'Cancel commands'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100417
418 // TODO update after adding in Background Service
419 // topology overlay selections
420 // F1: function () { t2tbs.fnKey(0); },
421 // F2: function () { t2tbs.fnKey(1); },
422 // F3: function () { t2tbs.fnKey(2); },
423 // F4: function () { t2tbs.fnKey(3); },
424 // F5: function () { t2tbs.fnKey(4); },
425 //
426 // _keyListener: t2tbs.keyListener.bind(t2tbs),
427
428 _helpFormat: [
429 ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B'],
430 ['X', 'Z', 'N', 'L', 'shift-L', 'U', 'R', 'E', 'dot'],
431 [], // this column reserved for overlay actions
432 ],
433 };
434 }
435
436
437 bindCommands(additional?: any) {
438
439 const am = this.actionMap();
440 const add = this.fs.isO(additional);
441
Sean Condonf4f54a12018-10-10 23:25:46 +0100442 this.ks.keyBindings(am);
443
444 this.ks.gestureNotes([
445 ['click', 'Select the item and show details'],
446 ['shift-click', 'Toggle selection state'],
447 ['drag', 'Reposition (and pin) device / host'],
448 ['cmd-scroll', 'Zoom in / out'],
449 ['cmd-drag', 'Pan'],
450 ]);
451 }
452
453 handleEscape() {
454
455 if (false) {
456 // TODO: Cancel show mastership
457 // TODO: Cancel Active overlay
458 // TODO: Reinstate with components
459 } else {
Sean Condonb2c483c2019-01-16 20:28:55 +0000460 this.nodeSelected(undefined);
Sean Condonf4f54a12018-10-10 23:25:46 +0100461 this.log.debug('Handling escape');
462 // } else if (t2rs.deselectAllNodes()) {
463 // // else if we have node selections, deselect them all
464 // // (work already done)
465 // } else if (t2rs.deselectLink()) {
466 // // else if we have a link selection, deselect it
467 // // (work already done)
468 // } else if (t2is.isVisible()) {
469 // // If the instance panel is visible, close it
470 // t2is.toggle();
471 // } else if (t2sp.isVisible()) {
472 // // If the summary panel is visible, close it
473 // t2sp.toggle();
474 }
475 }
476
Sean Condonb2c483c2019-01-16 20:28:55 +0000477 /**
478 * Updates the cache of preferences locally and onwards to the PrefsService
479 * @param what The attribute of the local topo2-prefs cache to update
480 * @param b the value to update it with
481 */
482 updatePrefsState(what: string, b: number) {
483 this.prefsState[what] = b;
484 this.ps.setPrefs(TOPO2_PREFS, this.prefsState);
Sean Condonf4f54a12018-10-10 23:25:46 +0100485 }
486
Sean Condonb2c483c2019-01-16 20:28:55 +0000487 /**
488 * When the button is clicked on the toolbar or the L key is pressed
489 * 1) cycle through options
490 * 2) flash up a message
491 * 3a) Update the local prefs cache
492 * 3b) And passes on to the global prefs service which sends back to the server
493 * 3c) It also has a knock on effect of passing it on to ForceSvgComponent
494 * because prefsState.dlbls is given as an input to it
495 * 3d) This will in turn pass it down to the DeviceSvgComponent which
496 * displays the label
497 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100498 protected cycleDeviceLabels() {
Sean Condonff85fbe2019-03-16 14:28:46 +0000499 const old: LabelToggle.Enum = this.prefsState.dlbls;
Sean Condon021f0fa2018-12-06 23:31:11 -0800500 const next = LabelToggle.next(old);
Sean Condon91481822019-01-01 13:56:14 +0000501 this.flashMsg = this.lionFn(TopologyComponent.deviceLabelFlashMessage(next));
Sean Condonb2c483c2019-01-16 20:28:55 +0000502 this.updatePrefsState(PREF_DLBLS, next);
Sean Condon021f0fa2018-12-06 23:31:11 -0800503 this.log.debug('Cycling device labels', old, next);
Sean Condonf4f54a12018-10-10 23:25:46 +0100504 }
505
506 protected cycleHostLabels() {
Sean Condonff85fbe2019-03-16 14:28:46 +0000507 const old: HostLabelToggle.Enum = this.prefsState.hlbls;
Sean Condon021f0fa2018-12-06 23:31:11 -0800508 const next = HostLabelToggle.next(old);
Sean Condon91481822019-01-01 13:56:14 +0000509 this.flashMsg = this.lionFn(TopologyComponent.hostLabelFlashMessage(next));
Sean Condonb2c483c2019-01-16 20:28:55 +0000510 this.updatePrefsState(PREF_HLBLS, next);
Sean Condon021f0fa2018-12-06 23:31:11 -0800511 this.log.debug('Cycling host labels', old, next);
Sean Condonf4f54a12018-10-10 23:25:46 +0100512 }
513
Sean Condon71910542019-02-16 18:16:42 +0000514 protected cycleGridDisplay() {
Sean Condonff85fbe2019-03-16 14:28:46 +0000515 const old: GridDisplayToggle.Enum = this.prefsState.grid;
Sean Condon71910542019-02-16 18:16:42 +0000516 const next = GridDisplayToggle.next(old);
517 this.flashMsg = this.lionFn(TopologyComponent.gridDisplayFlashMessage(next));
518 this.updatePrefsState(PREF_GRID, next);
519 this.log.debug('Cycling grid display', old, next);
520 }
521
Sean Condonb2c483c2019-01-16 20:28:55 +0000522 /**
523 * When the button is clicked on the toolbar or the B key is pressed
524 * 1) Find the inverse of the current state (held as 1 or 0)
525 * 2) Flash up a message on screen
526 * 3b) And passes on to the global prefs service which sends back to the server
527 * 3c) It also has a knock on effect of passing it on to ToolbarComponent
528 * because prefsState.bg is given as an input to it
Sean Condonff85fbe2019-03-16 14:28:46 +0000529 * @param token not currently used
Sean Condonb2c483c2019-01-16 20:28:55 +0000530 */
Sean Condon91481822019-01-01 13:56:14 +0000531 protected toggleBackground(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000532 const bg: boolean = !Boolean(this.prefsState.bg);
533 this.flashMsg = this.lionFn(bg ? 'show' : 'hide') +
Sean Condon91481822019-01-01 13:56:14 +0000534 ' ' + this.lionFn('fl_background_map');
Sean Condonb2c483c2019-01-16 20:28:55 +0000535 this.updatePrefsState(PREF_BG, bg ? 1 : 0);
536 this.log.debug('Toggling background', token, bg ? 'shown' : 'hidden');
Sean Condonf4f54a12018-10-10 23:25:46 +0100537 }
538
Sean Condon91481822019-01-01 13:56:14 +0000539 protected toggleDetails(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000540 const on: boolean = !Boolean(this.prefsState.detail);
541 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
542 ' ' + this.lionFn('fl_panel_details');
543 this.updatePrefsState(PREF_DETAIL, on ? 1 : 0);
544 this.log.debug('Toggling details', token);
Sean Condonf4f54a12018-10-10 23:25:46 +0100545 }
546
Sean Condon91481822019-01-01 13:56:14 +0000547 protected toggleInstancePanel(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000548 const on: boolean = !Boolean(this.prefsState.insts);
Sean Condon91481822019-01-01 13:56:14 +0000549 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
550 ' ' + this.lionFn('fl_panel_instances');
Sean Condonb2c483c2019-01-16 20:28:55 +0000551 this.updatePrefsState(PREF_INSTS, on ? 1 : 0);
Sean Condon91481822019-01-01 13:56:14 +0000552 this.log.debug('Toggling instances', token, on);
Sean Condonf4f54a12018-10-10 23:25:46 +0100553 }
554
555 protected toggleSummary() {
Sean Condonb2c483c2019-01-16 20:28:55 +0000556 const on: boolean = !Boolean(this.prefsState.summary);
Sean Condon91481822019-01-01 13:56:14 +0000557 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
558 ' ' + this.lionFn('fl_panel_summary');
Sean Condonb2c483c2019-01-16 20:28:55 +0000559 this.updatePrefsState(PREF_SUMMARY, on ? 1 : 0);
560 }
561
562 protected togglePorts(token?: KeysToken) {
563 const current: boolean = !Boolean(this.prefsState.porthl);
564 this.flashMsg = this.lionFn(current ? 'enable' : 'disable') +
565 ' ' + this.lionFn('fl_port_highlighting');
566 this.updatePrefsState(PREF_PORTHL, current ? 1 : 0);
567 this.log.debug(current ? 'Enable' : 'Disable', 'port highlighting');
568 }
569
570 protected toggleToolbar() {
571 const on: boolean = !Boolean(this.prefsState.toolbar);
572 this.updatePrefsState(PREF_TOOLBAR, on ? 1 : 0);
573 this.log.debug('toggling toolbar', on ? 'shown' : 'hidden');
574 }
575
576 protected toggleHosts() {
577 const current: boolean = !Boolean(this.prefsState.hosts);
578 this.flashMsg = this.lionFn('hosts') + ' ' +
579 this.lionFn(this.force.showHosts ? 'visible' : 'hidden');
580 this.updatePrefsState(PREF_HOSTS, current ? 1 : 0);
581 this.log.debug('toggling hosts: ', this.prefsState.hosts ? 'Show' : 'Hide');
582 }
583
584 protected toggleOfflineDevices() {
585 const on: boolean = !Boolean(this.prefsState.offdev);
586 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
587 ' ' + this.lionFn('fl_offline_devices');
588 this.updatePrefsState(PREF_OFFDEV, on ? 1 : 0);
589 this.log.debug('toggling offline devices', this.prefsState.offdev);
Sean Condonf4f54a12018-10-10 23:25:46 +0100590 }
591
592 protected resetZoom() {
Sean Condonff85fbe2019-03-16 14:28:46 +0000593 const zoomMapExtents = ZoomUtils.zoomToWindowSize(
594 this.bannerHeight, this.window.innerWidth, this.window.innerHeight);
595 this.zoomDirective.changeZoomLevel(zoomMapExtents, false);
Sean Condon91481822019-01-01 13:56:14 +0000596 this.flashMsg = this.lionFn('fl_pan_zoom_reset');
Sean Condonf4f54a12018-10-10 23:25:46 +0100597 }
598
Sean Condonf4f54a12018-10-10 23:25:46 +0100599 protected equalizeMasters() {
600 this.wss.sendEvent('equalizeMasters', null);
Sean Condon91481822019-01-01 13:56:14 +0000601 this.flashMsg = this.lionFn('fl_eq_masters');
Sean Condonf4f54a12018-10-10 23:25:46 +0100602 this.log.debug('equalizing masters');
Sean Condonf4f54a12018-10-10 23:25:46 +0100603 }
604
605 protected resetNodeLocation() {
Sean Condon91481822019-01-01 13:56:14 +0000606 // TODO: Implement reset locations
Sean Condon1ae15802019-03-02 09:07:18 +0000607 this.force.resetNodeLocations();
Sean Condon91481822019-01-01 13:56:14 +0000608 this.flashMsg = this.lionFn('fl_reset_node_locations');
Sean Condonf4f54a12018-10-10 23:25:46 +0100609 this.log.debug('resetting node location');
Sean Condonf4f54a12018-10-10 23:25:46 +0100610 }
611
612 protected unpinNode() {
Sean Condon91481822019-01-01 13:56:14 +0000613 // TODO: Implement this
Sean Condonf4f54a12018-10-10 23:25:46 +0100614 this.log.debug('unpinning node');
Sean Condonf4f54a12018-10-10 23:25:46 +0100615 }
616
Sean Condon91481822019-01-01 13:56:14 +0000617 /**
618 * Check to see if this is needed anymore
Sean Condonff85fbe2019-03-16 14:28:46 +0000619 * @param what - a key stroke
Sean Condon91481822019-01-01 13:56:14 +0000620 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100621 protected notValid(what) {
622 this.log.warn('topo.js getActionEntry(): Not a valid ' + what);
623 }
624
Sean Condon91481822019-01-01 13:56:14 +0000625 /**
626 * Check to see if this is needed anymore
Sean Condonff85fbe2019-03-16 14:28:46 +0000627 * @param key - a key stroke
Sean Condon91481822019-01-01 13:56:14 +0000628 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100629 getActionEntry(key) {
630 let entry;
631
632 if (!key) {
633 this.notValid('key');
634 return null;
635 }
636
637 entry = this.actionMap()[key];
638
639 if (!entry) {
640 this.notValid('actionMap (' + key + ') entry');
641 return null;
642 }
643 return this.fs.isA(entry) || [entry, ''];
644 }
645
Sean Condon91481822019-01-01 13:56:14 +0000646 /**
647 * An event handler that updates the details panel as items are
648 * selected in the forcesvg layer
649 * @param nodeOrLink the item to display details of
650 */
651 nodeSelected(nodeOrLink: UiElement) {
652 this.details.ngOnChanges({'selectedNode':
653 new SimpleChange(undefined, nodeOrLink, true)});
Sean Condon0c577f62018-11-18 22:40:05 +0000654 }
655
Sean Condon50855cf2018-12-23 15:37:42 +0000656 /**
657 * Enable traffic monitoring
658 */
659 monitorAllTraffic() {
Sean Condon91481822019-01-01 13:56:14 +0000660 // TODO: Implement support for toggling between bits, packets and octets
661 this.flashMsg = this.lionFn('tr_fl_pstats_bits');
Sean Condon50855cf2018-12-23 15:37:42 +0000662 this.trs.init(this.force);
663 }
664
665 /**
666 * Cancel traffic monitoring
667 */
668 cancelTraffic() {
Sean Condon91481822019-01-01 13:56:14 +0000669 this.flashMsg = this.lionFn('fl_monitoring_canceled');
Sean Condon50855cf2018-12-23 15:37:42 +0000670 this.trs.destroy();
671 }
Sean Condon91481822019-01-01 13:56:14 +0000672
Sean Condon0d064ec2019-02-04 21:53:53 +0000673 changeMap(map: MapObject) {
674 this.mapSelShown = false; // Hide the MapSelector component
675 this.mapIdState = map;
676 this.ps.setPrefs(TOPO_MAPID_PREFS, this.mapIdState);
677 this.log.debug('Map has been changed to ', map);
678 }
679
Sean Condon1ae15802019-03-02 09:07:18 +0000680 mapExtentsZoom(zoomMapExtents: TopoZoomPrefs) {
681 // this.zoomDirective.updateZoomState(zoomPrefs.tx, zoomPrefs.ty, zoomPrefs.sc);
682 this.zoomDirective.changeZoomLevel(zoomMapExtents);
683 this.log.debug('Map zoom prefs updated', zoomMapExtents);
684 }
685
Sean Condon91481822019-01-01 13:56:14 +0000686 /**
687 * Read the LION bundle for Toolbar and set up the lionFn
688 */
689 doLion() {
690 this.lionFn = this.lion.bundle('core.view.Topo');
691 }
692
693 /**
694 * A dummy implementation of the lionFn until the response is received and the LION
695 * bundle is received from the WebSocket
696 */
697 dummyLion(key: string): string {
698 return '%' + key + '%';
699 }
Sean Condonf4f54a12018-10-10 23:25:46 +0100700}