Moved Dashboad webapp on Angular 5 !
authorSebastien Douheret <sebastien.douheret@iot.bzh>
Fri, 10 Nov 2017 15:29:10 +0000 (16:29 +0100)
committerSebastien Douheret <sebastien.douheret@iot.bzh>
Fri, 10 Nov 2017 15:36:12 +0000 (16:36 +0100)
Webapp loading time decreased from 2.7s to 1.5sec !

Signed-off-by: Sebastien Douheret <sebastien.douheret@iot.bzh>
61 files changed:
.vscode/settings.json
webapp/.angular-cli.json [new file with mode: 0644]
webapp/.jshintrc [new file with mode: 0644]
webapp/gulp.conf.js [deleted file]
webapp/gulpfile.js [deleted file]
webapp/package.json
webapp/src/app/alert/alert.component.spec.ts [new file with mode: 0644]
webapp/src/app/alert/alert.component.ts
webapp/src/app/app-routing.module.ts [new file with mode: 0644]
webapp/src/app/app.component.ts
webapp/src/app/app.module.ts
webapp/src/app/app.routing.ts [deleted file]
webapp/src/app/common/safe.pipe.ts [new file with mode: 0644]
webapp/src/app/config/config.component.html
webapp/src/app/config/config.component.spec.ts [new file with mode: 0644]
webapp/src/app/config/config.component.ts
webapp/src/app/config/downloadXdsAgent.component.ts
webapp/src/app/devel/build/build.component.html
webapp/src/app/devel/build/build.component.spec.ts [new file with mode: 0644]
webapp/src/app/devel/build/build.component.ts
webapp/src/app/devel/devel.component.html
webapp/src/app/devel/devel.component.spec.ts [new file with mode: 0644]
webapp/src/app/devel/devel.component.ts
webapp/src/app/home/home.component.css [new file with mode: 0644]
webapp/src/app/home/home.component.html [new file with mode: 0644]
webapp/src/app/home/home.component.ts
webapp/src/app/main.ts [deleted file]
webapp/src/app/projects/projectAddModal.component.ts
webapp/src/app/projects/projectCard.component.ts
webapp/src/app/projects/projectsListAccordion.component.ts
webapp/src/app/sdks/sdkAddModal.component.html
webapp/src/app/sdks/sdkAddModal.component.ts
webapp/src/app/sdks/sdkCard.component.ts
webapp/src/app/sdks/sdkSelectDropdown.component.ts
webapp/src/app/sdks/sdksListAccordion.component.ts
webapp/src/app/services/alert.service.spec.ts [new file with mode: 0644]
webapp/src/app/services/alert.service.ts
webapp/src/app/services/config.service.spec.ts [new file with mode: 0644]
webapp/src/app/services/config.service.ts
webapp/src/app/services/project.service.ts
webapp/src/app/services/sdk.service.ts
webapp/src/app/services/utils.service.ts
webapp/src/app/services/xdsagent.service.ts
webapp/src/assets/css/main.css [new file with mode: 0644]
webapp/src/assets/favicon.ico [moved from webapp/assets/favicon.ico with 100% similarity]
webapp/src/assets/i18n/en.json [new file with mode: 0644]
webapp/src/assets/i18n/fr.json [new file with mode: 0644]
webapp/src/assets/images/iot-bzh-logo-small.png [moved from webapp/assets/images/iot-bzh-logo-small.png with 100% similarity]
webapp/src/assets/images/iot-graphx.jpg [moved from webapp/assets/images/iot-graphx.jpg with 100% similarity]
webapp/src/environments/environment.prod.ts [new file with mode: 0644]
webapp/src/environments/environment.ts [new file with mode: 0644]
webapp/src/index.html
webapp/src/main.ts [new file with mode: 0644]
webapp/src/polyfills.ts [new file with mode: 0644]
webapp/src/styles.css [new file with mode: 0644]
webapp/src/systemjs.config.js [deleted file]
webapp/src/tsconfig.app.json [new file with mode: 0644]
webapp/src/tsconfig.spec.json [new file with mode: 0644]
webapp/tsconfig.json
webapp/tslint.json
webapp/tslint.prod.json [deleted file]

index eafbcfa..033ceae 100644 (file)
@@ -1,60 +1,72 @@
 // Place your settings in this file to overwrite default and user settings.
 {
-  // Configure glob patterns for excluding files and folders.
-  "files.exclude": {
-    ".tmp": true,
-    ".git": true,
-    "glide.lock": true,
-    "vendor": true,
-    "debug": true,
-    "bin": true,
-    "tools": true,
-    "webapp/dist": true,
-    "webapp/node_modules": true
-  },
-  // Specify paths/files to ignore. (Supports Globs)
-  "cSpell.ignorePaths": [
-    "**/node_modules/**",
-    "**/vscode-extension/**",
-    "**/.git/**",
-    "**/vendor/**",
-    ".vscode",
-    "typings"
-  ],
-  // Words to add to dictionary for a workspace.
-  "cSpell.words": [
-    "apiv",
-    "gonic",
-    "devel",
-    "csrffound",
-    "Syncthing",
-    "STID",
-    "ISTCONFIG",
-    "socketio",
-    "ldflags",
-    "SThg",
-    "stconfig",
-    "Intf",
-    "dismissible",
-    "rpath",
-    "WSID",
-    "sess",
-    "IXDS",
-    "golib",
-    "xdsapi",
-    "xdsconfig",
-    "xdsserver",
-    "xdsagent",
-    "nbsp",
-    "Inot",
-    "inotify",
-    "cmdi",
-    "sdkid",
-    "Flds",
-    "prjs",
-    "iosk",
-    "CIFS",
-    "IPROJECT",
-    "unregister"
-  ]
+    // Configure glob patterns for excluding files and folders.
+    "files.exclude": {
+        ".tmp": true,
+        ".git": true,
+        "glide.lock": true,
+        "vendor": true,
+        "debug": true,
+        "bin": true,
+        "tools": true,
+        "webapp/dist": true,
+        "webapp/node_modules": true
+    },
+    // Specify paths/files to ignore. (Supports Globs)
+    "cSpell.ignorePaths": [
+        "**/node_modules/**",
+        "**/vscode-extension/**",
+        "**/.git/**",
+        "**/vendor/**",
+        ".vscode",
+        "typings"
+    ],
+    // Words to add to dictionary for a workspace.
+    "cSpell.words": [
+        "apiv",
+        "gonic",
+        "devel",
+        "csrffound",
+        "Syncthing",
+        "STID",
+        "ISTCONFIG",
+        "socketio",
+        "ldflags",
+        "SThg",
+        "stconfig",
+        "Intf",
+        "dismissible",
+        "rpath",
+        "WSID",
+        "sess",
+        "IXDS",
+        "golib",
+        "xdsapi",
+        "xdsconfig",
+        "xdsserver",
+        "xdsagent",
+        "nbsp",
+        "Inot",
+        "inotify",
+        "cmdi",
+        "sdkid",
+        "Flds",
+        "prjs",
+        "iosk",
+        "CIFS",
+        "IPROJECT",
+        "unregister",
+        "conv",
+        "PATHMAP",
+        "nospace",
+        "graphx",
+        "Truthy",
+        "darkviolet",
+        "dwnl"
+    ],
+
+    // codelyzer
+    "tslint.rulesDirectory": "./webapp/node_modules/codelyzer",
+    "typescript.tsdk": "webapp/node_modules/typescript/lib",
+    "tslint.configFile": "webapp/tslint.json"
 }
diff --git a/webapp/.angular-cli.json b/webapp/.angular-cli.json
new file mode 100644 (file)
index 0000000..202ea80
--- /dev/null
@@ -0,0 +1,62 @@
+{
+  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+  "project": {
+    "name": "xds-dashboard"
+  },
+  "apps": [
+    {
+      "root": "src",
+      "outDir": "dist",
+      "assets": [
+        "assets"
+      ],
+      "index": "index.html",
+      "main": "main.ts",
+      "polyfills": "polyfills.ts",
+      "test": "test.ts",
+      "tsconfig": "tsconfig.app.json",
+      "testTsconfig": "tsconfig.spec.json",
+      "prefix": "xds",
+      "styles": [
+        "styles.css",
+        "../node_modules/font-awesome/css/font-awesome.min.css",
+        "../node_modules/font-awesome-animation/dist/font-awesome-animation.min.css",
+        "../node_modules/bootstrap/dist/css/bootstrap.min.css"
+      ],
+      "scripts": [],
+      "environmentSource": "environments/environment.ts",
+      "environments": {
+        "dev": "environments/environment.ts",
+        "prod": "environments/environment.prod.ts"
+      }
+    }
+  ],
+  "e2e": {
+    "protractor": {
+      "config": "./protractor.conf.js"
+    }
+  },
+  "lint": [
+    {
+      "project": "src/tsconfig.app.json",
+      "exclude": "**/node_modules/**"
+    },
+    {
+      "project": "src/tsconfig.spec.json",
+      "exclude": "**/node_modules/**"
+    },
+    {
+      "project": "e2e/tsconfig.e2e.json",
+      "exclude": "**/node_modules/**"
+    }
+  ],
+  "test": {
+    "karma": {
+      "config": "./karma.conf.js"
+    }
+  },
+  "defaults": {
+    "styleExt": "css",
+    "component": {}
+  }
+}
diff --git a/webapp/.jshintrc b/webapp/.jshintrc
new file mode 100644 (file)
index 0000000..7a0ae5c
--- /dev/null
@@ -0,0 +1,7 @@
+{
+  "esversion": 6,
+  "undef": true,
+  "unused": false,
+  "globalstrict": true,
+  "predef": [ "console", "require", "module", "setInterval", "clearInterval", "__dirname"]
+}
\ No newline at end of file
diff --git a/webapp/gulp.conf.js b/webapp/gulp.conf.js
deleted file mode 100644 (file)
index 2e8fa17..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-"use strict";
-
-module.exports = {
-    prodMode: process.env.PRODUCTION || false,
-    outDir: "dist",
-    paths: {
-        tsSources: ["src/**/*.ts"],
-        srcDir: "src",
-        assets: ["assets/**"],
-        node_modules_libs: [
-            'core-js/client/shim.min.js',
-            'reflect-metadata/Reflect.js',
-            'rxjs-system-bundle/*.min.js',
-            'socket.io-client/dist/socket.io*.js',
-            'systemjs/dist/system-polyfills.js',
-            'systemjs/dist/system.src.js',
-            'zone.js/dist/**',
-            '@angular/**/bundles/**',
-            'ngx-cookie/bundles/**',
-            'ngx-bootstrap/bundles/**',
-            'bootstrap/dist/**',
-            'moment/*.min.js',
-            'font-awesome-animation/dist/font-awesome-animation.min.css',
-            'font-awesome/css/font-awesome.min.css',
-            'font-awesome/fonts/**'
-        ]
-    },
-    deploy: {
-        target_ip: 'ip',
-        username: "user",
-        //port: 6666,
-        dir: '/tmp/xds-agent'
-    }
-}
diff --git a/webapp/gulpfile.js b/webapp/gulpfile.js
deleted file mode 100644 (file)
index 0226380..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-"use strict";
-//FIXME in VSC/eslint or add to typings declare function require(v: string): any;
-
-// FIXME: Rework based on
-//   https://github.com/iotbzh/app-framework-templates/blob/master/templates/hybrid-html5/gulpfile.js
-// AND
-//   https://github.com/antonybudianto/angular-starter
-// and/or
-//   https://github.com/smmorneau/tour-of-heroes/blob/master/gulpfile.js
-
-const gulp = require("gulp"),
-    gulpif = require('gulp-if'),
-    del = require("del"),
-    sourcemaps = require('gulp-sourcemaps'),
-    tsc = require("gulp-typescript"),
-    tsProject = tsc.createProject("tsconfig.json"),
-    tslint = require('gulp-tslint'),
-    gulpSequence = require('gulp-sequence'),
-    rsync = require('gulp-rsync'),
-    conf = require('./gulp.conf');
-
-
-var tslintJsonFile = "./tslint.json"
-if (conf.prodMode) {
-    tslintJsonFile = "./tslint.prod.json"
-}
-
-
-/**
- * Remove output directory.
- */
-gulp.task('clean', (cb) => {
-    return del([conf.outDir], cb);
-});
-
-/**
- * Lint all custom TypeScript files.
- */
-gulp.task('tslint', function() {
-    return gulp.src(conf.paths.tsSources)
-        .pipe(tslint({
-            formatter: 'verbose',
-            configuration: tslintJsonFile
-        }))
-        .pipe(tslint.report());
-});
-
-/**
- * Compile TypeScript sources and create sourcemaps in build directory.
- */
-gulp.task("compile", ["tslint"], function() {
-    var tsResult = gulp.src(conf.paths.tsSources)
-        .pipe(sourcemaps.init())
-        .pipe(tsProject());
-    return tsResult.js
-        .pipe(sourcemaps.write(".", { sourceRoot: '/src' }))
-        .pipe(gulp.dest(conf.outDir));
-});
-
-/**
- * Copy all resources that are not TypeScript files into build directory.
- */
-gulp.task("resources", function() {
-    return gulp.src(["src/**/*", "!**/*.ts"])
-        .pipe(gulp.dest(conf.outDir));
-});
-
-/**
- * Copy all assets into build directory.
- */
-gulp.task("assets", function() {
-    return gulp.src(conf.paths.assets)
-        .pipe(gulp.dest(conf.outDir + "/assets"));
-});
-
-/**
- * Copy all required libraries into build directory.
- */
-gulp.task("libs", function() {
-    return gulp.src(conf.paths.node_modules_libs,
-        { cwd: "node_modules/**" })    /* Glob required here. */
-        .pipe(gulp.dest(conf.outDir + "/lib"));
-});
-
-/**
- * Watch for changes in TypeScript, HTML and CSS files.
- */
-gulp.task('watch', function () {
-    gulp.watch([conf.paths.tsSources], ['compile']).on('change', function (e) {
-        console.log('TypeScript file ' + e.path + ' has been changed. Compiling.');
-    });
-    gulp.watch(["src/**/*.html", "src/**/*.css"], ['resources']).on('change', function (e) {
-        console.log('Resource file ' + e.path + ' has been changed. Updating.');
-    });
-});
-
-/**
- * Build the project.
- */
-gulp.task("build", ['compile', 'resources', 'libs', 'assets'], function() {
-    console.log("Building the project ...");
-});
-
-/**
- * Deploy the project on another machine/container
- */
-gulp.task('rsync', function () {
-    return gulp.src(conf.outDir)
-        .pipe(rsync({
-            root: conf.outDir,
-            username: conf.deploy.username,
-            hostname: conf.deploy.target_ip,
-            port: conf.deploy.port || null,
-            archive: true,
-            recursive: true,
-            compress: true,
-            progress: false,
-            incremental: true,
-            destination: conf.deploy.dir
-        }));
-});
-
-gulp.task('deploy', gulpSequence('build', 'rsync'));
\ No newline at end of file
index 9c22f6b..f4f843f 100644 (file)
@@ -2,12 +2,13 @@
   "name": "xds-dashboard",
   "version": "1.0.0",
   "description": "X (cross) Development System dashboard",
-  "scripts": {
-    "clean": "gulp clean",
-    "compile": "gulp compile",
-    "build": "gulp build",
-    "start": "concurrently --kill-others \"gulp watch\" \"lite-server\""
-  },
+  "keywords": [
+    "XDS",
+    "AGL",
+    "IoT.bzh",
+    "angular",
+    "HTML5"
+  ],
   "repository": {
     "type": "git",
     "url": "https://github.com/iotbzh/xds-agent"
   "bugs": {
     "url": "https://github.com/iotbzh/xds-agent/issues"
   },
+  "scripts": {
+    "build": "ng build --prod --verbose",
+    "start": "ng serve --prod --port=8000",
+    "watch": "ng build --preserve-symlinks --watch",
+    "server": "node server/server.js",
+    "ng": "ng",
+    "test": "ng test",
+    "lint": "ng lint",
+    "e2e": "ng e2e"
+  },
   "dependencies": {
-    "@angular/common": "2.4.4",
-    "@angular/compiler": "2.4.4",
-    "@angular/core": "2.4.4",
-    "@angular/forms": "2.4.4",
-    "@angular/http": "2.4.4",
-    "@angular/platform-browser": "2.4.4",
-    "@angular/platform-browser-dynamic": "2.4.4",
-    "@angular/router": "3.4.4",
-    "@angular/upgrade": "2.4.4",
+    "@angular/animations": "5.0.1",
+    "@angular/common": "5.0.1",
+    "@angular/compiler": "5.0.1",
+    "@angular/core": "5.0.1",
+    "@angular/forms": "5.0.1",
+    "@angular/platform-browser": "5.0.1",
+    "@angular/platform-browser-dynamic": "5.0.1",
+    "@angular/router": "5.0.1",
+    "@ngx-translate/core": "^8.0.0",
+    "@ngx-translate/http-loader": "^2.0.0",
     "@types/core-js": "0.9.35",
     "@types/node": "7.0.5",
     "@types/socket.io-client": "^1.4.29",
     "core-js": "^2.4.1",
     "font-awesome": "^4.7.0",
     "font-awesome-animation": "0.0.10",
-    "ngx-bootstrap": "1.6.6",
+    "ng2-file-upload": "^1.2.0",
+    "ngx-bootstrap": "^2.0.0-beta.7",
     "ngx-cookie": "^1.0.0",
     "reflect-metadata": "^0.1.8",
-    "rxjs": "5.0.3",
-    "rxjs-system-bundle": "5.0.3",
+    "rxjs": "5.5.2",
     "socket.io-client": "^1.7.3",
     "socketio": "^1.0.0",
     "systemjs": "0.20.0",
-    "zone.js": "^0.7.6"
+    "zone.js": "^0.8.16"
   },
   "devDependencies": {
-    "concurrently": "^3.1.0",
-    "del": "^2.2.0",
-    "gulp": "^3.9.1",
-    "gulp-if": "2.0.2",
-    "gulp-rsync": "0.0.7",
-    "gulp-sequence": "^0.4.6",
-    "gulp-sourcemaps": "^1.9.1",
-    "gulp-tslint": "^7.0.1",
-    "gulp-typescript": "^3.1.3",
-    "lite-server": "^2.2.2",
-    "ts-node": "^1.7.2",
-    "tslint": "^4.0.2",
-    "typescript": "^2.2.1",
+    "@angular/cli": "1.5.0",
+    "@angular/compiler-cli": "5.0.1",
+    "@angular/language-service": "5.0.1",
+    "@types/jasmine": "~2.5.53",
+    "@types/jasminewd2": "~2.0.2",
+    "@types/node": "~6.0.60",
+    "codelyzer": "~4.0.1",
+    "jasmine-core": "~2.6.2",
+    "jasmine-spec-reporter": "~4.1.0",
+    "karma": "~1.7.0",
+    "karma-chrome-launcher": "~2.1.1",
+    "karma-cli": "~1.0.1",
+    "karma-coverage-istanbul-reporter": "^1.2.1",
+    "karma-jasmine": "~1.1.0",
+    "karma-jasmine-html-reporter": "^0.2.2",
+    "nodemon": "1.11.0",
+    "protractor": "~5.1.2",
+    "pump": "^1.0.2",
+    "ts-loader": "1.3.0",
+    "ts-node": "~3.2.0",
+    "tslint": "~5.4.3",
+    "typescript": "~2.4.0",
     "typings": "^2.0.0"
   }
 }
diff --git a/webapp/src/app/alert/alert.component.spec.ts b/webapp/src/app/alert/alert.component.spec.ts
new file mode 100644 (file)
index 0000000..3921dd6
--- /dev/null
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AlertComponent } from './alert.component';
+
+describe('AlertComponent', () => {
+  let component: AlertComponent;
+  let fixture: ComponentFixture<AlertComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ AlertComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(AlertComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
index 672d7bf..06c9bf5 100644 (file)
@@ -1,18 +1,19 @@
-import { Component } from '@angular/core';
-import { Observable } from 'rxjs';
+import { Component, ViewEncapsulation } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
 
-import {AlertService, IAlert} from '../services/alert.service';
+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>
-    `
+  <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 {
diff --git a/webapp/src/app/app-routing.module.ts b/webapp/src/app/app-routing.module.ts
new file mode 100644 (file)
index 0000000..36629de
--- /dev/null
@@ -0,0 +1,18 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+import { HomeComponent } from './home/home.component';
+import { ConfigComponent } from './config/config.component';
+import { DevelComponent } from './devel/devel.component';
+
+const routes: Routes = [
+    { path: 'config', component: ConfigComponent, data: { title: 'Config' } },
+    { path: 'home', component: HomeComponent, data: { title: 'Home' } },
+    { path: 'devel', component: DevelComponent, data: { title: 'Build & Deploy' } },
+    { path: '**', component: HomeComponent }
+];
+
+@NgModule({
+    imports: [RouterModule.forRoot(routes)],
+    exports: [RouterModule]
+})
+export class AppRoutingModule { }
index 40cfb24..0d1ce12 100644 (file)
@@ -1,37 +1,45 @@
-import { Component, OnInit, OnDestroy } from "@angular/core";
-import { Router } from '@angular/router';
-//TODO import {TranslateService} from "ng2-translate";
+import { Component, OnInit, OnDestroy } from '@angular/core';
+import { TranslateService } from '@ngx-translate/core';
+import { ConfigService, IConfig } from './services/config.service';
 
 @Component({
-    selector: 'app',
-    templateUrl: './app/app.component.html',
-    styleUrls: ['./app/app.component.css']
+    selector: 'app-root',
+    templateUrl: 'app.component.html',
+    styleUrls: ['app.component.css']
 })
 
 export class AppComponent implements OnInit, OnDestroy {
+    private defaultLanguage = 'en';
+    public isCollapsed = true;
 
-    isCollapsed: boolean = true;
-
-    private defaultLanguage: string = 'en';
-
-    // I initialize the app component.
-    //TODO constructor(private translate: TranslateService) {
-    constructor(public router: Router) {
+    constructor(private translate: TranslateService, private configSvr: ConfigService) {
     }
 
     ngOnInit() {
-
-        /* TODO
-        this.translate.addLangs(["en", "fr"]);
+        this.translate.addLangs(['en', 'fr']);
         this.translate.setDefaultLang(this.defaultLanguage);
 
-        let browserLang = this.translate.getBrowserLang();
+        const browserLang = this.translate.getBrowserLang();
         this.translate.use(browserLang.match(/en|fr/) ? browserLang : this.defaultLanguage);
-        */
+
+        this.configSvr.Conf$.subscribe((cfg: IConfig) => {
+            let lang: string;
+            switch (cfg.language) {
+                case 'ENG':
+                    lang = 'en';
+                    break;
+                case 'FRA':
+                    lang = 'fr';
+                    break;
+                default:
+                    lang = this.defaultLanguage;
+            }
+            this.translate.use(lang);
+        });
     }
 
     ngOnDestroy(): void {
+        // this.aglIdentityService.loginResponse.unsubscribe();
+        // this.aglIdentityService.logoutResponse.unsubscribe();
     }
-
-
 }
index c3fd586..31a7c2c 100644 (file)
@@ -1,7 +1,11 @@
 import { NgModule } from '@angular/core';
+import { HttpClientModule, HttpClient } from '@angular/common/http';
 import { BrowserModule } from '@angular/platform-browser';
-import { HttpModule } from "@angular/http";
 import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { TranslateModule, TranslateLoader } from '@ngx-translate/core';
+import { TranslateHttpLoader } from '@ngx-translate/http-loader';
+import { FileUploadModule } from 'ng2-file-upload';
+import { LocationStrategy, HashLocationStrategy } from '@angular/common';
 import { CookieModule } from 'ngx-cookie';
 
 // Import bootstrap
@@ -14,39 +18,51 @@ 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 { AppRoutingModule } from './app-routing.module';
+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 { ConfigComponent } from './config/config.component';
+import { DwnlAgentComponent } from './config/downloadXdsAgent.component';
+import { DevelComponent } from './devel/devel.component';
+import { BuildComponent } from './devel/build/build.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 { XDSAgentService } from "./services/xdsagent.service";
-import { ConfigService } from "./services/config.service";
-import { ProjectService } from "./services/project.service";
 import { AlertService } from './services/alert.service';
+import { ConfigService } from './services/config.service';
+import { ProjectService } from './services/project.service';
+import { SdkService } from './services/sdk.service';
 import { UtilsService } from './services/utils.service';
-import { SdkService } from "./services/sdk.service";
+import { XDSAgentService } from './services/xdsagent.service';
 
+import { SafePipe } from './common/safe.pipe';
 
+export function createTranslateLoader(http: HttpClient) {
+    return new TranslateHttpLoader(http, './assets/i18n/', '.json');
+}
 
 @NgModule({
     imports: [
         BrowserModule,
-        HttpModule,
         FormsModule,
         ReactiveFormsModule,
-        Routing,
+        HttpClientModule,
+        AppRoutingModule,
+        FileUploadModule,
+        TranslateModule.forRoot({
+            loader: {
+                provide: TranslateLoader,
+                useFactory: (createTranslateLoader),
+                deps: [HttpClient]
+            }
+        }),
         CookieModule.forRoot(),
         AlertModule.forRoot(),
         ModalModule.forRoot(),
@@ -58,13 +74,12 @@ import { SdkService } from "./services/sdk.service";
     ],
     declarations: [
         AppComponent,
-        AlertComponent,
         HomeComponent,
-        BuildComponent,
-        DevelComponent,
+        AlertComponent,
         ConfigComponent,
-        DlXdsAgentComponent,
-        CapitalizePipe,
+        DwnlAgentComponent,
+        DevelComponent,
+        BuildComponent,
         ProjectCardComponent,
         ProjectReadableTypePipe,
         ProjectsListAccordionComponent,
@@ -73,21 +88,21 @@ import { SdkService } from "./services/sdk.service";
         SdksListAccordionComponent,
         SdkSelectDropdownComponent,
         SdkAddModalComponent,
+        SafePipe
     ],
     providers: [
-        AppRoutingProviders,
         {
-            provide: Window,
-            useValue: window
+            provide: LocationStrategy, useClass: HashLocationStrategy,
         },
-        XDSAgentService,
+        AlertService,
         ConfigService,
         ProjectService,
-        AlertService,
-        UtilsService,
         SdkService,
+        UtilsService,
+        XDSAgentService
     ],
     bootstrap: [AppComponent]
 })
 export class AppModule {
+    constructor() { }
 }
diff --git a/webapp/src/app/app.routing.ts b/webapp/src/app/app.routing.ts
deleted file mode 100644 (file)
index f0d808f..0000000
+++ /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/common/safe.pipe.ts b/webapp/src/app/common/safe.pipe.ts
new file mode 100644 (file)
index 0000000..84fd6b5
--- /dev/null
@@ -0,0 +1,10 @@
+import { Pipe, PipeTransform } from '@angular/core';
+import { DomSanitizer } from '@angular/platform-browser';
+
+@Pipe({ name: 'safe' })
+export class SafePipe implements PipeTransform {
+    constructor(private sanitizer: DomSanitizer) { }
+    transform(url) {
+        return this.sanitizer.bypassSecurityTrustResourceUrl(url);
+    }
+}
index 4dbd238..ba3bd72 100644 (file)
@@ -22,7 +22,7 @@
                             <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"></dl-xds-agent>
+                                    <xds-dwnl-agent class="button"></xds-dwnl-agent>
                                 </div>
                             </td>
                         </tr>
@@ -62,7 +62,7 @@
     </div>
     <div class="panel-body" [collapse]="sdksIsCollapsed">
         <div class="row col-xs-12">
-            <sdks-list-accordion [sdks]="(sdks$ | async)"></sdks-list-accordion>
+            <xds-sdks-list-accordion [sdks]="(sdks$ | async)"></xds-sdks-list-accordion>
         </div>
     </div>
 </div>
     </div>
     <div class="panel-body" [collapse]="projectsIsCollapsed">
         <div class="row col-xs-12">
-            <projects-list-accordion [projects]="(projects$ | async)"></projects-list-accordion>
+            <xds-projects-list-accordion [projects]="(projects$ | async)"></xds-projects-list-accordion>
         </div>
     </div>
 </div>
 
 <!-- Modals -->
-<project-add-modal #childProjectModal [title]="'Add a new project'" [server-id]=curServerID>
-</project-add-modal>
-<sdk-add-modal  #childSdkModal [title]="'Add a new SDK'">
-</sdk-add-modal>
+<xds-project-add-modal #childProjectModal [title]="'Add a new project'" [server-id]=curServerID>
+</xds-project-add-modal>
+<xds-sdk-add-modal  #childSdkModal [title]="'Add a new SDK'">
+</xds-sdk-add-modal>
 
 <!-- only for debug -->
 <div *ngIf="false" class="row">
diff --git a/webapp/src/app/config/config.component.spec.ts b/webapp/src/app/config/config.component.spec.ts
new file mode 100644 (file)
index 0000000..ec5d3be
--- /dev/null
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ConfigComponent } from './config.component';
+
+describe('ConfigComponent', () => {
+  let component: ConfigComponent;
+  let fixture: ComponentFixture<ConfigComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ConfigComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ConfigComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
index 6377844..3db7f60 100644 (file)
@@ -1,19 +1,20 @@
-import { Component, ViewChild, OnInit } from "@angular/core";
+import { Component, OnInit, ViewChild, ViewEncapsulation } 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 } from "../services/config.service";
-import { ProjectService, IProject } from "../services/project.service";
-import { XDSAgentService, IAgentStatus, IXDSConfig } from "../services/xdsagent.service";
-import { AlertService } from "../services/alert.service";
-import { ProjectAddModalComponent } from "../projects/projectAddModal.component";
-import { SdkService, ISdk } from "../services/sdk.service";
-import { SdkAddModalComponent } from "../sdks/sdkAddModal.component";
+import { ConfigService, IConfig } from '../services/config.service';
+import { ProjectService, IProject } from '../services/project.service';
+import { XDSAgentService, IAgentStatus, IXDSConfig } from '../services/xdsagent.service';
+import { AlertService } from '../services/alert.service';
+import { ProjectAddModalComponent } from '../projects/projectAddModal.component';
+import { SdkService, ISdk } from '../services/sdk.service';
+import { SdkAddModalComponent } from '../sdks/sdkAddModal.component';
 
 @Component({
-    templateUrl: './app/config/config.component.html',
-    styleUrls: ['./app/config/config.component.css']
+  selector: 'app-config',
+  templateUrl: './config.component.html',
+  styleUrls: ['./config.component.css'],
+  encapsulation: ViewEncapsulation.None
 })
 
 // Inspired from https://embed.plnkr.co/jgDTXknPzAaqcg9XA9zq/
@@ -31,20 +32,20 @@ export class ConfigComponent implements OnInit {
     curProj: number;
     curServer: number;
     curServerID: string;
-    userEditedLabel: boolean = false;
+    userEditedLabel = false;
 
-    gConfigIsCollapsed: boolean = true;
-    sdksIsCollapsed: boolean = true;
-    projectsIsCollapsed: boolean = false;
+    gConfigIsCollapsed = true;
+    sdksIsCollapsed = true;
+    projectsIsCollapsed = false;
 
     // TODO replace by reactive FormControl + add validation
-    xdsServerConnected: boolean = false;
+    xdsServerConnected = false;
     xdsServerUrl: string;
     xdsServerRetry: 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,
+        'retry': false,
+        'rootDir': false,
     };
 
     constructor(
@@ -70,7 +71,7 @@ export class ConfigComponent implements OnInit {
             if (!cfg || cfg.servers.length < 1) {
                 return;
             }
-            let svr = cfg.servers[this.curServer];
+            const svr = cfg.servers[this.curServer];
             this.curServerID = svr.id;
             this.xdsServerConnected = svr.connected;
             this.xdsServerUrl = svr.url;
@@ -81,16 +82,16 @@ export class ConfigComponent implements OnInit {
 
     submitGlobConf(field: string) {
         switch (field) {
-            case "retry":
-                let re = new RegExp('^[0-9]+$');
-                let rr = parseInt(this.xdsServerRetry, 10);
+            case 'retry':
+                const re = new RegExp('^[0-9]+$');
+                const rr = parseInt(this.xdsServerRetry, 10);
                 if (re.test(this.xdsServerRetry) && rr >= 0) {
                     this.xdsAgentSvr.setServerRetry(this.curServerID, rr);
                 } else {
-                    this.alert.warning("Not a valid number", true);
+                    this.alert.warning('Not a valid number', true);
                 }
                 break;
-            case "rootDir":
+            case 'rootDir':
                 this.configSvr.projectsRootDir = this.projectsRootDir;
                 break;
             default:
@@ -100,7 +101,7 @@ export class ConfigComponent implements OnInit {
     }
 
     xdsAgentRestartConn() {
-        let url = this.xdsServerUrl;
+        const url = this.xdsServerUrl;
         this.xdsAgentSvr.setServerUrl(this.curServerID, url);
     }
 
index 0b63e50..3901331 100644 (file)
@@ -1,7 +1,7 @@
-import { Component, Input, Pipe, PipeTransform } from '@angular/core';
+import { Component } from '@angular/core';
 
 @Component({
-    selector: 'dl-xds-agent',
+    selector: 'xds-dwnl-agent',
     template: `
         <template #popTemplate>
             <h3>Install xds-agent:</h3>
@@ -28,20 +28,8 @@ import { Component, Input, Pipe, PipeTransform } from '@angular/core';
     `]
 })
 
-export class DlXdsAgentComponent {
+export class DwnlAgentComponent {
 
-    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;
-    }
+    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';
 }
index 2bcd2c7..0cf0290 100644 (file)
@@ -18,9 +18,9 @@
                             <th>Cross SDK</th>
                             <td>
                                 <!-- FIXME why not working ?
-                        <sdk-select-dropdown [sdks]="(sdks$ | async)"></sdk-select-dropdown>
+                        <xds-sdk-select-dropdown [sdks]="(sdks$ | async)"></xds-sdk-select-dropdown>
                         -->
-                                <sdk-select-dropdown></sdk-select-dropdown>
+                                <xds-sdk-select-dropdown></xds-sdk-select-dropdown>
                             </td>
                         </tr>
                         <tr>
@@ -83,7 +83,6 @@
                         <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>
diff --git a/webapp/src/app/devel/build/build.component.spec.ts b/webapp/src/app/devel/build/build.component.spec.ts
new file mode 100644 (file)
index 0000000..016192c
--- /dev/null
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BuildComponent } from './build.component';
+
+describe('BuildComponent', () => {
+  let component: BuildComponent;
+  let fixture: ComponentFixture<BuildComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ BuildComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(BuildComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
index 87df4e1..49f42eb 100644 (file)
@@ -1,21 +1,21 @@
-import { Component, AfterViewChecked, ElementRef, ViewChild, OnInit, Input } from '@angular/core';
-import { Observable } from 'rxjs';
+import { Component, ViewEncapsulation, AfterViewChecked, ElementRef, ViewChild, OnInit, Input } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
 import { FormControl, FormGroup, Validators, FormBuilder } from '@angular/forms';
 import { CookieService } from 'ngx-cookie';
 
 import 'rxjs/add/operator/scan';
 import 'rxjs/add/operator/startWith';
 
-import { XDSAgentService, ICmdOutput } from "../../services/xdsagent.service";
-import { ProjectService, IProject } from "../../services/project.service";
-import { AlertService, IAlert } from "../../services/alert.service";
-import { SdkService } from "../../services/sdk.service";
+import { XDSAgentService, ICmdOutput } from '../../services/xdsagent.service';
+import { ProjectService, IProject } from '../../services/project.service';
+import { AlertService, IAlert } from '../../services/alert.service';
+import { SdkService } from '../../services/sdk.service';
 
 @Component({
-    selector: 'panel-build',
-    moduleId: module.id,
+    selector: 'xds-panel-build',
     templateUrl: './build.component.html',
-    styleUrls: ['./build.component.css']
+    styleUrls: ['./build.component.css'],
+encapsulation: ViewEncapsulation.None
 })
 
 export class BuildComponent implements OnInit, AfterViewChecked {
@@ -24,9 +24,9 @@ export class BuildComponent implements OnInit, AfterViewChecked {
     @Input() curProject: IProject;
 
     public buildForm: FormGroup;
-    public subpathCtrl = new FormControl("", Validators.required);
-    public debugEnable: boolean = false;
-    public buildIsCollapsed: boolean = false;
+    public subpathCtrl = new FormControl('', Validators.required);
+    public debugEnable = false;
+    public buildIsCollapsed = false;
     public cmdOutput: string;
     public cmdInfo: string;
 
@@ -39,16 +39,16 @@ export class BuildComponent implements OnInit, AfterViewChecked {
         private sdkSvr: SdkService,
         private cookie: CookieService,
     ) {
-        this.cmdOutput = "";
-        this.cmdInfo = "";      // TODO: to be remove (only for debug)
+        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],
+            cmdClean: ['', Validators.nullValidator],
+            cmdPrebuild: ['', Validators.nullValidator],
+            cmdBuild: ['', Validators.nullValidator],
+            cmdPopulate: ['', Validators.nullValidator],
+            cmdArgs: ['', Validators.nullValidator],
+            envVars: ['', Validators.nullValidator],
         });
     }
 
@@ -56,13 +56,13 @@ export class BuildComponent implements OnInit, AfterViewChecked {
         // 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: "",
+            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
@@ -79,14 +79,14 @@ export class BuildComponent implements OnInit, AfterViewChecked {
             }
 
             if (exit && exit.code !== 0) {
-                this.cmdOutput += "--- Command exited with code " + exit.code + " ---\n\n";
+                this.cmdOutput += '--- Command exited with code ' + exit.code + ' ---\n\n';
             }
         });
 
         this._scrollToBottom();
 
         // only use for debug
-        this.debugEnable = (this.cookie.get("debug_build") === "1");
+        this.debugEnable = (this.cookie.get('debug_build') === '1');
     }
 
     ngAfterViewChecked() {
@@ -145,17 +145,17 @@ export class BuildComponent implements OnInit, AfterViewChecked {
             this.alertSvr.warning('No active project', true);
         }
 
-        let prjID = this.curProject.id;
+        const prjID = this.curProject.id;
 
         this.cmdOutput += this._outputHeader();
 
-        let sdkid = this.sdkSvr.getCurrentId();
+        const sdkid = this.sdkSvr.getCurrentId();
 
         // Detect key=value in env string to build array of string
-        let envArr = [];
+        const envArr = [];
         env.split(';').forEach(v => envArr.push(v.trim()));
 
-        let t0 = performance.now();
+        const t0 = performance.now();
         this.cmdInfo = 'Start build of ' + prjID + ' at ' + t0;
 
         this.xdsSvr.exec(prjID, dir, cmd, sdkid, args, envArr)
@@ -168,36 +168,6 @@ export class BuildComponent implements OnInit, AfterViewChecked {
             });
     }
 
-    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;
@@ -205,7 +175,7 @@ export class BuildComponent implements OnInit, AfterViewChecked {
     }
 
     private _computeTime(t0: number, t1?: number): string {
-        let enlap = Math.round((t1 || performance.now()) - t0);
+        const enlap = Math.round((t1 || performance.now()) - t0);
         if (enlap < 1000.0) {
             return enlap.toFixed(2) + ' ms';
         } else {
@@ -214,10 +184,10 @@ export class BuildComponent implements OnInit, AfterViewChecked {
     }
 
     private _outputHeader(): string {
-        return "--- " + new Date().toString() + " ---\n";
+        return '--- ' + new Date().toString() + ' ---\n';
     }
 
     private _outputFooter(): string {
-        return "\n";
+        return '\n';
     }
 }
index cc62889..495eed4 100644 (file)
@@ -30,7 +30,7 @@
 <div class="row">
     <!--<div class="col-md-8">-->
     <div class="col-md-12">
-        <panel-build [curProject]=curPrj></panel-build>
+        <xds-panel-build [curProject]=curPrj></xds-panel-build>
     </div>
     <!-- TODO: disable for now
     <div class="col-md-4">
diff --git a/webapp/src/app/devel/devel.component.spec.ts b/webapp/src/app/devel/devel.component.spec.ts
new file mode 100644 (file)
index 0000000..6483bf5
--- /dev/null
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { DevelComponent } from './devel.component';
+
+describe('DevelComponent', () => {
+  let component: DevelComponent;
+  let fixture: ComponentFixture<DevelComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ DevelComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(DevelComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
index 5c8b9f2..eda03ef 100644 (file)
@@ -1,17 +1,16 @@
-import { Component } from '@angular/core';
+import { Component, OnInit, ViewEncapsulation } from '@angular/core';
+import { Observable } from 'rxjs/Observable';
 
-import { Observable } from 'rxjs';
-
-import { ProjectService, IProject } from "../services/project.service";
+import { ProjectService, IProject } from '../services/project.service';
 
 @Component({
-    selector: 'devel',
-    moduleId: module.id,
+    selector: 'xds-devel',
     templateUrl: './devel.component.html',
     styleUrls: ['./devel.component.css'],
+  encapsulation: ViewEncapsulation.None
 })
 
-export class DevelComponent {
+export class DevelComponent implements OnInit {
 
     curPrj: IProject;
     Prjs$: Observable<IProject[]>;
@@ -23,7 +22,7 @@ export class DevelComponent {
         this.Prjs$ = this.projectSvr.Projects$;
         this.Prjs$.subscribe((prjs) => {
             // Select project if no one is selected or no project exists
-            if (this.curPrj && "id" in this.curPrj) {
+            if (this.curPrj && 'id' in this.curPrj) {
                 this.curPrj = prjs.find(p => p.id === this.curPrj.id) || prjs[0];
             } else if (this.curPrj == null) {
                 this.curPrj = prjs[0];
diff --git a/webapp/src/app/home/home.component.css b/webapp/src/app/home/home.component.css
new file mode 100644 (file)
index 0000000..7831443
--- /dev/null
@@ -0,0 +1,18 @@
+.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;
+}
diff --git a/webapp/src/app/home/home.component.html b/webapp/src/app/home/home.component.html
new file mode 100644 (file)
index 0000000..568fb9b
--- /dev/null
@@ -0,0 +1,13 @@
+<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>
index 0e3c995..66a2f30 100644 (file)
@@ -12,70 +12,35 @@ export interface ISlide {
 }
 
 @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>
-    `
+    selector: 'xds-home',
+    templateUrl: 'home.component.html',
+    styleUrls: ['home.component.css']
 })
 
 export class HomeComponent {
 
-    public carInterval: number = 4000;
+    public carInterval = 4000;
+    public activeSlideIndex = 0;
 
     // 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.",
+            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 !",
+            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>',
+            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 (file)
index 1f68ccc..0000000
+++ /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
index 1352060..0718f4c 100644 (file)
@@ -8,22 +8,22 @@ import 'rxjs/add/operator/map';
 import 'rxjs/add/operator/filter';
 import 'rxjs/add/operator/debounceTime';
 
-import { AlertService, IAlert } from "../services/alert.service";
-import { ProjectService, IProject, ProjectType, ProjectTypes } from "../services/project.service";
+import { AlertService, IAlert } from '../services/alert.service';
+import { ProjectService, IProject, ProjectType, ProjectTypes } from '../services/project.service';
 
 
 @Component({
-    selector: 'project-add-modal',
-    templateUrl: './app/projects/projectAddModal.component.html',
-    styleUrls: ['./app/projects/projectAddModal.component.css']
+    selector: 'xds-project-add-modal',
+    templateUrl: 'projectAddModal.component.html',
+    styleUrls: ['projectAddModal.component.css']
 })
-export class ProjectAddModalComponent {
+export class ProjectAddModalComponent implements OnInit {
     @ViewChild('childProjectModal') public childProjectModal: ModalDirective;
     @Input() title?: string;
     @Input('server-id') serverID: string;
 
-    cancelAction: boolean = false;
-    userEditedLabel: boolean = false;
+    cancelAction = false;
+    userEditedLabel = false;
     projectTypes = ProjectTypes;
 
     addProjectForm: FormGroup;
@@ -37,17 +37,17 @@ export class ProjectAddModalComponent {
         private fb: FormBuilder
     ) {
         // Define types (first one is special/placeholder)
-        this.projectTypes.unshift({ value: ProjectType.UNSET, display: "--Select a type--" });
+        this.projectTypes.unshift({ value: ProjectType.UNSET, display: '--Select a type--' });
 
-        this.typeCtrl = new FormControl(this.projectTypes[0].value, Validators.pattern("[A-Za-z]+"));
-        this.pathCliCtrl = new FormControl("", Validators.required);
-        this.pathSvrCtrl = new FormControl({ value: "", disabled: true }, [Validators.required, Validators.minLength(1)]);
+        this.typeCtrl = new FormControl(this.projectTypes[0].value, Validators.pattern('[A-Za-z]+'));
+        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],
+            label: ['', Validators.nullValidator],
         });
     }
 
@@ -57,15 +57,15 @@ export class ProjectAddModalComponent {
             .debounceTime(100)
             .filter(n => n)
             .map(n => {
-                let last = n.split('/');
+                const last = n.split('/');
                 let nm = n;
                 if (last.length > 0) {
                     nm = last.pop();
-                    if (nm === "" && last.length > 0) {
+                    if (nm === '' && last.length > 0) {
                         nm = last.pop();
                     }
                 }
-                return "Project_" + nm;
+                return 'Project_' + nm;
             })
             .subscribe(value => {
                 if (value && !this.userEditedLabel) {
@@ -77,8 +77,8 @@ export class ProjectAddModalComponent {
         this.typeCtrl.valueChanges
             .debounceTime(500)
             .subscribe(valType => {
-                let dis = (valType === String(ProjectType.SYNCTHING));
-                this.pathSvrCtrl.reset({ value: "", disabled: dis });
+                const dis = (valType === String(ProjectType.SYNCTHING));
+                this.pathSvrCtrl.reset({ value: '', disabled: dis });
             });
     }
 
@@ -93,19 +93,19 @@ export class ProjectAddModalComponent {
     }
 
     onKeyLabel(event: any) {
-        this.userEditedLabel = (this.addProjectForm.value.label !== "");
+        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>
+     <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);
+        console.log('files: ' + dir);
         let u = URL.createObjectURL(e.target.files[0]);
     }
     */
@@ -117,9 +117,9 @@ export class ProjectAddModalComponent {
             return;
         }
 
-        let formVal = this.addProjectForm.value;
+        const formVal = this.addProjectForm.value;
 
-        let type = formVal['type'].value;
+        const type = formVal['type'].value;
         this.projectSvr.Add({
             serverId: this.serverID,
             label: formVal['label'],
@@ -129,12 +129,12 @@ export class ProjectAddModalComponent {
             // FIXME: allow to set defaultSdkID from New Project config panel
         })
             .subscribe(prj => {
-                this.alert.info("Project " + prj.label + " successfully created.");
+                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;
+                const selectedType = this.projectTypes[0].value;
                 this.addProjectForm.patchValue({ type: selectedType });
 
             },
index fdacba4..a28b96c 100644 (file)
@@ -1,9 +1,9 @@
 import { Component, Input, Pipe, PipeTransform } from '@angular/core';
-import { ProjectService, IProject, ProjectType } from "../services/project.service";
-import { AlertService } from "../services/alert.service";
+import { ProjectService, IProject, ProjectType } from '../services/project.service';
+import { AlertService } from '../services/alert.service';
 
 @Component({
-    selector: 'project-card',
+    selector: 'xds-project-card',
     template: `
         <div class="row">
             <div class="col-xs-12">
@@ -44,7 +44,7 @@ import { AlertService } from "../services/alert.service";
             </tbody>
         </table >
     `,
-    styleUrls: ['./app/config/config.component.css']
+    styleUrls: ['../config/config.component.css']
 })
 
 export class ProjectCardComponent {
@@ -61,7 +61,7 @@ export class ProjectCardComponent {
         this.projectSvr.Delete(prj)
             .subscribe(res => {
             }, err => {
-                this.alert.error("Delete ERROR: " + err);
+                this.alert.error('Delete ERROR: ' + err);
             });
     }
 
@@ -69,7 +69,7 @@ export class ProjectCardComponent {
         this.projectSvr.Sync(prj)
             .subscribe(res => {
             }, err => {
-                this.alert.error("ERROR: " + err);
+                this.alert.error('ERROR: ' + err);
             });
     }
 
@@ -83,8 +83,8 @@ export class ProjectCardComponent {
 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)";
+            case ProjectType.NATIVE_PATHMAP: return 'Native (path mapping)';
+            case ProjectType.SYNCTHING: return 'Cloud (Syncthing)';
             default: return String(type);
         }
     }
index 210be5c..0dd2f12 100644 (file)
@@ -1,9 +1,9 @@
-import { Component, Input } from "@angular/core";
+import { Component, Input } from '@angular/core';
 
-import { IProject } from "../services/project.service";
+import { IProject } from '../services/project.service';
 
 @Component({
-    selector: 'projects-list-accordion',
+    selector: 'xds-projects-list-accordion',
     template: `
         <style>
             .fa.fa-exclamation-triangle {
@@ -25,7 +25,7 @@ import { IProject } from "../services/project.service";
                         <i class="fa" [ngClass]="{'fa-chevron-down': group.isOpen, 'fa-chevron-right': !group.isOpen}"></i>
                     </div>
                 </div>
-                <project-card [project]="prj"></project-card>
+                <xds-project-card [project]="prj"></xds-project-card>
             </accordion-group>
         </accordion>
     `
index 2c07fca..44c667e 100644 (file)
@@ -4,7 +4,7 @@
         <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()">
+                <button type="button" class="close pull-right" aria-label="Close" (click)="hide()">
                 <span aria-hidden="true">&times;</span>
                 </button>
             </div>
index b6c8eb2..064f02f 100644 (file)
@@ -2,8 +2,8 @@ import { Component, Input, ViewChild } from '@angular/core';
 import { ModalDirective } from 'ngx-bootstrap/modal';
 
 @Component({
-    selector: 'sdk-add-modal',
-    templateUrl: './app/sdks/sdkAddModal.component.html',
+    selector: 'xds-sdk-add-modal',
+    templateUrl: 'sdkAddModal.component.html',
 })
 export class SdkAddModalComponent {
     @ViewChild('sdkChildModal') public sdkChildModal: ModalDirective;
index 3256a0b..b277887 100644 (file)
@@ -1,8 +1,8 @@
 import { Component, Input } from '@angular/core';
-import { ISdk } from "../services/sdk.service";
+import { ISdk } from '../services/sdk.service';
 
 @Component({
-    selector: 'sdk-card',
+    selector: 'xds-sdk-card',
     template: `
         <div class="row">
             <div class="col-xs-12">
@@ -38,7 +38,7 @@ import { ISdk } from "../services/sdk.service";
             </tbody>
         </table >
     `,
-    styleUrls: ['./app/config/config.component.css']
+    styleUrls: ['../config/config.component.css']
 })
 
 export class SdkCardComponent {
index a2fe37a..7cd2dc7 100644 (file)
@@ -1,9 +1,9 @@
-import { Component, Input } from "@angular/core";
+import { Component, OnInit, Input } from '@angular/core';
 
-import { ISdk, SdkService } from "../services/sdk.service";
+import { ISdk, SdkService } from '../services/sdk.service';
 
 @Component({
-    selector: 'sdk-select-dropdown',
+    selector: 'xds-sdk-select-dropdown',
     template: `
         <div class="btn-group" dropdown *ngIf="curSdk" >
             <button dropdownToggle type="button" class="btn btn-primary dropdown-toggle" style="width: 20em;">
@@ -17,11 +17,11 @@ import { ISdk, SdkService } from "../services/sdk.service";
         </div>
     `
 })
-export class SdkSelectDropdownComponent {
+export class SdkSelectDropdownComponent implements OnInit {
 
     // FIXME investigate to understand why not working with sdks as input
-    // <sdk-select-dropdown [sdks]="(sdks$ | async)"></sdk-select-dropdown>
-    //@Input() sdks: ISdk[];
+    // <xds-sdk-select-dropdown [sdks]="(sdks$ | async)"></xds-sdk-select-dropdown>
+    // @Input() sdks: ISdk[];
     sdks: ISdk[];
 
     curSdk: ISdk;
index 9d5f7e9..73ad182 100644 (file)
@@ -1,9 +1,9 @@
-import { Component, Input } from "@angular/core";
+import { Component, Input } from '@angular/core';
 
-import { ISdk } from "../services/sdk.service";
+import { ISdk } from '../services/sdk.service';
 
 @Component({
-    selector: 'sdks-list-accordion',
+    selector: 'xds-sdks-list-accordion',
     template: `
         <accordion>
             <accordion-group #group *ngFor="let sdk of sdks">
@@ -12,7 +12,7 @@ import { ISdk } from "../services/sdk.service";
                     <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>
+                <xds-sdk-card [sdk]="sdk"></xds-sdk-card>
             </accordion-group>
         </accordion>
     `
diff --git a/webapp/src/app/services/alert.service.spec.ts b/webapp/src/app/services/alert.service.spec.ts
new file mode 100644 (file)
index 0000000..66a8477
--- /dev/null
@@ -0,0 +1,15 @@
+import { TestBed, inject } from '@angular/core/testing';
+
+import { AlertService } from './alert.service';
+
+describe('AlertService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [AlertService]
+    });
+  });
+
+  it('should be created', inject([AlertService], (service: AlertService) => {
+    expect(service).toBeTruthy();
+  }));
+});
index 2978e84..aee5827 100644 (file)
@@ -4,7 +4,7 @@ import { Observable } from 'rxjs/Observable';
 import { Subject } from 'rxjs/Subject';
 
 
-export type AlertType = "danger" | "warning" | "info" | "success";
+export type AlertType = 'danger' | 'warning' | 'info' | 'success';
 
 export interface IAlert {
     type: AlertType;
@@ -22,7 +22,7 @@ export class AlertService {
     private _alerts: IAlert[];
     private alertsSubject = <Subject<IAlert[]>>new Subject();
     private uid = 0;
-    private defaultDissmissTmo = 5; // in seconds
+    private defaultDismissTmo = 5; // in seconds
 
     constructor(private sanitizer: DomSanitizer) {
         this.alerts = this.alertsSubject.asObservable();
@@ -32,20 +32,20 @@ export class AlertService {
 
     public error(msg: string, dismissTime?: number) {
         this.add({
-            type: "danger", msg: msg, dismissible: true, dismissTimeout: dismissTime
+            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) });
+        this.add({ type: 'warning', msg: msg, dismissible: true, dismissTimeout: (dismissible ? this.defaultDismissTmo : 0) });
     }
 
     public info(msg: string) {
-        this.add({ type: "info", msg: msg, dismissible: true, dismissTimeout: this.defaultDissmissTmo });
+        this.add({ type: 'info', msg: msg, dismissible: true, dismissTimeout: this.defaultDismissTmo });
     }
 
     public add(al: IAlert) {
-        let msg = String(al.msg).replace("\n", "<br>");
+        const msg = String(al.msg).replace('\n', '<br>');
         this._alerts.push({
             show: true,
             type: al.type,
@@ -59,7 +59,7 @@ export class AlertService {
     }
 
     public del(al: IAlert) {
-        let idx = this._alerts.findIndex((a) => a.id === al.id);
+        const 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.spec.ts b/webapp/src/app/services/config.service.spec.ts
new file mode 100644 (file)
index 0000000..a20d4ba
--- /dev/null
@@ -0,0 +1,15 @@
+import { TestBed, inject } from '@angular/core/testing';
+
+import { ConfigService } from './config.service';
+
+describe('ConfigService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [ConfigService]
+    });
+  });
+
+  it('should be created', inject([ConfigService], (service: ConfigService) => {
+    expect(service).toBeTruthy();
+  }));
+});
index bbe2fb8..ffe2b45 100644 (file)
@@ -3,10 +3,11 @@ import { CookieService } from 'ngx-cookie';
 import { Observable } from 'rxjs/Observable';
 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
 
-import { AlertService, IAlert } from "../services/alert.service";
-import { UtilsService } from "../services/utils.service";
+import { AlertService, IAlert } from '../services/alert.service';
+import { UtilsService } from '../services/utils.service';
 
 export interface IConfig {
+    language: string;
     projectsRootDir: string;
 }
 
@@ -18,7 +19,7 @@ export class ConfigService {
     private confSubject: BehaviorSubject<IConfig>;
     private confStore: IConfig;
 
-    constructor(private _window: Window,
+    constructor(
         private cookie: CookieService,
         private alert: AlertService,
         private utils: UtilsService,
@@ -31,14 +32,15 @@ export class ConfigService {
     // Load config
     load() {
         // Try to retrieve previous config from cookie
-        let cookConf = this.cookie.getObject("xds-config");
+        const cookConf = this.cookie.getObject('xds-config');
         if (cookConf != null) {
             this.confStore = <IConfig>cookConf;
         } else {
             // Set default config
             this.confStore = {
-                projectsRootDir: "",
-                //projects: []
+                language: 'ENG',
+                projectsRootDir: '',
+                // projects: []
             };
         }
     }
@@ -49,8 +51,8 @@ export class ConfigService {
         this.confSubject.next(Object.assign({}, this.confStore));
 
         // Don't save projects in cookies (too big!)
-        let cfg = Object.assign({}, this.confStore);
-        this.cookie.putObject("xds-config", cfg);
+        const cfg = Object.assign({}, this.confStore);
+        this.cookie.putObject('xds-config', cfg);
     }
 
     set projectsRootDir(p: string) {
index 53adc80..61d8f1c 100644 (file)
@@ -2,25 +2,25 @@ import { Injectable, SecurityContext } from '@angular/core';
 import { Observable } from 'rxjs/Observable';
 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
 
-import { XDSAgentService, IXDSProjectConfig } from "../services/xdsagent.service";
+import { XDSAgentService, IXDSProjectConfig } from '../services/xdsagent.service';
 
 export enum ProjectType {
-    UNSET = "",
-    NATIVE_PATHMAP = "PathMap",
-    SYNCTHING = "CloudSync"
+    UNSET = '',
+    NATIVE_PATHMAP = 'PathMap',
+    SYNCTHING = 'CloudSync'
 }
 
-export var ProjectTypes = [
-    { value: ProjectType.NATIVE_PATHMAP, display: "Path mapping" },
-    { value: ProjectType.SYNCTHING, display: "Cloud Sync" }
+export const 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 const ProjectStatus = {
+    ErrorConfig: 'ErrorConfig',
+    Disable: 'Disable',
+    Enable: 'Enable',
+    Pause: 'Pause',
+    Syncing: 'Syncing'
 };
 
 export interface IProject {
@@ -61,7 +61,7 @@ export class ProjectService {
 
         // Update Project data
         this.xdsSvr.ProjectState$.subscribe(prj => {
-            let i = this._getProjectIdx(prj.id);
+            const i = this._getProjectIdx(prj.id);
             if (i >= 0) {
                 // XXX for now, only isInSync and status may change
                 this._prjsList[i].isInSync = prj.isInSync;
@@ -76,20 +76,20 @@ export class ProjectService {
             if (ev && ev.data && ev.data.id) {
                 this._addProject(ev.data);
             } else {
-                console.log("Warning: received events with unknown data: ev=", ev);
+                console.log('Warning: received events with unknown data: ev=', ev);
             }
         });
         this.xdsSvr.addEventListener('event:project-delete', (ev) => {
             if (ev && ev.data && ev.data.id) {
-                let idx = this._prjsList.findIndex(item => item.id === ev.data.id);
+                const idx = this._prjsList.findIndex(item => item.id === ev.data.id);
                 if (idx === -1) {
-                    console.log("Warning: received events on unknown project id: ev=", ev);
+                    console.log('Warning: received events on unknown project id: ev=', ev);
                     return;
                 }
                 this._prjsList.splice(idx, 1);
                 this.prjsSubject.next(Object.assign([], this._prjsList));
             } else {
-                console.log("Warning: received events with unknown data: ev=", ev);
+                console.log('Warning: received events with unknown data: ev=', ev);
             }
         });
 
@@ -107,14 +107,14 @@ export class ProjectService {
         if (this.current && this.current.id) {
             return this.current.id;
         }
-        return "";
+        return '';
     }
 
     Add(prj: IProject): Observable<IProject> {
-        let xdsPrj: IXDSProjectConfig = {
-            id: "",
+        const xdsPrj: IXDSProjectConfig = {
+            id: '',
             serverId: prj.serverId,
-            label: prj.label || "",
+            label: prj.label || '',
             clientPath: prj.pathClient.trim(),
             serverPath: prj.pathServer,
             type: prj.type,
@@ -122,23 +122,23 @@ export class ProjectService {
         };
         // Send config to XDS server
         return this.xdsSvr.addProject(xdsPrj)
-            .map(xdsPrj => this._convToIProject(xdsPrj));
+            .map(xp => this._convToIProject(xp));
     }
 
     Delete(prj: IProject): Observable<IProject> {
-        let idx = this._getProjectIdx(prj.id);
-        let delPrj = prj;
+        const idx = this._getProjectIdx(prj.id);
+        const delPrj = prj;
         if (idx === -1) {
-            throw new Error("Invalid project id (id=" + prj.id + ")");
+            throw new Error('Invalid project id (id=' + prj.id + ')');
         }
         return this.xdsSvr.deleteProject(prj.id)
-            .map(res => { return delPrj; });
+            .map(res => delPrj);
     }
 
     Sync(prj: IProject): Observable<string> {
-        let idx = this._getProjectIdx(prj.id);
+        const idx = this._getProjectIdx(prj.id);
         if (idx === -1) {
-            throw new Error("Invalid project id (id=" + prj.id + ")");
+            throw new Error('Invalid project id (id=' + prj.id + ')');
         }
         return this.xdsSvr.syncProject(prj.id);
     }
@@ -155,7 +155,7 @@ export class ProjectService {
 
     private _convToIProject(rPrj: IXDSProjectConfig): IProject {
         // Convert XDSFolderConfig to IProject
-        let pp: IProject = {
+        const pp: IProject = {
             id: rPrj.id,
             serverId: rPrj.serverId,
             label: rPrj.label,
@@ -174,7 +174,7 @@ export class ProjectService {
     private _addProject(rPrj: IXDSProjectConfig, noNext?: boolean): IProject {
 
         // Convert XDSFolderConfig to IProject
-        let pp = this._convToIProject(rPrj);
+        const pp = this._convToIProject(rPrj);
 
         // add new project
         this._prjsList.push(pp);
index 6d8a5f6..d492774 100644 (file)
@@ -2,7 +2,7 @@ import { Injectable, SecurityContext } from '@angular/core';
 import { Observable } from 'rxjs/Observable';
 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
 
-import { XDSAgentService } from "../services/xdsagent.service";
+import { XDSAgentService } from '../services/xdsagent.service';
 
 export interface ISdk {
     id: string;
@@ -29,7 +29,7 @@ export class SdkService {
                 return;
             }
             // FIXME support multiple server
-            //cfg.servers.forEach(svr => {
+            // cfg.servers.forEach(svr => {
             this.xdsSvr.getSdks(cfg.servers[0].id).subscribe((s) => {
                 this._sdksList = s;
                 this.sdksSubject.next(s);
@@ -49,6 +49,6 @@ export class SdkService {
         if (this.current && this.current.id) {
             return this.current.id;
         }
-        return "";
+        return '';
     }
 }
index 84b9ab6..e665e2a 100644 (file)
@@ -5,29 +5,29 @@ 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";
+        const 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 "";
+            return '';
         };
 
         let OSName = checkField(navigator.platform);
-        if (OSName === "") {
+        if (OSName === '') {
             OSName = checkField(navigator.appVersion);
         }
-        if (OSName === "") {
-            OSName = "Unknown OS";
+        if (OSName === '') {
+            OSName = 'Unknown OS';
         }
         if (lowerCase) {
             return OSName.toLowerCase();
         }
         return OSName;
     }
-}
\ No newline at end of file
+}
index c4f2787..23880ff 100644 (file)
@@ -1,6 +1,6 @@
-import { Injectable } from '@angular/core';
-import { Http, Headers, RequestOptionsArgs, Response } from '@angular/http';
-import { Location } from '@angular/common';
+import { Injectable, Inject } from '@angular/core';
+import { HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
+import { DOCUMENT } from '@angular/common';
 import { Observable } from 'rxjs/Observable';
 import { Subject } from 'rxjs/Subject';
 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
@@ -8,7 +8,7 @@ import * as io from 'socket.io-client';
 
 import { AlertService } from './alert.service';
 import { ISdk } from './sdk.service';
-import { ProjectType} from "./project.service";
+import { ProjectType } from './project.service';
 
 // Import RxJs required methods
 import 'rxjs/add/operator/map';
@@ -115,14 +115,16 @@ export class XDSAgentService {
 
     private socket: SocketIOClient.Socket;
 
-    constructor(private http: Http, private _window: Window, private alert: AlertService) {
+    constructor( @Inject(DOCUMENT) private document: Document,
+        private http: HttpClient, private alert: AlertService) {
 
         this.XdsConfig$ = this.configSubject.asObservable();
         this.Status$ = this.statusSubject.asObservable();
 
-        this.baseUrl = this._window.location.origin + '/api/v1';
+        const originUrl = this.document.location.origin;
+        this.baseUrl = originUrl + '/api/v1';
 
-        let re = this._window.location.origin.match(/http[s]?:\/\/([^\/]*)[\/]?/);
+        const re = originUrl.match(/http[s]?:\/\/([^\/]*)[\/]?/);
         if (re === null || re.length < 2) {
             console.error('ERROR: cannot determine Websocket url');
         } else {
@@ -188,8 +190,8 @@ export class XDSAgentService {
         // (project-add and project-delete events are managed by project.service)
         this.socket.on('event:server-config', ev => {
             if (ev && ev.data) {
-                let cfg: IXDServerCfg = ev.data;
-                let idx = this._config.servers.findIndex(el => el.id === cfg.id);
+                const cfg: IXDServerCfg = ev.data;
+                const idx = this._config.servers.findIndex(el => el.id === cfg.id);
                 if (idx >= 0) {
                     this._config.servers[idx] = Object.assign({}, cfg);
                 }
@@ -231,7 +233,7 @@ export class XDSAgentService {
     }
 
     setServerRetry(serverID: string, r: number) {
-        let svr = this._getServer(serverID);
+        const svr = this._getServer(serverID);
         if (!svr) {
             return Observable.of([]);
         }
@@ -249,7 +251,7 @@ export class XDSAgentService {
     }
 
     setServerUrl(serverID: string, url: string) {
-        let svr = this._getServer(serverID);
+        const svr = this._getServer(serverID);
         if (!svr) {
             return Observable.of([]);
         }
@@ -269,7 +271,7 @@ export class XDSAgentService {
     ** SDKs
     ***/
     getSdks(serverID: string): Observable<ISdk[]> {
-        let svr = this._getServer(serverID);
+        const svr = this._getServer(serverID);
         if (!svr || !svr.connected) {
             return Observable.of([]);
         }
@@ -305,42 +307,29 @@ export class XDSAgentService {
                 id: prjID,
                 rpath: dir,
                 cmd: cmd,
-                sdkID: sdkid || "",
+                sdkID: sdkid || '',
                 args: args || [],
                 env: env || [],
             });
     }
 
-    make(prjID: string, dir: string, sdkid?: string, args?: string[], env?: string[]): Observable<any> {
-        // SEB TODO add serverID
-        return this._post('/make',
-            {
-                id: prjID,
-                rpath: dir,
-                sdkID: sdkid,
-                args: args || [],
-                env: env || [],
-            });
-    }
-
-
     /**
     ** Private functions
     ***/
 
     private _RegisterEvents() {
         // Register to all existing events
-        this._post('/events/register', { "name": "event:all" })
+        this._post('/events/register', { 'name': 'event:all' })
             .subscribe(
             res => { },
             error => {
-                this.alert.error("ERROR while registering to all events: ", error);
+                this.alert.error('ERROR while registering to all events: ', error);
             }
             );
     }
 
     private _getServer(ID: string): IXDServerCfg {
-        let svr = this._config.servers.filter(item => item.id === ID);
+        const svr = this._config.servers.filter(item => item.id === ID);
         if (svr.length < 1) {
             return null;
         }
@@ -349,7 +338,7 @@ export class XDSAgentService {
 
     private _attachAuthHeaders(options?: any) {
         options = options || {};
-        let headers = options.headers || new Headers();
+        const headers = options.headers || new HttpHeaders();
         // headers.append('Authorization', 'Basic ' + btoa('username:password'));
         headers.append('Accept', 'application/json');
         headers.append('Content-Type', 'application/json');
@@ -361,31 +350,24 @@ export class XDSAgentService {
 
     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() || 'Agent error';
-            e = body.error || JSON.stringify(body);
-            if (!e || e === "" || e === '{"isTrusted":true}') {
-                e = `${err.status} - ${err.statusText || 'Unknown error'}`;
-            }
-        } else if (typeof err === "object") {
+        if (err instanceof HttpErrorResponse) {
+            e = err.error || err.message || 'Unknown error';
+        } else if (typeof err === 'object') {
             if (err.statusText) {
                 e = err.statusText;
             } else if (err.error) {
diff --git a/webapp/src/assets/css/main.css b/webapp/src/assets/css/main.css
new file mode 100644 (file)
index 0000000..4a42c83
--- /dev/null
@@ -0,0 +1,5 @@
+html,
+body {
+    height: 100%;
+    margin: 0 auto;
+}
diff --git a/webapp/src/assets/i18n/en.json b/webapp/src/assets/i18n/en.json
new file mode 100644 (file)
index 0000000..c5f242c
--- /dev/null
@@ -0,0 +1,33 @@
+{
+    "LOGIN": {
+        "EMAIL": "Email",
+        "PASSWORD": "Password",
+        "SUBMIT_LOGIN": "Login"
+    },
+    "HOME": {
+        "TITLE": "Welcome"
+    },
+    "MENUBAR": {
+        "HOME": "Home",
+        "BUILD": "Build"
+    },
+    "SETTINGS": {
+        "HOME": {
+            "TITLE": "Settings"
+        }
+    },
+    "EVENT_EMMITER": {
+        "SEL_LANG": "Select Language"
+    },
+    "POPUP": {
+        "CONFIRM": "Confirm switching user",
+        "CANCEL": "Cancel",
+        "TIME-LEFT": "Time left",
+        "SECONDS": "seconds"
+    },
+    "TOOLTIP": {
+        "PROJECTS": {
+            "NEW": "new project successfully created"
+        }
+    }
+}
diff --git a/webapp/src/assets/i18n/fr.json b/webapp/src/assets/i18n/fr.json
new file mode 100644 (file)
index 0000000..c2b4fb6
--- /dev/null
@@ -0,0 +1,33 @@
+{
+    "LOGIN": {
+        "EMAIL": "Email",
+        "PASSWORD": "Mot de Passe",
+        "SUBMIT_LOGIN": "S'identifier"
+    },
+    "HOME": {
+        "TITLE": "Bienvenue"
+    },
+    "MENUBAR": {
+        "HOME": "Accueil",
+        "BUILD": "Build"
+    },
+    "SETTINGS": {
+        "HOME": {
+            "TITLE": "Paramètres"
+        }
+    },
+    "EVENT_EMMITER": {
+        "SEL_LANG": "Selection de la langue"
+    },
+    "POPUP": {
+        "CONFIRM": "Confirmer le changement de compte",
+        "CANCEL": "Annuler",
+        "TIME-LEFT": "Temps restant",
+        "SECONDS": "secondes"
+    },
+    "TOOLTIP": {
+        "PROJECTS": {
+            "NEW": "un nouveau projet a Ã©té créé"
+        }
+    }
+}
diff --git a/webapp/src/environments/environment.prod.ts b/webapp/src/environments/environment.prod.ts
new file mode 100644 (file)
index 0000000..86bb4ef
--- /dev/null
@@ -0,0 +1,6 @@
+export const environment = {
+    production: true,
+    maxConnectionRetry: 10,
+
+    debug: false,                // enable console.debug statements
+};
diff --git a/webapp/src/environments/environment.ts b/webapp/src/environments/environment.ts
new file mode 100644 (file)
index 0000000..c09231e
--- /dev/null
@@ -0,0 +1,6 @@
+export const environment = {
+    production: false,
+    maxConnectionRetry: 10,
+
+    debug: true,                // enable console.debug statements
+};
index 290b4be..ca8176f 100644 (file)
@@ -1,50 +1,24 @@
+<!doctype html>
 <html>
-
 <head>
-    <title>
-        XDS Dashboard
-    </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="lib/font-awesome/css/font-awesome.min.css">
-    <link rel="stylesheet" href="lib/font-awesome-animation/dist/font-awesome-animation.min.css">
+  <meta charset="utf-8">
+  <title>XDS Dashboard</title>
+  <base href="/">
 
-    <!-- 1. Load libraries -->
-    <!-- Polyfill(s) for older browsers -->
-    <script src="lib/core-js/client/shim.min.js"></script>
-
-    <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>
-
-    <!-- 2. Configure SystemJS -->
-    <script src="systemjs.config.js"></script>
-    <script>
-        System.import('app')
-            .then(null, console.error.bind(console));
-    </script>
-
-    <script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
+  <meta name="viewport" content="width=device-width, initial-scale=1">
+  <link rel="icon" type="image/x-icon" href="assets/favicon.ico">
 
+  <link rel="stylesheet" href="./assets/css/main.css">
 </head>
 
-<!-- 3. Display the application -->
-
 <body style="padding-top: 70px;">   <!-- padding needed due to fixed navbar -->
-    <app>
+    <app-root>
         <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>
+    </app-root>
 </body>
 
 </html>
diff --git a/webapp/src/main.ts b/webapp/src/main.ts
new file mode 100644 (file)
index 0000000..401abe5
--- /dev/null
@@ -0,0 +1,11 @@
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+    enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/webapp/src/polyfills.ts b/webapp/src/polyfills.ts
new file mode 100644 (file)
index 0000000..7831e97
--- /dev/null
@@ -0,0 +1,72 @@
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ *      file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE9, IE10 and IE11 requires all of the following polyfills. **/
+// import 'core-js/es6/symbol';
+// import 'core-js/es6/object';
+// import 'core-js/es6/function';
+// import 'core-js/es6/parse-int';
+// import 'core-js/es6/parse-float';
+// import 'core-js/es6/number';
+// import 'core-js/es6/math';
+// import 'core-js/es6/string';
+// import 'core-js/es6/date';
+// import 'core-js/es6/array';
+// import 'core-js/es6/regexp';
+// import 'core-js/es6/map';
+// import 'core-js/es6/weak-map';
+// import 'core-js/es6/set';
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js';  // Run `npm install --save classlist.js`.
+
+/** Evergreen browsers require these. **/
+import 'core-js/es6/reflect';
+import 'core-js/es7/reflect';
+
+
+/**
+ * Required to support Web Animations `@angular/animation`.
+ * Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
+ **/
+// import 'web-animations-js';  // Run `npm install --save web-animations-js`.
+
+
+
+/***************************************************************************************************
+ * Zone JS is required by Angular itself.
+ */
+import 'zone.js/dist/zone';  // Included with Angular CLI.
+
+
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
+
+/**
+ * Date, currency, decimal and percent pipes.
+ * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
+ */
+// import 'intl';  // Run `npm install --save intl`.
+/**
+ * Need to import at least one locale-data with intl.
+ */
+// import 'intl/locale-data/jsonp/en';
diff --git a/webapp/src/styles.css b/webapp/src/styles.css
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/webapp/src/systemjs.config.js b/webapp/src/systemjs.config.js
deleted file mode 100644 (file)
index 15c52ba..0000000
+++ /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);
diff --git a/webapp/src/tsconfig.app.json b/webapp/src/tsconfig.app.json
new file mode 100644 (file)
index 0000000..39ba8db
--- /dev/null
@@ -0,0 +1,13 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/app",
+    "baseUrl": "./",
+    "module": "es2015",
+    "types": []
+  },
+  "exclude": [
+    "test.ts",
+    "**/*.spec.ts"
+  ]
+}
diff --git a/webapp/src/tsconfig.spec.json b/webapp/src/tsconfig.spec.json
new file mode 100644 (file)
index 0000000..63d89ff
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/spec",
+    "baseUrl": "./",
+    "module": "commonjs",
+    "target": "es5",
+    "types": [
+      "jasmine",
+      "node"
+    ]
+  },
+  "files": [
+    "test.ts"
+  ],
+  "include": [
+    "**/*.spec.ts",
+    "**/*.d.ts"
+  ]
+}
index 9bad681..0fdb5c8 100644 (file)
@@ -1,18 +1,19 @@
 {
+  "compileOnSave": false,
   "compilerOptions": {
-    "outDir": "dist/app",
-    "target": "es5",
-    "module": "commonjs",
-    "moduleResolution": "node",
+    "outDir": "./dist/out-tsc",
     "sourceMap": true,
+    "declaration": false,
+    "moduleResolution": "node",
     "emitDecoratorMetadata": true,
     "experimentalDecorators": true,
-    "removeComments": false,
-    "noImplicitAny": false,
-    "noStrictGenericChecks": true   // better to switch to RxJS 5.4.2 ; workaround https://stackoverflow.com/questions/44810195/how-do-i-get-around-this-subject-incorrectly-extends-observable-error-in-types
-  },
-  "exclude": [
-    "gulpfile.ts",
-    "node_modules"
-  ]
-}
+    "target": "es5",
+    "typeRoots": [
+      "node_modules/@types"
+    ],
+    "lib": [
+      "es2017",
+      "dom"
+    ]
+  }
+}
\ No newline at end of file
index 15969a4..22f2336 100644 (file)
 {
-  "rules": {
-    "class-name": true,
-    "curly": true,
-    "eofline": false,
-    "forin": true,
-    "indent": [
-      true,
-      4
+    "rulesDirectory": [
+        "node_modules/codelyzer"
     ],
-    "label-position": true,
-    "max-line-length": [
-      true,
-      140
-    ],
-    "no-arg": true,
-    "no-bitwise": true,
-    "no-console": [
-      true,
-      "info",
-      "time",
-      "timeEnd",
-      "trace"
-    ],
-    "no-construct": true,
-    "no-debugger": true,
-    "no-duplicate-variable": true,
-    "no-empty": false,
-    "no-eval": true,
-    "no-string-literal": false,
-    "no-trailing-whitespace": true,
-    "no-use-before-declare": true,
-    "one-line": [
-      true,
-      "check-open-brace",
-      "check-catch",
-      "check-else",
-      "check-whitespace"
-    ],
-    "radix": true,
-    "semicolon": true,
-    "triple-equals": [
-      true,
-      "allow-null-check"
-    ],
-    "variable-name": false,
-    "whitespace": [
-      true,
-      "check-branch",
-      "check-decl",
-      "check-operator",
-      "check-separator"
-    ]
-  }
+    "rules": {
+        "arrow-return-shorthand": true,
+        "callable-types": true,
+        "class-name": true,
+        "comment-format": [
+            true,
+            "check-space"
+        ],
+        "curly": true,
+        "eofline": true,
+        "forin": true,
+        "import-blacklist": [
+            true,
+            "rxjs"
+        ],
+        "import-spacing": true,
+        "indent": [
+            true,
+            "spaces"
+        ],
+        "interface-over-type-literal": true,
+        "label-position": true,
+        "max-line-length": [
+            true,
+            140
+        ],
+        "member-access": false,
+        "member-ordering": [
+            true,
+            {
+                "order": [
+                    "static-field",
+                    "instance-field",
+                    "static-method",
+                    "instance-method"
+                ]
+            }
+        ],
+        "no-arg": true,
+        "no-bitwise": true,
+        "no-console": [
+            true,
+            "debug",
+            "info",
+            "time",
+            "timeEnd",
+            "trace"
+        ],
+        "no-construct": true,
+        "no-debugger": true,
+        "no-duplicate-super": true,
+        "no-empty": false,
+        "no-empty-interface": true,
+        "no-eval": true,
+        "no-inferrable-types": [
+            true,
+            "ignore-params"
+        ],
+        "no-misused-new": true,
+        "no-non-null-assertion": true,
+        "no-shadowed-variable": true,
+        "no-string-literal": false,
+        "no-string-throw": true,
+        "no-switch-case-fall-through": true,
+        "no-trailing-whitespace": true,
+        "no-unnecessary-initializer": true,
+        "no-unused-expression": true,
+        "no-use-before-declare": true,
+        "no-var-keyword": true,
+        "object-literal-sort-keys": false,
+        "one-line": [
+            true,
+            "check-open-brace",
+            "check-catch",
+            "check-else",
+            "check-whitespace"
+        ],
+        "prefer-const": true,
+        "quotemark": [
+            true,
+            "single"
+        ],
+        "radix": true,
+        "semicolon": [
+            true,
+            "always"
+        ],
+        "triple-equals": [
+            true,
+            "allow-null-check"
+        ],
+        "typedef-whitespace": [
+            true,
+            {
+                "call-signature": "nospace",
+                "index-signature": "nospace",
+                "parameter": "nospace",
+                "property-declaration": "nospace",
+                "variable-declaration": "nospace"
+            }
+        ],
+        "typeof-compare": true,
+        "unified-signatures": true,
+        "variable-name": false,
+        "whitespace": [
+            true,
+            "check-branch",
+            "check-decl",
+            "check-operator",
+            "check-separator",
+            "check-type"
+        ],
+        "directive-selector": [
+            true,
+            "attribute",
+            "app",
+            "camelCase"
+        ],
+        "component-selector": [
+            true,
+            "element",
+            ["app", "xds"],
+            "kebab-case"
+        ],
+        "use-input-property-decorator": true,
+        "use-output-property-decorator": true,
+        "use-host-property-decorator": true,
+        "no-input-rename": false,
+        "no-output-rename": false,
+        "use-life-cycle-interface": true,
+        "use-pipe-transform-interface": true,
+        "component-class-suffix": true,
+        "directive-class-suffix": true,
+        "no-access-missing-member": true,
+        "templates-use-public": true,
+        "invoke-injectable": true
+    }
 }
diff --git a/webapp/tslint.prod.json b/webapp/tslint.prod.json
deleted file mode 100644 (file)
index aa64c7f..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-{
-  "rules": {
-    "class-name": true,
-    "curly": true,
-    "eofline": false,
-    "forin": true,
-    "indent": [
-      true,
-      4
-    ],
-    "label-position": true,
-    "max-line-length": [
-      true,
-      140
-    ],
-    "no-arg": true,
-    "no-bitwise": true,
-    "no-console": [
-      true,
-      "debug",
-      "info",
-      "time",
-      "timeEnd",
-      "trace"
-    ],
-    "no-construct": true,
-    "no-debugger": true,
-    "no-duplicate-variable": true,
-    "no-empty": false,
-    "no-eval": true,
-    "no-string-literal": false,
-    "no-trailing-whitespace": true,
-    "no-use-before-declare": true,
-    "one-line": [
-      true,
-      "check-open-brace",
-      "check-catch",
-      "check-else",
-      "check-whitespace"
-    ],
-    "radix": true,
-    "semicolon": true,
-    "triple-equals": [
-      true,
-      "allow-null-check"
-    ],
-    "variable-name": false,
-    "whitespace": [
-      true,
-      "check-branch",
-      "check-decl",
-      "check-operator",
-      "check-separator"
-    ]
-  }
-}