blob: d7055a44385cc7dc2c4b073ab5f5a5b66dc52b02 [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 Condon91481822019-01-01 13:56:14 +000025 FnService, IconService,
Sean Condon0c577f62018-11-18 22:40:05 +000026 KeysService,
Sean Condon91481822019-01-01 13:56:14 +000027 KeysToken, LionService,
Sean Condon0c577f62018-11-18 22:40:05 +000028 LogService,
29 PrefsService,
30 SvgUtilService,
31 WebSocketService,
Sean Condonff85fbe2019-03-16 14:28:46 +000032 TopoZoomPrefs, ZoomUtils
Sean Condonf4f54a12018-10-10 23:25:46 +010033} from 'gui2-fw-lib';
Sean Condon0c577f62018-11-18 22:40:05 +000034import {InstanceComponent} from '../panel/instance/instance.component';
Sean Condon0c577f62018-11-18 22:40:05 +000035import {DetailsComponent} from '../panel/details/details.component';
36import {BackgroundSvgComponent} from '../layer/backgroundsvg/backgroundsvg.component';
37import {ForceSvgComponent} from '../layer/forcesvg/forcesvg.component';
38import {TopologyService} from '../topology.service';
Sean Condon91481822019-01-01 13:56:14 +000039import {
Sean Condon71910542019-02-16 18:16:42 +000040 GridDisplayToggle,
Sean Condon91481822019-01-01 13:56:14 +000041 HostLabelToggle,
42 LabelToggle,
43 UiElement
44} from '../layer/forcesvg/models';
Sean Condonb2c483c2019-01-16 20:28:55 +000045import {
46 INSTANCE_TOGGLE, SUMMARY_TOGGLE, DETAILS_TOGGLE,
47 HOSTS_TOGGLE, OFFLINE_TOGGLE, PORTS_TOGGLE,
48 BKGRND_TOGGLE, CYCLELABELS_BTN, CYCLEHOSTLABEL_BTN,
Sean Condon71910542019-02-16 18:16:42 +000049 CYCLEGRIDDISPLAY_BTN, RESETZOOM_BTN, EQMASTER_BTN,
Sean Condon0d064ec2019-02-04 21:53:53 +000050 CANCEL_TRAFFIC, ALL_TRAFFIC, QUICKHELP_BTN, BKGRND_SELECT
Sean Condonb2c483c2019-01-16 20:28:55 +000051} from '../panel/toolbar/toolbar.component';
Sean Condon50855cf2018-12-23 15:37:42 +000052import {TrafficService} from '../traffic.service';
Sean Condon91481822019-01-01 13:56:14 +000053import {ZoomableDirective} from '../layer/zoomable.directive';
Sean Condon0d064ec2019-02-04 21:53:53 +000054import {MapObject} from '../layer/maputils';
Sean Condonf4f54a12018-10-10 23:25:46 +010055
Sean Condonb2c483c2019-01-16 20:28:55 +000056const TOPO2_PREFS = 'topo2_prefs';
Sean Condon0d064ec2019-02-04 21:53:53 +000057const TOPO_MAPID_PREFS = 'topo_mapid';
58
Sean Condonb2c483c2019-01-16 20:28:55 +000059const PREF_BG = 'bg';
60const PREF_DETAIL = 'detail';
61const PREF_DLBLS = 'dlbls';
62const PREF_HLBLS = 'hlbls';
Sean Condon71910542019-02-16 18:16:42 +000063const PREF_GRID = 'grid';
Sean Condonb2c483c2019-01-16 20:28:55 +000064const PREF_HOSTS = 'hosts';
65const PREF_INSTS = 'insts';
66const PREF_OFFDEV = 'offdev';
67const PREF_PORTHL = 'porthl';
68const PREF_SUMMARY = 'summary';
69const PREF_TOOLBAR = 'toolbar';
70
71/**
Sean Condon0d064ec2019-02-04 21:53:53 +000072 * Model of the topo2_prefs object - this is a subset of the overall Prefs returned
Sean Condonb2c483c2019-01-16 20:28:55 +000073 * by the server
74 */
75export interface Topo2Prefs {
76 bg: number;
77 detail: number;
78 dlbls: number;
79 hlbls: number;
80 hosts: number;
81 insts: number;
82 offdev: number;
83 porthl: number;
84 spr: number;
85 ovid: string;
86 summary: number;
87 toolbar: number;
Sean Condon71910542019-02-16 18:16:42 +000088 grid: number;
Sean Condonb2c483c2019-01-16 20:28:55 +000089}
90
Sean Condonf4f54a12018-10-10 23:25:46 +010091/**
92 * ONOS GUI Topology View
93 *
94 * This Topology View component is the top level component in a hierarchy that
95 * comprises the whole Topology View
96 *
97 * There are three main parts (panels, graphical and breadcrumbs)
98 * The panel hierarchy
99 * |-- Instances Panel (shows ONOS instances)
100 * |-- Summary Panel (summary of ONOS)
101 * |-- Toolbar Panel (the toolbar)
102 * |-- Details Panel (when a node is selected in the Force graphical view (see below))
103 *
104 * The graphical hierarchy contains
105 * Topology (this)
106 * |-- No Devices Connected (only of there are no nodes to show)
107 * |-- Zoom Layer (everything beneath this can be zoomed and panned)
108 * |-- Background (container for any backgrounds - can be toggled on and off)
109 * |-- Map
110 * |-- Forces (all of the nodes and links laid out by a d3.force simulation)
111 *
112 * The breadcrumbs
113 * |-- Breadcrumb (in region view a way of navigating back up through regions)
114 */
115@Component({
116 selector: 'onos-topology',
117 templateUrl: './topology.component.html',
118 styleUrls: ['./topology.component.css']
119})
Sean Condonff85fbe2019-03-16 14:28:46 +0000120export class TopologyComponent implements AfterContentInit, OnInit, OnDestroy {
121 @Input() bannerHeight: number = 48;
Sean Condonaa4366d2018-11-02 14:29:01 +0000122 // These are references to the components inserted in the template
Sean Condonf4f54a12018-10-10 23:25:46 +0100123 @ViewChild(InstanceComponent) instance: InstanceComponent;
Sean Condonf4f54a12018-10-10 23:25:46 +0100124 @ViewChild(DetailsComponent) details: DetailsComponent;
Sean Condonaa4366d2018-11-02 14:29:01 +0000125 @ViewChild(BackgroundSvgComponent) background: BackgroundSvgComponent;
126 @ViewChild(ForceSvgComponent) force: ForceSvgComponent;
Sean Condon91481822019-01-01 13:56:14 +0000127 @ViewChild(ZoomableDirective) zoomDirective: ZoomableDirective;
Sean Condonf4f54a12018-10-10 23:25:46 +0100128
129 flashMsg: string = '';
Sean Condonb2c483c2019-01-16 20:28:55 +0000130 // These are used as defaults if nothing is set on the server
131 prefsState: Topo2Prefs = <Topo2Prefs>{
132 bg: 0,
133 detail: 1,
134 dlbls: 0,
135 hlbls: 2,
136 hosts: 0,
137 insts: 1,
138 offdev: 1,
139 ovid: 'traffic', // default to traffic overlay
140 porthl: 1,
141 spr: 0,
142 summary: 1,
143 toolbar: 0,
Sean Condon71910542019-02-16 18:16:42 +0000144 grid: 0
Sean Condonb2c483c2019-01-16 20:28:55 +0000145 };
Sean Condon0d064ec2019-02-04 21:53:53 +0000146
147 mapIdState: MapObject = <MapObject>{
148 id: undefined,
149 scale: 1.0
150 };
151 mapSelShown: boolean = false;
Sean Condon91481822019-01-01 13:56:14 +0000152 lionFn; // Function
Sean Condon55c30532018-10-29 12:26:57 +0000153
Sean Condon71910542019-02-16 18:16:42 +0000154 gridShown: boolean = true;
155 geoGridShown: boolean = true;
156
Sean Condonf4f54a12018-10-10 23:25:46 +0100157 constructor(
158 protected log: LogService,
159 protected fs: FnService,
160 protected ks: KeysService,
161 protected sus: SvgUtilService,
162 protected ps: PrefsService,
Sean Condon55c30532018-10-29 12:26:57 +0000163 protected wss: WebSocketService,
Sean Condonaa4366d2018-11-02 14:29:01 +0000164 protected ts: TopologyService,
Sean Condon91481822019-01-01 13:56:14 +0000165 protected trs: TrafficService,
166 protected is: IconService,
167 private lion: LionService,
Sean Condonff85fbe2019-03-16 14:28:46 +0000168 @Inject('Window') public window: any,
Sean Condonf4f54a12018-10-10 23:25:46 +0100169 ) {
Sean Condon91481822019-01-01 13:56:14 +0000170 if (this.lion.ubercache.length === 0) {
171 this.lionFn = this.dummyLion;
172 this.lion.loadCbs.set('topo-toolbar', () => this.doLion());
173 } else {
174 this.doLion();
175 }
Sean Condonf4f54a12018-10-10 23:25:46 +0100176
Sean Condon91481822019-01-01 13:56:14 +0000177 this.is.loadIconDef('bird');
178 this.is.loadIconDef('active');
179 this.is.loadIconDef('uiAttached');
180 this.is.loadIconDef('m_switch');
181 this.is.loadIconDef('m_roadm');
182 this.is.loadIconDef('m_router');
183 this.is.loadIconDef('m_uiAttached');
184 this.is.loadIconDef('m_endstation');
185 this.is.loadIconDef('m_ports');
186 this.is.loadIconDef('m_summary');
187 this.is.loadIconDef('m_details');
188 this.is.loadIconDef('m_map');
Sean Condon0d064ec2019-02-04 21:53:53 +0000189 this.is.loadIconDef('m_selectMap');
Sean Condon91481822019-01-01 13:56:14 +0000190 this.is.loadIconDef('m_cycleLabels');
Sean Condon71910542019-02-16 18:16:42 +0000191 this.is.loadIconDef('m_cycleGridDisplay');
Sean Condon91481822019-01-01 13:56:14 +0000192 this.is.loadIconDef('m_resetZoom');
193 this.is.loadIconDef('m_eqMaster');
194 this.is.loadIconDef('m_unknown');
195 this.is.loadIconDef('m_allTraffic');
196 this.is.loadIconDef('deviceTable');
197 this.is.loadIconDef('flowTable');
198 this.is.loadIconDef('portTable');
199 this.is.loadIconDef('groupTable');
200 this.is.loadIconDef('meterTable');
201 this.is.loadIconDef('triangleUp');
Sean Condonf4f54a12018-10-10 23:25:46 +0100202 this.log.debug('Topology component constructed');
203 }
204
Sean Condon91481822019-01-01 13:56:14 +0000205 /**
206 * Static functions must come before member variables
Sean Condonff85fbe2019-03-16 14:28:46 +0000207 * @param index Corresponds to LabelToggle.Enum index
Sean Condon91481822019-01-01 13:56:14 +0000208 */
Sean Condon021f0fa2018-12-06 23:31:11 -0800209 private static deviceLabelFlashMessage(index: number): string {
210 switch (index) {
Sean Condon91481822019-01-01 13:56:14 +0000211 case 0: return 'fl_device_labels_hide';
212 case 1: return 'fl_device_labels_show_friendly';
213 case 2: return 'fl_device_labels_show_id';
Sean Condon021f0fa2018-12-06 23:31:11 -0800214 }
215 }
216
217 private static hostLabelFlashMessage(index: number): string {
218 switch (index) {
Sean Condon91481822019-01-01 13:56:14 +0000219 case 0: return 'fl_host_labels_hide';
220 case 1: return 'fl_host_labels_show_friendly';
221 case 2: return 'fl_host_labels_show_ip';
222 case 3: return 'fl_host_labels_show_mac';
Sean Condon021f0fa2018-12-06 23:31:11 -0800223 }
224 }
225
Sean Condon71910542019-02-16 18:16:42 +0000226 private static gridDisplayFlashMessage(index: number): string {
227 switch (index) {
228 case 0: return 'fl_grid_display_hide';
229 case 1: return 'fl_grid_display_1000';
230 case 2: return 'fl_grid_display_geo';
231 case 3: return 'fl_grid_display_both';
232 }
233 }
234
Sean Condon91481822019-01-01 13:56:14 +0000235 /**
236 * Pass the list of Key Commands to the KeyService, and initialize the Topology
237 * Service - which communicates with through the WebSocket to the ONOS server
238 * to get the nodes and links.
239 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100240 ngOnInit() {
241 this.bindCommands();
Sean Condonaa4366d2018-11-02 14:29:01 +0000242 // The components from the template are handed over to TopologyService here
243 // so that WebSocket responses can be passed back in to them
244 // The handling of the WebSocket call is delegated out to the Topology
245 // Service just to compartmentalize things a bit
246 this.ts.init(this.instance, this.background, this.force);
Sean Condonb2c483c2019-01-16 20:28:55 +0000247
248 this.ps.addListener((data) => this.prefsUpdateHandler(data));
249 this.prefsState = this.ps.getPrefs(TOPO2_PREFS, this.prefsState);
Sean Condon0d064ec2019-02-04 21:53:53 +0000250 this.mapIdState = this.ps.getPrefs(TOPO_MAPID_PREFS, this.mapIdState);
Sean Condonff85fbe2019-03-16 14:28:46 +0000251
Sean Condonf4f54a12018-10-10 23:25:46 +0100252 this.log.debug('Topology component initialized');
253 }
254
Sean Condonff85fbe2019-03-16 14:28:46 +0000255 ngAfterContentInit(): void {
256 // Scale the window initially - then after resize
257 const zoomMapExtents = ZoomUtils.zoomToWindowSize(
258 this.bannerHeight, this.window.innerWidth, this.window.innerHeight);
259 this.zoomDirective.changeZoomLevel(zoomMapExtents, true);
260 this.log.debug('Topology zoom initialized',
261 this.bannerHeight, this.window.innerWidth, this.window.innerHeight,
262 zoomMapExtents);
263 }
264
Sean Condon91481822019-01-01 13:56:14 +0000265 /**
Sean Condonb2c483c2019-01-16 20:28:55 +0000266 * Callback function that's called whenever new Prefs are received from WebSocket
267 *
268 * Note: At present the backend server does not filter updated by logged in user,
269 * so you might get updates pertaining to a different user
270 */
271 prefsUpdateHandler(data: any): void {
272 // Extract the TOPO2 prefs from it
Sean Condon0d064ec2019-02-04 21:53:53 +0000273 if (data[TOPO2_PREFS]) {
274 this.prefsState = data[TOPO2_PREFS];
275 }
Sean Condon0d064ec2019-02-04 21:53:53 +0000276 this.log.debug('Updated topo2 prefs', this.prefsState, this.mapIdState);
Sean Condonb2c483c2019-01-16 20:28:55 +0000277 }
278
279 /**
Sean Condon91481822019-01-01 13:56:14 +0000280 * When this component is being stopped, disconnect the TopologyService from
281 * the WebSocket
282 */
Sean Condonaa4366d2018-11-02 14:29:01 +0000283 ngOnDestroy() {
284 this.ts.destroy();
Sean Condonb2c483c2019-01-16 20:28:55 +0000285 this.ps.removeListener((data) => this.prefsUpdateHandler(data));
Sean Condonaa4366d2018-11-02 14:29:01 +0000286 this.log.debug('Topology component destroyed');
287 }
288
Sean Condonff85fbe2019-03-16 14:28:46 +0000289 @HostListener('window:resize', ['$event'])
290 onResize(event) {
291 const zoomMapExtents = ZoomUtils.zoomToWindowSize(
292 this.bannerHeight, event.target.innerWidth, event.target.innerHeight);
293 this.zoomDirective.changeZoomLevel(zoomMapExtents, true);
294 this.log.debug('Topology window resize',
295 event.target.innerWidth, event.target.innerHeight, this.bannerHeight, zoomMapExtents);
296 }
297
Sean Condon91481822019-01-01 13:56:14 +0000298 /**
299 * When ever a toolbar button is clicked, an event is sent up from toolbar
300 * component which is caught and passed on to here.
301 * @param name The name of the button that was clicked
302 */
303 toolbarButtonClicked(name: string) {
304 switch (name) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000305 case INSTANCE_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000306 this.toggleInstancePanel();
307 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000308 case SUMMARY_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000309 this.toggleSummary();
310 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000311 case DETAILS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000312 this.toggleDetails();
313 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000314 case HOSTS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000315 this.toggleHosts();
316 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000317 case OFFLINE_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000318 this.toggleOfflineDevices();
319 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000320 case PORTS_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000321 this.togglePorts();
322 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000323 case BKGRND_TOGGLE:
Sean Condon91481822019-01-01 13:56:14 +0000324 this.toggleBackground();
325 break;
Sean Condon0d064ec2019-02-04 21:53:53 +0000326 case BKGRND_SELECT:
327 this.mapSelShown = !this.mapSelShown;
328 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000329 case CYCLELABELS_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000330 this.cycleDeviceLabels();
331 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000332 case CYCLEHOSTLABEL_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000333 this.cycleHostLabels();
334 break;
Sean Condon71910542019-02-16 18:16:42 +0000335 case CYCLEGRIDDISPLAY_BTN:
336 this.cycleGridDisplay();
337 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000338 case RESETZOOM_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000339 this.resetZoom();
340 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000341 case EQMASTER_BTN:
Sean Condon91481822019-01-01 13:56:14 +0000342 this.equalizeMasters();
343 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000344 case CANCEL_TRAFFIC:
Sean Condon91481822019-01-01 13:56:14 +0000345 this.cancelTraffic();
346 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000347 case ALL_TRAFFIC:
Sean Condon91481822019-01-01 13:56:14 +0000348 this.monitorAllTraffic();
349 break;
Sean Condonb2c483c2019-01-16 20:28:55 +0000350 case QUICKHELP_BTN:
351 this.ks.quickHelpShown = true;
352 break;
Sean Condon91481822019-01-01 13:56:14 +0000353 default:
354 this.log.warn('Unhandled Toolbar action', name);
355 }
356 }
357
358 /**
359 * The list of key strokes that will be active in the Topology View.
360 *
361 * This action map is passed to the KeyService through the bindCommands()
362 * when this component is being initialized
363 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100364 actionMap() {
365 return {
Sean Condon50855cf2018-12-23 15:37:42 +0000366 A: [() => {this.monitorAllTraffic(); }, 'Monitor all traffic'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100367 B: [(token) => {this.toggleBackground(token); }, 'Toggle background'],
368 D: [(token) => {this.toggleDetails(token); }, 'Toggle details panel'],
Sean Condon71910542019-02-16 18:16:42 +0000369 E: [() => {this.equalizeMasters(); }, 'Equalize mastership roles'],
370 H: [() => {this.toggleHosts(); }, 'Toggle host visibility'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100371 I: [(token) => {this.toggleInstancePanel(token); }, 'Toggle ONOS Instance Panel'],
Sean Condon0d064ec2019-02-04 21:53:53 +0000372 G: [() => {this.mapSelShown = !this.mapSelShown; }, 'Show map selection dialog'],
Sean Condon71910542019-02-16 18:16:42 +0000373 L: [() => {this.cycleDeviceLabels(); }, 'Cycle device labels'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100374 M: [() => {this.toggleOfflineDevices(); }, 'Toggle offline visibility'],
Sean Condon71910542019-02-16 18:16:42 +0000375 O: [() => {this.toggleSummary(); }, 'Toggle the Summary Panel'],
376 P: [(token) => {this.togglePorts(token); }, 'Toggle Port Highlighting'],
377 Q: [() => {this.cycleGridDisplay(); }, 'Cycle grid display'],
378 R: [() => {this.resetZoom(); }, 'Reset pan / zoom'],
379 U: [() => {this.unpinNode(); }, 'Unpin node (mouse over)'],
380 X: [() => {this.resetNodeLocation(); }, 'Reset Node Location'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100381 dot: [() => {this.toggleToolbar(); }, 'Toggle Toolbar'],
Sean Condon50855cf2018-12-23 15:37:42 +0000382 0: [() => {this.cancelTraffic(); }, 'Cancel traffic monitoring'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100383 'shift-L': [() => {this.cycleHostLabels(); }, 'Cycle host labels'],
384
385 // -- instance color palette debug
Sean Condon55c30532018-10-29 12:26:57 +0000386 9: () => {
387 this.sus.cat7().testCard(d3.select('svg#topo2'));
Sean Condonf4f54a12018-10-10 23:25:46 +0100388 },
389
Sean Condonb2c483c2019-01-16 20:28:55 +0000390 esc: [() => {this.handleEscape(); }, 'Cancel commands'],
Sean Condonf4f54a12018-10-10 23:25:46 +0100391
392 // TODO update after adding in Background Service
393 // topology overlay selections
394 // F1: function () { t2tbs.fnKey(0); },
395 // F2: function () { t2tbs.fnKey(1); },
396 // F3: function () { t2tbs.fnKey(2); },
397 // F4: function () { t2tbs.fnKey(3); },
398 // F5: function () { t2tbs.fnKey(4); },
399 //
400 // _keyListener: t2tbs.keyListener.bind(t2tbs),
401
402 _helpFormat: [
403 ['I', 'O', 'D', 'H', 'M', 'P', 'dash', 'B'],
404 ['X', 'Z', 'N', 'L', 'shift-L', 'U', 'R', 'E', 'dot'],
405 [], // this column reserved for overlay actions
406 ],
407 };
408 }
409
410
411 bindCommands(additional?: any) {
412
413 const am = this.actionMap();
414 const add = this.fs.isO(additional);
415
Sean Condonf4f54a12018-10-10 23:25:46 +0100416 this.ks.keyBindings(am);
417
418 this.ks.gestureNotes([
419 ['click', 'Select the item and show details'],
420 ['shift-click', 'Toggle selection state'],
421 ['drag', 'Reposition (and pin) device / host'],
422 ['cmd-scroll', 'Zoom in / out'],
423 ['cmd-drag', 'Pan'],
424 ]);
425 }
426
427 handleEscape() {
428
429 if (false) {
430 // TODO: Cancel show mastership
431 // TODO: Cancel Active overlay
432 // TODO: Reinstate with components
433 } else {
Sean Condonb2c483c2019-01-16 20:28:55 +0000434 this.nodeSelected(undefined);
Sean Condonf4f54a12018-10-10 23:25:46 +0100435 this.log.debug('Handling escape');
436 // } else if (t2rs.deselectAllNodes()) {
437 // // else if we have node selections, deselect them all
438 // // (work already done)
439 // } else if (t2rs.deselectLink()) {
440 // // else if we have a link selection, deselect it
441 // // (work already done)
442 // } else if (t2is.isVisible()) {
443 // // If the instance panel is visible, close it
444 // t2is.toggle();
445 // } else if (t2sp.isVisible()) {
446 // // If the summary panel is visible, close it
447 // t2sp.toggle();
448 }
449 }
450
Sean Condonb2c483c2019-01-16 20:28:55 +0000451 /**
452 * Updates the cache of preferences locally and onwards to the PrefsService
453 * @param what The attribute of the local topo2-prefs cache to update
454 * @param b the value to update it with
455 */
456 updatePrefsState(what: string, b: number) {
457 this.prefsState[what] = b;
458 this.ps.setPrefs(TOPO2_PREFS, this.prefsState);
Sean Condonf4f54a12018-10-10 23:25:46 +0100459 }
460
Sean Condonb2c483c2019-01-16 20:28:55 +0000461 /**
462 * When the button is clicked on the toolbar or the L key is pressed
463 * 1) cycle through options
464 * 2) flash up a message
465 * 3a) Update the local prefs cache
466 * 3b) And passes on to the global prefs service which sends back to the server
467 * 3c) It also has a knock on effect of passing it on to ForceSvgComponent
468 * because prefsState.dlbls is given as an input to it
469 * 3d) This will in turn pass it down to the DeviceSvgComponent which
470 * displays the label
471 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100472 protected cycleDeviceLabels() {
Sean Condonff85fbe2019-03-16 14:28:46 +0000473 const old: LabelToggle.Enum = this.prefsState.dlbls;
Sean Condon021f0fa2018-12-06 23:31:11 -0800474 const next = LabelToggle.next(old);
Sean Condon91481822019-01-01 13:56:14 +0000475 this.flashMsg = this.lionFn(TopologyComponent.deviceLabelFlashMessage(next));
Sean Condonb2c483c2019-01-16 20:28:55 +0000476 this.updatePrefsState(PREF_DLBLS, next);
Sean Condon021f0fa2018-12-06 23:31:11 -0800477 this.log.debug('Cycling device labels', old, next);
Sean Condonf4f54a12018-10-10 23:25:46 +0100478 }
479
480 protected cycleHostLabels() {
Sean Condonff85fbe2019-03-16 14:28:46 +0000481 const old: HostLabelToggle.Enum = this.prefsState.hlbls;
Sean Condon021f0fa2018-12-06 23:31:11 -0800482 const next = HostLabelToggle.next(old);
Sean Condon91481822019-01-01 13:56:14 +0000483 this.flashMsg = this.lionFn(TopologyComponent.hostLabelFlashMessage(next));
Sean Condonb2c483c2019-01-16 20:28:55 +0000484 this.updatePrefsState(PREF_HLBLS, next);
Sean Condon021f0fa2018-12-06 23:31:11 -0800485 this.log.debug('Cycling host labels', old, next);
Sean Condonf4f54a12018-10-10 23:25:46 +0100486 }
487
Sean Condon71910542019-02-16 18:16:42 +0000488 protected cycleGridDisplay() {
Sean Condonff85fbe2019-03-16 14:28:46 +0000489 const old: GridDisplayToggle.Enum = this.prefsState.grid;
Sean Condon71910542019-02-16 18:16:42 +0000490 const next = GridDisplayToggle.next(old);
491 this.flashMsg = this.lionFn(TopologyComponent.gridDisplayFlashMessage(next));
492 this.updatePrefsState(PREF_GRID, next);
493 this.log.debug('Cycling grid display', old, next);
494 }
495
Sean Condonb2c483c2019-01-16 20:28:55 +0000496 /**
497 * When the button is clicked on the toolbar or the B key is pressed
498 * 1) Find the inverse of the current state (held as 1 or 0)
499 * 2) Flash up a message on screen
500 * 3b) And passes on to the global prefs service which sends back to the server
501 * 3c) It also has a knock on effect of passing it on to ToolbarComponent
502 * because prefsState.bg is given as an input to it
Sean Condonff85fbe2019-03-16 14:28:46 +0000503 * @param token not currently used
Sean Condonb2c483c2019-01-16 20:28:55 +0000504 */
Sean Condon91481822019-01-01 13:56:14 +0000505 protected toggleBackground(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000506 const bg: boolean = !Boolean(this.prefsState.bg);
507 this.flashMsg = this.lionFn(bg ? 'show' : 'hide') +
Sean Condon91481822019-01-01 13:56:14 +0000508 ' ' + this.lionFn('fl_background_map');
Sean Condonb2c483c2019-01-16 20:28:55 +0000509 this.updatePrefsState(PREF_BG, bg ? 1 : 0);
510 this.log.debug('Toggling background', token, bg ? 'shown' : 'hidden');
Sean Condonf4f54a12018-10-10 23:25:46 +0100511 }
512
Sean Condon91481822019-01-01 13:56:14 +0000513 protected toggleDetails(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000514 const on: boolean = !Boolean(this.prefsState.detail);
515 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
516 ' ' + this.lionFn('fl_panel_details');
517 this.updatePrefsState(PREF_DETAIL, on ? 1 : 0);
518 this.log.debug('Toggling details', token);
Sean Condonf4f54a12018-10-10 23:25:46 +0100519 }
520
Sean Condon91481822019-01-01 13:56:14 +0000521 protected toggleInstancePanel(token?: KeysToken) {
Sean Condonb2c483c2019-01-16 20:28:55 +0000522 const on: boolean = !Boolean(this.prefsState.insts);
Sean Condon91481822019-01-01 13:56:14 +0000523 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
524 ' ' + this.lionFn('fl_panel_instances');
Sean Condonb2c483c2019-01-16 20:28:55 +0000525 this.updatePrefsState(PREF_INSTS, on ? 1 : 0);
Sean Condon91481822019-01-01 13:56:14 +0000526 this.log.debug('Toggling instances', token, on);
Sean Condonf4f54a12018-10-10 23:25:46 +0100527 }
528
529 protected toggleSummary() {
Sean Condonb2c483c2019-01-16 20:28:55 +0000530 const on: boolean = !Boolean(this.prefsState.summary);
Sean Condon91481822019-01-01 13:56:14 +0000531 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
532 ' ' + this.lionFn('fl_panel_summary');
Sean Condonb2c483c2019-01-16 20:28:55 +0000533 this.updatePrefsState(PREF_SUMMARY, on ? 1 : 0);
534 }
535
536 protected togglePorts(token?: KeysToken) {
537 const current: boolean = !Boolean(this.prefsState.porthl);
538 this.flashMsg = this.lionFn(current ? 'enable' : 'disable') +
539 ' ' + this.lionFn('fl_port_highlighting');
540 this.updatePrefsState(PREF_PORTHL, current ? 1 : 0);
541 this.log.debug(current ? 'Enable' : 'Disable', 'port highlighting');
542 }
543
544 protected toggleToolbar() {
545 const on: boolean = !Boolean(this.prefsState.toolbar);
546 this.updatePrefsState(PREF_TOOLBAR, on ? 1 : 0);
547 this.log.debug('toggling toolbar', on ? 'shown' : 'hidden');
548 }
549
550 protected toggleHosts() {
551 const current: boolean = !Boolean(this.prefsState.hosts);
552 this.flashMsg = this.lionFn('hosts') + ' ' +
553 this.lionFn(this.force.showHosts ? 'visible' : 'hidden');
554 this.updatePrefsState(PREF_HOSTS, current ? 1 : 0);
555 this.log.debug('toggling hosts: ', this.prefsState.hosts ? 'Show' : 'Hide');
556 }
557
558 protected toggleOfflineDevices() {
559 const on: boolean = !Boolean(this.prefsState.offdev);
560 this.flashMsg = this.lionFn(on ? 'show' : 'hide') +
561 ' ' + this.lionFn('fl_offline_devices');
562 this.updatePrefsState(PREF_OFFDEV, on ? 1 : 0);
563 this.log.debug('toggling offline devices', this.prefsState.offdev);
Sean Condonf4f54a12018-10-10 23:25:46 +0100564 }
565
566 protected resetZoom() {
Sean Condonff85fbe2019-03-16 14:28:46 +0000567 const zoomMapExtents = ZoomUtils.zoomToWindowSize(
568 this.bannerHeight, this.window.innerWidth, this.window.innerHeight);
569 this.zoomDirective.changeZoomLevel(zoomMapExtents, false);
Sean Condon91481822019-01-01 13:56:14 +0000570 this.flashMsg = this.lionFn('fl_pan_zoom_reset');
Sean Condonf4f54a12018-10-10 23:25:46 +0100571 }
572
Sean Condonf4f54a12018-10-10 23:25:46 +0100573 protected equalizeMasters() {
574 this.wss.sendEvent('equalizeMasters', null);
Sean Condon91481822019-01-01 13:56:14 +0000575 this.flashMsg = this.lionFn('fl_eq_masters');
Sean Condonf4f54a12018-10-10 23:25:46 +0100576 this.log.debug('equalizing masters');
Sean Condonf4f54a12018-10-10 23:25:46 +0100577 }
578
579 protected resetNodeLocation() {
Sean Condon91481822019-01-01 13:56:14 +0000580 // TODO: Implement reset locations
Sean Condon1ae15802019-03-02 09:07:18 +0000581 this.force.resetNodeLocations();
Sean Condon91481822019-01-01 13:56:14 +0000582 this.flashMsg = this.lionFn('fl_reset_node_locations');
Sean Condonf4f54a12018-10-10 23:25:46 +0100583 this.log.debug('resetting node location');
Sean Condonf4f54a12018-10-10 23:25:46 +0100584 }
585
586 protected unpinNode() {
Sean Condon91481822019-01-01 13:56:14 +0000587 // TODO: Implement this
Sean Condonf4f54a12018-10-10 23:25:46 +0100588 this.log.debug('unpinning node');
Sean Condonf4f54a12018-10-10 23:25:46 +0100589 }
590
Sean Condon91481822019-01-01 13:56:14 +0000591 /**
592 * Check to see if this is needed anymore
Sean Condonff85fbe2019-03-16 14:28:46 +0000593 * @param what - a key stroke
Sean Condon91481822019-01-01 13:56:14 +0000594 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100595 protected notValid(what) {
596 this.log.warn('topo.js getActionEntry(): Not a valid ' + what);
597 }
598
Sean Condon91481822019-01-01 13:56:14 +0000599 /**
600 * Check to see if this is needed anymore
Sean Condonff85fbe2019-03-16 14:28:46 +0000601 * @param key - a key stroke
Sean Condon91481822019-01-01 13:56:14 +0000602 */
Sean Condonf4f54a12018-10-10 23:25:46 +0100603 getActionEntry(key) {
604 let entry;
605
606 if (!key) {
607 this.notValid('key');
608 return null;
609 }
610
611 entry = this.actionMap()[key];
612
613 if (!entry) {
614 this.notValid('actionMap (' + key + ') entry');
615 return null;
616 }
617 return this.fs.isA(entry) || [entry, ''];
618 }
619
Sean Condon91481822019-01-01 13:56:14 +0000620 /**
621 * An event handler that updates the details panel as items are
622 * selected in the forcesvg layer
623 * @param nodeOrLink the item to display details of
624 */
625 nodeSelected(nodeOrLink: UiElement) {
626 this.details.ngOnChanges({'selectedNode':
627 new SimpleChange(undefined, nodeOrLink, true)});
Sean Condon0c577f62018-11-18 22:40:05 +0000628 }
629
Sean Condon50855cf2018-12-23 15:37:42 +0000630 /**
631 * Enable traffic monitoring
632 */
633 monitorAllTraffic() {
Sean Condon91481822019-01-01 13:56:14 +0000634 // TODO: Implement support for toggling between bits, packets and octets
635 this.flashMsg = this.lionFn('tr_fl_pstats_bits');
Sean Condon50855cf2018-12-23 15:37:42 +0000636 this.trs.init(this.force);
637 }
638
639 /**
640 * Cancel traffic monitoring
641 */
642 cancelTraffic() {
Sean Condon91481822019-01-01 13:56:14 +0000643 this.flashMsg = this.lionFn('fl_monitoring_canceled');
Sean Condon50855cf2018-12-23 15:37:42 +0000644 this.trs.destroy();
645 }
Sean Condon91481822019-01-01 13:56:14 +0000646
Sean Condon0d064ec2019-02-04 21:53:53 +0000647 changeMap(map: MapObject) {
648 this.mapSelShown = false; // Hide the MapSelector component
649 this.mapIdState = map;
650 this.ps.setPrefs(TOPO_MAPID_PREFS, this.mapIdState);
651 this.log.debug('Map has been changed to ', map);
652 }
653
Sean Condon1ae15802019-03-02 09:07:18 +0000654 mapExtentsZoom(zoomMapExtents: TopoZoomPrefs) {
655 // this.zoomDirective.updateZoomState(zoomPrefs.tx, zoomPrefs.ty, zoomPrefs.sc);
656 this.zoomDirective.changeZoomLevel(zoomMapExtents);
657 this.log.debug('Map zoom prefs updated', zoomMapExtents);
658 }
659
Sean Condon91481822019-01-01 13:56:14 +0000660 /**
661 * Read the LION bundle for Toolbar and set up the lionFn
662 */
663 doLion() {
664 this.lionFn = this.lion.bundle('core.view.Topo');
665 }
666
667 /**
668 * A dummy implementation of the lionFn until the response is received and the LION
669 * bundle is received from the WebSocket
670 */
671 dummyLion(key: string): string {
672 return '%' + key + '%';
673 }
Sean Condonf4f54a12018-10-10 23:25:46 +0100674}