aboutsummaryrefslogtreecommitdiffstats
path: root/webapp/src/app/pages/sdks/sdk-management
diff options
context:
space:
mode:
authorSebastien Douheret <sebastien.douheret@iot.bzh>2017-12-21 15:07:04 +0100
committerSebastien Douheret <sebastien.douheret@iot.bzh>2017-12-23 00:43:11 +0100
commit45f6472d1e8ecad428da314a6d762143f033865d (patch)
tree3d4f3f413ab752fcb0d5c661fd3fec63ba5f5c24 /webapp/src/app/pages/sdks/sdk-management
parenta85f3ef5017e7e1406476194cd5f3e848a3718f9 (diff)
Added new SDKs management supportv1.0.0-rc2
Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
Diffstat (limited to 'webapp/src/app/pages/sdks/sdk-management')
-rw-r--r--webapp/src/app/pages/sdks/sdk-management/sdk-install.component.ts131
-rw-r--r--webapp/src/app/pages/sdks/sdk-management/sdk-management.component.html26
-rw-r--r--webapp/src/app/pages/sdks/sdk-management/sdk-management.component.scss83
-rw-r--r--webapp/src/app/pages/sdks/sdk-management/sdk-management.component.ts168
4 files changed, 408 insertions, 0 deletions
diff --git a/webapp/src/app/pages/sdks/sdk-management/sdk-install.component.ts b/webapp/src/app/pages/sdks/sdk-management/sdk-install.component.ts
new file mode 100644
index 0000000..c9c518f
--- /dev/null
+++ b/webapp/src/app/pages/sdks/sdk-management/sdk-install.component.ts
@@ -0,0 +1,131 @@
+/**
+* @license
+* Copyright (C) 2017 "IoT.bzh"
+* Author Sebastien Douheret <sebastien@iot.bzh>
+*
+* 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, Input, ViewChild, AfterViewChecked, ElementRef } from '@angular/core';
+import { DomSanitizer } from '@angular/platform-browser';
+import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
+
+import { AlertService } from '../../../@core-xds/services/alert.service';
+import { SdkService, ISdk } from '../../../@core-xds/services/sdk.service';
+
+@Component({
+ selector: 'xds-sdk-install-modal',
+ template: `
+ <div tabindex="-1">
+ <div class="modal-header">
+ SDK installation
+ </div>
+
+ <div class="modal-body row">
+ <div class="col-12 text-center">
+ Installation of <b> {{ sdk?.name }} '</b> <span [innerHTML]="instStatus"></span>
+ </div>
+ <br>
+ <br>
+ <div class="col-12 text-center">
+ <textarea rows="20" class="textarea-scroll" #scrollOutput [innerHtml]="installOutput"></textarea>
+ </div>
+ <div class="col-12 text-center">
+ <button type="button" class="btn" tabindex="1"
+ [ngClass]="(btnName=='Cancel')?'btn-default':'btn-primary'"
+ (click)="onBtnClick()">{{ btnName }}</button>
+ </div>
+ </div>
+
+ <!-- <div *ngIf="footer!=''" class="modal-footer">
+ <div class="col-12 text-center">
+ </div>
+ </div> -->
+ </div>
+ `,
+ styles: [`
+ .btn {
+ margin-top: 2em;
+ min-width: 10em;
+ }
+ .textarea-scroll {
+ font-family: monospace;
+ width: 100%;
+ overflow-y: scroll;
+ `],
+})
+
+export class SdkInstallComponent implements OnInit {
+ @Input() sdk;
+ @ViewChild('scrollOutput') private scrollContainer: ElementRef;
+
+ constructor(
+ private modalRef: NgbActiveModal,
+ private sanitizer: DomSanitizer,
+ private alert: AlertService,
+ private sdkSvr: SdkService,
+ ) { }
+
+ onInstallSub: any;
+ installOutput = '';
+ btnName = 'Cancel';
+ instStatus = '';
+
+ ngOnInit() {
+ this.instStatus = 'in progress...';
+
+ this.onInstallSub = this.sdkSvr.onInstall().subscribe(ev => {
+ if (ev.exited) {
+ this.btnName = 'OK';
+ this.instStatus = '<font color="green"> Done. </font>';
+
+ if (ev.code === 0) {
+ this.alert.info('SDK ' + ev.sdk.name + ' successfully installed.');
+
+ } else {
+ if (ev.sdk.lastError !== '') {
+ this.alert.error(ev.sdk.lastError);
+ } else {
+ this.alert.error('SDK ' + ev.sdk.name + ' installation failed. ' + ev.error);
+ }
+ }
+
+ } else {
+ if (ev.stdout !== '') {
+ this.installOutput += ev.stdout;
+ }
+ if (ev.stderr !== '') {
+ this.installOutput += ev.stderr;
+ }
+ this._scrollToBottom();
+ }
+ });
+ }
+
+ onBtnClick(): void {
+ this.onInstallSub.unsubscribe();
+ if (this.btnName === 'Cancel') {
+ this.btnName = 'OK';
+ this.instStatus = '<b><font color="red"> ABORTED </font></b>';
+ this.sdkSvr.abortInstall(this.sdk).subscribe(r => { }, err => this.alert.error(err));
+ } else {
+ this.modalRef.close();
+ }
+ }
+
+ private _scrollToBottom(): void {
+ try {
+ this.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight;
+ } catch (err) { }
+ }
+}
diff --git a/webapp/src/app/pages/sdks/sdk-management/sdk-management.component.html b/webapp/src/app/pages/sdks/sdk-management/sdk-management.component.html
new file mode 100644
index 0000000..0587194
--- /dev/null
+++ b/webapp/src/app/pages/sdks/sdk-management/sdk-management.component.html
@@ -0,0 +1,26 @@
+<div class="row">
+ <div class="col-12">
+ <nb-card-body>
+ <div class="col-9">
+ <nb-actions size="medium">
+ <nb-action>
+ <a href="#/pages/sdks" class="btn" role="Button">
+ <i id="hack-i" class="fa fa-list-alt"></i>
+ <span id="hack-span">Switch to basic SDKs view</span>
+ </a>
+ </nb-action>
+ </nb-actions>
+ </div>
+ </nb-card-body>
+ </div>
+
+ <nb-card>
+ <nb-card-header>
+ <span>SDKs Management</span>
+ </nb-card-header>
+
+ <nb-card-body>
+ <ng2-smart-table [settings]="settings" [source]="sdks" (custom)="onCustom($event)"></ng2-smart-table>
+ </nb-card-body>
+ </nb-card>
+</div>
diff --git a/webapp/src/app/pages/sdks/sdk-management/sdk-management.component.scss b/webapp/src/app/pages/sdks/sdk-management/sdk-management.component.scss
new file mode 100644
index 0000000..0ba2741
--- /dev/null
+++ b/webapp/src/app/pages/sdks/sdk-management/sdk-management.component.scss
@@ -0,0 +1,83 @@
+@import '../../../@theme/styles/themes';
+@import '~@nebular/theme/components/card/card.component.theme';
+// FIXME SEB: remove this ugly hack and use nb-theme
+#hack-i {
+ color: #a4abb3; // nb-theme(color-fg);
+ font-size: 1.5rem;
+ margin-right: 1rem;
+}
+
+#hack-span {
+ font-family: nb-theme(font-secondary);
+ font-weight: nb-theme(font-weight-bold);
+ color: #2a2a2a; // nb-theme(color-fg-heading);
+ text-transform: uppercase;
+}
+
+@include nb-install-component() {
+ nb-card-body {
+ display: flex;
+ align-items: center;
+ }
+ .action-groups-header {
+ flex-basis: 20%;
+ color: nb-theme(card-header-fg-heading);
+ font-family: nb-theme(card-header-font-family);
+ font-size: nb-theme(card-header-font-size);
+ font-weight: nb-theme(card-header-font-weight);
+ }
+ .nb-actions {
+ flex-basis: 80%;
+ }
+ .right {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ order: 1;
+ flex-direction: row-reverse;
+ }
+ nb-actions > nb-action {
+ padding: 0;
+ }
+ nb-action {
+ i {
+ color: nb-theme(color-fg);
+ font-size: 1.5rem;
+ margin-right: 1rem;
+ }
+ span {
+ font-family: nb-theme(font-secondary);
+ font-weight: nb-theme(font-weight-bold);
+ color: nb-theme(color-fg-heading);
+ text-transform: uppercase;
+ }
+ button {
+ margin: 0 auto;
+ padding: 0;
+ cursor: pointer;
+ border: none;
+ background: none;
+ display: flex;
+ align-items: center;
+ &:focus {
+ box-shadow: none;
+ outline: none;
+ }
+ }
+ }
+}
+
+td.ng2-smart-actions {
+ height: auto !important;
+}
+
+nav.ng2-smart-pagination-nav {
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.ng2-smart-pagination .page-link.page-link-prev,
+.page-link.page-link-next {
+ font-size: 1em !important;
+}
diff --git a/webapp/src/app/pages/sdks/sdk-management/sdk-management.component.ts b/webapp/src/app/pages/sdks/sdk-management/sdk-management.component.ts
new file mode 100644
index 0000000..c885238
--- /dev/null
+++ b/webapp/src/app/pages/sdks/sdk-management/sdk-management.component.ts
@@ -0,0 +1,168 @@
+/**
+* @license
+* Copyright (C) 2017 "IoT.bzh"
+* Author Sebastien Douheret <sebastien@iot.bzh>
+*
+* 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, ViewEncapsulation, OnInit, isDevMode } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
+import { LocalDataSource } from 'ng2-smart-table';
+import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
+import { ConfirmModalComponent, EType } from '../../confirm/confirm-modal/confirm-modal.component';
+import { SdkInstallComponent } from './sdk-install.component';
+
+import { AlertService } from '../../../@core-xds/services/alert.service';
+import { SdkService, ISdk } from '../../../@core-xds/services/sdk.service';
+import { ISdkMessage } from '../../../@core-xds/services/xdsagent.service';
+
+interface ISdkMgt extends ISdk {
+ link: string;
+ selected: boolean;
+}
+
+/*
+ * FIXME / TODO:
+ * - support install of multi SDKs (see settings.selectMode: 'multi')
+ * - add Uninstall button (use delete)
+ * - add (mouseover) to display description, date, size, ...
+ */
+
+@Component({
+ selector: 'xds-sdk-management',
+ templateUrl: 'sdk-management.component.html',
+ styleUrls: ['sdk-management.component.scss'],
+ encapsulation: ViewEncapsulation.None,
+})
+
+export class SdkManagementComponent implements OnInit {
+
+ sdks$: Observable<ISdk[]>;
+ sdks: ISdkMgt[];
+ source: LocalDataSource = new LocalDataSource();
+
+ settings = {
+ mode: 'external',
+ actions: {
+ add: false,
+ edit: false,
+ delete: false, // TODO, add delete == uninstall
+ custom: [
+ { name: 'install', title: '<i class="nb-plus"></i>' },
+ ],
+ },
+ delete: {
+ deleteButtonContent: '<i class="nb-trash"></i>',
+ confirmDelete: true,
+ },
+ columns: {
+ name: { title: 'Name', editable: false },
+ profile: { title: 'Profile', editable: false, filter: {} },
+ arch: { title: 'Architecture', editable: false, filter: {} },
+ version: { title: 'Version', editable: false },
+ // TODO: add status when delete supported:
+ // status: { title: 'Status', editable: false },
+ link: { title: 'Link', editable: false, type: 'html', filter: false, width: '2%' },
+ },
+ };
+
+ constructor(
+ private alert: AlertService,
+ private sdkSvr: SdkService,
+ private modalService: NgbModal,
+ ) { }
+
+ ngOnInit() {
+ this.sdkSvr.Sdks$.subscribe(sdks => {
+ const profMap = {};
+ const archMap = {};
+ this.sdks = [];
+ sdks.forEach(s => {
+ // only display not installed SDK
+ if (s.status !== 'Not Installed') {
+ return;
+ }
+ profMap[s.profile] = s.profile;
+ archMap[s.arch] = s.arch;
+
+ const sm = <ISdkMgt>s;
+ sm.selected = false;
+ if (s.url !== '') {
+ sm.link = '<a href="' + s.url.substr(0, s.url.lastIndexOf('/')) + '" target="_blank" class="fa fa-external-link"></a>';
+ }
+ this.sdks.push(sm);
+
+ });
+
+ // Add text box filter for Profile and Arch columns
+ const profList = []; Object.keys(profMap).forEach(a => profList.push({ value: a, title: a }));
+ this.settings.columns.profile.filter = {
+ type: 'list',
+ config: { selectText: 'Select...', list: profList },
+ };
+
+ const archList = []; Object.keys(archMap).forEach(a => archList.push({ value: a, title: a }));
+ this.settings.columns.arch.filter = {
+ type: 'list',
+ config: { selectText: 'Select...', list: archList },
+ };
+
+ // update sources
+ this.source.load(this.sdks);
+
+ });
+ }
+
+ onCustom(event): void {
+ if (event.action === 'install') {
+ const sdk = <ISdkMgt>event.data;
+ const modal = this.modalService.open(ConfirmModalComponent, {
+ size: 'lg',
+ backdrop: 'static',
+ container: 'nb-layout',
+ });
+ modal.componentInstance.title = 'Confirm SDK installation';
+ modal.componentInstance.type = EType.YesNo;
+ modal.componentInstance.question = `
+ Please confirm installation of <b>` + sdk.name + `'</b> SDK ?<br>
+ <br>
+ <i><small>(size: ` + sdk.size + `, date: ` + sdk.date + `)</small></i>`;
+
+ modal.result.then(res => {
+ if (res === 'yes') {
+ // Request installation
+ this.sdkSvr.install(sdk).subscribe(r => { }, err => this.alert.error(err));
+
+ const modalInstall = this.modalService.open(SdkInstallComponent, {
+ size: 'lg',
+ backdrop: 'static',
+ container: 'nb-layout',
+ });
+ modalInstall.componentInstance.sdk = sdk;
+ }
+ });
+
+
+ } else if (event.action === 'uninstall') {
+ // TODO
+
+ } else {
+ /* tslint:disable:no-console */
+ if (isDevMode) {
+ console.error('onCustom: unknown event action: ', event);
+ }
+ }
+ }
+
+}