blob: 79fa3108146b5745e202037bc705cb09d9f12b9d [file] [log] [blame]
/*
* Copyright 2015-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an 'AS IS' BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
import { DialogService } from '../../../fw/layer/dialog.service';
import { FnService } from '../../../fw/util/fn.service';
import { IconService } from '../../../fw/svg/icon.service';
import { KeyService } from '../../../fw/util/key.service';
import { LionService } from '../../../fw/util/lion.service';
import { LoadingService } from '../../../fw/layer/loading.service';
import { LogService } from '../../../log.service';
import { TableBaseImpl, TableResponse, TableFilter, SortParams, SortDir } from '../../../fw/widget/table.base';
import { UrlFnService } from '../../../fw/remote/urlfn.service';
import { WebSocketService } from '../../../fw/remote/websocket.service';
import { TableFilterPipe } from '../../../fw/widget/tablefilter.pipe';
const INSTALLED = 'INSTALLED';
const ACTIVE = 'ACTIVE';
const appMgmtReq = 'appManagementRequest';
const topPdg = 60;
const panelWidth = 540;
const pName = 'application-details-panel';
const detailsReq = 'appDetailsRequest';
const detailsResp = 'appDetailsResponse';
const fileUploadUrl = 'applications/upload';
const activateOption = '?activate=true';
/** Prefix to access the REST service for applications */
export const APPURLPREFIX = '../../ui/rs/applications/'; // TODO: This is a hack to work off GUIv1 URL
/** Suffix to access the icon of the application - gives back an image */
export const ICONURLSUFFIX = '/icon';
const downloadSuffix = '/download';
const dialogId = 'app-dialog';
const dialogOpts = {
edge: 'right',
width: 400,
};
const strongWarning = {
'org.onosproject.drivers': true,
};
const propOrder = ['id', 'state', 'category', 'version', 'origin', 'role'];
/**
* Model of the data returned through the Web Socket about apps.
*/
interface AppTableResponse extends TableResponse {
apps: App[];
}
/**
* Model of the data returned through Web Socket for a single App
*/
export interface App {
category: string;
desc: string;
features: string[];
icon: string;
id: string;
origin: string;
permissions: string[];
readme: string;
required_apps: string[];
role: string;
state: string;
title: string;
url: string;
version: string;
_iconid_state: string;
}
/**
* Model of the Control Button
*/
interface CtrlBtnState {
installed: boolean;
selection: string;
active: boolean;
}
/**
* ONOS GUI -- Apps View Component
*/
@Component({
selector: 'onos-apps',
templateUrl: './apps.component.html',
styleUrls: [
'./apps.component.css', './apps.theme.css',
'../../../fw/widget/table.css', '../../../fw/widget/table.theme.css'
]
})
export class AppsComponent extends TableBaseImpl implements OnInit, OnDestroy {
// deferred localization strings
lionFn; // Function
warnDeactivate: string;
warnOwnRisk: string;
ctrlBtnState: CtrlBtnState;
detailsPanel: any;
appFile: any;
activateImmediately = '';
uploadTip: string;
activateTip: string;
deactivateTip: string;
uninstallTip: string;
downloadTip: string;
constructor(
protected fs: FnService,
private ds: DialogService,
private is: IconService,
private ks: KeyService,
private lion: LionService,
protected ls: LoadingService,
protected log: LogService,
private ufs: UrlFnService,
protected wss: WebSocketService,
@Inject('Window') private window: Window,
) {
super(fs, null, log, wss, 'app');
this.responseCallback = this.appResponseCb;
// pre-populate sort so active apps are at the top of the list
this.sortParams = {
firstCol: 'state',
firstDir: SortDir.desc,
secondCol: 'title',
secondDir: SortDir.asc,
};
// We want doLion() to be called only after the Lion
// service is populated (from the WebSocket)
// If lion is not ready we make do with a dummy function
// As soon a lion gets loaded this function will be replaced with
// the real thing
if (this.lion.ubercache.length === 0) {
this.lionFn = this.dummyLion;
this.lion.loadCbs.set('apps', () => this.doLion());
} else {
this.doLion();
}
this.ctrlBtnState = <CtrlBtnState>{
installed: false,
active: false
};
}
/**
* Initialize querying the WebSocket for App table details
*/
ngOnInit() {
this.init();
}
/**
* Stop sending queries to WebSocket
*/
ngOnDestroy() {
this.lion.loadCbs.delete('apps');
this.destroy();
this.log.debug('AppComponent destroyed');
}
/**
* The callback called when App data returns from WSS
*/
appResponseCb(data: AppTableResponse) {
this.log.debug('App response received for ', data.apps.length, 'apps');
}
refreshCtrls() {
let row;
let rowIdx;
if (this.ctrlBtnState.selection) {
rowIdx = this.fs.find(this.selId, this.tableData);
row = rowIdx >= 0 ? this.tableData[rowIdx] : null;
this.ctrlBtnState.installed = row && row.state === INSTALLED;
this.ctrlBtnState.active = row && row.state === ACTIVE;
} else {
this.ctrlBtnState.installed = false;
this.ctrlBtnState.active = false;
}
}
createConfirmationText(action, itemId) {
// let content = this.ds.createDiv();
// content.append('p').text(this.lionFn(action) + ' ' + itemId);
// if (strongWarning[itemId]) {
// content.append('p').html(
// this.fs.sanitize(this.warnDeactivate) +
// '<br>' +
// this.fs.sanitize(this.warnOwnRisk)
// ).classed('strong', true);
// }
// return content;
}
confirmAction(action): void {
const itemId = this.selId;
const spar = this.sortParams;
function dOk() {
this.log.debug('Initiating', action, 'of', itemId);
this.wss.sendEvent(appMgmtReq, {
action: action,
name: itemId,
sortCol: spar.firstCol,
sortDir: spar.firstDir,
});
if (action === 'uninstall') {
this.detailsPanel.hide();
} else {
this.wss.sendEvent(detailsReq, { id: itemId });
}
}
function dCancel() {
this.log.debug('Canceling', action, 'of', itemId);
}
// this.ds.openDialog(dialogId, dialogOpts)
// .setTitle(this.lionFn('dlg_confirm_action'))
// .addContent(this.createConfirmationText(action, itemId))
// .addOk(dOk)
// .addCancel(dCancel)
// .bindKeys();
}
appAction(action) {
if (this.ctrlBtnState.selection) {
this.confirmAction(action);
}
}
downloadApp() {
if (this.ctrlBtnState.selection) {
(<any>this.window).location = APPURLPREFIX + this.selId + ICONURLSUFFIX;
}
}
/**
* Read the LION bundle for App and set up the lionFn
*/
doLion() {
this.lionFn = this.lion.bundle('core.view.App');
this.warnDeactivate = this.lionFn('dlg_warn_deactivate');
this.warnOwnRisk = this.lionFn('dlg_warn_own_risk');
this.uploadTip = this.lionFn('tt_ctl_upload');
this.activateTip = this.lionFn('tt_ctl_activate');
this.deactivateTip = this.lionFn('tt_ctl_deactivate');
this.uninstallTip = this.lionFn('tt_ctl_uninstall');
this.downloadTip = this.lionFn('tt_ctl_download');
}
appDropped() {
this.activateImmediately = activateOption;
// $scope.$emit('FileChanged'); // TODO: Implement this
this.appFile = null;
}
}