blob: ed6d30a489ac87023714588dea043186c11c7925 [file] [log] [blame]
Sean Condon83fc39f2018-04-19 18:56:13 +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 */
Sean Condona00bf382018-06-23 07:54:01 +010016import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
Sean Condon83fc39f2018-04-19 18:56:13 +010017import { DialogService } from '../../fw/layer/dialog.service';
18import { FnService } from '../../fw/util/fn.service';
19import { IconService } from '../../fw/svg/icon.service';
20import { KeyService } from '../../fw/util/key.service';
21import { LionService } from '../../fw/util/lion.service';
Sean Condon2bd11b72018-06-15 08:00:48 +010022import { LoadingService } from '../../fw/layer/loading.service';
Sean Condon83fc39f2018-04-19 18:56:13 +010023import { LogService } from '../../log.service';
24import { PanelService } from '../../fw/layer/panel.service';
Sean Condon2bd11b72018-06-15 08:00:48 +010025import { TableBaseImpl, TableResponse } from '../../fw/widget/tablebase';
Sean Condon83fc39f2018-04-19 18:56:13 +010026import { UrlFnService } from '../../fw/remote/urlfn.service';
27import { WebSocketService } from '../../fw/remote/websocket.service';
28
Sean Condon2bd11b72018-06-15 08:00:48 +010029const INSTALLED = 'INSTALLED';
30const ACTIVE = 'ACTIVE';
31const appMgmtReq = 'appManagementRequest';
32const topPdg = 60;
33const panelWidth = 540;
34const pName = 'application-details-panel';
35const detailsReq = 'appDetailsRequest';
36const detailsResp = 'appDetailsResponse';
37const fileUploadUrl = 'applications/upload';
38const activateOption = '?activate=true';
39const appUrlPrefix = 'rs/applications/';
40const iconUrlSuffix = '/icon';
41const downloadSuffix = '/download';
42const dialogId = 'app-dialog';
43const dialogOpts = {
44 edge: 'right',
45 width: 400,
46};
47const strongWarning = {
48 'org.onosproject.drivers': true,
49};
50const propOrder = ['id', 'state', 'category', 'version', 'origin', 'role'];
51
52interface AppTableResponse extends TableResponse {
53 apps: Apps[];
54}
55
56interface Apps {
57 category: string;
58 desc: string;
59 features: string;
60 icon: string;
61 id: string;
62 origin: string;
63 permissions: string;
64 readme: string;
65 required_apps: string;
66 role: string;
67 state: string;
68 title: string;
69 url: string;
70 version: string;
71 _iconid_state: string;
72}
73
74interface CtrlBtnState {
75 installed: boolean;
76 selection: string;
77 active: boolean;
78}
79
Sean Condon83fc39f2018-04-19 18:56:13 +010080/**
81 * ONOS GUI -- Apps View Component
82 */
83@Component({
84 selector: 'onos-apps',
85 templateUrl: './apps.component.html',
Sean Condon2bd11b72018-06-15 08:00:48 +010086 styleUrls: [
87 './apps.component.css', './apps.theme.css',
88 '../../fw/widget/table.css', '../../fw/widget/table-theme.css'
89 ]
Sean Condon83fc39f2018-04-19 18:56:13 +010090})
Sean Condon2bd11b72018-06-15 08:00:48 +010091export class AppsComponent extends TableBaseImpl implements OnInit, OnDestroy {
92
93 // deferred localization strings
94 lionFn; // Function
95 warnDeactivate: string;
96 warnOwnRisk: string;
97 friendlyProps: string[];
98 ctrlBtnState: CtrlBtnState;
99 detailsPanel: any;
Sean Condona00bf382018-06-23 07:54:01 +0100100 appFile: any;
101 activateImmediately = '';
102
103 uploadTip: string;
104 activateTip: string;
105 deactivateTip: string;
106 uninstallTip: string;
107 downloadTip: string;
Sean Condon83fc39f2018-04-19 18:56:13 +0100108
109 constructor(
Sean Condon2bd11b72018-06-15 08:00:48 +0100110 protected fs: FnService,
Sean Condon83fc39f2018-04-19 18:56:13 +0100111 private ds: DialogService,
112 private is: IconService,
113 private ks: KeyService,
Sean Condon2bd11b72018-06-15 08:00:48 +0100114 private lion: LionService,
115 protected ls: LoadingService,
116 protected log: LogService,
Sean Condon83fc39f2018-04-19 18:56:13 +0100117 private ps: PanelService,
Sean Condon83fc39f2018-04-19 18:56:13 +0100118 private ufs: UrlFnService,
Sean Condon2bd11b72018-06-15 08:00:48 +0100119 protected wss: WebSocketService,
Sean Condona00bf382018-06-23 07:54:01 +0100120 @Inject('Window') private window: Window,
Sean Condon83fc39f2018-04-19 18:56:13 +0100121 ) {
Sean Condon2bd11b72018-06-15 08:00:48 +0100122 super(fs, null, log, wss, 'app');
123 this.responseCallback = this.appResponseCb;
124 this.sortParams = {
125 firstCol: 'state',
126 firstDir: 'desc',
127 secondCol: 'title',
128 secondDir: 'asc',
129 };
130 // We want doLion() to be called only after the Lion service is populated (from the WebSocket)
131 this.lion.loadCb = (() => this.doLion());
132 this.ctrlBtnState = <CtrlBtnState>{
133 installed: false,
134 active: false
135 };
136 if (this.lion.ubercache.length === 0) {
137 this.lionFn = this.dummyLion;
138 } else {
139 this.doLion();
140 }
Sean Condona00bf382018-06-23 07:54:01 +0100141 this.uploadTip = this.lionFn('tt_ctl_upload');
142 this.activateTip = this.lionFn('tt_ctl_activate');
143 this.deactivateTip = this.lionFn('tt_ctl_deactivate');
144 this.uninstallTip = this.lionFn('tt_ctl_uninstall');
145 this.downloadTip = this.lionFn('tt_ctl_download');
Sean Condon83fc39f2018-04-19 18:56:13 +0100146 }
147
148 ngOnInit() {
Sean Condon2bd11b72018-06-15 08:00:48 +0100149 this.init();
150 this.log.debug('AppComponent initialized');
Sean Condon83fc39f2018-04-19 18:56:13 +0100151 }
152
Sean Condon2bd11b72018-06-15 08:00:48 +0100153 ngOnDestroy() {
154 this.destroy();
155 this.log.debug('AppComponent destroyed');
156 }
157
158 /**
159 * The callback called when App data returns from WSS
160 */
161 appResponseCb(data: AppTableResponse) {
162 this.log.debug('App response received for ', data.apps.length, 'apps');
163 }
164
165 refreshCtrls() {
166 let row;
167 let rowIdx;
168 if (this.ctrlBtnState.selection) {
169 rowIdx = this.fs.find(this.selId, this.tableData);
170 row = rowIdx >= 0 ? this.tableData[rowIdx] : null;
171
172 this.ctrlBtnState.installed = row && row.state === INSTALLED;
173 this.ctrlBtnState.active = row && row.state === ACTIVE;
174 } else {
175 this.ctrlBtnState.installed = false;
176 this.ctrlBtnState.active = false;
177 }
178 }
179
180 createConfirmationText(action, itemId) {
181// let content = this.ds.createDiv();
182// content.append('p').text(this.lionFn(action) + ' ' + itemId);
183// if (strongWarning[itemId]) {
184// content.append('p').html(
185// this.fs.sanitize(this.warnDeactivate) +
186// '<br>' +
187// this.fs.sanitize(this.warnOwnRisk)
188// ).classed('strong', true);
189// }
190// return content;
191 }
192
193 confirmAction(action): void {
194 const itemId = this.selId;
195 const spar = this.sortParams;
196
197 function dOk() {
198 this.log.debug('Initiating', action, 'of', itemId);
199 this.wss.sendEvent(appMgmtReq, {
200 action: action,
201 name: itemId,
202 sortCol: spar.sortCol,
203 sortDir: spar.sortDir,
204 });
205 if (action === 'uninstall') {
206 this.detailsPanel.hide();
207 } else {
208 this.wss.sendEvent(detailsReq, { id: itemId });
209 }
210 }
211
212 function dCancel() {
213 this.log.debug('Canceling', action, 'of', itemId);
214 }
215
216// this.ds.openDialog(dialogId, dialogOpts)
217// .setTitle(this.lionFn('dlg_confirm_action'))
218// .addContent(this.createConfirmationText(action, itemId))
219// .addOk(dOk)
220// .addCancel(dCancel)
221// .bindKeys();
222 }
223
224 appAction(action) {
225 if (this.ctrlBtnState.selection) {
226 this.confirmAction(action);
227 }
228 }
229
230 downloadApp() {
231 if (this.ctrlBtnState.selection) {
232 (<any>this.window).location = appUrlPrefix + this.selId + downloadSuffix;
233 }
234 }
235
236 /**
237 * Read the LION bundle for App - this should replace the dummyLion implementation
238 * of lionFn with a function from the LION Service
239 */
240 doLion() {
241 this.lionFn = this.lion.bundle('core.view.App');
242
243 this.warnDeactivate = this.lionFn('dlg_warn_deactivate');
244 this.warnOwnRisk = this.lionFn('dlg_warn_own_risk');
245
246 this.friendlyProps = [
247 this.lionFn('app_id'), this.lionFn('state'),
248 this.lionFn('category'), this.lionFn('version'),
249 this.lionFn('origin'), this.lionFn('role'),
250 ];
251 }
252
253 /**
254 * A dummy implementation of the lionFn until the response is received and the LION
255 * bundle is received from the WebSocket
256 */
257 dummyLion(key: string): string {
258 return '%' + key + '%';
259 }
Sean Condona00bf382018-06-23 07:54:01 +0100260
261 appDropped() {
262 this.activateImmediately = activateOption;
263// $scope.$emit('FileChanged'); // TODO: Implement this
264 this.appFile = null;
265 }
Sean Condon83fc39f2018-04-19 18:56:13 +0100266}