diff --git a/dashboard/.editorconfig b/dashboard/.editorconfig
new file mode 100644
index 0000000..b8a6e57
--- /dev/null
+++ b/dashboard/.editorconfig
@@ -0,0 +1,19 @@
+# http://editorconfig.org
+root = true
+
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+
+[*.md]
+max_line_length = 0
+trim_trailing_whitespace = false
+
+# Indentation override
+#[lib/**.js]
+#[{package.json,.travis.yml}]
+#[**/**.js]
diff --git a/dashboard/.gitignore b/dashboard/.gitignore
new file mode 100644
index 0000000..c9c982d
--- /dev/null
+++ b/dashboard/.gitignore
@@ -0,0 +1,3 @@
+src/app/**/*.js.map
+src/app/**/*.js
+node_modules/
\ No newline at end of file
diff --git a/dashboard/bs-config.json b/dashboard/bs-config.json
new file mode 100644
index 0000000..4e58595
--- /dev/null
+++ b/dashboard/bs-config.json
@@ -0,0 +1,8 @@
+{
+ "server": {
+ "baseDir": "src",
+ "routes": {
+ "/node_modules": "node_modules"
+ }
+ }
+}
diff --git a/dashboard/package.json b/dashboard/package.json
new file mode 100644
index 0000000..df18ef0
--- /dev/null
+++ b/dashboard/package.json
@@ -0,0 +1,63 @@
+{
+ "name": "angular-quickstart",
+ "version": "1.0.0",
+ "description": "QuickStart package.json from the documentation, supplemented with testing support",
+ "scripts": {
+ "build": "tsc -p src/",
+ "build:watch": "tsc -p src/ -w",
+ "build:e2e": "tsc -p e2e/",
+ "serve": "lite-server -c=bs-config.json",
+ "serve:e2e": "lite-server -c=bs-config.e2e.json",
+ "prestart": "npm run build",
+ "start": "concurrently \"npm run build:watch\" \"npm run serve\"",
+ "pree2e": "npm run build:e2e",
+ "e2e": "concurrently \"npm run serve:e2e\" \"npm run protractor\" --kill-others --success first",
+ "preprotractor": "webdriver-manager update",
+ "protractor": "protractor protractor.config.js",
+ "pretest": "npm run build",
+ "test": "concurrently \"npm run build:watch\" \"karma start karma.conf.js\"",
+ "pretest:once": "npm run build",
+ "test:once": "karma start karma.conf.js --single-run",
+ "lint": "tslint ./src/**/*.ts -t verbose"
+ },
+ "keywords": [],
+ "author": "",
+ "license": "MIT",
+ "dependencies": {
+ "@angular/common": "~4.0.0",
+ "@angular/compiler": "~4.0.0",
+ "@angular/core": "~4.0.0",
+ "@angular/forms": "~4.0.0",
+ "@angular/http": "~4.0.0",
+ "@angular/platform-browser": "~4.0.0",
+ "@angular/platform-browser-dynamic": "~4.0.0",
+ "@angular/router": "~4.0.0",
+
+ "angular-in-memory-web-api": "~0.3.0",
+ "systemjs": "0.19.40",
+ "core-js": "^2.4.1",
+ "rxjs": "5.0.1",
+ "zone.js": "^0.8.4"
+ },
+ "devDependencies": {
+ "concurrently": "^3.2.0",
+ "lite-server": "^2.2.2",
+ "typescript": "~2.1.0",
+
+ "canonical-path": "0.0.2",
+ "tslint": "^3.15.1",
+ "lodash": "^4.16.4",
+ "jasmine-core": "~2.4.1",
+ "karma": "^1.3.0",
+ "karma-chrome-launcher": "^2.0.0",
+ "karma-cli": "^1.0.1",
+ "karma-jasmine": "^1.0.2",
+ "karma-jasmine-html-reporter": "^0.2.2",
+ "protractor": "~4.0.14",
+ "rimraf": "^2.5.4",
+
+ "@types/node": "^6.0.46",
+ "@types/jasmine": "2.5.36"
+ },
+ "repository": {}
+}
diff --git a/dashboard/src/app/app-routing.module.ts b/dashboard/src/app/app-routing.module.ts
new file mode 100644
index 0000000..73f447f
--- /dev/null
+++ b/dashboard/src/app/app-routing.module.ts
@@ -0,0 +1,20 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { DashboardComponent } from './dashboard.component';
+import { HeroesComponent } from './heroes.component';
+import { HeroDetailComponent } from './hero-detail.component';
+
+const routes: Routes = [
+ { path: '', redirectTo: '/dashboard', pathMatch: 'full' },
+ { path: 'dashboard', component: DashboardComponent },
+ { path: 'detail/:id', component: HeroDetailComponent },
+ { path: 'heroes', component: HeroesComponent }
+];
+
+@NgModule({
+ imports: [ RouterModule.forRoot(routes) ],
+ exports: [ RouterModule ]
+})
+
+export class AppRoutingModule {}
diff --git a/dashboard/src/app/app.component.css b/dashboard/src/app/app.component.css
new file mode 100644
index 0000000..7bf5317
--- /dev/null
+++ b/dashboard/src/app/app.component.css
@@ -0,0 +1,33 @@
+h1 {
+ font-size: 1.2em;
+ color: #999;
+ margin-bottom: 0;
+}
+
+h2 {
+ font-size: 2em;
+ margin-top: 0;
+ padding-top: 0;
+}
+
+nav a {
+ padding: 5px 10px;
+ text-decoration: none;
+ margin-top: 10px;
+ display: inline-block;
+ background-color: #eee;
+ border-radius: 4px;
+}
+
+nav a:visited, a:link {
+ color: #607D8B;
+}
+
+nav a:hover {
+ color: #039be5;
+ background-color: #CFD8DC;
+}
+
+nav a.active {
+ color: #039be5;
+}
diff --git a/dashboard/src/app/app.component.ts b/dashboard/src/app/app.component.ts
new file mode 100644
index 0000000..fb04804
--- /dev/null
+++ b/dashboard/src/app/app.component.ts
@@ -0,0 +1,18 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'my-app',
+ template: `
+
{{title}}
+
+
+ `,
+ styleUrls: [ './app.component.css' ]
+})
+
+export class AppComponent {
+ title = 'Tour of Heroes';
+}
\ No newline at end of file
diff --git a/dashboard/src/app/app.module.ts b/dashboard/src/app/app.module.ts
new file mode 100644
index 0000000..68e67ec
--- /dev/null
+++ b/dashboard/src/app/app.module.ts
@@ -0,0 +1,37 @@
+import { NgModule } from '@angular/core';
+import { BrowserModule } from '@angular/platform-browser';
+import { FormsModule } from '@angular/forms'
+import { HttpModule } from '@angular/http'
+
+// Imports for loading & configuring the in-memory web api
+import { InMemoryWebApiModule } from 'angular-in-memory-web-api';
+import { InMemoryDataService } from './in-memory-data.service';
+
+import { AppComponent } from './app.component';
+import { HeroDetailComponent } from './hero-detail.component';
+import { HeroesComponent } from './heroes.component';
+import { HeroService } from './hero.service';
+import { DashboardComponent } from './dashboard.component'
+
+import { AppRoutingModule } from './app-routing.module'
+
+@NgModule({
+ imports: [
+ BrowserModule,
+ FormsModule,
+ HttpModule,
+ InMemoryWebApiModule.forRoot(InMemoryDataService),
+ AppRoutingModule
+ ],
+ declarations: [
+ AppComponent,
+ HeroDetailComponent,
+ HeroesComponent,
+ DashboardComponent
+ ],
+ providers: [
+ HeroService
+ ],
+ bootstrap: [ AppComponent ]
+})
+export class AppModule { }
diff --git a/dashboard/src/app/dashboard.component.css b/dashboard/src/app/dashboard.component.css
new file mode 100644
index 0000000..07bb407
--- /dev/null
+++ b/dashboard/src/app/dashboard.component.css
@@ -0,0 +1,74 @@
+[class*='col-'] {
+ float: left;
+ padding-right: 20px;
+ padding-bottom: 20px;
+}
+
+[class*='col-']:last-of-type {
+ padding-right: 0;
+}
+
+a {
+ text-decoration: none;
+}
+
+*, *:after, *:before {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+
+h3 {
+ text-align: center; margin-bottom: 0;
+}
+
+h4 {
+ position: relative;
+}
+
+.grid {
+ margin: 0;
+}
+
+.col-1-4 {
+ width: 25%;
+}
+
+.module {
+ padding: 20px;
+ text-align: center;
+ color: #eee;
+ max-height: 120px;
+ min-width: 120px;
+ background-color: #607D8B;
+ border-radius: 2px;
+}
+
+.module:hover {
+ background-color: #EEE;
+ cursor: pointer;
+ color: #607d8b;
+}
+
+.grid-pad {
+ padding: 10px 0;
+}
+
+.grid-pad > [class*='col-']:last-of-type {
+ padding-right: 20px;
+}
+
+@media (max-width: 600px) {
+ .module {
+ font-size: 10px;
+ max-height: 75px; }
+}
+
+@media (max-width: 1024px) {
+ .grid {
+ margin: 0;
+ }
+ .module {
+ min-width: 60px;
+ }
+}
diff --git a/dashboard/src/app/dashboard.component.html b/dashboard/src/app/dashboard.component.html
new file mode 100644
index 0000000..8c916a4
--- /dev/null
+++ b/dashboard/src/app/dashboard.component.html
@@ -0,0 +1,8 @@
+Top Heroes
+
\ No newline at end of file
diff --git a/dashboard/src/app/dashboard.component.ts b/dashboard/src/app/dashboard.component.ts
new file mode 100644
index 0000000..2af59e3
--- /dev/null
+++ b/dashboard/src/app/dashboard.component.ts
@@ -0,0 +1,21 @@
+import { Component, OnInit } from '@angular/core';
+
+import { Hero } from './hero'
+import { HeroService } from './hero.service'
+
+@Component({
+ selector: 'my-dashboard',
+ templateUrl: './dashboard.component.html',
+ styleUrls: [ './dashboard.component.css' ]
+})
+
+export class DashboardComponent implements OnInit {
+ heroes: Hero[] = [];
+
+ constructor(private heroService: HeroService) { }
+
+ ngOnInit(): void {
+ this.heroService.getHeroes()
+ .then(heroes => this.heroes = heroes.slice(1,5));
+ }
+}
\ No newline at end of file
diff --git a/dashboard/src/app/hero-detail.component.css b/dashboard/src/app/hero-detail.component.css
new file mode 100644
index 0000000..bf3f77a
--- /dev/null
+++ b/dashboard/src/app/hero-detail.component.css
@@ -0,0 +1,33 @@
+label {
+ display: inline-block;
+ width: 3em;
+ margin: .5em 0;
+ color: #607D8B;
+ font-weight: bold;
+}
+
+input {
+ height: 2em;
+ font-size: 1em;
+ padding-left: .4em;
+}
+
+button {
+ margin-top: 20px;
+ font-family: Arial;
+ background-color: #eee;
+ border: none;
+ padding: 5px 10px;
+ border-radius: 4px;
+ cursor: pointer; cursor: hand;
+}
+
+button:hover {
+ background-color: #cfd8dc;
+}
+
+button:disabled {
+ background-color: #eee;
+ color: #ccc;
+ cursor: auto;
+}
diff --git a/dashboard/src/app/hero-detail.component.html b/dashboard/src/app/hero-detail.component.html
new file mode 100644
index 0000000..119ec12
--- /dev/null
+++ b/dashboard/src/app/hero-detail.component.html
@@ -0,0 +1,11 @@
+
+
{{hero.name}} details!
+
+ {{hero.id}}
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/src/app/hero-detail.component.ts b/dashboard/src/app/hero-detail.component.ts
new file mode 100644
index 0000000..f5a9a28
--- /dev/null
+++ b/dashboard/src/app/hero-detail.component.ts
@@ -0,0 +1,37 @@
+import 'rxjs/add/operator/switchMap';
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute, Params } from '@angular/router'
+import { Location } from '@angular/common'
+
+import { HeroService } from './hero.service'
+import { Hero } from './hero';
+
+@Component({
+ selector: 'hero-detail',
+ templateUrl: './hero-detail.component.html'
+})
+
+export class HeroDetailComponent implements OnInit {
+ hero: Hero;
+
+ constructor(
+ private heroService: HeroService,
+ private route: ActivatedRoute,
+ private location: Location
+ ) { }
+
+ ngOnInit(): void {
+ this.route.params
+ .switchMap((params: Params) => this.heroService.getHero(+params['id']))
+ .subscribe(hero => this.hero = hero);
+ }
+
+ save(): void {
+ this.heroService.update(this.hero)
+ .then(() => this.goBack());
+ }
+
+ goBack(): void {
+ this.location.back();
+ }
+}
\ No newline at end of file
diff --git a/dashboard/src/app/hero.service.ts b/dashboard/src/app/hero.service.ts
new file mode 100644
index 0000000..4f7c0d9
--- /dev/null
+++ b/dashboard/src/app/hero.service.ts
@@ -0,0 +1,57 @@
+import { Injectable } from '@angular/core';
+import { Headers, Http } from '@angular/http';
+
+import 'rxjs/add/operator/toPromise';
+
+import { Hero } from './hero';
+
+@Injectable()
+export class HeroService {
+ private heroesUrl = 'api/heroes'; // URL to web api
+ private headers = new Headers({'Content-Type': 'application/json'});
+
+ constructor(private http: Http) { }
+
+ getHeroes(): Promise {
+ return this.http.get(this.heroesUrl)
+ .toPromise()
+ .then(response => response.json().data as Hero[])
+ .catch(this.handleError);
+ }
+
+ update(hero: Hero): Promise {
+ const url = `${this.heroesUrl}/${hero.id}`;
+ return this.http.put(url, JSON.stringify(hero), {headers: this.headers})
+ .toPromise()
+ .then(() => hero)
+ .catch(this.handleError);
+ }
+
+ create(name: string): Promise {
+ return this.http.post(this.heroesUrl, JSON.stringify({name: name}), {headers: this.headers})
+ .toPromise()
+ .then(res => res.json().data as Hero)
+ .catch(this.handleError);
+ }
+
+ delete(id: number): Promise {
+ const url = `${this.heroesUrl}/${id}`;
+ return this.http.delete(url, {headers: this.headers})
+ .toPromise()
+ .then(() => null)
+ .catch(this.handleError);
+ }
+
+ getHero(id: number): Promise {
+ const url = `${this.heroesUrl}/${id}`;
+ return this.http.get(url)
+ .toPromise()
+ .then(response => response.json().data as Hero)
+ .catch(this.handleError);
+ }
+
+ private handleError(error: any): Promise {
+ console.error('An error occurred', error); // for demo purposes only
+ return Promise.reject(error.message || error);
+ }
+}
\ No newline at end of file
diff --git a/dashboard/src/app/hero.ts b/dashboard/src/app/hero.ts
new file mode 100644
index 0000000..de9c91e
--- /dev/null
+++ b/dashboard/src/app/hero.ts
@@ -0,0 +1,4 @@
+export class Hero {
+ id: number;
+ name: string;
+}
\ No newline at end of file
diff --git a/dashboard/src/app/heroes.component.css b/dashboard/src/app/heroes.component.css
new file mode 100644
index 0000000..f6cde89
--- /dev/null
+++ b/dashboard/src/app/heroes.component.css
@@ -0,0 +1,61 @@
+.selected {
+ background-color: #CFD8DC !important;
+ color: white;
+}
+
+.heroes {
+ margin: 0 0 2em 0;
+ list-style-type: none;
+ padding: 0;
+ width: 15em;
+}
+
+.heroes li {
+ cursor: pointer;
+ position: relative;
+ left: 0;
+ background-color: #EEE;
+ margin: .5em;
+ padding: .3em 0;
+ height: 1.6em;
+ border-radius: 4px;
+}
+
+.heroes li.selected:hover {
+ background-color: #BBD8DC !important;
+ color: white;
+}
+
+.heroes li:hover {
+ color: #607D8B;
+ background-color: #DDD;
+ left: .1em;
+}
+
+.heroes .text {
+ position: relative;
+ top: -3px;
+}
+
+.heroes .badge {
+ display: inline-block;
+ font-size: small;
+ color: white;
+ padding: 0.8em 0.7em 0 0.7em;
+ background-color: #607D8B;
+ line-height: 1em;
+ position: relative;
+ left: -1px;
+ top: -4px;
+ height: 1.8em;
+ margin-right: .8em;
+ border-radius: 4px 0 0 4px;
+}
+
+button.delete {
+ float:right;
+ margin-top: 2px;
+ margin-right: .8em;
+ background-color: gray !important;
+ color:white;
+}
\ No newline at end of file
diff --git a/dashboard/src/app/heroes.component.html b/dashboard/src/app/heroes.component.html
new file mode 100644
index 0000000..014c99e
--- /dev/null
+++ b/dashboard/src/app/heroes.component.html
@@ -0,0 +1,20 @@
+My Heroes
+
+ -
+ {{hero.id}} {{hero.name}}
+
+
+
+
+
{{selectedHero.name | uppercase}} is my hero
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dashboard/src/app/heroes.component.ts b/dashboard/src/app/heroes.component.ts
new file mode 100644
index 0000000..367a844
--- /dev/null
+++ b/dashboard/src/app/heroes.component.ts
@@ -0,0 +1,65 @@
+import { Component } from '@angular/core';
+import { OnInit } from '@angular/core';
+import { Router } from '@angular/router';
+
+import { Hero } from './hero';
+
+import { HeroService } from './hero.service';
+
+@Component({
+ selector: 'my-heroes',
+ templateUrl: './heroes.component.html',
+ styleUrls: [ './heroes.component.css' ]
+})
+
+export class HeroesComponent implements OnInit {
+ heroes: Hero[];
+ selectedHero: Hero;
+
+ constructor(
+ private heroService: HeroService,
+ private router: Router
+ ) { }
+
+ ngOnInit(): void {
+ this.getHeroes();
+ }
+
+ onSelect(hero: Hero) {
+ this.selectedHero = hero;
+ }
+
+ getHeroes(): void {
+ // this.heroService.getHeroes().then(heroes => this.heroes = heroes);
+ this.heroService.getHeroes().then(heroes => this.heroes = heroes);
+ }
+
+ add(name: string): void {
+ name = name.trim();
+ if (!name) {
+ return
+ }
+
+ this.heroService.create(name)
+ .then(hero => {
+ this.heroes.push(hero);
+ this.selectedHero = null;
+ });
+ }
+
+ delete(hero: Hero): void {
+ this.heroService
+ .delete(hero.id)
+ .then(() => {
+ this.heroes = this.heroes.filter(h => h !== hero);
+ if (this.selectedHero === hero) { this.selectedHero = null; }
+ });
+ }
+
+ gotoDetail(): void {
+ this.router.navigate(['/detail', this.selectedHero.id]);
+ }
+
+}
+
+
diff --git a/dashboard/src/app/in-memory-data.service.ts b/dashboard/src/app/in-memory-data.service.ts
new file mode 100644
index 0000000..a70163d
--- /dev/null
+++ b/dashboard/src/app/in-memory-data.service.ts
@@ -0,0 +1,19 @@
+import { InMemoryDbService } from 'angular-in-memory-web-api';
+
+export class InMemoryDataService implements InMemoryDbService {
+ createDb() {
+ let heroes = [
+ {id: 11, name: 'Mr. Nice'},
+ {id: 12, name: 'Narco'},
+ {id: 13, name: 'Bombasto'},
+ {id: 14, name: 'Celeritas'},
+ {id: 15, name: 'Magneta'},
+ {id: 16, name: 'RubberMan'},
+ {id: 17, name: 'Dynama'},
+ {id: 18, name: 'Dr IQ'},
+ {id: 19, name: 'Magma'},
+ {id: 20, name: 'Tornado'}
+ ];
+ return {heroes};
+ }
+}
diff --git a/dashboard/src/favicon.ico b/dashboard/src/favicon.ico
new file mode 100644
index 0000000..8081c7c
Binary files /dev/null and b/dashboard/src/favicon.ico differ
diff --git a/dashboard/src/index.html b/dashboard/src/index.html
new file mode 100644
index 0000000..8327435
--- /dev/null
+++ b/dashboard/src/index.html
@@ -0,0 +1,25 @@
+
+
+
+ Angular QuickStart
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Loading AppComponent content here ...
+
+
diff --git a/dashboard/src/main.js b/dashboard/src/main.js
new file mode 100644
index 0000000..b668eef
--- /dev/null
+++ b/dashboard/src/main.js
@@ -0,0 +1,5 @@
+"use strict";
+var platform_browser_dynamic_1 = require("@angular/platform-browser-dynamic");
+var app_module_1 = require("./app/app.module");
+platform_browser_dynamic_1.platformBrowserDynamic().bootstrapModule(app_module_1.AppModule);
+//# sourceMappingURL=main.js.map
\ No newline at end of file
diff --git a/dashboard/src/main.js.map b/dashboard/src/main.js.map
new file mode 100644
index 0000000..0326ae4
--- /dev/null
+++ b/dashboard/src/main.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":";AAAA,8EAA2E;AAE3E,+CAA6C;AAE7C,iDAAsB,EAAE,CAAC,eAAe,CAAC,sBAAS,CAAC,CAAC"}
\ No newline at end of file
diff --git a/dashboard/src/main.ts b/dashboard/src/main.ts
new file mode 100644
index 0000000..311c44b
--- /dev/null
+++ b/dashboard/src/main.ts
@@ -0,0 +1,5 @@
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { AppModule } from './app/app.module';
+
+platformBrowserDynamic().bootstrapModule(AppModule);
diff --git a/dashboard/src/styles.css b/dashboard/src/styles.css
new file mode 100644
index 0000000..17eaeac
--- /dev/null
+++ b/dashboard/src/styles.css
@@ -0,0 +1,27 @@
+/* Master Styles */
+h1 {
+ color: #369;
+ font-family: Arial, Helvetica, sans-serif;
+ font-size: 250%;
+}
+
+h2, h3 {
+ color: #444;
+ font-family: Arial, Helvetica, sans-serif;
+ font-weight: lighter;
+}
+
+body {
+ margin: 2em;
+}
+
+body, input[text], button {
+ color: #888;
+ font-family: Cambria, Georgia;
+}
+
+/* . . . */
+/* everywhere else */
+* {
+ font-family: Arial, Helvetica, sans-serif;
+}
diff --git a/dashboard/src/systemjs-angular-loader.js b/dashboard/src/systemjs-angular-loader.js
new file mode 100644
index 0000000..8b10054
--- /dev/null
+++ b/dashboard/src/systemjs-angular-loader.js
@@ -0,0 +1,49 @@
+var templateUrlRegex = /templateUrl\s*:(\s*['"`](.*?)['"`]\s*)/gm;
+var stylesRegex = /styleUrls *:(\s*\[[^\]]*?\])/g;
+var stringRegex = /(['`"])((?:[^\\]\\\1|.)*?)\1/g;
+
+module.exports.translate = function(load){
+ if (load.source.indexOf('moduleId') != -1) return load;
+
+ var url = document.createElement('a');
+ url.href = load.address;
+
+ var basePathParts = url.pathname.split('/');
+
+ basePathParts.pop();
+ var basePath = basePathParts.join('/');
+
+ var baseHref = document.createElement('a');
+ baseHref.href = this.baseURL;
+ baseHref = baseHref.pathname;
+
+ if (!baseHref.startsWith('/base/')) { // it is not karma
+ basePath = basePath.replace(baseHref, '');
+ }
+
+ load.source = load.source
+ .replace(templateUrlRegex, function(match, quote, url){
+ var resolvedUrl = url;
+
+ if (url.startsWith('.')) {
+ resolvedUrl = basePath + url.substr(1);
+ }
+
+ return 'templateUrl: "' + resolvedUrl + '"';
+ })
+ .replace(stylesRegex, function(match, relativeUrls) {
+ var urls = [];
+
+ while ((match = stringRegex.exec(relativeUrls)) !== null) {
+ if (match[2].startsWith('.')) {
+ urls.push('"' + basePath + match[2].substr(1) + '"');
+ } else {
+ urls.push('"' + match[2] + '"');
+ }
+ }
+
+ return "styleUrls: [" + urls.join(', ') + "]";
+ });
+
+ return load;
+};
diff --git a/dashboard/src/systemjs.config.extras.js b/dashboard/src/systemjs.config.extras.js
new file mode 100644
index 0000000..027dfe5
--- /dev/null
+++ b/dashboard/src/systemjs.config.extras.js
@@ -0,0 +1,11 @@
+/**
+ * Add barrels and stuff
+ * Adjust as necessary for your application needs.
+ */
+// (function (global) {
+// System.config({
+// packages: {
+// // add packages here
+// }
+// });
+// })(this);
diff --git a/dashboard/src/systemjs.config.js b/dashboard/src/systemjs.config.js
new file mode 100644
index 0000000..129704a
--- /dev/null
+++ b/dashboard/src/systemjs.config.js
@@ -0,0 +1,45 @@
+/**
+ * System configuration for Angular samples
+ * Adjust as necessary for your application needs.
+ */
+(function (global) {
+ System.config({
+ paths: {
+ // paths serve as alias
+ 'npm:': 'node_modules/'
+ },
+ // 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',
+
+ // other libraries
+ 'rxjs': 'npm:rxjs',
+ 'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js'
+ },
+ // packages tells the System loader how to load when no filename and/or no extension
+ packages: {
+ app: {
+ defaultExtension: 'js',
+ meta: {
+ './*.js': {
+ loader: 'systemjs-angular-loader.js'
+ }
+ }
+ },
+ rxjs: {
+ defaultExtension: 'js'
+ }
+ }
+ });
+})(this);
diff --git a/dashboard/src/tsconfig.json b/dashboard/src/tsconfig.json
new file mode 100644
index 0000000..2c7260d
--- /dev/null
+++ b/dashboard/src/tsconfig.json
@@ -0,0 +1,13 @@
+{
+ "compilerOptions": {
+ "target": "es5",
+ "module": "commonjs",
+ "moduleResolution": "node",
+ "sourceMap": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "lib": [ "es2015", "dom" ],
+ "noImplicitAny": true,
+ "suppressImplicitAnyIndexErrors": true
+ }
+}
diff --git a/dashboard/tslint.json b/dashboard/tslint.json
new file mode 100644
index 0000000..276453f
--- /dev/null
+++ b/dashboard/tslint.json
@@ -0,0 +1,93 @@
+{
+ "rules": {
+ "class-name": true,
+ "comment-format": [
+ true,
+ "check-space"
+ ],
+ "curly": true,
+ "eofline": true,
+ "forin": true,
+ "indent": [
+ true,
+ "spaces"
+ ],
+ "label-position": true,
+ "label-undefined": true,
+ "max-line-length": [
+ true,
+ 140
+ ],
+ "member-access": false,
+ "member-ordering": [
+ true,
+ "static-before-instance",
+ "variables-before-functions"
+ ],
+ "no-arg": true,
+ "no-bitwise": true,
+ "no-console": [
+ true,
+ "debug",
+ "info",
+ "time",
+ "timeEnd",
+ "trace"
+ ],
+ "no-construct": true,
+ "no-debugger": true,
+ "no-duplicate-key": true,
+ "no-duplicate-variable": true,
+ "no-empty": false,
+ "no-eval": true,
+ "no-inferrable-types": true,
+ "no-shadowed-variable": true,
+ "no-string-literal": false,
+ "no-switch-case-fall-through": true,
+ "no-trailing-whitespace": true,
+ "no-unused-expression": true,
+ "no-unused-variable": true,
+ "no-unreachable": 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"
+ ],
+ "quotemark": [
+ true,
+ "single"
+ ],
+ "radix": true,
+ "semicolon": [
+ "always"
+ ],
+ "triple-equals": [
+ true,
+ "allow-null-check"
+ ],
+ "typedef-whitespace": [
+ true,
+ {
+ "call-signature": "nospace",
+ "index-signature": "nospace",
+ "parameter": "nospace",
+ "property-declaration": "nospace",
+ "variable-declaration": "nospace"
+ }
+ ],
+ "variable-name": false,
+ "whitespace": [
+ true,
+ "check-branch",
+ "check-decl",
+ "check-operator",
+ "check-separator",
+ "check-type"
+ ]
+ }
+}