blob: 807a014f2ff7497a9d737f7651399a2e123c5140 [file] [log] [blame]
Sean Condon2bd11b72018-06-15 08:00:48 +01001/*
2 * Copyright 2015-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16import { Injectable } from '@angular/core';
17import { FnService } from '../util/fn.service';
18import { LoadingService } from '../layer/loading.service';
19import { LogService } from '../../log.service';
20import { WebSocketService } from '../remote/websocket.service';
21
22const REFRESH_INTERVAL = 2000;
23
24/**
25 * Base model of table view - implemented by Table components
26 */
27export interface TableBase {
28 annots: TableAnnots;
29 autoRefresh: boolean;
30 autoRefreshTip: string;
31 changedData: any;
32 payloadParams: any;
33 selId: string;
34 sortParams: any;
35 tableData: any[];
36 toggleRefresh(): void;
37 selectCallback(event: any, selRow: any): void;
38 parentSelCb(event: any, selRow: any): void;
39 sortCallback(): void;
40 responseCallback(): void;
41}
42
43interface TableAnnots {
44 noRowsMsg: string;
45}
46
47/**
48 * A model of data returned in a TableResponse
49 *
50 * There is an interface extending from this one in the parent component
51 */
52export interface TableResponse {
53 annots: any;
54 // There will be other parts to the response depending on table type
55 // Expect one called tag+'s' e.g. devices or apps
56}
57
58/**
59 * ONOS GUI -- Widget -- Table Base class
60 */
61export class TableBaseImpl implements TableBase {
62 // attributes from the interface
63 public annots: TableAnnots;
64 autoRefresh: boolean = true;
65 autoRefreshTip: string = 'Toggle auto refresh'; // TODO: get LION string
66 changedData: string[] = [];
67 payloadParams: any;
68 selId: string = undefined;
69 sortParams: any;
70 tableData: any[] = [];
71 toggleRefresh; // Function
72 selectCallback; // Function
73 parentSelCb = null;
74 sortCallback; // Function
75 responseCallback; // Function
76
77 private root: string;
78 private req: string;
79 private resp: string;
80 private refreshPromise: any = null;
81 private handlers: string[] = [];
82
83 constructor(
84 protected fs: FnService,
85 protected ls: LoadingService,
86 protected log: LogService,
87 protected wss: WebSocketService,
88 protected tag: string,
89 protected idKey: string = 'id',
90 protected query: string = '',
91 protected selCb = () => ({}) // Function
92 ) {
93 this.root = tag + 's';
94 this.req = tag + 'DataRequest';
95 this.resp = tag + 'DataResponse';
96
97 this.sortCallback = this.requestTableData;
98 this.selectCallback = this.rowSelectionCb;
99 this.toggleRefresh = () => {
100 this.autoRefresh = !this.autoRefresh;
101 this.autoRefresh ? this.startRefresh() : this.stopRefresh();
102 };
103 }
104
105 init() {
106 this.wss.bindHandlers(new Map<string, (data) => void>([
107 [this.resp, (data) => this.tableDataResponseCb(data)]
108 ]));
109 this.handlers.push(this.resp);
110
111 this.annots = <TableAnnots>{
112 noRowsMsg: ''
113 };
114
115 // Now send the WebSocket request and make it repeat every 2 seconds
116 this.requestTableData();
117 this.startRefresh();
118
119 this.log.debug('TableBase initialized');
120 }
121
122 destroy() {
123 this.wss.unbindHandlers(this.handlers);
124 this.stopRefresh();
125 this.ls.stop();
126 }
127
128 /**
129 * A callback that executes when the table data that was requested
130 * on WebSocketService arrives.
131 *
132 * Happens every 2 seconds
133 */
134 tableDataResponseCb(data: TableResponse) {
135 this.ls.stop();
136
137 const newTableData: any[] = Array.from(data[this.root]);
138 this.annots.noRowsMsg = data.annots.no_rows_msg;
139
140 // If the onResp() function is set then call it
141 if (this.responseCallback) {
142 this.responseCallback(data);
143 }
144 this.changedData = [];
145
146 // checks if data changed for row flashing
147 if (JSON.stringify(newTableData) !== JSON.stringify(this.tableData)) {
148 this.log.debug('table data has changed');
149 const oldTableData: any[] = this.tableData;
150 this.tableData = [ ...newTableData ]; // ES6 spread syntax
151 // only flash the row if the data already exists
152 if (oldTableData.length > 0) {
153 for (const idx in newTableData) {
154 if (!this.fs.containsObj(oldTableData, newTableData[idx])) {
155 this.changedData.push(newTableData[idx][this.idKey]);
156 }
157 }
158 }
159 }
160 }
161
162 /**
163 * Table Data Request
164 */
165 requestTableData() {
166 const p = Object.assign({}, this.sortParams, this.payloadParams, this.query);
167
168 // Allow it to sit in pending events
169 if (this.wss.isConnected()) {
170 if (this.fs.debugOn('table')) {
171 this.log.debug('Table data REQUEST:', this.req, p);
172 }
173 this.wss.sendEvent(this.req, p);
174 this.ls.start();
175 }
176 }
177
178 /**
179 * Row Selected
180 */
181 rowSelectionCb(event: any, selRow: any) {
182 const selId: string = selRow[this.idKey];
183 this.selId = (this.selId === selId) ? undefined : selId;
184 if (this.parentSelCb) {
185 this.log.debug('Parent called on Row', selId, 'selected');
186 this.parentSelCb(event, selRow);
187 }
188 }
189
190 /**
191 * autoRefresh functions
192 */
193 startRefresh() {
194 this.refreshPromise =
195 setInterval(() => {
196 if (!this.ls.waiting()) {
197 if (this.fs.debugOn('table')) {
198 this.log.debug('Refreshing ' + this.root + ' page');
199 }
200 this.requestTableData();
201 }
202 }, REFRESH_INTERVAL);
203 }
204
205 stopRefresh() {
206 if (this.refreshPromise) {
207 clearInterval(this.refreshPromise);
208 this.refreshPromise = null;
209 }
210 }
211
212 isChanged(id: string): boolean {
213 return (this.fs.inArray(id, this.changedData) === -1) ? false : true;
214 }
215}