diff options
author | 2017-09-25 13:50:27 +0200 | |
---|---|---|
committer | 2017-11-06 15:57:03 +0100 | |
commit | ac9e80f7f32a1c04c171a4d208f0ab7d3a5ca154 (patch) | |
tree | 9660a93b24ea6d4eb466d93127c4a298d5015521 /webapp/src | |
parent | 1e0b1b4c1271e3668ec5ef1ba58cb84fe00f0f53 (diff) |
Moved web Dashboard to xds-agent
Xds-Server now only provides a minimal page to get basic instructions.
Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
Diffstat (limited to 'webapp/src')
40 files changed, 79 insertions, 3332 deletions
diff --git a/webapp/src/app/alert/alert.component.ts b/webapp/src/app/alert/alert.component.ts deleted file mode 100644 index 672d7bf..0000000 --- a/webapp/src/app/alert/alert.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component } from '@angular/core'; -import { Observable } from 'rxjs'; - -import {AlertService, IAlert} from '../services/alert.service'; - -@Component({ - selector: 'app-alert', - template: ` - <div style="width:80%; margin-left:auto; margin-right:auto;" *ngFor="let alert of (alerts$ | async)"> - <alert *ngIf="alert.show" [type]="alert.type" [dismissible]="alert.dismissible" [dismissOnTimeout]="alert.dismissTimeout" - (onClose)="onClose(alert)"> - <div style="text-align:center;" [innerHtml]="alert.msg"></div> - </alert> - </div> - ` -}) - -export class AlertComponent { - - alerts$: Observable<IAlert[]>; - - constructor(private alertSvr: AlertService) { - this.alerts$ = this.alertSvr.alerts; - } - - onClose(al) { - this.alertSvr.del(al); - } - -} diff --git a/webapp/src/app/app.component.css b/webapp/src/app/app.component.css deleted file mode 100644 index a47ad13..0000000 --- a/webapp/src/app/app.component.css +++ /dev/null @@ -1,31 +0,0 @@ -.navbar { - background-color: whitesmoke; -} - -.navbar-brand { - font-size: x-large; - font-variant: small-caps; - color: #5a28a1; -} - -a.navbar-brand { - margin-top: 5px; -} - - -.navbar-nav ul li a { - color: #fff; -} - -.menu-text { - color: #fff; -} - -#logo-iot { - padding: 0 2px; - height: 60px; -} - -li>a { - color:#5a28a1; -} diff --git a/webapp/src/app/app.component.html b/webapp/src/app/app.component.html deleted file mode 100644 index a889b12..0000000 --- a/webapp/src/app/app.component.html +++ /dev/null @@ -1,30 +0,0 @@ -<nav class="navbar navbar-fixed-top"> - <!-- navbar-inverse"> --> - <div class="container-fluid"> - <div class="navbar-header"> - <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#myNavbar" - [attr.aria-expanded]="!isCollapsed" (click)="isCollapsed = !isCollapsed;" [ngClass]="{'collapsed': isCollapsed}"> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - <span class="icon-bar"></span> - </button> - - <img class="navbar-brand" id="logo-iot" src="assets/images/iot-bzh-logo-small.png"> - <a class="navbar-brand" href="#">X(cross) Development System Dashboard</a> - </div> - - <div class="collapse navbar-collapse" [ngClass]="{'in': !isCollapsed}" id="myNavbar"> - <ul class="nav navbar-nav navbar-right"> - <li><a routerLink="/config"><i class="fa fa-2x fa-cog" title="Open configuration page" (click)="isCollapsed=true;"></i></a></li> - <li><a routerLink="/devel"><i class="fa fa-2x fa-play-circle" title="Open build page" (click)="isCollapsed=true;"></i></a></li> - <li><a routerLink="/home"><i class="fa fa-2x fa-home" title="Back to home page" (click)="isCollapsed=true;"></i></a></li> - </ul> - </div> - </div> -</nav> - -<app-alert id="alert"></app-alert> - -<div style="margin:10px;"> - <router-outlet></router-outlet> -</div> diff --git a/webapp/src/app/app.component.ts b/webapp/src/app/app.component.ts deleted file mode 100644 index 40cfb24..0000000 --- a/webapp/src/app/app.component.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { Component, OnInit, OnDestroy } from "@angular/core"; -import { Router } from '@angular/router'; -//TODO import {TranslateService} from "ng2-translate"; - -@Component({ - selector: 'app', - templateUrl: './app/app.component.html', - styleUrls: ['./app/app.component.css'] -}) - -export class AppComponent implements OnInit, OnDestroy { - - isCollapsed: boolean = true; - - private defaultLanguage: string = 'en'; - - // I initialize the app component. - //TODO constructor(private translate: TranslateService) { - constructor(public router: Router) { - } - - ngOnInit() { - - /* TODO - this.translate.addLangs(["en", "fr"]); - this.translate.setDefaultLang(this.defaultLanguage); - - let browserLang = this.translate.getBrowserLang(); - this.translate.use(browserLang.match(/en|fr/) ? browserLang : this.defaultLanguage); - */ - } - - ngOnDestroy(): void { - } - - -} diff --git a/webapp/src/app/app.module.ts b/webapp/src/app/app.module.ts deleted file mode 100644 index 10ff7a4..0000000 --- a/webapp/src/app/app.module.ts +++ /dev/null @@ -1,97 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; -import { HttpModule } from "@angular/http"; -import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { CookieModule } from 'ngx-cookie'; - -// Import bootstrap -import { AlertModule } from 'ngx-bootstrap/alert'; -import { ModalModule } from 'ngx-bootstrap/modal'; -import { AccordionModule } from 'ngx-bootstrap/accordion'; -import { CarouselModule } from 'ngx-bootstrap/carousel'; -import { PopoverModule } from 'ngx-bootstrap/popover'; -import { CollapseModule } from 'ngx-bootstrap/collapse'; -import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; - -// Import the application components and services. -import { Routing, AppRoutingProviders } from './app.routing'; -import { AppComponent } from "./app.component"; -import { AlertComponent } from './alert/alert.component'; -import { ConfigComponent } from "./config/config.component"; -import { DlXdsAgentComponent, CapitalizePipe } from "./config/downloadXdsAgent.component"; -import { ProjectCardComponent } from "./projects/projectCard.component"; -import { ProjectReadableTypePipe } from "./projects/projectCard.component"; -import { ProjectsListAccordionComponent } from "./projects/projectsListAccordion.component"; -import { ProjectAddModalComponent} from "./projects/projectAddModal.component"; -import { SdkCardComponent } from "./sdks/sdkCard.component"; -import { SdksListAccordionComponent } from "./sdks/sdksListAccordion.component"; -import { SdkSelectDropdownComponent } from "./sdks/sdkSelectDropdown.component"; -import { SdkAddModalComponent} from "./sdks/sdkAddModal.component"; - -import { HomeComponent } from "./home/home.component"; -import { DevelComponent } from "./devel/devel.component"; -import { BuildComponent } from "./devel/build/build.component"; -import { DeployComponent } from "./devel/deploy/deploy.component"; -import { XDSServerService } from "./services/xdsserver.service"; -import { XDSAgentService } from "./services/xdsagent.service"; -import { SyncthingService } from "./services/syncthing.service"; -import { ConfigService } from "./services/config.service"; -import { AlertService } from './services/alert.service'; -import { UtilsService } from './services/utils.service'; -import { SdkService } from "./services/sdk.service"; - - - -@NgModule({ - imports: [ - BrowserModule, - HttpModule, - FormsModule, - ReactiveFormsModule, - Routing, - CookieModule.forRoot(), - AlertModule.forRoot(), - ModalModule.forRoot(), - AccordionModule.forRoot(), - CarouselModule.forRoot(), - PopoverModule.forRoot(), - CollapseModule.forRoot(), - BsDropdownModule.forRoot(), - ], - declarations: [ - AppComponent, - AlertComponent, - HomeComponent, - BuildComponent, - DevelComponent, - DeployComponent, - ConfigComponent, - DlXdsAgentComponent, - CapitalizePipe, - ProjectCardComponent, - ProjectReadableTypePipe, - ProjectsListAccordionComponent, - ProjectAddModalComponent, - SdkCardComponent, - SdksListAccordionComponent, - SdkSelectDropdownComponent, - SdkAddModalComponent, - ], - providers: [ - AppRoutingProviders, - { - provide: Window, - useValue: window - }, - XDSServerService, - XDSAgentService, - ConfigService, - SyncthingService, - AlertService, - UtilsService, - SdkService, - ], - bootstrap: [AppComponent] -}) -export class AppModule { -} diff --git a/webapp/src/app/app.routing.ts b/webapp/src/app/app.routing.ts deleted file mode 100644 index f0d808f..0000000 --- a/webapp/src/app/app.routing.ts +++ /dev/null @@ -1,19 +0,0 @@ -import {Routes, RouterModule} from "@angular/router"; -import {ModuleWithProviders} from "@angular/core"; -import {ConfigComponent} from "./config/config.component"; -import {HomeComponent} from "./home/home.component"; -import {DevelComponent} from "./devel/devel.component"; - - -const appRoutes: Routes = [ - {path: '', redirectTo: 'home', pathMatch: 'full'}, - - {path: 'config', component: ConfigComponent, data: {title: 'Config'}}, - {path: 'home', component: HomeComponent, data: {title: 'Home'}}, - {path: 'devel', component: DevelComponent, data: {title: 'Build & Deploy'}} -]; - -export const AppRoutingProviders: any[] = []; -export const Routing: ModuleWithProviders = RouterModule.forRoot(appRoutes, { - useHash: true -}); diff --git a/webapp/src/app/config/config.component.css b/webapp/src/app/config/config.component.css deleted file mode 100644 index 6412f9a..0000000 --- a/webapp/src/app/config/config.component.css +++ /dev/null @@ -1,35 +0,0 @@ -.fa-big { - font-size: 20px; - font-weight: bold; -} - -.fa-size-x2 { - font-size: 20px; -} - -h2 { - font-family: sans-serif; - font-variant: small-caps; - font-size: x-large; -} - -th span { - font-weight: 100; -} - -th label { - font-weight: 100; - margin-bottom: 0; -} - -tr.info>th { - vertical-align: middle; -} - -tr.info>td { - vertical-align: middle; -} - -.panel-heading { - background: aliceblue; -} diff --git a/webapp/src/app/config/config.component.html b/webapp/src/app/config/config.component.html deleted file mode 100644 index c36ba02..0000000 --- a/webapp/src/app/config/config.component.html +++ /dev/null @@ -1,106 +0,0 @@ -<div class="panel panel-default"> - <div class="panel-heading"> - <h2 class="panel-title" (click)="gConfigIsCollapsed = !gConfigIsCollapsed"> - Global Configuration - <div class="pull-right"> - <span class="fa fa-fw fa-exchange fa-size-x2" [style.color]="((serverStatus$ | async)?.WS_connected)?'green':'red'"></span> - - <button class="btn btn-link" (click)="gConfigIsCollapsed = !gConfigIsCollapsed; $event.stopPropagation()"> - <span class="fa fa-big" [ngClass]="{'fa-angle-double-down': gConfigIsCollapsed, 'fa-angle-double-right': !gConfigIsCollapsed}"></span> - </button> - </div> - </h2> - </div> - <div class="panel-body" [collapse]="gConfigIsCollapsed && (agentStatus$ | async)?.connected"> - <div class="row"> - <div class="col-xs-12"> - <table class="table table-condensed"> - <tbody> - <tr [ngClass]="{'info': (agentStatus$ | async)?.connected, 'danger': !(agentStatus$ | async)?.connected}"> - <th><label>XDS local Agent URL</label></th> - <td> <input type="text" [(ngModel)]="xdsAgentUrl"></td> - <td style="white-space: nowrap"> - <div class="btn-group"> - <button class="btn btn-link" (click)="xdsAgentRestartConn()"><span class="fa fa-refresh fa-size-x2"></span></button> - <dl-xds-agent class="button" [packageUrls]="(config$ | async).xdsAgentPackages"></dl-xds-agent> - </div> - </td> - </tr> - <tr class="info"> - <th><label>Local Agent connection retry</label></th> - <td> <input type="text" [(ngModel)]="xdsAgentRetry" (ngModelChange)="showApplyBtn['retry'] = true"></td> - <td> - <button *ngIf="showApplyBtn['retry']" class="btn btn-primary btn-xs" (click)="submitGlobConf('retry')">APPLY</button> - </td> - </tr> - <tr [ngClass]="{'info': (localSTStatus$ | async)?.connected, 'danger': !(localSTStatus$ | async)?.connected}"> - <th><label>Local Sync-tool URL</label></th> - <td> <input type="text" [(ngModel)]="syncToolUrl"></td> - <td> - <button class="btn btn-link" (click)="xdsAgentRestartConn()"><span class="fa fa-refresh fa-size-x2"></span></button> - </td> - </tr> - <tr class="info"> - <th><label>Local Projects root directory</label></th> - <td> <input type="text" [(ngModel)]="projectsRootDir" (ngModelChange)="showApplyBtn['rootDir'] = true"></td> - <td> - <button *ngIf="showApplyBtn['rootDir']" class="btn btn-primary btn-xs" (click)="submitGlobConf('rootDir')">APPLY</button> - </td> - </tr> - </tbody> - </table> - </div> - </div> - </div> -</div> - -<div class="panel panel-default"> - <div class="panel-heading"> - <h2 class="panel-title" (click)="sdksIsCollapsed = !sdksIsCollapsed"> - Cross SDKs - <div class="pull-right"> - <button class="btn btn-link" (click)="childSdkModal.show(); $event.stopPropagation()"><span class="fa fa-plus fa-size-x2"></span></button> - - <button class="btn btn-link" (click)="sdksIsCollapsed = !sdksIsCollapsed; $event.stopPropagation()"> - <span class="fa fa-big" [ngClass]="{'fa-angle-double-down': sdksIsCollapsed, 'fa-angle-double-right': !sdksIsCollapsed}"></span> - </button> - </div> - </h2> - </div> - <div class="panel-body" [collapse]="sdksIsCollapsed"> - <div class="row col-xs-12"> - <sdks-list-accordion [sdks]="(sdks$ | async)"></sdks-list-accordion> - </div> - </div> -</div> - -<div class="panel panel-default"> - <div class="panel-heading"> - <h2 class="panel-title" (click)="projectsIsCollapsed = !projectsIsCollapsed; $event.stopPropagation()"> - Projects - <div class="pull-right"> - <button class="btn btn-link" (click)="childProjectModal.show(); $event.stopPropagation()"><span class="fa fa-plus fa-size-x2"></span></button> - - <button class="btn btn-link" (click)="projectsIsCollapsed = !projectsIsCollapsed; $event.stopPropagation()"> - <span class="fa fa-big" [ngClass]="{'fa-angle-double-down': projectsIsCollapsed, 'fa-angle-double-right': !projectsIsCollapsed}"></span> - </button> - </div> - </h2> - </div> - <div class="panel-body" [collapse]="projectsIsCollapsed"> - <div class="row col-xs-12"> - <projects-list-accordion [projects]="(config$ | async).projects"></projects-list-accordion> - </div> - </div> -</div> - -<!-- Modals --> -<project-add-modal #childProjectModal [title]="'Add a new project'"> -</project-add-modal> -<sdk-add-modal #childSdkModal [title]="'Add a new SDK'"> -</sdk-add-modal> - -<!-- only for debug --> -<div *ngIf="false" class="row"> - {{config$ | async | json}} -</div> diff --git a/webapp/src/app/config/config.component.ts b/webapp/src/app/config/config.component.ts deleted file mode 100644 index b107e81..0000000 --- a/webapp/src/app/config/config.component.ts +++ /dev/null @@ -1,106 +0,0 @@ -import { Component, ViewChild, OnInit } from "@angular/core"; -import { Observable } from 'rxjs/Observable'; -import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms'; -import { CollapseModule } from 'ngx-bootstrap/collapse'; - -import { ConfigService, IConfig, IxdsAgentPackage } from "../services/config.service"; -import { XDSServerService, IServerStatus, IXDSAgentInfo } from "../services/xdsserver.service"; -import { XDSAgentService, IAgentStatus } from "../services/xdsagent.service"; -import { SyncthingService, ISyncThingStatus } from "../services/syncthing.service"; -import { AlertService } from "../services/alert.service"; -import { ISdk, SdkService } from "../services/sdk.service"; -import { ProjectAddModalComponent } from "../projects/projectAddModal.component"; -import { SdkAddModalComponent } from "../sdks/sdkAddModal.component"; - -@Component({ - templateUrl: './app/config/config.component.html', - styleUrls: ['./app/config/config.component.css'] -}) - -// Inspired from https://embed.plnkr.co/jgDTXknPzAaqcg9XA9zq/ -// and from http://plnkr.co/edit/vCdjZM?p=preview - -export class ConfigComponent implements OnInit { - @ViewChild('childProjectModal') childProjectModal: ProjectAddModalComponent; - @ViewChild('childSdkModal') childSdkModal: SdkAddModalComponent; - - config$: Observable<IConfig>; - sdks$: Observable<ISdk[]>; - serverStatus$: Observable<IServerStatus>; - agentStatus$: Observable<IAgentStatus>; - localSTStatus$: Observable<ISyncThingStatus>; - - curProj: number; - userEditedLabel: boolean = false; - xdsAgentPackages: IxdsAgentPackage[] = []; - - gConfigIsCollapsed: boolean = true; - sdksIsCollapsed: boolean = true; - projectsIsCollapsed: boolean = false; - - // TODO replace by reactive FormControl + add validation - syncToolUrl: string; - xdsAgentUrl: string; - xdsAgentRetry: string; - projectsRootDir: string; // FIXME: should be remove when projectAddModal will always return full path - showApplyBtn = { // Used to show/hide Apply buttons - "retry": false, - "rootDir": false, - }; - - constructor( - private configSvr: ConfigService, - private xdsServerSvr: XDSServerService, - private xdsAgentSvr: XDSAgentService, - private stSvr: SyncthingService, - private sdkSvr: SdkService, - private alert: AlertService, - ) { - } - - ngOnInit() { - this.config$ = this.configSvr.conf; - this.sdks$ = this.sdkSvr.Sdks$; - this.serverStatus$ = this.xdsServerSvr.Status$; - this.agentStatus$ = this.xdsAgentSvr.Status$; - this.localSTStatus$ = this.stSvr.Status$; - - // Bind xdsAgentUrl to baseURL - this.config$.subscribe(cfg => { - this.syncToolUrl = cfg.localSThg.URL; - this.xdsAgentUrl = cfg.xdsAgent.URL; - this.xdsAgentRetry = String(cfg.xdsAgent.retry); - this.projectsRootDir = cfg.projectsRootDir; - this.xdsAgentPackages = cfg.xdsAgentPackages; - }); - - } - - submitGlobConf(field: string) { - switch (field) { - case "retry": - let re = new RegExp('^[0-9]+$'); - let rr = parseInt(this.xdsAgentRetry, 10); - if (re.test(this.xdsAgentRetry) && rr >= 0) { - this.configSvr.xdsAgentRetry = rr; - } else { - this.alert.warning("Not a valid number", true); - } - break; - case "rootDir": - this.configSvr.projectsRootDir = this.projectsRootDir; - break; - default: - return; - } - this.showApplyBtn[field] = false; - } - - xdsAgentRestartConn() { - let aUrl = this.xdsAgentUrl; - this.configSvr.syncToolURL = this.syncToolUrl; - this.configSvr.xdsAgentUrl = aUrl; - this.configSvr.loadProjects(); - } - -} diff --git a/webapp/src/app/config/downloadXdsAgent.component.ts b/webapp/src/app/config/downloadXdsAgent.component.ts deleted file mode 100644 index b35a17f..0000000 --- a/webapp/src/app/config/downloadXdsAgent.component.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { Component, Input, Pipe, PipeTransform } from '@angular/core'; - -import { IxdsAgentPackage } from "../services/config.service"; - -@Component({ - selector: 'dl-xds-agent', - /* XXX - cleanup - template: ` - <template #popTemplate> - <h3>Download xds-agent packages:</h3> - <ul> - <li *ngFor="let p of packageUrls"> - <a href="{{p.url}}">{{p.os | capitalize}} - {{p.arch}} ({{p.version}}) </a> - </li> - </ul> - <button type="button" class="btn btn-sm" (click)="pop.hide()"> Cancel </button> - </template> - <button type="button" class="btn btn-link fa fa-download fa-size-x2" - [popover]="popTemplate" - #pop="bs-popover" - placement="left"> - </button> - `, -*/ - template: ` - <template #popTemplate> - <h3>Install xds-agent:</h3> - <ul> - <li>On Linux machine <a href="{{url_OS_Linux}}" target="_blank"> - <span class="fa fa-external-link"></span></a></li> - - <li>On Windows machine <a href="{{url_OS_Other}}" target="_blank"><span class="fa fa-external-link"></span></a></li> - - <li>On MacOS machine <a href="{{url_OS_Other}}" target="_blank"><span class="fa fa-external-link"></span></a></li> - </ul> - <button type="button" class="btn btn-sm" (click)="pop.hide()"> Cancel </button> - </template> - <button type="button" class="btn btn-link fa fa-download fa-size-x2" - [popover]="popTemplate" - #pop="bs-popover" - placement="left"> - </button> - `, - styles: [` - .fa-size-x2 { - font-size: 20px; - } - `] -}) - -export class DlXdsAgentComponent { - - @Input() packageUrls: IxdsAgentPackage[]; - - public url_OS_Linux = "https://en.opensuse.org/LinuxAutomotive#Installation_AGL_XDS"; - public url_OS_Other = "https://github.com/iotbzh/xds-agent#how-to-install-on-other-platform"; -} - -@Pipe({ - name: 'capitalize' -}) -export class CapitalizePipe implements PipeTransform { - transform(value: string): string { - if (value) { - return value.charAt(0).toUpperCase() + value.slice(1); - } - return value; - } -} diff --git a/webapp/src/app/devel/build/build.component.css b/webapp/src/app/devel/build/build.component.css deleted file mode 100644 index 695a89b..0000000 --- a/webapp/src/app/devel/build/build.component.css +++ /dev/null @@ -1,54 +0,0 @@ -.vcenter { - display: inline-block; - vertical-align: middle; -} - -.blocks .btn-primary { - margin-left: 5px; - margin-right: 5px; - margin-top: 5px; - border-radius: 4px !important; -} - -.table-center { - width: 80%; - margin-left: auto; - margin-right: auto; -} - -.table-borderless>tbody>tr>td, -.table-borderless>tbody>tr>th, -.table-borderless>tfoot>tr>td, -.table-borderless>tfoot>tr>th, -.table-borderless>thead>tr>td, -.table-borderless>thead>tr>th { - border: none; -} - -.table-in-accordion>tbody>tr>th { - width: 30% -} - -.btn-large { - width: 10em; -} - -.fa-big { - font-size: 18px; - font-weight: bold; -} - -.textarea-scroll { - width: 100%; - overflow-y: scroll; -} - -h2 { - font-family: sans-serif; - font-variant: small-caps; - font-size: x-large; -} - -.panel-heading { - background: aliceblue; -} diff --git a/webapp/src/app/devel/build/build.component.html b/webapp/src/app/devel/build/build.component.html deleted file mode 100644 index 2bcd2c7..0000000 --- a/webapp/src/app/devel/build/build.component.html +++ /dev/null @@ -1,115 +0,0 @@ -<div class="panel panel-default"> - <div class="panel-heading"> - <h2 class="panel-title" (click)="buildIsCollapsed = !buildIsCollapsed"> - Build - <div class="pull-right"> - <button class="btn btn-link" (click)="buildIsCollapsed = !buildIsCollapsed; $event.stopPropagation()"> - <span class="fa fa-big" [ngClass]="{'fa-angle-double-down': buildIsCollapsed, 'fa-angle-double-right': !buildIsCollapsed}"></span> - </button> - </div> - </h2> - </div> - <div class="panel-body" [collapse]="buildIsCollapsed"> - <form [formGroup]="buildForm"> - <div class="col-xs-12"> - <table class="table table-borderless table-center"> - <tbody> - <tr> - <th>Cross SDK</th> - <td> - <!-- FIXME why not working ? - <sdk-select-dropdown [sdks]="(sdks$ | async)"></sdk-select-dropdown> - --> - <sdk-select-dropdown></sdk-select-dropdown> - </td> - </tr> - <tr> - <th>Project root path</th> - <td> <input type="text" disabled style="width:99%;" [value]="curProject && curProject.pathClient"></td> - </tr> - <tr> - <th>Sub-path</th> - <td> <input type="text" style="width:99%;" formControlName="subpath"> </td> - </tr> - <tr> - <td colspan="2"> - <accordion> - <accordion-group #group> - <div accordion-heading> - Advanced Settings - <i class="pull-right float-xs-right fa" [ngClass]="{'fa-chevron-down': group.isOpen, 'fa-chevron-right': !group.isOpen}"></i> - </div> - - <table class="table table-borderless table-in-accordion"> - <tbody> - <tr> - <th>Clean Command</th> - <td> <input type="text" style="width:99%;" formControlName="cmdClean"> </td> - </tr> - <tr> - <th>Pre-Build Command</th> - <td> <input type="text" style="width:99%;" formControlName="cmdPrebuild"> </td> - </tr> - <tr> - <th>Build Command</th> - <td> <input type="text" style="width:99%;" formControlName="cmdBuild"> </td> - </tr> - <tr> - <th>Populate Command</th> - <td> <input type="text" style="width:99%;" formControlName="cmdPopulate"> </td> - </tr> - <tr> - <th>Env variables</th> - <td> <input type="text" style="width:99%;" formControlName="envVars"> </td> - </tr> - <tr *ngIf="debugEnable"> - <th>Args variables</th> - <td> <input type="text" style="width:99%;" formControlName="cmdArgs"> </td> - </tr> - </tbody> - </table> - </accordion-group> - </accordion> - </td> - </tr> - </tbody> - </table> - </div> - <div class="row"> - <div class="col-xs-12 text-center"> - <div class="btn-group blocks"> - <button class="btn btn-primary btn-large" (click)="clean()" [disabled]="!curProject ">Clean</button> - <button class="btn btn-primary btn-large" (click)="preBuild()" [disabled]="!curProject">Pre-Build</button> - <button class="btn btn-primary btn-large" (click)="build()" [disabled]="!curProject">Build</button> - <button class="btn btn-primary btn-large" (click)="populate()" [disabled]="!curProject ">Populate</button> - <button *ngIf="debugEnable" class="btn btn-primary btn-large" (click)="execCmd()" [disabled]="!curProject ">Execute command</button> - <button *ngIf="debugEnable" class="btn btn-primary btn-large" (click)="make()" [disabled]="!curProject ">Make</button> - </div> - </div> - </div> - </form> - - <div style="margin-left: 2em; margin-right: 2em; "> - <div class="row "> - <div class="col-xs-10"> - <div class="row "> - <div class="col-xs-4"> - <label>Command Output</label> - </div> - <div class="col-xs-8" style="font-size:x-small; margin-top:5px;"> - {{ cmdInfo }} - </div> - </div> - </div> - <div class="col-xs-2"> - <button class="btn btn-link pull-right " (click)="reset() "><span class="fa fa-eraser fa-size-x2"></span></button> - </div> - </div> - <div class="row "> - <div class="col-xs-12 text-center "> - <textarea rows="20" class="textarea-scroll" #scrollOutput>{{ cmdOutput }}</textarea> - </div> - </div> - </div> - </div> -</div> diff --git a/webapp/src/app/devel/build/build.component.ts b/webapp/src/app/devel/build/build.component.ts deleted file mode 100644 index 48a5824..0000000 --- a/webapp/src/app/devel/build/build.component.ts +++ /dev/null @@ -1,223 +0,0 @@ -import { Component, AfterViewChecked, ElementRef, ViewChild, OnInit, Input } from '@angular/core'; -import { Observable } from 'rxjs'; -import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms'; -import { CookieService } from 'ngx-cookie'; - -import 'rxjs/add/operator/scan'; -import 'rxjs/add/operator/startWith'; - -import { XDSServerService, ICmdOutput } from "../../services/xdsserver.service"; -import { ConfigService, IConfig, IProject } from "../../services/config.service"; -import { AlertService, IAlert } from "../../services/alert.service"; -import { SdkService } from "../../services/sdk.service"; - -@Component({ - selector: 'panel-build', - moduleId: module.id, - templateUrl: './build.component.html', - styleUrls: ['./build.component.css'] -}) - -export class BuildComponent implements OnInit, AfterViewChecked { - @ViewChild('scrollOutput') private scrollContainer: ElementRef; - - @Input() curProject: IProject; - - public buildForm: FormGroup; - public subpathCtrl = new FormControl("", Validators.required); - public debugEnable: boolean = false; - public buildIsCollapsed: boolean = false; - public cmdOutput: string; - public cmdInfo: string; - - private startTime: Map<string, number> = new Map<string, number>(); - - constructor(private configSvr: ConfigService, - private xdsSvr: XDSServerService, - private fb: FormBuilder, - private alertSvr: AlertService, - private sdkSvr: SdkService, - private cookie: CookieService, - ) { - this.cmdOutput = ""; - this.cmdInfo = ""; // TODO: to be remove (only for debug) - this.buildForm = fb.group({ - subpath: this.subpathCtrl, - cmdClean: ["", Validators.nullValidator], - cmdPrebuild: ["", Validators.nullValidator], - cmdBuild: ["", Validators.nullValidator], - cmdPopulate: ["", Validators.nullValidator], - cmdArgs: ["", Validators.nullValidator], - envVars: ["", Validators.nullValidator], - }); - } - - ngOnInit() { - // Set default settings - // TODO save & restore values from cookies - this.buildForm.patchValue({ - subpath: "", - cmdClean: "rm -rf build", - cmdPrebuild: "mkdir -p build && cd build && cmake ..", - cmdBuild: "cd build && make", - cmdPopulate: "cd build && make remote-target-populate", - cmdArgs: "", - envVars: "", - }); - - // Command output data tunneling - this.xdsSvr.CmdOutput$.subscribe(data => { - this.cmdOutput += data.stdout; - this.cmdOutput += data.stderr; - }); - - // Command exit - this.xdsSvr.CmdExit$.subscribe(exit => { - if (this.startTime.has(exit.cmdID)) { - this.cmdInfo = 'Last command duration: ' + this._computeTime(this.startTime.get(exit.cmdID)); - this.startTime.delete(exit.cmdID); - } - - if (exit && exit.code !== 0) { - this.cmdOutput += "--- Command exited with code " + exit.code + " ---\n\n"; - } - }); - - this._scrollToBottom(); - - // only use for debug - this.debugEnable = (this.cookie.get("debug_build") === "1"); - } - - ngAfterViewChecked() { - this._scrollToBottom(); - } - - reset() { - this.cmdOutput = ''; - } - - clean() { - this._exec( - this.buildForm.value.cmdClean, - this.buildForm.value.subpath, - [], - this.buildForm.value.envVars); - } - - preBuild() { - this._exec( - this.buildForm.value.cmdPrebuild, - this.buildForm.value.subpath, - [], - this.buildForm.value.envVars); - } - - build() { - this._exec( - this.buildForm.value.cmdBuild, - this.buildForm.value.subpath, - [], - this.buildForm.value.envVars - ); - } - - populate() { - this._exec( - this.buildForm.value.cmdPopulate, - this.buildForm.value.subpath, - [], // args - this.buildForm.value.envVars - ); - } - - execCmd() { - this._exec( - this.buildForm.value.cmdArgs, - this.buildForm.value.subpath, - [], - this.buildForm.value.envVars - ); - } - - private _exec(cmd: string, dir: string, args: string[], env: string) { - if (!this.curProject) { - this.alertSvr.warning('No active project', true); - } - - let prjID = this.curProject.id; - - this.cmdOutput += this._outputHeader(); - - let sdkid = this.sdkSvr.getCurrentId(); - - // Detect key=value in env string to build array of string - let envArr = []; - env.split(';').forEach(v => envArr.push(v.trim())); - - let t0 = performance.now(); - this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0; - - this.xdsSvr.exec(prjID, dir, cmd, sdkid, args, envArr) - .subscribe(res => { - this.startTime.set(String(res.cmdID), t0); - }, - err => { - this.cmdInfo = 'Last command duration: ' + this._computeTime(t0); - this.alertSvr.error('ERROR: ' + err); - }); - } - - make(args: string) { - if (!this.curProject) { - this.alertSvr.warning('No active project', true); - } - - let prjID = this.curProject.id; - - this.cmdOutput += this._outputHeader(); - - let sdkid = this.sdkSvr.getCurrentId(); - - let argsArr = args ? args.split(' ') : this.buildForm.value.cmdArgs.split(' '); - - // Detect key=value in env string to build array of string - let envArr = []; - this.buildForm.value.envVars.split(';').forEach(v => envArr.push(v.trim())); - - let t0 = performance.now(); - this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0; - - this.xdsSvr.make(prjID, this.buildForm.value.subpath, sdkid, argsArr, envArr) - .subscribe(res => { - this.startTime.set(String(res.cmdID), t0); - }, - err => { - this.cmdInfo = 'Last command duration: ' + this._computeTime(t0); - this.alertSvr.error('ERROR: ' + err); - }); - } - - private _scrollToBottom(): void { - try { - this.scrollContainer.nativeElement.scrollTop = this.scrollContainer.nativeElement.scrollHeight; - } catch (err) { } - } - - private _computeTime(t0: number, t1?: number): string { - let enlap = Math.round((t1 || performance.now()) - t0); - if (enlap < 1000.0) { - return enlap.toFixed(2) + ' ms'; - } else { - return (enlap / 1000.0).toFixed(3) + ' seconds'; - } - } - - private _outputHeader(): string { - return "--- " + new Date().toString() + " ---\n"; - } - - private _outputFooter(): string { - return "\n"; - } -} diff --git a/webapp/src/app/devel/deploy/deploy.component.css b/webapp/src/app/devel/deploy/deploy.component.css deleted file mode 100644 index c1b39d8..0000000 --- a/webapp/src/app/devel/deploy/deploy.component.css +++ /dev/null @@ -1,45 +0,0 @@ -.vcenter { - display: inline-block; - vertical-align: middle; -} - -.blocks .btn-primary { - margin-left: 5px; - margin-right: 5px; - margin-top: 5px; - border-radius: 4px !important; -} - -.table-center { - width: 99%; - margin-left: auto; - margin-right: auto; -} - -.table-borderless>tbody>tr>td, -.table-borderless>tbody>tr>th, -.table-borderless>tfoot>tr>td, -.table-borderless>tfoot>tr>th, -.table-borderless>thead>tr>td, -.table-borderless>thead>tr>th { - border: none; -} - -.btn-large { - width: 10em; -} - -.fa-size-x2 { - font-size: 18px; -} - -.textarea-scroll { - width: 100%; - overflow-y: scroll; -} - -h2 { - font-family: sans-serif; - font-variant: small-caps; - font-size: x-large; -}
\ No newline at end of file diff --git a/webapp/src/app/devel/deploy/deploy.component.html b/webapp/src/app/devel/deploy/deploy.component.html deleted file mode 100644 index 7a15fa6..0000000 --- a/webapp/src/app/devel/deploy/deploy.component.html +++ /dev/null @@ -1,31 +0,0 @@ -<div class="panel panel-default"> - <div class="panel-heading"> - <h2 class="panel-title">Deployment</h2> - </div> - <div class="panel-body"> - <form [formGroup]="deployForm"> - <div class="col-xs-12"> - <table class="table table-borderless table-center"> - <tbody> - <tr> - <th>Board IP</th> - <td> <input type="text" style="width:99%;" formControlName="boardIP" placeholder="1.2.3.4"> </td> - </tr> - <tr> - <th>File to deploy</th> - <td> <input type="text" style="width:99%;" formControlName="wgtFile"> </td> - </tr> - </tbody> - </table> - </div> - <div class="row"> - <div class="col-xs-12 text-center"> - <div class="btn-group blocks"> - <button class="btn btn-primary btn-large" (click)="deploy()" [disabled]="!curProject ">Deploy</button> - </div> - </div> - </div> - </form> - - </div> -</div>
\ No newline at end of file diff --git a/webapp/src/app/devel/deploy/deploy.component.ts b/webapp/src/app/devel/deploy/deploy.component.ts deleted file mode 100644 index e51b7f2..0000000 --- a/webapp/src/app/devel/deploy/deploy.component.ts +++ /dev/null @@ -1,63 +0,0 @@ -import { Component, OnInit, Input } from "@angular/core"; -import { Observable } from 'rxjs'; -import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms'; - -import 'rxjs/add/operator/scan'; -import 'rxjs/add/operator/startWith'; - -import { XDSAgentService, IXDSDeploy } from "../../services/xdsagent.service"; -import { ConfigService, IConfig, IProject } from "../../services/config.service"; -import { AlertService, IAlert } from "../../services/alert.service"; -import { SdkService } from "../../services/sdk.service"; - -@Component({ - selector: 'panel-deploy', - moduleId: module.id, - templateUrl: './deploy.component.html', - styleUrls: ['./deploy.component.css'] -}) - -export class DeployComponent implements OnInit { - - @Input() curProject: IProject; - - deploying: boolean; - deployForm: FormGroup; - - constructor(private configSvr: ConfigService, - private xdsAgent: XDSAgentService, - private fb: FormBuilder, - private alert: AlertService, - ) { - this.deployForm = fb.group({ - boardIP: ["", Validators.nullValidator], - wgtFile: ["", Validators.nullValidator], - }); - } - - ngOnInit() { - this.deploying = false; - if (this.curProject && this.curProject.pathClient) { - this.deployForm.patchValue({ wgtFile: this.curProject.pathClient }); - } - } - - deploy() { - this.deploying = true; - - this.xdsAgent.deploy( - { - boardIP: this.deployForm.value.boardIP, - file: this.deployForm.value.wgtFile - } - ).subscribe(res => { - this.deploying = false; - }, err => { - this.deploying = false; - let msg = '<span>ERROR while deploying "' + this.deployForm.value.wgtFile + '"<br>'; - msg += err; - msg += '</span>'; - this.alert.error(msg); - }); - } -} diff --git a/webapp/src/app/devel/devel.component.css b/webapp/src/app/devel/devel.component.css deleted file mode 100644 index 4b03dcb..0000000 --- a/webapp/src/app/devel/devel.component.css +++ /dev/null @@ -1,19 +0,0 @@ -.table-center { - width: 60%; - margin-left: auto; - margin-right: auto; -} - -.table-borderless>tbody>tr>td, -.table-borderless>tbody>tr>th, -.table-borderless>tfoot>tr>td, -.table-borderless>tfoot>tr>th, -.table-borderless>thead>tr>td, -.table-borderless>thead>tr>th { - border: none; -} - -a.dropdown-item.disabled { - pointer-events:none; - opacity:0.4; -} diff --git a/webapp/src/app/devel/devel.component.html b/webapp/src/app/devel/devel.component.html deleted file mode 100644 index 8e71c58..0000000 --- a/webapp/src/app/devel/devel.component.html +++ /dev/null @@ -1,40 +0,0 @@ -<div class="row"> - <div class="col-md-8"> - <table class="table table-borderless table-center"> - <tbody> - <tr> - <th style="border: none;">Project</th> - <td> - <div class="btn-group" dropdown *ngIf="curPrj"> - <button dropdownToggle type="button" class="btn btn-primary dropdown-toggle" style="width: 20em;"> - {{curPrj.label}} - <span class="caret" style="float: right; margin-top: 8px;"></span> - </button> - <ul *dropdownMenu class="dropdown-menu" role="menu"> - <li role="menuitem"><a class="dropdown-item" *ngFor="let prj of (config$ | async)?.projects" [class.disabled]="!prj.isUsable" - (click)="curPrj=prj">{{prj.label}}</a> - </li> - - </ul> - </div> - <span *ngIf="!curPrj" style="color:red; font-style: italic;"> - No project detected, please create first a project using the configuration page. - </span> - </td> - </tr> - </tbody> - </table> - </div> -</div> - -<div class="row"> - <!--<div class="col-md-8">--> - <div class="col-md-12"> - <panel-build [curProject]=curPrj></panel-build> - </div> - <!-- TODO: disable for now - <div class="col-md-4"> - <panel-deploy [curProject]=curPrj></panel-deploy> - </div> - --> -</div> diff --git a/webapp/src/app/devel/devel.component.ts b/webapp/src/app/devel/devel.component.ts deleted file mode 100644 index f40f25f..0000000 --- a/webapp/src/app/devel/devel.component.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Component } from '@angular/core'; - -import { Observable } from 'rxjs'; - -import { ConfigService, IConfig, IProject } from "../services/config.service"; - -@Component({ - selector: 'devel', - moduleId: module.id, - templateUrl: './devel.component.html', - styleUrls: ['./devel.component.css'], -}) - -export class DevelComponent { - - curPrj: IProject; - config$: Observable<IConfig>; - - constructor(private configSvr: ConfigService) { - } - - ngOnInit() { - this.config$ = this.configSvr.conf; - this.config$.subscribe((cfg) => { - // Select project if no one is selected or no project exists - if (this.curPrj && "id" in this.curPrj) { - this.curPrj = cfg.projects.find(p => p.id === this.curPrj.id) || cfg.projects[0]; - } else if (this.curPrj == null && "projects" in cfg) { - this.curPrj = cfg.projects[0]; - } else { - this.curPrj = null; - } - }); - } -} diff --git a/webapp/src/app/home/home.component.ts b/webapp/src/app/home/home.component.ts deleted file mode 100644 index 0e3c995..0000000 --- a/webapp/src/app/home/home.component.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { Component, OnInit } from '@angular/core'; - -export interface ISlide { - img?: string; - imgAlt?: string; - hText?: string; - hHtml?: string; - text?: string; - html?: string; - btn?: string; - btnHref?: string; -} - -@Component({ - selector: 'home', - moduleId: module.id, - template: ` - <style> - .wide img { - width: 98%; - } - .carousel-item { - max-height: 90%; - } - h1, h2, h3, h4, p { - color: #330066; - } - .html-inner { - color: #330066; - } - h1 { - font-size: 4em; - } - p { - font-size: 2.5em; - } - - </style> - - <div class="wide"> - <carousel [interval]="carInterval" [(activeSlide)]="activeSlideIndex"> - <slide *ngFor="let sl of slides; let index=index"> - <img [src]="sl.img" [alt]="sl.imgAlt"> - <div class="carousel-caption"> - <h1 *ngIf="sl.hText">{{ sl.hText }}</h1> - <h1 *ngIf="sl.hHtml" class="html-inner" [innerHtml]="sl.hHtml"></h1> - <p *ngIf="sl.text">{{ sl.text }}</p> - <div *ngIf="sl.html" class="html-inner" [innerHtml]="sl.html"></div> - </div> - </slide> - </carousel> - </div> - ` -}) - -export class HomeComponent { - - public carInterval: number = 4000; - - // FIXME SEB - Add more slides and info - public slides: ISlide[] = [ - { - img: 'assets/images/iot-graphx.jpg', - imgAlt: "iot graphx image", - hText: "Welcome to XDS Dashboard !", - text: "X(cross) Development System allows developers to easily cross-compile applications.", - }, - { - img: 'assets/images/iot-graphx.jpg', - imgAlt: "iot graphx image", - hText: "Create, Build, Deploy, Enjoy !", - }, - { - img: 'assets/images/iot-graphx.jpg', - imgAlt: "iot graphx image", - hHtml: '<p>To Start: click on <i class="fa fa-cog" style="color:#9d9d9d;"></i> icon and add new folder</p>', - } - ]; - - constructor() { } -}
\ No newline at end of file diff --git a/webapp/src/app/main.ts b/webapp/src/app/main.ts deleted file mode 100644 index 1f68ccc..0000000 --- a/webapp/src/app/main.ts +++ /dev/null @@ -1,6 +0,0 @@ -import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; -import {AppModule} from './app.module'; - -const platform = platformBrowserDynamic(); - -platform.bootstrapModule(AppModule);
\ No newline at end of file diff --git a/webapp/src/app/projects/projectAddModal.component.css b/webapp/src/app/projects/projectAddModal.component.css deleted file mode 100644 index 77f73a5..0000000 --- a/webapp/src/app/projects/projectAddModal.component.css +++ /dev/null @@ -1,24 +0,0 @@ -.table-borderless>tbody>tr>td, -.table-borderless>tbody>tr>th, -.table-borderless>tfoot>tr>td, -.table-borderless>tfoot>tr>th, -.table-borderless>thead>tr>td, -.table-borderless>thead>tr>th { - border: none; -} - -tr>th { - vertical-align: middle; -} - -tr>td { - vertical-align: middle; -} - -th label { - margin-bottom: 0; -} - -td input { - width: 100%; -} diff --git a/webapp/src/app/projects/projectAddModal.component.html b/webapp/src/app/projects/projectAddModal.component.html deleted file mode 100644 index dc84985..0000000 --- a/webapp/src/app/projects/projectAddModal.component.html +++ /dev/null @@ -1,54 +0,0 @@ -<div bsModal #childProjectModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" - [config]="{backdrop: 'static'}" aria-hidden="true"> - <div class="modal-dialog modal-lg"> - <div class="modal-content"> - <div class="modal-header"> - <h4 class="modal-title pull-left">{{title}}</h4> - <button type="button" class="close pull-right" aria-label="Close" (click)="hide()"> - <span aria-hidden="true">×</span> - </button> - </div> - - <form [formGroup]="addProjectForm" (ngSubmit)="onSubmit()"> - <div class="modal-body"> - <div class="row "> - <div class="col-xs-12"> - <table class="table table-borderless"> - <tbody> - <tr> - <th><label>Sharing Type </label></th> - <td><select class="form-control" formControlName="type"> - <option *ngFor="let t of projectTypes" [value]="t.value">{{t.display}} - </option> - </select> - </td> - </tr> - <tr> - <th><label for="select-local-path">Local Path </label></th> - <td><input type="text" id="select-local-path" formControlName="pathCli" placeholder="/tmp/myProject" (change)="onChangeLocalProject($event)"></td> - </tr> - <tr> - <th><label for="select-server-path">Server Path </label></th> - <td><input type="text" id="select-server-path" formControlName="pathSvr"></td> - </tr> - <tr> - <th><label for="select-label">Label </label></th> - <td><input type="text" formControlName="label" id="select-label" (keyup)="onKeyLabel($event)"></td> - </tr> - </tbody> - </table> - </div> - </div> - </div> - <div class="modal-footer"> - <div class="pull-left"> - <button class="btn btn-default" (click)="cancelAction=true; hide()"> Cancel </button> - </div> - <div class=""> - <button class="btn btn-primary" type="submit" [disabled]="!addProjectForm.valid">Add Folder</button> - </div> - </div> - </form> - </div> - </div> -</div> diff --git a/webapp/src/app/projects/projectAddModal.component.ts b/webapp/src/app/projects/projectAddModal.component.ts deleted file mode 100644 index 7ef5b5e..0000000 --- a/webapp/src/app/projects/projectAddModal.component.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { Component, Input, ViewChild, OnInit } from '@angular/core'; -import { Observable } from 'rxjs/Observable'; -import { ModalDirective } from 'ngx-bootstrap/modal'; -import { FormControl, FormGroup, Validators, FormBuilder, ValidatorFn, AbstractControl } from '@angular/forms'; - -// Import RxJs required methods -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/filter'; -import 'rxjs/add/operator/debounceTime'; - -import { AlertService, IAlert } from "../services/alert.service"; -import { - ConfigService, IConfig, IProject, ProjectType, ProjectTypes, - IxdsAgentPackage -} from "../services/config.service"; - - -@Component({ - selector: 'project-add-modal', - templateUrl: './app/projects/projectAddModal.component.html', - styleUrls: ['./app/projects/projectAddModal.component.css'] -}) -export class ProjectAddModalComponent { - @ViewChild('childProjectModal') public childProjectModal: ModalDirective; - @Input() title?: string; - - config$: Observable<IConfig>; - - cancelAction: boolean = false; - userEditedLabel: boolean = false; - projectTypes = ProjectTypes; - - addProjectForm: FormGroup; - typeCtrl: FormControl; - pathCliCtrl: FormControl; - pathSvrCtrl: FormControl; - - constructor( - private alert: AlertService, - private configSvr: ConfigService, - private fb: FormBuilder - ) { - // Define types (first one is special/placeholder) - this.projectTypes.unshift({ value: -1, display: "--Select a type--" }); - - this.typeCtrl = new FormControl(this.projectTypes[0].value, Validators.pattern("[0-9]+")); - this.pathCliCtrl = new FormControl("", Validators.required); - this.pathSvrCtrl = new FormControl({ value: "", disabled: true }, [Validators.required, Validators.minLength(1)]); - - this.addProjectForm = fb.group({ - type: this.typeCtrl, - pathCli: this.pathCliCtrl, - pathSvr: this.pathSvrCtrl, - label: ["", Validators.nullValidator], - }); - } - - ngOnInit() { - this.config$ = this.configSvr.conf; - - // Auto create label name - this.pathCliCtrl.valueChanges - .debounceTime(100) - .filter(n => n) - .map(n => { - let last = n.split('/'); - let nm = n; - if (last.length > 0) { - nm = last.pop(); - if (nm === "" && last.length > 0) { - nm = last.pop(); - } - } - return "Project_" + nm; - }) - .subscribe(value => { - if (value && !this.userEditedLabel) { - this.addProjectForm.patchValue({ label: value }); - } - }); - - // Handle disabling of Server path - this.typeCtrl.valueChanges - .debounceTime(500) - .subscribe(valType => { - let dis = (valType === String(ProjectType.SYNCTHING)); - this.pathSvrCtrl.reset({ value: "", disabled: dis }); - }); - } - - show() { - this.cancelAction = false; - this.childProjectModal.show(); - } - - hide() { - this.childProjectModal.hide(); - } - - onKeyLabel(event: any) { - this.userEditedLabel = (this.addProjectForm.value.label !== ""); - } - - /* FIXME: change input to file type - <td><input type="file" id="select-local-path" webkitdirectory - formControlName="pathCli" placeholder="myProject" (change)="onChangeLocalProject($event)"></td> - - onChangeLocalProject(e) { - if e.target.files.length < 1 { - console.log('NO files'); - } - let dir = e.target.files[0].webkitRelativePath; - console.log("files: " + dir); - let u = URL.createObjectURL(e.target.files[0]); - } - */ - onChangeLocalProject(e) { - } - - onSubmit() { - if (this.cancelAction) { - return; - } - - let formVal = this.addProjectForm.value; - - let type = formVal['type'].value; - let numType = Number(formVal['type']); - this.configSvr.addProject({ - label: formVal['label'], - pathClient: formVal['pathCli'], - pathServer: formVal['pathSvr'], - type: numType, - // FIXME: allow to set defaultSdkID from New Project config panel - }) - .subscribe(prj => { - this.alert.info("Project " + prj.label + " successfully created."); - this.hide(); - - // Reset Value for the next creation - this.addProjectForm.reset(); - let selectedType = this.projectTypes[0].value; - this.addProjectForm.patchValue({ type: selectedType }); - - }, - err => { - this.alert.error("Configuration ERROR: " + err, 60); - this.hide(); - }); - } - -} diff --git a/webapp/src/app/projects/projectCard.component.ts b/webapp/src/app/projects/projectCard.component.ts deleted file mode 100644 index a7ca9a3..0000000 --- a/webapp/src/app/projects/projectCard.component.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { Component, Input, Pipe, PipeTransform } from '@angular/core'; -import { ConfigService, IProject, ProjectType } from "../services/config.service"; -import { AlertService } from "../services/alert.service"; - -@Component({ - selector: 'project-card', - template: ` - <div class="row"> - <div class="col-xs-12"> - <div class="text-right" role="group"> - <button class="btn btn-link" (click)="delete(project)"> - <span class="fa fa-trash fa-size-x2"></span> - </button> - </div> - </div> - </div> - - <table class="table table-striped"> - <tbody> - <tr> - <th><span class="fa fa-fw fa-id-badge"></span> <span>Project ID</span></th> - <td>{{ project.id }}</td> - </tr> - <tr> - <th><span class="fa fa-fw fa-exchange"></span> <span>Sharing type</span></th> - <td>{{ project.type | readableType }}</td> - </tr> - <tr> - <th><span class="fa fa-fw fa-folder-open-o"></span> <span>Local path</span></th> - <td>{{ project.pathClient }}</td> - </tr> - <tr *ngIf="project.pathServer && project.pathServer != ''"> - <th><span class="fa fa-fw fa-folder-open-o"></span> <span>Server path</span></th> - <td>{{ project.pathServer }}</td> - </tr> - <tr> - <th><span class="fa fa-fw fa-flag"></span> <span>Status</span></th> - <td>{{ project.status }} - {{ project.isInSync ? "Up to Date" : "Out of Sync"}} - <button *ngIf="!project.isInSync" class="btn btn-link" (click)="sync(project)"> - <span class="fa fa-refresh fa-size-x2"></span> - </button> - </td> - </tr> - </tbody> - </table > - `, - styleUrls: ['./app/config/config.component.css'] -}) - -export class ProjectCardComponent { - - @Input() project: IProject; - - constructor( - private alert: AlertService, - private configSvr: ConfigService - ) { - } - - delete(prj: IProject) { - this.configSvr.deleteProject(prj) - .subscribe(res => { - }, err => { - this.alert.error("Delete local ERROR: " + err); - }); - } - - sync(prj: IProject) { - this.configSvr.syncProject(prj) - .subscribe(res => { - }, err => { - this.alert.error("ERROR: " + err); - }); - } - -} - -// Remove APPS. prefix if translate has failed -@Pipe({ - name: 'readableType' -}) - -export class ProjectReadableTypePipe implements PipeTransform { - transform(type: ProjectType): string { - switch (type) { - case ProjectType.NATIVE_PATHMAP: return "Native (path mapping)"; - case ProjectType.SYNCTHING: return "Cloud (Syncthing)"; - default: return String(type); - } - } -} diff --git a/webapp/src/app/projects/projectsListAccordion.component.ts b/webapp/src/app/projects/projectsListAccordion.component.ts deleted file mode 100644 index 6e697f4..0000000 --- a/webapp/src/app/projects/projectsListAccordion.component.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { Component, Input } from "@angular/core"; - -import { IProject } from "../services/config.service"; - -@Component({ - selector: 'projects-list-accordion', - template: ` - <style> - .fa.fa-exclamation-triangle { - margin-right: 2em; - color: red; - } - .fa.fa-refresh { - margin-right: 10px; - color: darkviolet; - } - </style> - <accordion> - <accordion-group #group *ngFor="let prj of projects"> - <div accordion-heading> - {{ prj.label }} - <div class="pull-right"> - <i *ngIf="prj.status == 'Syncing'" class="fa fa-refresh faa-spin animated"></i> - <i *ngIf="!prj.isInSync && prj.status != 'Syncing'" class="fa fa-exclamation-triangle"></i> - <i class="fa" [ngClass]="{'fa-chevron-down': group.isOpen, 'fa-chevron-right': !group.isOpen}"></i> - </div> - </div> - <project-card [project]="prj"></project-card> - </accordion-group> - </accordion> - ` -}) -export class ProjectsListAccordionComponent { - - @Input() projects: IProject[]; - -} - - diff --git a/webapp/src/app/sdks/sdkAddModal.component.html b/webapp/src/app/sdks/sdkAddModal.component.html deleted file mode 100644 index 2c07fca..0000000 --- a/webapp/src/app/sdks/sdkAddModal.component.html +++ /dev/null @@ -1,23 +0,0 @@ -<div bsModal #sdkChildModal="bs-modal" class="modal fade" tabindex="-1" role="dialog" aria-labelledby="mySmallModalLabel" - aria-hidden="true"> - <div class="modal-dialog modal-lg"> - <div class="modal-content"> - <div class="modal-header"> - <h4 class="modal-title pull-left">{{title}}</h4> - <button type="button" class="close pull-right" aria-label="Close" (click)="hideChildModal()"> - <span aria-hidden="true">×</span> - </button> - </div> - <div class="modal-body"> - <ng-content select=".modal-body"> </ng-content> - <i>Not available for now.</i> - </div> - - <div class="modal-footer"> - <div class="pull-left"> - <button class="btn btn-default" (click)="hide()"> Cancel </button> - </div> - </div> - </div> - </div> -</div> diff --git a/webapp/src/app/sdks/sdkAddModal.component.ts b/webapp/src/app/sdks/sdkAddModal.component.ts deleted file mode 100644 index b6c8eb2..0000000 --- a/webapp/src/app/sdks/sdkAddModal.component.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { Component, Input, ViewChild } from '@angular/core'; -import { ModalDirective } from 'ngx-bootstrap/modal'; - -@Component({ - selector: 'sdk-add-modal', - templateUrl: './app/sdks/sdkAddModal.component.html', -}) -export class SdkAddModalComponent { - @ViewChild('sdkChildModal') public sdkChildModal: ModalDirective; - - @Input() title?: string; - - // TODO - constructor() { - } - - show() { - this.sdkChildModal.show(); - } - - hide() { - this.sdkChildModal.hide(); - } -} diff --git a/webapp/src/app/sdks/sdkCard.component.ts b/webapp/src/app/sdks/sdkCard.component.ts deleted file mode 100644 index 579d224..0000000 --- a/webapp/src/app/sdks/sdkCard.component.ts +++ /dev/null @@ -1,51 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { ISdk } from "../services/sdk.service"; - -@Component({ - selector: 'sdk-card', - template: ` - <div class="row"> - <div class="col-xs-12"> - <div class="text-right" role="group"> - <button disabled class="btn btn-link" (click)="delete(sdk)"><span class="fa fa-trash fa-size-x2"></span></button> - </div> - </div> - </div> - - <table class="table table-striped"> - <tbody> - <tr> - <th><span class="fa fa-fw fa-id-badge"></span> <span>Profile</span></th> - <td>{{ sdk.profile }}</td> - </tr> - <tr> - <th><span class="fa fa-fw fa-tasks"></span> <span>Architecture</span></th> - <td>{{ sdk.arch }}</td> - </tr> - <tr> - <th><span class="fa fa-fw fa-code-fork"></span> <span>Version</span></th> - <td>{{ sdk.version }}</td> - </tr> - <tr> - <th><span class="fa fa-fw fa-folder-open-o"></span> <span>Sdk path</span></th> - <td>{{ sdk.path}}</td> - </tr> - - </tbody> - </table > - `, - styleUrls: ['./app/config/config.component.css'] -}) - -export class SdkCardComponent { - - @Input() sdk: ISdk; - - constructor() { } - - - delete(sdk: ISdk) { - // Not supported for now - } - -} diff --git a/webapp/src/app/sdks/sdkSelectDropdown.component.ts b/webapp/src/app/sdks/sdkSelectDropdown.component.ts deleted file mode 100644 index a2fe37a..0000000 --- a/webapp/src/app/sdks/sdkSelectDropdown.component.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { Component, Input } from "@angular/core"; - -import { ISdk, SdkService } from "../services/sdk.service"; - -@Component({ - selector: 'sdk-select-dropdown', - template: ` - <div class="btn-group" dropdown *ngIf="curSdk" > - <button dropdownToggle type="button" class="btn btn-primary dropdown-toggle" style="width: 20em;"> - {{curSdk.name}} <span class="caret" style="float: right; margin-top: 8px;"></span> - </button> - <ul *dropdownMenu class="dropdown-menu" role="menu"> - <li role="menuitem"><a class="dropdown-item" *ngFor="let sdk of sdks" (click)="select(sdk)"> - {{sdk.name}}</a> - </li> - </ul> - </div> - ` -}) -export class SdkSelectDropdownComponent { - - // FIXME investigate to understand why not working with sdks as input - // <sdk-select-dropdown [sdks]="(sdks$ | async)"></sdk-select-dropdown> - //@Input() sdks: ISdk[]; - sdks: ISdk[]; - - curSdk: ISdk; - - constructor(private sdkSvr: SdkService) { } - - ngOnInit() { - this.curSdk = this.sdkSvr.getCurrent(); - this.sdkSvr.Sdks$.subscribe((s) => { - if (s) { - this.sdks = s; - if (this.curSdk === null || s.indexOf(this.curSdk) === -1) { - this.sdkSvr.setCurrent(this.curSdk = s.length ? s[0] : null); - } - } - }); - } - - select(s) { - this.sdkSvr.setCurrent(this.curSdk = s); - } -} - - diff --git a/webapp/src/app/sdks/sdksListAccordion.component.ts b/webapp/src/app/sdks/sdksListAccordion.component.ts deleted file mode 100644 index 9d5f7e9..0000000 --- a/webapp/src/app/sdks/sdksListAccordion.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Component, Input } from "@angular/core"; - -import { ISdk } from "../services/sdk.service"; - -@Component({ - selector: 'sdks-list-accordion', - template: ` - <accordion> - <accordion-group #group *ngFor="let sdk of sdks"> - <div accordion-heading> - {{ sdk.name }} - <i class="pull-right float-xs-right fa" - [ngClass]="{'fa-chevron-down': group.isOpen, 'fa-chevron-right': !group.isOpen}"></i> - </div> - <sdk-card [sdk]="sdk"></sdk-card> - </accordion-group> - </accordion> - ` -}) -export class SdksListAccordionComponent { - - @Input() sdks: ISdk[]; - -} - - diff --git a/webapp/src/app/services/alert.service.ts b/webapp/src/app/services/alert.service.ts deleted file mode 100644 index c3cae7a..0000000 --- a/webapp/src/app/services/alert.service.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { Injectable, SecurityContext } from '@angular/core'; -import { DomSanitizer } from '@angular/platform-browser'; -import { Observable } from 'rxjs/Observable'; -import { Subject } from 'rxjs/Subject'; - - -export type AlertType = "danger" | "warning" | "info" | "success"; - -export interface IAlert { - type: AlertType; - msg: string; - show?: boolean; - dismissible?: boolean; - dismissTimeout?: number; // close alert after this time (in seconds) - id?: number; -} - -@Injectable() -export class AlertService { - public alerts: Observable<IAlert[]>; - - private _alerts: IAlert[]; - private alertsSubject = <Subject<IAlert[]>>new Subject(); - private uid = 0; - private defaultDissmissTmo = 5; // in seconds - - constructor(private sanitizer: DomSanitizer) { - this.alerts = this.alertsSubject.asObservable(); - this._alerts = []; - this.uid = 0; - } - - public error(msg: string, dismissTime?: number) { - this.add({ - type: "danger", msg: msg, dismissible: true, dismissTimeout: dismissTime - }); - } - - public warning(msg: string, dismissible?: boolean) { - this.add({ type: "warning", msg: msg, dismissible: true, dismissTimeout: (dismissible ? this.defaultDissmissTmo : 0) }); - } - - public info(msg: string) { - this.add({ type: "info", msg: msg, dismissible: true, dismissTimeout: this.defaultDissmissTmo }); - } - - public add(al: IAlert) { - this._alerts.push({ - show: true, - type: al.type, - msg: this.sanitizer.sanitize(SecurityContext.HTML, al.msg), - dismissible: al.dismissible || true, - dismissTimeout: (al.dismissTimeout * 1000) || 0, - id: this.uid, - }); - this.uid += 1; - this.alertsSubject.next(this._alerts); - } - - public del(al: IAlert) { - let idx = this._alerts.findIndex((a) => a.id === al.id); - if (idx > -1) { - this._alerts.splice(idx, 1); - } - } -} diff --git a/webapp/src/app/services/config.service.ts b/webapp/src/app/services/config.service.ts deleted file mode 100644 index 6cab73c..0000000 --- a/webapp/src/app/services/config.service.ts +++ /dev/null @@ -1,422 +0,0 @@ -import { Injectable, OnInit } from '@angular/core'; -import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http'; -import { Location } from '@angular/common'; -import { CookieService } from 'ngx-cookie'; -import { Observable } from 'rxjs/Observable'; -import { Subscriber } from 'rxjs/Subscriber'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; - -// Import RxJs required methods -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/observable/throw'; -import 'rxjs/add/operator/mergeMap'; - - -import { XDSServerService, IXDSFolderConfig } from "../services/xdsserver.service"; -import { XDSAgentService } from "../services/xdsagent.service"; -import { SyncthingService, ISyncThingProject, ISyncThingStatus } from "../services/syncthing.service"; -import { AlertService, IAlert } from "../services/alert.service"; -import { UtilsService } from "../services/utils.service"; - -export enum ProjectType { - NATIVE_PATHMAP = 1, - SYNCTHING = 2 -} - -export var ProjectTypes = [ - { value: ProjectType.NATIVE_PATHMAP, display: "Path mapping" }, - { value: ProjectType.SYNCTHING, display: "Cloud Sync" } -]; - -export var ProjectStatus = { - ErrorConfig: "ErrorConfig", - Disable: "Disable", - Enable: "Enable", - Pause: "Pause", - Syncing: "Syncing" -}; - -export interface IProject { - id?: string; - label: string; - pathClient: string; - pathServer?: string; - type: ProjectType; - status?: string; - isInSync?: boolean; - isUsable?: boolean; - serverPrjDef?: IXDSFolderConfig; - isExpanded?: boolean; - visible?: boolean; - defaultSdkID?: string; -} - -export interface IXDSAgentConfig { - URL: string; - retry: number; -} - -export interface ILocalSTConfig { - ID: string; - URL: string; - retry: number; - tilde: string; -} - -export interface IxdsAgentPackage { - os: string; - arch: string; - version: string; - url: string; -} - -export interface IConfig { - xdsServerURL: string; - xdsAgent: IXDSAgentConfig; - xdsAgentPackages: IxdsAgentPackage[]; - projectsRootDir: string; - projects: IProject[]; - localSThg: ILocalSTConfig; -} - -@Injectable() -export class ConfigService { - - public conf: Observable<IConfig>; - - private confSubject: BehaviorSubject<IConfig>; - private confStore: IConfig; - private AgentConnectObs = null; - private stConnectObs = null; - - constructor(private _window: Window, - private cookie: CookieService, - private xdsServerSvr: XDSServerService, - private xdsAgentSvr: XDSAgentService, - private stSvr: SyncthingService, - private alert: AlertService, - private utils: UtilsService, - ) { - this.load(); - this.confSubject = <BehaviorSubject<IConfig>>new BehaviorSubject(this.confStore); - this.conf = this.confSubject.asObservable(); - - // force to load projects - this.loadProjects(); - } - - // Load config - load() { - // Try to retrieve previous config from cookie - let cookConf = this.cookie.getObject("xds-config"); - if (cookConf != null) { - this.confStore = <IConfig>cookConf; - } else { - // Set default config - this.confStore = { - xdsServerURL: this._window.location.origin + '/api/v1', - xdsAgent: { - URL: 'http://localhost:8010', - retry: 10, - }, - xdsAgentPackages: [], - projectsRootDir: "", - projects: [], - localSThg: { - ID: null, - URL: "http://localhost:8386", - retry: 10, // 10 seconds - tilde: "", - } - }; - } - - // Update XDS Agent tarball url - this.xdsServerSvr.getXdsAgentInfo().subscribe(nfo => { - this.confStore.xdsAgentPackages = []; - nfo.tarballs && nfo.tarballs.forEach(el => - this.confStore.xdsAgentPackages.push({ - os: el.os, - arch: el.arch, - version: el.version, - url: el.fileUrl - }) - ); - this.confSubject.next(Object.assign({}, this.confStore)); - }); - - // Update Project data - this.xdsServerSvr.FolderStateChange$.subscribe(prj => { - let i = this._getProjectIdx(prj.id); - if (i >= 0) { - // XXX for now, only isInSync and status may change - this.confStore.projects[i].isInSync = prj.isInSync; - this.confStore.projects[i].status = prj.status; - this.confStore.projects[i].isUsable = this._isUsableProject(prj); - this.confSubject.next(Object.assign({}, this.confStore)); - } - }); - } - - // Save config into cookie - save() { - // Notify subscribers - this.confSubject.next(Object.assign({}, this.confStore)); - - // Don't save projects in cookies (too big!) - let cfg = Object.assign({}, this.confStore); - delete (cfg.projects); - this.cookie.putObject("xds-config", cfg); - } - - loadProjects() { - // Setup connection with local XDS agent - if (this.AgentConnectObs) { - try { - this.AgentConnectObs.unsubscribe(); - } catch (err) { } - this.AgentConnectObs = null; - } - - let cfg = this.confStore.xdsAgent; - this.AgentConnectObs = this.xdsAgentSvr.connect(cfg.retry, cfg.URL) - .subscribe((sts) => { - //console.log("Agent sts", sts); - // FIXME: load projects from local XDS Agent and - // not directly from local syncthing - this._loadProjectFromLocalST(); - - }, error => { - if (error.indexOf("XDS local Agent not responding") !== -1) { - let rootUrl = "http://docs.automotivelinux.org/docs/devguides/en/dev/reference/"; - let url_OS_Linux = rootUrl + "xds/part-1/1_install-client.html#install-packages-for-debian-distro-type"; - let url_OS_Other = rootUrl + "xds/part-1/1_install-client.html#install-for-other-platforms-windows--macos"; - let msg = `<span><strong>` + error + `<br></strong> - You may need to install and execute XDS-Agent: <br> - On Linux machine <a href="` + url_OS_Linux + `" target="_blank"><span - class="fa fa-external-link"></span></a> - <br> - On Windows machine <a href="` + url_OS_Other + `" target="_blank"><span - class="fa fa-external-link"></span></a> - <br> - On MacOS machine <a href="` + url_OS_Other + `" target="_blank"><span - class="fa fa-external-link"></span></a> - `; - this.alert.error(msg); - } else { - this.alert.error(error); - } - }); - } - - private _loadProjectFromLocalST() { - // Remove previous subscriber if existing - if (this.stConnectObs) { - try { - this.stConnectObs.unsubscribe(); - } catch (err) { } - this.stConnectObs = null; - } - - // FIXME: move this code and all logic about syncthing inside XDS Agent - // Setup connection with local SyncThing - let retry = this.confStore.localSThg.retry; - let url = this.confStore.localSThg.URL; - this.stConnectObs = this.stSvr.connect(retry, url).subscribe((sts) => { - this.confStore.localSThg.ID = sts.ID; - this.confStore.localSThg.tilde = sts.tilde; - if (this.confStore.projectsRootDir === "") { - this.confStore.projectsRootDir = sts.tilde; - } - - // Rebuild projects definition from local and remote syncthing - this.confStore.projects = []; - - this.xdsServerSvr.getProjects().subscribe(remotePrj => { - this.stSvr.getProjects().subscribe(localPrj => { - remotePrj.forEach(rPrj => { - let lPrj = localPrj.filter(item => item.id === rPrj.id); - if (lPrj.length > 0 || rPrj.type === ProjectType.NATIVE_PATHMAP) { - this._addProject(rPrj, true); - } - }); - this.confSubject.next(Object.assign({}, this.confStore)); - }), error => this.alert.error('Could not load initial state of local projects.'); - }), error => this.alert.error('Could not load initial state of remote projects.'); - - }, error => { - if (error.indexOf("Syncthing local daemon not responding") !== -1) { - let msg = "<span><strong>" + error + "<br></strong>"; - msg += "Please check that local XDS-Agent is running.<br>"; - msg += "</span>"; - this.alert.error(msg); - } else { - this.alert.error(error); - } - }); - } - - set syncToolURL(url: string) { - this.confStore.localSThg.URL = url; - this.save(); - } - - set xdsAgentRetry(r: number) { - this.confStore.localSThg.retry = r; - this.confStore.xdsAgent.retry = r; - this.save(); - } - - set xdsAgentUrl(url: string) { - this.confStore.xdsAgent.URL = url; - this.save(); - } - - - set projectsRootDir(p: string) { - if (p.charAt(0) === '~') { - p = this.confStore.localSThg.tilde + p.substring(1); - } - this.confStore.projectsRootDir = p; - this.save(); - } - - getLabelRootName(): string { - let id = this.confStore.localSThg.ID; - if (!id || id === "") { - return null; - } - return id.slice(0, 15); - } - - addProject(prj: IProject): Observable<IProject> { - // Substitute tilde with to user home path - let pathCli = prj.pathClient.trim(); - if (pathCli.charAt(0) === '~') { - pathCli = this.confStore.localSThg.tilde + pathCli.substring(1); - - // Must be a full path (on Linux or Windows) - } else if (!((pathCli.charAt(0) === '/') || - (pathCli.charAt(1) === ':' && (pathCli.charAt(2) === '\\' || pathCli.charAt(2) === '/')))) { - pathCli = this.confStore.projectsRootDir + '/' + pathCli; - } - - let xdsPrj: IXDSFolderConfig = { - id: "", - label: prj.label || "", - path: pathCli, - type: prj.type, - defaultSdkID: prj.defaultSdkID, - dataPathMap: { - serverPath: prj.pathServer, - }, - dataCloudSync: { - syncThingID: this.confStore.localSThg.ID, - } - }; - // Send config to XDS server - let newPrj = prj; - return this.xdsServerSvr.addProject(xdsPrj) - .flatMap(resStRemotePrj => { - xdsPrj = resStRemotePrj; - if (xdsPrj.type === ProjectType.SYNCTHING) { - // FIXME REWORK local ST config - // move logic to server side tunneling-back by WS - let stData = xdsPrj.dataCloudSync; - - // Now setup local config - let stLocPrj: ISyncThingProject = { - id: xdsPrj.id, - label: xdsPrj.label, - path: xdsPrj.path, - serverSyncThingID: stData.builderSThgID - }; - - // Set local Syncthing config - return this.stSvr.addProject(stLocPrj); - - } else { - return Observable.of(null); - } - }) - .map(resStLocalPrj => { - this._addProject(xdsPrj); - return newPrj; - }); - } - - deleteProject(prj: IProject): Observable<IProject> { - let idx = this._getProjectIdx(prj.id); - let delPrj = prj; - if (idx === -1) { - throw new Error("Invalid project id (id=" + prj.id + ")"); - } - return this.xdsServerSvr.deleteProject(prj.id) - .flatMap(res => { - if (prj.type === ProjectType.SYNCTHING) { - return this.stSvr.deleteProject(prj.id); - } - return Observable.of(null); - }) - .map(res => { - this.confStore.projects.splice(idx, 1); - return delPrj; - }); - } - - syncProject(prj: IProject): Observable<string> { - let idx = this._getProjectIdx(prj.id); - if (idx === -1) { - throw new Error("Invalid project id (id=" + prj.id + ")"); - } - return this.xdsServerSvr.syncProject(prj.id); - } - - private _isUsableProject(p) { - return p && p.isInSync && - (p.status === ProjectStatus.Enable) && - (p.status !== ProjectStatus.Syncing); - } - - private _getProjectIdx(id: string): number { - return this.confStore.projects.findIndex((item) => item.id === id); - } - - private _addProject(rPrj: IXDSFolderConfig, noNext?: boolean) { - - // Convert XDSFolderConfig to IProject - let pp: IProject = { - id: rPrj.id, - label: rPrj.label, - pathClient: rPrj.path, - pathServer: rPrj.dataPathMap.serverPath, - type: rPrj.type, - status: rPrj.status, - isInSync: rPrj.isInSync, - isUsable: this._isUsableProject(rPrj), - defaultSdkID: rPrj.defaultSdkID, - serverPrjDef: Object.assign({}, rPrj), // do a copy - }; - - // add new project - this.confStore.projects.push(pp); - - // sort project array - this.confStore.projects.sort((a, b) => { - if (a.label < b.label) { - return -1; - } - if (a.label > b.label) { - return 1; - } - return 0; - }); - - // FIXME: maybe reduce subject to only .project - //this.confSubject.next(Object.assign({}, this.confStore).project); - if (!noNext) { - this.confSubject.next(Object.assign({}, this.confStore)); - } - } -} diff --git a/webapp/src/app/services/sdk.service.ts b/webapp/src/app/services/sdk.service.ts deleted file mode 100644 index fa4cd55..0000000 --- a/webapp/src/app/services/sdk.service.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { Injectable, SecurityContext } from '@angular/core'; -import { Observable } from 'rxjs/Observable'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; - -import { XDSServerService } from "../services/xdsserver.service"; - -export interface ISdk { - id: string; - profile: string; - version: string; - arch: number; - path: string; -} - -@Injectable() -export class SdkService { - public Sdks$: Observable<ISdk[]>; - - private _sdksList = []; - private current: ISdk; - private sdksSubject = <BehaviorSubject<ISdk[]>>new BehaviorSubject(this._sdksList); - - constructor(private xdsSvr: XDSServerService) { - this.current = null; - this.Sdks$ = this.sdksSubject.asObservable(); - - this.xdsSvr.getSdks().subscribe((s) => { - this._sdksList = s; - this.sdksSubject.next(s); - }); - } - - public setCurrent(s: ISdk) { - this.current = s; - } - - public getCurrent(): ISdk { - return this.current; - } - - public getCurrentId(): string { - if (this.current && this.current.id) { - return this.current.id; - } - return ""; - } -}
\ No newline at end of file diff --git a/webapp/src/app/services/syncthing.service.ts b/webapp/src/app/services/syncthing.service.ts deleted file mode 100644 index 2e6da1c..0000000 --- a/webapp/src/app/services/syncthing.service.ts +++ /dev/null @@ -1,348 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http'; -import { CookieService } from 'ngx-cookie'; -import { Location } from '@angular/common'; -import { Observable } from 'rxjs/Observable'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; - -// Import RxJs required methods -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/observable/throw'; -import 'rxjs/add/observable/of'; -import 'rxjs/add/observable/timer'; -import 'rxjs/add/operator/retryWhen'; - -export interface ISyncThingProject { - id: string; - path: string; - serverSyncThingID: string; - label?: string; -} - -export interface ISyncThingStatus { - ID: string; - baseURL: string; - connected: boolean; - connectionRetry: number; - tilde: string; - rawStatus: any; -} - -// Private interfaces of Syncthing -const ISTCONFIG_VERSION = 20; - -interface ISTFolderDeviceConfiguration { - deviceID: string; - introducedBy: string; -} -interface ISTFolderConfiguration { - id: string; - label: string; - path: string; - type?: number; - devices?: ISTFolderDeviceConfiguration[]; - rescanIntervalS?: number; - ignorePerms?: boolean; - autoNormalize?: boolean; - minDiskFreePct?: number; - versioning?: { type: string; params: string[] }; - copiers?: number; - pullers?: number; - hashers?: number; - order?: number; - ignoreDelete?: boolean; - scanProgressIntervalS?: number; - pullerSleepS?: number; - pullerPauseS?: number; - maxConflicts?: number; - disableSparseFiles?: boolean; - disableTempIndexes?: boolean; - fsync?: boolean; - paused?: boolean; -} - -interface ISTDeviceConfiguration { - deviceID: string; - name?: string; - address?: string[]; - compression?: string; - certName?: string; - introducer?: boolean; - skipIntroductionRemovals?: boolean; - introducedBy?: string; - paused?: boolean; - allowedNetwork?: string[]; -} - -interface ISTGuiConfiguration { - enabled: boolean; - address: string; - user?: string; - password?: string; - useTLS: boolean; - apiKey?: string; - insecureAdminAccess?: boolean; - theme: string; - debugging: boolean; - insecureSkipHostcheck?: boolean; -} - -interface ISTOptionsConfiguration { - listenAddresses: string[]; - globalAnnounceServer: string[]; - // To be completed ... -} - -interface ISTConfiguration { - version: number; - folders: ISTFolderConfiguration[]; - devices: ISTDeviceConfiguration[]; - gui: ISTGuiConfiguration; - options: ISTOptionsConfiguration; - ignoredDevices: string[]; -} - -// Default settings -const DEFAULT_GUI_PORT = 8386; -const DEFAULT_GUI_API_KEY = "1234abcezam"; -const DEFAULT_RESCAN_INTERV = 0; // 0: use syncthing-inotify to detect changes - - -@Injectable() -export class SyncthingService { - - public Status$: Observable<ISyncThingStatus>; - - private baseRestUrl: string; - private apikey: string; - private localSTID: string; - private stCurVersion: number; - private connectionMaxRetry: number; - private _status: ISyncThingStatus = { - ID: null, - baseURL: "", - connected: false, - connectionRetry: 0, - tilde: "", - rawStatus: null, - }; - private statusSubject = <BehaviorSubject<ISyncThingStatus>>new BehaviorSubject(this._status); - - constructor(private http: Http, private _window: Window, private cookie: CookieService) { - this._status.baseURL = 'http://localhost:' + DEFAULT_GUI_PORT; - this.baseRestUrl = this._status.baseURL + '/rest'; - this.apikey = DEFAULT_GUI_API_KEY; - this.stCurVersion = -1; - this.connectionMaxRetry = 10; // 10 seconds - - this.Status$ = this.statusSubject.asObservable(); - } - - connect(retry: number, url?: string): Observable<ISyncThingStatus> { - if (url) { - this._status.baseURL = url; - this.baseRestUrl = this._status.baseURL + '/rest'; - } - this._status.connected = false; - this._status.ID = null; - this._status.connectionRetry = 0; - this.connectionMaxRetry = retry || 3600; // 1 hour - return this.getStatus(); - } - - getID(): Observable<string> { - if (this._status.ID != null) { - return Observable.of(this._status.ID); - } - return this.getStatus().map(sts => sts.ID); - } - - getStatus(): Observable<ISyncThingStatus> { - return this._get('/system/status') - .map((status) => { - this._status.ID = status["myID"]; - this._status.tilde = status["tilde"]; - console.debug('ST local ID', this._status.ID); - - this._status.rawStatus = status; - - return this._status; - }); - } - - getProjects(): Observable<ISTFolderConfiguration[]> { - return this._getConfig() - .map((conf) => conf.folders); - } - - addProject(prj: ISyncThingProject): Observable<ISTFolderConfiguration> { - return this.getID() - .flatMap(() => this._getConfig()) - .flatMap((stCfg) => { - let newDevID = prj.serverSyncThingID; - - // Add new Device if needed - let dev = stCfg.devices.filter(item => item.deviceID === newDevID); - if (dev.length <= 0) { - stCfg.devices.push( - { - deviceID: newDevID, - name: "Builder_" + newDevID.slice(0, 15), - address: ["dynamic"], - } - ); - } - - // Add or update Folder settings - let label = prj.label || ""; - let scanInterval = parseInt(this.cookie.get("st-rescanInterval"), 10) || DEFAULT_RESCAN_INTERV; - let folder: ISTFolderConfiguration = { - id: prj.id, - label: label, - path: prj.path, - devices: [{ deviceID: newDevID, introducedBy: "" }], - autoNormalize: true, - rescanIntervalS: scanInterval, - }; - - let idx = stCfg.folders.findIndex(item => item.id === prj.id); - if (idx === -1) { - stCfg.folders.push(folder); - } else { - let newFld = Object.assign({}, stCfg.folders[idx], folder); - stCfg.folders[idx] = newFld; - } - - // Set new config - return this._setConfig(stCfg); - }) - .flatMap(() => this._getConfig()) - .map((newConf) => { - let idx = newConf.folders.findIndex(item => item.id === prj.id); - return newConf.folders[idx]; - }); - } - - deleteProject(id: string): Observable<ISTFolderConfiguration> { - let delPrj: ISTFolderConfiguration; - return this._getConfig() - .flatMap((conf: ISTConfiguration) => { - let idx = conf.folders.findIndex(item => item.id === id); - if (idx === -1) { - throw new Error("Cannot delete project: not found"); - } - delPrj = Object.assign({}, conf.folders[idx]); - conf.folders.splice(idx, 1); - return this._setConfig(conf); - }) - .map(() => delPrj); - } - - /* - * --- Private functions --- - */ - private _getConfig(): Observable<ISTConfiguration> { - return this._get('/system/config'); - } - - private _setConfig(cfg: ISTConfiguration): Observable<any> { - return this._post('/system/config', cfg); - } - - private _attachAuthHeaders(options?: any) { - options = options || {}; - let headers = options.headers || new Headers(); - // headers.append('Authorization', 'Basic ' + btoa('username:password')); - headers.append('Accept', 'application/json'); - headers.append('Content-Type', 'application/json'); - if (this.apikey !== "") { - headers.append('X-API-Key', this.apikey); - - } - options.headers = headers; - return options; - } - - private _checkAlive(): Observable<boolean> { - if (this._status.connected) { - return Observable.of(true); - } - - return this.http.get(this.baseRestUrl + '/system/version', this._attachAuthHeaders()) - .map((r) => this._status.connected = true) - .retryWhen((attempts) => { - this._status.connectionRetry = 0; - return attempts.flatMap(error => { - this._status.connected = false; - if (++this._status.connectionRetry >= this.connectionMaxRetry) { - return Observable.throw("Syncthing local daemon not responding (url=" + this._status.baseURL + ")"); - } else { - return Observable.timer(1000); - } - }); - }); - } - - private _getAPIVersion(): Observable<number> { - if (this.stCurVersion !== -1) { - return Observable.of(this.stCurVersion); - } - - return this.http.get(this.baseRestUrl + '/system/config', this._attachAuthHeaders()) - .map((res: Response) => { - let conf: ISTConfiguration = res.json(); - this.stCurVersion = (conf && conf.version) || -1; - return this.stCurVersion; - }) - .catch(this._handleError); - } - - private _checkAPIVersion(): Observable<number> { - return this._getAPIVersion().map(ver => { - if (ver !== ISTCONFIG_VERSION) { - throw new Error("Unsupported Syncthing version api (" + ver + - " != " + ISTCONFIG_VERSION + ") !"); - } - return ver; - }); - } - - private _get(url: string): Observable<any> { - return this._checkAlive() - .flatMap(() => this._checkAPIVersion()) - .flatMap(() => this.http.get(this.baseRestUrl + url, this._attachAuthHeaders())) - .map((res: Response) => res.json()) - .catch(this._handleError); - } - - private _post(url: string, body: any): Observable<any> { - return this._checkAlive() - .flatMap(() => this._checkAPIVersion()) - .flatMap(() => this.http.post(this.baseRestUrl + url, JSON.stringify(body), this._attachAuthHeaders())) - .map((res: Response) => { - if (res && res.status && res.status === 200) { - return res; - } - throw new Error(res.toString()); - - }) - .catch(this._handleError); - } - - private _handleError(error: Response | any) { - // In a real world app, you might use a remote logging infrastructure - let errMsg: string; - if (this._status) { - this._status.connected = false; - } - if (error instanceof Response) { - const body = error.json() || 'Server error'; - const err = body.error || JSON.stringify(body); - errMsg = `${error.status} - ${error.statusText || ''} ${err}`; - } else { - errMsg = error.message ? error.message : error.toString(); - } - return Observable.throw(errMsg); - } -} diff --git a/webapp/src/app/services/utils.service.ts b/webapp/src/app/services/utils.service.ts deleted file mode 100644 index 84b9ab6..0000000 --- a/webapp/src/app/services/utils.service.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Injectable } from '@angular/core'; - -@Injectable() -export class UtilsService { - constructor() { } - - getOSName(lowerCase?: boolean): string { - var checkField = function (ff) { - if (ff.indexOf("Linux") !== -1) { - return "Linux"; - } else if (ff.indexOf("Win") !== -1) { - return "Windows"; - } else if (ff.indexOf("Mac") !== -1) { - return "MacOS"; - } else if (ff.indexOf("X11") !== -1) { - return "UNIX"; - } - return ""; - }; - - let OSName = checkField(navigator.platform); - if (OSName === "") { - OSName = checkField(navigator.appVersion); - } - if (OSName === "") { - OSName = "Unknown OS"; - } - if (lowerCase) { - return OSName.toLowerCase(); - } - return OSName; - } -}
\ No newline at end of file diff --git a/webapp/src/app/services/xdsagent.service.ts b/webapp/src/app/services/xdsagent.service.ts deleted file mode 100644 index c6c52c8..0000000 --- a/webapp/src/app/services/xdsagent.service.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http'; -import { Location } from '@angular/common'; -import { Observable } from 'rxjs/Observable'; -import { Subject } from 'rxjs/Subject'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import * as io from 'socket.io-client'; - -import { AlertService } from './alert.service'; - - -// Import RxJs required methods -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/observable/throw'; - -export interface IXDSVersion { - version: string; - apiVersion: string; - gitTag: string; - -} - -export interface IXDSDeploy { - boardIP: string; - file: string; -} - -export interface IAgentStatus { - baseURL: string; - connected: boolean; - WS_connected: boolean; - connectionRetry: number; - version: string; -} - -// Default settings -const DEFAULT_PORT = 8010; -const DEFAULT_API_KEY = "1234abcezam"; -const API_VERSION = "v1"; - -@Injectable() -export class XDSAgentService { - public Status$: Observable<IAgentStatus>; - - private baseRestUrl: string; - private wsUrl: string; - private connectionMaxRetry: number; - private apikey: string; - private _status: IAgentStatus = { - baseURL: "", - connected: false, - WS_connected: false, - connectionRetry: 0, - version: "", - }; - private statusSubject = <BehaviorSubject<IAgentStatus>>new BehaviorSubject(this._status); - - - private socket: SocketIOClient.Socket; - - constructor(private http: Http, private _window: Window, private alert: AlertService) { - - this.Status$ = this.statusSubject.asObservable(); - - this.apikey = DEFAULT_API_KEY; // FIXME Add dynamic allocated key - this._initURLs('http://localhost:' + DEFAULT_PORT); - } - - connect(retry: number, url?: string): Observable<IAgentStatus> { - if (url) { - this._initURLs(url); - } - this._status.connected = false; - this._status.connectionRetry = 0; - this.connectionMaxRetry = retry || 3600; // 1 hour - - // Init IO Socket connection - this._handleIoSocket(); - - // Get Version in order to check connection via a REST request - return this.getVersion() - .map((v) => { - this._status.version = v.version; - this.statusSubject.next(Object.assign({}, this._status)); - return this._status; - }); - } - - public getVersion(): Observable<IXDSVersion> { - return this._get('/version'); - } - - public deploy(dpy: IXDSDeploy) { - return this._post('/deploy', dpy); - } - - private _initURLs(url: string) { - this._status.baseURL = url; - this.baseRestUrl = this._status.baseURL + '/api/' + API_VERSION; - let re = this._status.baseURL.match(/http[s]?:\/\/([^\/]*)[\/]?/); - if (re === null || re.length < 2) { - this.wsUrl = ''; - console.error('ERROR: cannot determine Websocket url'); - return; - } - this.wsUrl = 'ws://' + re[1]; - } - - private _WSState(sts: boolean) { - this._status.WS_connected = sts; - this.statusSubject.next(Object.assign({}, this._status)); - } - - private _handleIoSocket() { - this.socket = io(this.wsUrl, { transports: ['websocket'] }); - - this.socket.on('connect_error', (res) => { - this._WSState(false); - console.error('WS Connect_error ', res); - }); - - this.socket.on('connect', (res) => { - this._WSState(true); - }); - - this.socket.on('disconnection', (res) => { - this._WSState(false); - this.alert.error('WS disconnection: ' + res); - }); - - this.socket.on('error', (err) => { - console.error('WS error:', err); - }); - - } - - private _attachAuthHeaders(options?: any) { - options = options || {}; - let headers = options.headers || new Headers(); - // headers.append('Authorization', 'Basic ' + btoa('username:password')); - headers.append('Accept', 'application/json'); - headers.append('Content-Type', 'application/json'); - if (this.apikey !== "") { - headers.append('X-API-Key', this.apikey); - - } - - options.headers = headers; - return options; - } - - private _checkAlive(): Observable<boolean> { - if (this._status.connected) { - return Observable.of(true); - } - - return this.http.get(this.baseRestUrl + "/version", this._attachAuthHeaders()) - .map((r) => this._status.connected = true) - .retryWhen((attempts) => { - this._status.connectionRetry = 0; - return attempts.flatMap(error => { - this._status.connected = false; - if (++this._status.connectionRetry >= this.connectionMaxRetry) { - return Observable.throw("XDS local Agent not responding (url=" + this._status.baseURL + ")"); - } else { - return Observable.timer(1000); - } - }); - }); - } - - private _get(url: string): Observable<any> { - return this._checkAlive() - .flatMap(() => this.http.get(this.baseRestUrl + url, this._attachAuthHeaders())) - .map((res: Response) => res.json()) - .catch(this._decodeError); - } - private _post(url: string, body: any): Observable<any> { - return this._checkAlive() - .flatMap(() => this.http.post(this.baseRestUrl + url, JSON.stringify(body), this._attachAuthHeaders())) - .map((res: Response) => res.json()) - .catch(this._decodeError); - } - private _delete(url: string): Observable<any> { - return this._checkAlive() - .flatMap(() => this.http.delete(this.baseRestUrl + url, this._attachAuthHeaders())) - .map((res: Response) => res.json()) - .catch(this._decodeError); - } - - private _decodeError(err: Response | any) { - let e: string; - if (this._status) { - this._status.connected = false; - } - if (err instanceof Response) { - const body = err.json() || 'Server error'; - e = body.error || JSON.stringify(body); - if (!e || e === "") { - e = `${err.status} - ${err.statusText || 'Unknown error'}`; - } - } else if (typeof err === "object") { - if (err.statusText) { - e = err.statusText; - } else if (err.error) { - e = String(err.error); - } else { - e = JSON.stringify(err); - } - } else { - e = err.message ? err.message : err.toString(); - } - return Observable.throw(e); - } -} diff --git a/webapp/src/app/services/xdsserver.service.ts b/webapp/src/app/services/xdsserver.service.ts deleted file mode 100644 index b69a196..0000000 --- a/webapp/src/app/services/xdsserver.service.ts +++ /dev/null @@ -1,296 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http'; -import { Location } from '@angular/common'; -import { Observable } from 'rxjs/Observable'; -import { Subject } from 'rxjs/Subject'; -import { BehaviorSubject } from 'rxjs/BehaviorSubject'; -import * as io from 'socket.io-client'; - -import { AlertService } from './alert.service'; -import { ISdk } from './sdk.service'; - - -// Import RxJs required methods -import 'rxjs/add/operator/map'; -import 'rxjs/add/operator/catch'; -import 'rxjs/add/observable/throw'; -import 'rxjs/add/operator/mergeMap'; - - -export interface IXDSConfigProject { - id: string; - path: string; - clientSyncThingID: string; - type: number; - label?: string; - defaultSdkID?: string; -} - -interface IXDSBuilderConfig { - ip: string; - port: string; - syncThingID: string; -} - -export interface IXDSFolderConfig { - id: string; - label: string; - path: string; - type: number; - status?: string; - isInSync?: boolean; - defaultSdkID: string; - - // FIXME better with union but tech pb with go code - //data?: IXDSPathMapConfig|IXDSCloudSyncConfig; - dataPathMap?: IXDSPathMapConfig; - dataCloudSync?: IXDSCloudSyncConfig; -} - -export interface IXDSPathMapConfig { - // TODO - serverPath: string; -} - -export interface IXDSCloudSyncConfig { - syncThingID: string; - builderSThgID?: string; -} - -interface IXDSConfig { - version: number; - builder: IXDSBuilderConfig; - folders: IXDSFolderConfig[]; -} - -export interface IXDSAgentTarball { - os: string; - arch: string; - version: string; - rawVersion: string; - fileUrl: string; -} - -export interface IXDSAgentInfo { - tarballs: IXDSAgentTarball[]; -} - -export interface ISdkMessage { - wsID: string; - msgType: string; - data: any; -} - -export interface ICmdOutput { - cmdID: string; - timestamp: string; - stdout: string; - stderr: string; -} - -export interface ICmdExit { - cmdID: string; - timestamp: string; - code: number; - error: string; -} - -export interface IServerStatus { - WS_connected: boolean; - -} - -const FOLDER_TYPE_CLOUDSYNC = 2; - -@Injectable() -export class XDSServerService { - - public CmdOutput$ = <Subject<ICmdOutput>>new Subject(); - public CmdExit$ = <Subject<ICmdExit>>new Subject(); - public FolderStateChange$ = <Subject<IXDSFolderConfig>>new Subject(); - public Status$: Observable<IServerStatus>; - - - private baseUrl: string; - private wsUrl: string; - private _status = { WS_connected: false }; - private statusSubject = <BehaviorSubject<IServerStatus>>new BehaviorSubject(this._status); - - - private socket: SocketIOClient.Socket; - - constructor(private http: Http, private _window: Window, private alert: AlertService) { - - this.Status$ = this.statusSubject.asObservable(); - - this.baseUrl = this._window.location.origin + '/api/v1'; - let re = this._window.location.origin.match(/http[s]?:\/\/([^\/]*)[\/]?/); - if (re === null || re.length < 2) { - console.error('ERROR: cannot determine Websocket url'); - } else { - this.wsUrl = 'ws://' + re[1]; - this._handleIoSocket(); - this._RegisterEvents(); - } - } - - private _WSState(sts: boolean) { - this._status.WS_connected = sts; - this.statusSubject.next(Object.assign({}, this._status)); - } - - private _handleIoSocket() { - this.socket = io(this.wsUrl, { transports: ['websocket'] }); - - this.socket.on('connect_error', (res) => { - this._WSState(false); - console.error('WS Connect_error ', res); - }); - - this.socket.on('connect', (res) => { - this._WSState(true); - }); - - this.socket.on('disconnection', (res) => { - this._WSState(false); - this.alert.error('WS disconnection: ' + res); - }); - - this.socket.on('error', (err) => { - console.error('WS error:', err); - }); - - this.socket.on('make:output', data => { - this.CmdOutput$.next(Object.assign({}, <ICmdOutput>data)); - }); - - this.socket.on('make:exit', data => { - this.CmdExit$.next(Object.assign({}, <ICmdExit>data)); - }); - - this.socket.on('exec:output', data => { - this.CmdOutput$.next(Object.assign({}, <ICmdOutput>data)); - }); - - this.socket.on('exec:exit', data => { - this.CmdExit$.next(Object.assign({}, <ICmdExit>data)); - }); - - this.socket.on('event:FolderStateChanged', ev => { - if (ev && ev.folder) { - this.FolderStateChange$.next(Object.assign({}, ev.folder)); - } - }); - } - - private _RegisterEvents() { - let ev = "FolderStateChanged"; - this._post('/events/register', { "name": ev }) - .subscribe( - res => { }, - error => { - this.alert.error("ERROR while registering events " + ev + ": ", error); - } - ); - } - - getSdks(): Observable<ISdk[]> { - return this._get('/sdks'); - } - - getXdsAgentInfo(): Observable<IXDSAgentInfo> { - return this._get('/xdsagent/info'); - } - - getProjects(): Observable<IXDSFolderConfig[]> { - return this._get('/folders'); - } - - addProject(cfg: IXDSFolderConfig): Observable<IXDSFolderConfig> { - return this._post('/folder', cfg); - } - - deleteProject(id: string): Observable<IXDSFolderConfig> { - return this._delete('/folder/' + id); - } - - syncProject(id: string): Observable<string> { - return this._post('/folder/sync/' + id, {}); - } - - exec(prjID: string, dir: string, cmd: string, sdkid?: string, args?: string[], env?: string[]): Observable<any> { - return this._post('/exec', - { - id: prjID, - rpath: dir, - cmd: cmd, - sdkid: sdkid || "", - args: args || [], - env: env || [], - }); - } - - make(prjID: string, dir: string, sdkid?: string, args?: string[], env?: string[]): Observable<any> { - return this._post('/make', - { - id: prjID, - rpath: dir, - sdkid: sdkid, - args: args || [], - env: env || [], - }); - } - - - private _attachAuthHeaders(options?: any) { - options = options || {}; - let headers = options.headers || new Headers(); - // headers.append('Authorization', 'Basic ' + btoa('username:password')); - headers.append('Accept', 'application/json'); - headers.append('Content-Type', 'application/json'); - // headers.append('Access-Control-Allow-Origin', '*'); - - options.headers = headers; - return options; - } - - private _get(url: string): Observable<any> { - return this.http.get(this.baseUrl + url, this._attachAuthHeaders()) - .map((res: Response) => res.json()) - .catch(this._decodeError); - } - private _post(url: string, body: any): Observable<any> { - return this.http.post(this.baseUrl + url, JSON.stringify(body), this._attachAuthHeaders()) - .map((res: Response) => res.json()) - .catch((error) => { - return this._decodeError(error); - }); - } - private _delete(url: string): Observable<any> { - return this.http.delete(this.baseUrl + url, this._attachAuthHeaders()) - .map((res: Response) => res.json()) - .catch(this._decodeError); - } - - private _decodeError(err: any) { - let e: string; - if (err instanceof Response) { - const body = err.json() || 'Server error'; - e = body.error || JSON.stringify(body); - if (!e || e === "") { - e = `${err.status} - ${err.statusText || 'Unknown error'}`; - } - } else if (typeof err === "object") { - if (err.statusText) { - e = err.statusText; - } else if (err.error) { - e = String(err.error); - } else { - e = JSON.stringify(err); - } - } else { - e = err.message ? err.message : err.toString(); - } - return Observable.throw(e); - } -} diff --git a/webapp/src/index.html b/webapp/src/index.html index 290b4be..45ac90d 100644 --- a/webapp/src/index.html +++ b/webapp/src/index.html @@ -2,49 +2,97 @@ <head> <title> - XDS Dashboard + XDS Server </title> - <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel="icon" type="image/x-icon" href="assets/favicon.ico"> - <!-- TODO cleanup - <link rel="stylesheet" href="lib/foundation-sites/dist/css/foundation.min.css"> - --> - <link <link href="lib/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet"> + <link rel="stylesheet" href="font-awesome.min.css"> - <link rel="stylesheet" href="lib/font-awesome/css/font-awesome.min.css"> - <link rel="stylesheet" href="lib/font-awesome-animation/dist/font-awesome-animation.min.css"> + <style> + body.page-content { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + position: relative; + height: 100%; + width: auto; + text-align: center; + background: url("assets/images/background_iot_bzh_light.png") 0 0 no-repeat; + background-color: lightgrey; + background-size: cover; + background-position: center; + color: #FFFFFF; + } - <!-- 1. Load libraries --> - <!-- Polyfill(s) for older browsers --> - <script src="lib/core-js/client/shim.min.js"></script> + img { + width: 15em; + } - <script src="lib/zone.js/dist/zone.js"></script> - <script src="lib/reflect-metadata/Reflect.js"></script> - <script src="lib/systemjs/dist/system.src.js"></script> + li { + list-style: none; + font-size: x-large; + padding-bottom: 10px; + } - <!-- 2. Configure SystemJS --> - <script src="systemjs.config.js"></script> - <script> - System.import('app') - .then(null, console.error.bind(console)); - </script> + a { + color: royalblue; + } - <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script> + i.fa { + font-size: smaller; + } + #dashbButton { + font-size: large; + font-weight: bold; + background: none; + color: royalblue; + } + </style> </head> -<!-- 3. Display the application --> +<body class="page-content"> + + <img id="logo-iot" src="assets/images/iot-bzh-logo-small.png"> + + <h1 id="title">X(cross) Development System</h1> + + <h2>Please start XDS agent on your machine<br> and + <br> connect to XDS Dashboard + </h2> + + <button id="dashbButton"> + Try to connect to dashboard<br> + http://localhost:8000 + </button> + <script type="text/javascript"> + document.getElementById("dashbButton").onclick = function () { + location.href = "http://localhost:8000"; + }; + </script> + <i style="font:xx-small;">(URL may depend on your configuration)</i> + + <br><br><br> -<body style="padding-top: 70px;"> <!-- padding needed due to fixed navbar --> - <app> - <div style="text-align:center; position:absolute; top:50%; width:100%; transform:translate(0,-50%);"> - <img id="logo-iot" src="assets/images/iot-bzh-logo-small.png"> - <br> Loading... - <i class="fa fa-spinner fa-spin fa-fw"></i> - </div> - </app> + <h2>For more information, please refer to XDS User's Guide:</h2> + <ul> + <li> + <a href="http://docs.automotivelinux.org/docs/devguides/en/dev/reference/xds/part-1/1_install-client.html"> + Install instructions <i class="fa fa-external-link" aria-hidden="true"></i> + </a> + </li> + <li> + <a href="http://docs.automotivelinux.org/docs/devguides/en/dev/#xcross-development-system-user's-guide"> + Online User's guide <i class="fa fa-external-link" aria-hidden="true"></i> + </a> + </li> + <li> + <a href="http://iot.bzh/download/public/2017/XDS/docs/XDS_UsersGuide.pdf"> + User's guide (PDF file) <i class="fa fa-external-link" aria-hidden="true"></i> + </a> + </li> + </ul> </body> </html> diff --git a/webapp/src/systemjs.config.js b/webapp/src/systemjs.config.js deleted file mode 100644 index 15c52ba..0000000 --- a/webapp/src/systemjs.config.js +++ /dev/null @@ -1,69 +0,0 @@ -(function (global) { - System.config({ - paths: { - // paths serve as alias - 'npm:': 'lib/' - }, - bundles: { - "npm:rxjs-system-bundle/Rx.system.min.js": [ - "rxjs", - "rxjs/*", - "rxjs/operator/*", - "rxjs/observable/*", - "rxjs/scheduler/*", - "rxjs/symbol/*", - "rxjs/add/operator/*", - "rxjs/add/observable/*", - "rxjs/util/*" - ] - }, - // map tells the System loader where to look for things - map: { - // our app is within the app folder - app: 'app', - // angular bundles - '@angular/core': 'npm:@angular/core/bundles/core.umd.js', - '@angular/common': 'npm:@angular/common/bundles/common.umd.js', - '@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js', - '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', - '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', - '@angular/http': 'npm:@angular/http/bundles/http.umd.js', - '@angular/router': 'npm:@angular/router/bundles/router.umd.js', - '@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js', - 'ngx-cookie': 'npm:ngx-cookie/bundles/ngx-cookie.umd.js', - // ng2-bootstrap - 'moment': 'npm:moment', - 'ngx-bootstrap/alert': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', - 'ngx-bootstrap/modal': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', - 'ngx-bootstrap/accordion': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', - 'ngx-bootstrap/carousel': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', - 'ngx-bootstrap/popover': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', - 'ngx-bootstrap/dropdown': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', - 'ngx-bootstrap/collapse': 'npm:ngx-bootstrap/bundles/ngx-bootstrap.umd.min.js', - // other libraries - 'socket.io-client': 'npm:socket.io-client/dist/socket.io.min.js' - }, - // packages tells the System loader how to load when no filename and/or no extension - packages: { - 'app': { - main: './main.js', - defaultExtension: 'js' - }, - 'rxjs': { - defaultExtension: false - }, - 'socket.io-client': { - defaultExtension: 'js' - }, - 'ngx-bootstrap': { - format: 'cjs', - main: 'bundles/ng2-bootstrap.umd.js', - defaultExtension: 'js' - }, - 'moment': { - main: 'moment.js', - defaultExtension: 'js' - } - } - }); -})(this); |