@ -0,0 +1,223 @@ | |||||
## Ignore Visual Studio temporary files, build results, and | |||||
## files generated by popular Visual Studio add-ons. | |||||
coverage/**/** | |||||
client/**/*.js | |||||
/doc | |||||
client/**/*.js.map | |||||
npm-debug.log* | |||||
# User-specific files | |||||
*.suo | |||||
*.user | |||||
*.userosscache | |||||
*.sln.docstates | |||||
# User-specific files (MonoDevelop/Xamarin Studio) | |||||
*.userprefs | |||||
# Build results | |||||
[Dd]ebug/ | |||||
[Dd]ebugPublic/ | |||||
[Rr]elease/ | |||||
[Rr]eleases/ | |||||
x64/ | |||||
x86/ | |||||
bld/ | |||||
[Bb]in/ | |||||
[Oo]bj/ | |||||
# Visual Studio 2015 cache/options directory | |||||
.vs/ | |||||
# MSTest test Results | |||||
[Tt]est[Rr]esult*/ | |||||
[Bb]uild[Ll]og.* | |||||
# NUNIT | |||||
*.VisualState.xml | |||||
TestResult.xml | |||||
# Build Results of an ATL Project | |||||
[Dd]ebugPS/ | |||||
[Rr]eleasePS/ | |||||
dlldata.c | |||||
# DNX | |||||
project.lock.json | |||||
artifacts/ | |||||
*_i.c | |||||
*_p.c | |||||
*_i.h | |||||
*.ilk | |||||
*.meta | |||||
*.obj | |||||
*.pch | |||||
*.pdb | |||||
*.pgc | |||||
*.pgd | |||||
*.rsp | |||||
*.sbr | |||||
*.tlb | |||||
*.tli | |||||
*.tlh | |||||
*.tmp | |||||
*.tmp_proj | |||||
*.log | |||||
*.vspscc | |||||
*.vssscc | |||||
.builds | |||||
*.pidb | |||||
*.svclog | |||||
*.scc | |||||
# Chutzpah Test files | |||||
_Chutzpah* | |||||
# Visual C++ cache files | |||||
ipch/ | |||||
*.aps | |||||
*.ncb | |||||
*.opensdf | |||||
*.sdf | |||||
*.cachefile | |||||
# Visual Studio profiler | |||||
*.psess | |||||
*.vsp | |||||
*.vspx | |||||
# TFS 2012 Local Workspace | |||||
$tf/ | |||||
# Guidance Automation Toolkit | |||||
*.gpState | |||||
# ReSharper is a .NET coding add-in | |||||
_ReSharper*/ | |||||
*.[Rr]e[Ss]harper | |||||
*.DotSettings.user | |||||
# JustCode is a .NET coding add-in | |||||
.JustCode | |||||
# TeamCity is a build add-in | |||||
_TeamCity* | |||||
# DotCover is a Code Coverage Tool | |||||
*.dotCover | |||||
# NCrunch | |||||
_NCrunch_* | |||||
.*crunch*.local.xml | |||||
# MightyMoose | |||||
*.mm.* | |||||
AutoTest.Net/ | |||||
# Web workbench (sass) | |||||
.sass-cache/ | |||||
# Installshield output folder | |||||
[Ee]xpress/ | |||||
# DocProject is a documentation generator add-in | |||||
DocProject/buildhelp/ | |||||
DocProject/Help/*.HxT | |||||
DocProject/Help/*.HxC | |||||
DocProject/Help/*.hhc | |||||
DocProject/Help/*.hhk | |||||
DocProject/Help/*.hhp | |||||
DocProject/Help/Html2 | |||||
DocProject/Help/html | |||||
# Click-Once directory | |||||
publish/ | |||||
# Publish Web Output | |||||
*.[Pp]ublish.xml | |||||
*.azurePubxml | |||||
## TODO: Comment the next line if you want to checkin your | |||||
## web deploy settings but do note that will include unencrypted | |||||
## passwords | |||||
#*.pubxml | |||||
*.publishproj | |||||
# NuGet Packages | |||||
*.nupkg | |||||
# The packages folder can be ignored because of Package Restore | |||||
**/packages/* | |||||
# except build/, which is used as an MSBuild target. | |||||
!**/packages/build/ | |||||
# Uncomment if necessary however generally it will be regenerated when needed | |||||
#!**/packages/repositories.config | |||||
# Windows Azure Build Output | |||||
csx/ | |||||
*.build.csdef | |||||
# Windows Store app package directory | |||||
AppPackages/ | |||||
# Visual Studio cache files | |||||
# files ending in .cache can be ignored | |||||
*.[Cc]ache | |||||
# but keep track of directories ending in .cache | |||||
!*.[Cc]ache/ | |||||
# Others | |||||
ClientBin/ | |||||
[Ss]tyle[Cc]op.* | |||||
~$* | |||||
*~ | |||||
*.dbmdl | |||||
*.dbproj.schemaview | |||||
*.pfx | |||||
*.publishsettings | |||||
node_modules/ | |||||
bower_components/ | |||||
**/wwwroot/tmp/ | |||||
**/wwwroot/*.bundle.map | |||||
**/wwwroot/*.js | |||||
/wwwroot/dist/ | |||||
orleans.codegen.cs | |||||
# RIA/Silverlight projects | |||||
Generated_Code/ | |||||
# Backup & report files from converting an old project file | |||||
# to a newer Visual Studio version. Backup files are not needed, | |||||
# because we have git ;-) | |||||
_UpgradeReport_Files/ | |||||
Backup*/ | |||||
UpgradeLog*.XML | |||||
UpgradeLog*.htm | |||||
# SQL Server files | |||||
*.mdf | |||||
*.ldf | |||||
# Business Intelligence projects | |||||
*.rdl.data | |||||
*.bim.layout | |||||
*.bim_*.settings | |||||
# Microsoft Fakes | |||||
FakesAssemblies/ | |||||
# Node.js Tools for Visual Studio | |||||
.ntvs_analysis.dat | |||||
# Visual Studio 6 build log | |||||
*.plg | |||||
# Visual Studio 6 workspace options file | |||||
*.opt | |||||
# LightSwitch generated files | |||||
GeneratedArtifacts/ | |||||
_Pvt_Extensions/ | |||||
ModelManifest.xml |
@ -0,0 +1,237 @@ | |||||
/Properties/launchSettings.json | |||||
## Ignore Visual Studio temporary files, build results, and | |||||
## files generated by popular Visual Studio add-ons. | |||||
# User-specific files | |||||
*.suo | |||||
*.user | |||||
*.userosscache | |||||
*.sln.docstates | |||||
# User-specific files (MonoDevelop/Xamarin Studio) | |||||
*.userprefs | |||||
# Build results | |||||
[Dd]ebug/ | |||||
[Dd]ebugPublic/ | |||||
[Rr]elease/ | |||||
[Rr]eleases/ | |||||
x64/ | |||||
x86/ | |||||
build/ | |||||
bld/ | |||||
bin/ | |||||
Bin/ | |||||
obj/ | |||||
Obj/ | |||||
# Visual Studio 2015 cache/options directory | |||||
.vs/ | |||||
/wwwroot/dist/ | |||||
# MSTest test Results | |||||
[Tt]est[Rr]esult*/ | |||||
[Bb]uild[Ll]og.* | |||||
# NUNIT | |||||
*.VisualState.xml | |||||
TestResult.xml | |||||
# Build Results of an ATL Project | |||||
[Dd]ebugPS/ | |||||
[Rr]eleasePS/ | |||||
dlldata.c | |||||
# DNX | |||||
project.lock.json | |||||
artifacts/ | |||||
*_i.c | |||||
*_p.c | |||||
*_i.h | |||||
*.ilk | |||||
*.meta | |||||
*.obj | |||||
*.pch | |||||
*.pdb | |||||
*.pgc | |||||
*.pgd | |||||
*.rsp | |||||
*.sbr | |||||
*.tlb | |||||
*.tli | |||||
*.tlh | |||||
*.tmp | |||||
*.tmp_proj | |||||
*.log | |||||
*.vspscc | |||||
*.vssscc | |||||
.builds | |||||
*.pidb | |||||
*.svclog | |||||
*.scc | |||||
# Chutzpah Test files | |||||
_Chutzpah* | |||||
# Visual C++ cache files | |||||
ipch/ | |||||
*.aps | |||||
*.ncb | |||||
*.opendb | |||||
*.opensdf | |||||
*.sdf | |||||
*.cachefile | |||||
# Visual Studio profiler | |||||
*.psess | |||||
*.vsp | |||||
*.vspx | |||||
*.sap | |||||
# TFS 2012 Local Workspace | |||||
$tf/ | |||||
# Guidance Automation Toolkit | |||||
*.gpState | |||||
# ReSharper is a .NET coding add-in | |||||
_ReSharper*/ | |||||
*.[Rr]e[Ss]harper | |||||
*.DotSettings.user | |||||
# JustCode is a .NET coding add-in | |||||
.JustCode | |||||
# TeamCity is a build add-in | |||||
_TeamCity* | |||||
# DotCover is a Code Coverage Tool | |||||
*.dotCover | |||||
# NCrunch | |||||
_NCrunch_* | |||||
.*crunch*.local.xml | |||||
nCrunchTemp_* | |||||
# MightyMoose | |||||
*.mm.* | |||||
AutoTest.Net/ | |||||
# Web workbench (sass) | |||||
.sass-cache/ | |||||
# Installshield output folder | |||||
[Ee]xpress/ | |||||
# DocProject is a documentation generator add-in | |||||
DocProject/buildhelp/ | |||||
DocProject/Help/*.HxT | |||||
DocProject/Help/*.HxC | |||||
DocProject/Help/*.hhc | |||||
DocProject/Help/*.hhk | |||||
DocProject/Help/*.hhp | |||||
DocProject/Help/Html2 | |||||
DocProject/Help/html | |||||
# Click-Once directory | |||||
publish/ | |||||
# Publish Web Output | |||||
*.[Pp]ublish.xml | |||||
*.azurePubxml | |||||
# TODO: Comment the next line if you want to checkin your web deploy settings | |||||
# but database connection strings (with potential passwords) will be unencrypted | |||||
*.pubxml | |||||
*.publishproj | |||||
# NuGet Packages | |||||
*.nupkg | |||||
# The packages folder can be ignored because of Package Restore | |||||
**/packages/* | |||||
# except build/, which is used as an MSBuild target. | |||||
!**/packages/build/ | |||||
# Uncomment if necessary however generally it will be regenerated when needed | |||||
#!**/packages/repositories.config | |||||
# Microsoft Azure Build Output | |||||
csx/ | |||||
*.build.csdef | |||||
# Microsoft Azure Emulator | |||||
ecf/ | |||||
rcf/ | |||||
# Microsoft Azure ApplicationInsights config file | |||||
ApplicationInsights.config | |||||
# Windows Store app package directory | |||||
AppPackages/ | |||||
BundleArtifacts/ | |||||
# Visual Studio cache files | |||||
# files ending in .cache can be ignored | |||||
*.[Cc]ache | |||||
# but keep track of directories ending in .cache | |||||
!*.[Cc]ache/ | |||||
# Others | |||||
ClientBin/ | |||||
~$* | |||||
*~ | |||||
*.dbmdl | |||||
*.dbproj.schemaview | |||||
*.pfx | |||||
*.publishsettings | |||||
node_modules/ | |||||
orleans.codegen.cs | |||||
# RIA/Silverlight projects | |||||
Generated_Code/ | |||||
# Backup & report files from converting an old project file | |||||
# to a newer Visual Studio version. Backup files are not needed, | |||||
# because we have git ;-) | |||||
_UpgradeReport_Files/ | |||||
Backup*/ | |||||
UpgradeLog*.XML | |||||
UpgradeLog*.htm | |||||
# SQL Server files | |||||
*.mdf | |||||
*.ldf | |||||
# Business Intelligence projects | |||||
*.rdl.data | |||||
*.bim.layout | |||||
*.bim_*.settings | |||||
# Microsoft Fakes | |||||
FakesAssemblies/ | |||||
# GhostDoc plugin setting file | |||||
*.GhostDoc.xml | |||||
# Node.js Tools for Visual Studio | |||||
.ntvs_analysis.dat | |||||
# Visual Studio 6 build log | |||||
*.plg | |||||
# Visual Studio 6 workspace options file | |||||
*.opt | |||||
# Visual Studio LightSwitch build output | |||||
**/*.HTMLClient/GeneratedArtifacts | |||||
**/*.DesktopClient/GeneratedArtifacts | |||||
**/*.DesktopClient/ModelManifest.xml | |||||
**/*.Server/GeneratedArtifacts | |||||
**/*.Server/ModelManifest.xml | |||||
_Pvt_Extensions | |||||
# Paket dependency manager | |||||
.paket/paket.exe | |||||
# FAKE - F# Make | |||||
.fake/ |
@ -0,0 +1,2 @@ | |||||
// Extra variables that live on Global that will be replaced by webpack DefinePlugin | |||||
// declare var process: any; |
@ -0,0 +1,23 @@ | |||||
import './polyfills'; | |||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; | |||||
import { enableProdMode } from '@angular/core'; | |||||
import { AppModule } from './modules/app.module'; | |||||
if (process.env.ENV === 'Development') { | |||||
// Development | |||||
} else { | |||||
// Production | |||||
enableProdMode(); | |||||
} | |||||
platformBrowserDynamic().bootstrapModule(AppModule); | |||||
// Basic hot reloading support. Automatically reloads and restarts the Angular 2 app each time | |||||
// you modify source files. This will not preserve any application state other than the URL. | |||||
declare var module: any; | |||||
if (module.hot) { | |||||
module.hot.accept(); | |||||
} |
@ -0,0 +1,9 @@ | |||||
$primary-colour: #00A69C; | |||||
$primary-accent: #83D01B; | |||||
$white-colour: #FFFFFF; | |||||
$grey-colour: #E2E2E2; | |||||
$text-colour: #757575; | |||||
$grey-box-shadow: 10px 10px 20px #F2F2F2; | |||||
$grey-box-border: 1px solid #DDDDDD; |
@ -0,0 +1,14 @@ | |||||
<!-- header component --> | |||||
<appc-header></appc-header> | |||||
<div class="container"> | |||||
<!-- component routing placeholder --> | |||||
<router-outlet></router-outlet> | |||||
</div> | |||||
<div class="container"> | |||||
<!-- footer component --> | |||||
<appc-footer></appc-footer> | |||||
</div> |
@ -0,0 +1,2 @@ | |||||
@import './_variables.scss'; | |||||
@ -0,0 +1,37 @@ | |||||
import { Title } from '@angular/platform-browser'; | |||||
import { Component, ViewEncapsulation, OnInit } from '@angular/core'; | |||||
import { RouterModule } from '@angular/router'; | |||||
import { TranslateService } from 'ng2-translate/ng2-translate'; | |||||
import { DataService } from './shared/services/data.service'; | |||||
/* | |||||
* App Component | |||||
* Top Level Component | |||||
*/ | |||||
@Component({ | |||||
selector: 'appc-app', | |||||
styleUrls: ['./app.component.scss'], | |||||
templateUrl: './app.component.html' | |||||
}) | |||||
export class AppComponent implements OnInit { | |||||
constructor(private translate: TranslateService, private titleService: Title) { | |||||
// this language will be used as a fallback when a translation isn't found in the current language | |||||
translate.setDefaultLang('en'); | |||||
// the lang to use, if the lang isn't available, it will use the current loader to get them | |||||
translate.use('en'); | |||||
} | |||||
ngOnInit() { | |||||
this.translate.get('title') | |||||
.subscribe(title => this.setTitle(title)); | |||||
} | |||||
public setTitle(newTitle: string) { | |||||
this.titleService.setTitle(newTitle); | |||||
} | |||||
} |
@ -0,0 +1,29 @@ | |||||
import { NgModule, NgModuleFactoryLoader } from '@angular/core'; | |||||
import { BrowserModule } from '@angular/platform-browser'; | |||||
// import { FormsModule } from '@angular/forms'; | |||||
import { HttpModule } from '@angular/http'; | |||||
import { RouterModule } from '@angular/Router'; | |||||
import { routing } from './app.routes'; | |||||
import { AppService } from './app.service'; | |||||
import { AppComponent } from './app.component'; | |||||
import { SharedModule } from './shared/shared.module'; | |||||
import { CatalogModule } from './catalog/catalog.module'; | |||||
@NgModule({ | |||||
declarations: [AppComponent], | |||||
imports: [ | |||||
BrowserModule, | |||||
routing, | |||||
// FormsModule, | |||||
HttpModule, | |||||
// Only module that app module loads | |||||
SharedModule.forRoot(), | |||||
CatalogModule | |||||
], | |||||
providers: [ | |||||
AppService | |||||
], | |||||
bootstrap: [AppComponent] | |||||
}) | |||||
export class AppModule { } |
@ -0,0 +1,15 @@ | |||||
import { Routes, RouterModule } from '@angular/router'; | |||||
export const routes: Routes = [ | |||||
{ path: '', redirectTo: 'catalog', pathMatch: 'full' } | |||||
// Lazy async modules | |||||
// { | |||||
// path: 'login', loadChildren: () => new Promise(resolve => { | |||||
// (require as any).ensure([], (require: any) => { | |||||
// resolve(require('./+login/login.module').LoginModule); | |||||
// }); | |||||
// }) | |||||
// } | |||||
]; | |||||
export const routing = RouterModule.forRoot(routes); |
@ -0,0 +1,6 @@ | |||||
import { Injectable } from '@angular/core'; | |||||
@Injectable() | |||||
export class AppService { | |||||
constructor() { } | |||||
} |
@ -0,0 +1,42 @@ | |||||
<div class="catalog-banner"> | |||||
<img class="catalog-banner-image" src="../../images/main_banner.png" /> | |||||
<div class="container"> | |||||
<img src="../../images/main_banner_text.png" class="catalog-banner-text" /> | |||||
</div> | |||||
</div> | |||||
<div class="catalog-filter"> | |||||
<div class="catalog-filter-container"> | |||||
<div class="container"> | |||||
<select> | |||||
<option>Opción 1</option> | |||||
<option>Opción 2</option> | |||||
</select> | |||||
<select> | |||||
<option>Opción 1</option> | |||||
<option>Opción 2</option> | |||||
</select> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="catalog-content row"> | |||||
<div class="col-md-4 catalog-content-item"> | |||||
<img src="https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt"/> | |||||
<button class="catalog-content-item-button">[ ADD TO CART ]</button> | |||||
</div> | |||||
<div class="col-md-4 catalog-content-item"> | |||||
<img src="https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" /> | |||||
<button class="catalog-content-item-button">[ ADD TO CART ]</button> | |||||
</div> | |||||
<div class="col-md-4 catalog-content-item"> | |||||
<img src="https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" /> | |||||
<button class="catalog-content-item-button">[ ADD TO CART ]</button> | |||||
</div> | |||||
<div class="col-md-4 catalog-content-item"> | |||||
<img src="https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" /> | |||||
<button class="catalog-content-item-button">[ ADD TO CART ]</button> | |||||
</div> | |||||
<div class="col-md-4 catalog-content-item"> | |||||
<img src="https://fakeimg.pl/370x240/EEEEEE/000/?text=RoslynRedT-Shirt" /> | |||||
<button class="catalog-content-item-button">[ ADD TO CART ]</button> | |||||
</div> | |||||
</div> |
@ -0,0 +1,55 @@ | |||||
@import '../_variables.scss'; | |||||
.catalog{ | |||||
&-banner { | |||||
height: 258px; | |||||
vertical-align:middle; | |||||
&-image { | |||||
width: 100%; | |||||
position: absolute; | |||||
left: 0; | |||||
height: 258px; | |||||
} | |||||
&-text { | |||||
position:relative; | |||||
top: 75px; | |||||
} | |||||
} | |||||
&-filter { | |||||
height: 65px; | |||||
&-container { | |||||
position:absolute; | |||||
width:100%; | |||||
background-color: $primary-colour; | |||||
left:0; | |||||
height: 65px; | |||||
} | |||||
} | |||||
&-content{ | |||||
margin-top: 10px; | |||||
&-item { | |||||
text-align: center; | |||||
&-image{ | |||||
} | |||||
&-button { | |||||
width: 255px; | |||||
height: 45px; | |||||
padding: 10px 20px 10px 20px; | |||||
background-color: $primary-accent; | |||||
color: white; | |||||
font-size: 16px; | |||||
margin: 10px 0; | |||||
border:none; | |||||
} | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,15 @@ | |||||
import { Component, OnInit } from '@angular/core'; | |||||
@Component({ | |||||
selector: 'appc-catalog', | |||||
styleUrls: ['./catalog.component.scss'], | |||||
templateUrl: './catalog.component.html' | |||||
}) | |||||
export class CatalogComponent implements OnInit { | |||||
constructor() { } | |||||
ngOnInit() { | |||||
console.log('catalog component loaded'); | |||||
} | |||||
} |
@ -0,0 +1,11 @@ | |||||
import { NgModule } from '@angular/core'; | |||||
import { CatalogComponent } from './catalog.component'; | |||||
import { routing } from './catalog.routes'; | |||||
@NgModule({ | |||||
imports: [routing], | |||||
declarations: [CatalogComponent] | |||||
}) | |||||
export class CatalogModule { } |
@ -0,0 +1,9 @@ | |||||
import { Routes, RouterModule } from '@angular/router'; | |||||
import { CatalogComponent } from './catalog.component'; | |||||
const routes: Routes = [ | |||||
{ path: 'catalog', component: CatalogComponent } | |||||
]; | |||||
export const routing = RouterModule.forChild(routes); |
@ -0,0 +1,3 @@ | |||||
<h1>404!</h1> | |||||
<p>Page you are looking for does not exists.</p> |
@ -0,0 +1,11 @@ | |||||
/* tslint:disable:no-unused-variable */ | |||||
import { TestBed, async } from '@angular/core/testing'; | |||||
import { PageNotFoundComponent } from './page-not-found.component'; | |||||
describe('Component: PageNotFound', () => { | |||||
it('should create an instance', () => { | |||||
let component = new PageNotFoundComponent(); | |||||
expect(component).toBeTruthy(); | |||||
}); | |||||
}); |
@ -0,0 +1,15 @@ | |||||
import { Component, OnInit } from '@angular/core'; | |||||
@Component({ | |||||
selector: 'appc-page-not-found', | |||||
templateUrl: './page-not-found.component.html', | |||||
styleUrls: ['./page-not-found.component.scss'] | |||||
}) | |||||
export class PageNotFoundComponent implements OnInit { | |||||
constructor() { } | |||||
ngOnInit() { | |||||
} | |||||
} |
@ -0,0 +1,10 @@ | |||||
import { Component, Input } from '@angular/core'; | |||||
@Component({ | |||||
selector: 'appc-page-heading', | |||||
template: `<h4>{{text}}</h4>` | |||||
}) | |||||
export class PageHeadingComponent { | |||||
@Input() text: string; | |||||
constructor() { } | |||||
} |
@ -0,0 +1,41 @@ | |||||
import { | |||||
fakeAsync, | |||||
tick, | |||||
TestBed | |||||
} from '@angular/core/testing'; | |||||
import { Component } from '@angular/core'; | |||||
import { By } from '@angular/platform-browser/src/dom/debug/by'; | |||||
// Load the implementations that should be tested | |||||
import { XLargeDirective } from './x-large.directive'; | |||||
describe('x-large directive', () => { | |||||
// Create a test component to test directives | |||||
@Component({ | |||||
template: '<div x-large>Content</div>' | |||||
}) | |||||
class TestComponent { } | |||||
beforeEach(() => { | |||||
TestBed.configureTestingModule({ | |||||
declarations: [ | |||||
XLargeDirective, | |||||
TestComponent | |||||
] | |||||
}); | |||||
}); | |||||
it('should sent font-size to x-large', fakeAsync(() => { | |||||
TestBed.compileComponents().then(() => { | |||||
const fixture = TestBed.createComponent(TestComponent); | |||||
fixture.detectChanges(); | |||||
tick(); | |||||
const element = fixture.debugElement.query(By.css('div')); | |||||
// expect(element.nativeElement.style.fontSize).toBe('x-large'); | |||||
}); | |||||
})); | |||||
}); |
@ -0,0 +1,18 @@ | |||||
import { Directive, ElementRef, Renderer } from '@angular/core'; | |||||
/* | |||||
* Directive | |||||
* XLarge is a simple directive to show how one is made | |||||
*/ | |||||
@Directive({ | |||||
selector: '[appdXlarge]' // using [ ] means selecting attributes | |||||
}) | |||||
export class XLargeDirective { | |||||
constructor(element: ElementRef, renderer: Renderer) { | |||||
// simple DOM manipulation to set font size to x-large | |||||
// `nativeElement` is the direct reference to the DOM element | |||||
// element.nativeElement.style.fontSize = 'x-large'; | |||||
// for server/webworker support use the renderer | |||||
renderer.setElementStyle(element.nativeElement, 'fontSize', 'x-large'); | |||||
} | |||||
} |
@ -0,0 +1,36 @@ | |||||
export class ControlBase<T>{ | |||||
value: T; | |||||
key: string; | |||||
label: string; | |||||
placeholder: string; | |||||
required: boolean; | |||||
minlength: number; | |||||
maxlength: number; | |||||
order: number; | |||||
type: string; | |||||
class: string; | |||||
constructor(options: { | |||||
value?: T, | |||||
key?: string, | |||||
label?: string, | |||||
placeholder?: string, | |||||
required?: boolean, | |||||
minlength?: number, | |||||
maxlength?: number, | |||||
order?: number, | |||||
type?: string, | |||||
class?: string; | |||||
} = {}) { | |||||
this.value = options.value; | |||||
this.key = options.key || ''; | |||||
this.label = options.label || ''; | |||||
this.placeholder = options.placeholder || ''; | |||||
this.required = !!options.required; | |||||
this.minlength = options.minlength; | |||||
this.maxlength = options.maxlength; | |||||
this.order = options.order === undefined ? 1 : options.order; | |||||
this.type = options.type || ''; | |||||
this.class = options.class || ''; | |||||
} | |||||
} |
@ -0,0 +1,11 @@ | |||||
import { ControlBase } from './control-base'; | |||||
export class ControlCheckbox extends ControlBase<string> { | |||||
type: string; | |||||
constructor(options: any = {}) { | |||||
super(options); | |||||
this.type = 'checkbox'; | |||||
this.value = options.value || false; | |||||
} | |||||
} |
@ -0,0 +1,11 @@ | |||||
import { ControlBase } from './control-base'; | |||||
export class ControlDropdown extends ControlBase<string> { | |||||
options: { key: string, value: string }[] = []; | |||||
constructor(options: any = {}) { | |||||
super(options); | |||||
this.type = 'dropdown'; | |||||
this.options = options.options || []; | |||||
} | |||||
} |
@ -0,0 +1,8 @@ | |||||
import { ControlBase } from './control-base'; | |||||
export class ControlTextbox extends ControlBase<boolean> { | |||||
constructor(options: any = {}) { | |||||
super(options); | |||||
this.type = options.type || 'textbox'; | |||||
} | |||||
} |
@ -0,0 +1,26 @@ | |||||
<!--{{f.controls[control.key] | json}}--> | |||||
<div #f="ngForm" [formGroup]="form" [ngSwitch]="control.type" class="form-group {{control.class}}" [class.has-danger]="invalid" | |||||
[class.has-success]="valid" [class.form-check]="control.type === 'checkbox'"> | |||||
<label *ngSwitchCase="'dropdown'" [attr.for]="control.key" class="col-form-label">{{control.label}}</label> | |||||
<select *ngSwitchCase="'dropdown'" [id]="control.key" [formControlName]="control.key" [class.form-control-success]="valid" | |||||
[class.form-control-danger]="invalid" class="form-control"> | |||||
<option *ngFor="let opt of control.options" [value]="opt.key">{{opt.value}}</option> | |||||
</select> | |||||
<label *ngSwitchCase="'checkbox'" [attr.for]="control.key" class="form-check-label"> | |||||
<input #ck *ngSwitchCase="'checkbox'" (change)="control.value = ck.checked" [id]="control.key" [formControlName]="control.key" | |||||
[type]="control.type" class="form-check-input"> | |||||
{{control.label}} | |||||
</label> | |||||
<!--This is not the switch case because of multiple control types--> | |||||
<label *ngIf="control.type === 'textbox' || control.type === 'email' || control.type === 'password'" [attr.for]="control.key" class="col-form-label">{{control.label}}</label> | |||||
<input *ngIf="control.type === 'textbox' || control.type === 'email' || control.type === 'password'" [id]="control.key" [formControlName]="control.key" [type]="control.type" | |||||
[placeholder]="control.placeholder" [class.form-control-success]="valid" [class.form-control-danger]="invalid" class="form-control"> | |||||
<appc-control-error-message [form]="f" [control]="control"></appc-control-error-message> | |||||
</div> |
@ -0,0 +1,26 @@ | |||||
import { Component, Input } from '@angular/core'; | |||||
import { FormGroup } from '@angular/forms'; | |||||
import { ControlBase } from './control-base'; | |||||
import { ErrorMessageComponent } from './error-message.component'; | |||||
@Component({ | |||||
selector: 'appc-dynamic-control', | |||||
templateUrl: './dynamic-form-control.component.html' | |||||
}) | |||||
export class DynamicFormControlComponent { | |||||
@Input() control; | |||||
@Input() form; | |||||
constructor() { | |||||
this.control = undefined; | |||||
this.form = undefined; | |||||
} | |||||
get valid() { | |||||
return this.form.controls[this.control.key].valid; | |||||
} | |||||
get invalid() { | |||||
return !this.form.controls[this.control.key].valid && this.form.controls[this.control.key].touched; | |||||
} | |||||
} |
@ -0,0 +1,5 @@ | |||||
<form class="{{formClass}}" (ngSubmit)="onSubmit()" [formGroup]="form" novalidate role="form"> | |||||
<appc-dynamic-control *ngFor="let ctrl of controls" [control]="ctrl" [form]="form"></appc-dynamic-control> | |||||
<button type="submit" class="btn btn-primary pull-right" [disabled]="!form.valid">{{btnText}}</button> | |||||
</form> |
@ -0,0 +1,30 @@ | |||||
import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; | |||||
import { FormGroup } from '@angular/forms'; | |||||
import { ControlBase } from './control-base'; | |||||
import { FormControlService } from './form-control.service'; | |||||
@Component({ | |||||
selector: 'appc-dynamic-form', | |||||
templateUrl: './dynamic-form.component.html' | |||||
}) | |||||
export class DynamicFormComponent implements OnInit { | |||||
@Input() controls: ControlBase<any>[] = []; | |||||
@Input() btnText: string = 'Submit'; // Default value at least | |||||
@Input() formClass: string = 'form-horizontal'; | |||||
// Note: don't keep name of output events as same as native events such as submit etc. | |||||
@Output() formsubmit: EventEmitter<any> = new EventEmitter<any>(); | |||||
form: FormGroup; | |||||
constructor(private _controlService: FormControlService) { } | |||||
ngOnInit() { | |||||
let sortedControls = this.controls.sort((a, b) => a.order - b.order); | |||||
this.form = this._controlService.toControlGroup(sortedControls); | |||||
} | |||||
onSubmit() { | |||||
this.formsubmit.emit(this.form.value); | |||||
} | |||||
} |
@ -0,0 +1,25 @@ | |||||
import { Component, Host, Input } from '@angular/core'; | |||||
import { FormGroupDirective } from '@angular/forms'; | |||||
import { ControlBase } from './control-base'; | |||||
import { ValidationService } from './validation.service'; | |||||
@Component({ | |||||
selector: 'appc-control-error-message', | |||||
template: `<div *ngIf="errorMessage" class="form-control-feedback"> {{errorMessage}} </div>` | |||||
}) | |||||
export class ErrorMessageComponent { | |||||
@Input() control: ControlBase<any>; | |||||
@Input() form: FormGroupDirective; | |||||
constructor() { } | |||||
get errorMessage() { | |||||
let c = this.form.form.get(this.control.key); | |||||
for (let propertyName in c.errors) { | |||||
if (c.errors.hasOwnProperty(propertyName) && c.touched) { | |||||
return ValidationService.getValidatorErrorMessage(propertyName, this.control.minlength || this.control.maxlength); | |||||
} | |||||
} | |||||
return undefined; | |||||
} | |||||
} |
@ -0,0 +1,7 @@ | |||||
<div class="alert alert-danger" *ngIf="errors?.length > 0"> | |||||
<ul> | |||||
<li *ngFor="let error of errors"> | |||||
{{error}} | |||||
</li> | |||||
</ul> | |||||
</div> |
@ -0,0 +1,11 @@ | |||||
import { Component, Input } from '@angular/core'; | |||||
@Component({ | |||||
selector: 'appc-error-summary', | |||||
templateUrl: './error-summary.component.html' | |||||
}) | |||||
export class ErrorSummaryComponent { | |||||
@Input() errors: string | string[]; | |||||
constructor() { } | |||||
} |
@ -0,0 +1,41 @@ | |||||
import { Injectable } from '@angular/core'; | |||||
import { FormControl, FormGroup, Validators } from '@angular/forms'; | |||||
import { ControlBase } from './control-base'; | |||||
import { ValidationService } from './validation.service'; | |||||
@Injectable() | |||||
export class FormControlService { | |||||
constructor() { } | |||||
toControlGroup(controls: ControlBase<any>[]) { | |||||
let group: any = {}; | |||||
controls.forEach(control => { | |||||
let validators = []; | |||||
// Required | |||||
if (control.required) { | |||||
validators.push(Validators.required); | |||||
} | |||||
// Minlength | |||||
if (control.minlength) { | |||||
validators.push(Validators.minLength(control.minlength)); | |||||
} | |||||
// Maxlength | |||||
if (control.maxlength) { | |||||
validators.push(Validators.minLength(control.maxlength)); | |||||
} | |||||
if (control.type === 'email') { | |||||
validators.push(ValidationService.emailValidator); | |||||
} | |||||
// Password | |||||
if (control.type === 'password') { | |||||
validators.push(ValidationService.passwordValidator); | |||||
} | |||||
group[control.key] = new FormControl(control.value || '', validators); | |||||
}); | |||||
return new FormGroup(group); | |||||
} | |||||
} |
@ -0,0 +1,42 @@ | |||||
export class ValidationService { | |||||
static getValidatorErrorMessage(code: string, fieldLength: number) { | |||||
let config: any = { | |||||
'required': 'This is a required field', | |||||
'minlength': 'Minimum length is ' + fieldLength, | |||||
'maxlength': 'Maximum length is ' + fieldLength, | |||||
'invalidCreditCard': 'Invalid credit card number', | |||||
'invalidEmailAddress': 'Invalid email address', | |||||
'invalidPassword': 'Password must be at least 6 characters long, and contain a number and special character.' | |||||
}; | |||||
return config[code]; | |||||
} | |||||
static creditCardValidator(control: any) { | |||||
// Visa, MasterCard, American Express, Diners Club, Discover, JCB | |||||
if (control.value.match(/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6(?:011|5[0-9][0-9])[0-9]{12}|3[47][0-9]{13}|3(?:0[0-5]|[68][0-9])[0-9]{11}|(?:2131|1800|35\d{3})\d{11})$/)) { | |||||
return undefined; | |||||
} else { | |||||
return { 'invalidCreditCard': true }; | |||||
} | |||||
} | |||||
static emailValidator(control: any) { | |||||
// RFC 2822 compliant regex | |||||
if (control.value.match(/[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/)) { | |||||
return undefined; | |||||
} else { | |||||
return { 'invalidEmailAddress': true }; | |||||
} | |||||
} | |||||
static passwordValidator(control: any) { | |||||
// {6,100} - Assert password is between 6 and 100 characters | |||||
// (?=.*[0-9]) - Assert a string has at least one number | |||||
if (control.value.match(/^(?=.*[0-9])[a-zA-Z0-9!"@#$%^&*]{6,100}$/)) { | |||||
return undefined; | |||||
} else { | |||||
return { 'invalidPassword': true }; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,8 @@ | |||||
<footer class="text-muted"> | |||||
<div class="container"> | |||||
<hr> | |||||
<p class="text-muted"> | |||||
© 2015-2016 {{'title' | translate}} Company | |||||
</p> | |||||
</div> | |||||
</footer> |
@ -0,0 +1,8 @@ | |||||
@import '../../_variables.scss'; | |||||
.footer { | |||||
padding-top: 40px; | |||||
padding-bottom: 40px; | |||||
margin-top: 40px; | |||||
border-top: 1px solid #eee; | |||||
} |
@ -0,0 +1,10 @@ | |||||
import { Component } from '@angular/core'; | |||||
@Component({ | |||||
selector: 'appc-footer', | |||||
styleUrls: ['./footer.component.scss'], | |||||
templateUrl: './footer.component.html' | |||||
}) | |||||
export class FooterComponent { | |||||
constructor() { } | |||||
} |
@ -0,0 +1,62 @@ | |||||
<header class="navbar navbar-light navbar-static-top"> | |||||
<div class="container"> | |||||
<nav> | |||||
<div class="clearfix"> | |||||
<!--<button class="navbar-toggler float-xs-right hidden-sm-up collapsed" type="button" data-toggle="collapse" data-target="#bd-main-nav" | |||||
aria-controls="bd-main-nav" aria-expanded="false" aria-label="Toggle navigation" (click)="toggleNav()"> | |||||
☰ | |||||
</button> | |||||
<a class="navbar-brand hidden-sm-up header-brand" routerLink="home"> | |||||
Ng2fbBootstrap | |||||
<img src="../../../images/brand.png" /> | |||||
</a>--> | |||||
</div> | |||||
<div class="" id="bd-main-nav" aria-expanded="false" style="height: 0px;"> | |||||
<a class="navbar-brand" routerLink="home"> | |||||
<img src="../../../images/brand.png" /> | |||||
</a> | |||||
<!--<ul class="nav navbar-nav"> | |||||
<li class="nav-item"> | |||||
<a class="nav-item nav-link" routerLinkActive="active" routerLink="home">Home</a> | |||||
</li> | |||||
<li class="nav-item"> | |||||
<a class="nav-item nav-link" routerLinkActive="active" routerLink="examples">Examples</a> | |||||
</li> | |||||
<li> | |||||
<ul class="nav float-xs-left float-md-right"> | |||||
<li class="nav-item" *ngIf="authService.isLoggedIn() && authService.user()"> | |||||
<a class="nav-item nav-link" routerLinkActive="active" routerLink="profile"> | |||||
<i class="fa fa-user"></i> {{authService.user().displayName}} | |||||
</a> | |||||
</li> | |||||
<li class="nav-item" *ngIf="!authService.isLoggedIn()"> | |||||
<a class="nav-item nav-link" routerLinkActive="active" routerLink="register"> | |||||
<i class="fa fa-user"></i> Register | |||||
</a> | |||||
</li> | |||||
<li class="nav-item" *ngIf="!authService.isLoggedIn()"> | |||||
<a class="nav-item nav-link" routerLinkActive="active" routerLink="login"> | |||||
<i class="fa fa-sign-in"></i>Login | |||||
</a> | |||||
</li> | |||||
<li class="nav-item" *ngIf="authService.isLoggedIn() && authService.user()?.roles?.indexOf('Admin') > -1"> | |||||
<a class="nav-item nav-link" routerLinkActive="active" routerLink="admin"> | |||||
<i class="fa fa-gear"></i> Admin | |||||
</a> | |||||
</li> | |||||
<li class="nav-item" *ngIf="authService.isLoggedIn()"> | |||||
<a class="nav-item nav-link" (click)="authService.logout()" routerLinkActive="active" href="javascript:void(null);"> | |||||
<i class="fa fa-sign-out"></i> Logout | |||||
</a> | |||||
</li> | |||||
</ul> | |||||
</li> | |||||
</ul>--> | |||||
</div> | |||||
</nav> | |||||
</div> | |||||
</header> |
@ -0,0 +1,5 @@ | |||||
@import '../../_variables.scss'; | |||||
.header-brand { | |||||
background-image:url('../../../images/brand.png') | |||||
} |
@ -0,0 +1,18 @@ | |||||
import { Component, Inject } from '@angular/core'; | |||||
import { Router } from '@angular/router'; | |||||
import { AuthService } from '../services/auth.service'; | |||||
@Component({ | |||||
selector: 'appc-header', | |||||
styleUrls: ['./header.component.scss'], | |||||
templateUrl: './header.component.html' | |||||
}) | |||||
export class HeaderComponent { | |||||
isCollapsed: boolean = true; | |||||
constructor(private router: Router, private authService: AuthService) { } | |||||
toggleNav() { | |||||
this.isCollapsed = !this.isCollapsed; | |||||
} | |||||
} |
@ -0,0 +1,3 @@ | |||||
export class OperationResult { | |||||
constructor(public succeeded: boolean, public message: string) { } | |||||
} |
@ -0,0 +1,13 @@ | |||||
import { User } from './user.model'; | |||||
// todo: I dont think user follows angular style guides | |||||
describe('User Model', () => { | |||||
it('has displayName', () => { | |||||
let userModel: User = {displayName: 'test', roles: ['1']}; | |||||
expect(userModel.displayName).toEqual('test'); | |||||
}); | |||||
it('has displayName', () => { | |||||
let userModel: User = {displayName: 'test', roles: ['admin']}; | |||||
expect(userModel.roles[0]).toEqual('admin'); | |||||
}); | |||||
}); |
@ -0,0 +1,4 @@ | |||||
export class User { | |||||
constructor(public displayName: string, public roles: string[]) { | |||||
} | |||||
} |
@ -0,0 +1,21 @@ | |||||
import { UppercasePipe } from './uppercase.pipe'; | |||||
describe('Pipe appfUppercase', () => { | |||||
let pipe: UppercasePipe; | |||||
beforeEach(() => { | |||||
pipe = new UppercasePipe(); | |||||
}); | |||||
it('transforms "abc" to "ABC"', () => { | |||||
expect(pipe.transform('abc')).toEqual('ABC'); | |||||
}); | |||||
it('transforms "abc def" to "ABC DEF"', () => { | |||||
expect(pipe.transform('abc def')).toEqual('ABC DEF'); | |||||
}); | |||||
it('leaves "ABC DEF" unchanged', () => { | |||||
expect(pipe.transform('ABC DEF')).toEqual('ABC DEF'); | |||||
}); | |||||
}); |
@ -0,0 +1,10 @@ | |||||
import { Pipe, PipeTransform } from '@angular/core'; | |||||
@Pipe({ | |||||
name: 'appfUppercase' | |||||
}) | |||||
export class UppercasePipe implements PipeTransform { | |||||
transform(value: string) { | |||||
return value.toUpperCase(); | |||||
} | |||||
} |
@ -0,0 +1,207 @@ | |||||
// CREDIT: | |||||
// The vast majority of this code came right from Ben Nadel's post: | |||||
// http://www.bennadel.com/blog/3047-creating-specialized-http-clients-in-angular-2-beta-8.htm | |||||
// | |||||
// My updates are mostly adapting it for Typescript: | |||||
// 1. Importing required modules | |||||
// 2. Adding type notations | |||||
// 3. Using the 'fat-arrow' syntax to properly scope in-line functions | |||||
// | |||||
import 'rxjs/add/operator/map'; | |||||
import 'rxjs/add/operator/catch'; | |||||
import 'rxjs/add/operator/finally'; | |||||
import { Injectable } from '@angular/core'; | |||||
import { Http, Response, RequestOptions, RequestMethod, URLSearchParams } from '@angular/http'; | |||||
import { Observable } from 'rxjs/Observable'; | |||||
import { Subject } from 'rxjs/Subject'; | |||||
import { HttpErrorHandlerService } from './http-error-handler.service'; | |||||
// Import the rxjs operators we need (in a production app you'll | |||||
// probably want to import only the operators you actually use) | |||||
// | |||||
export class ApiGatewayOptions { | |||||
method: RequestMethod; | |||||
url: string; | |||||
headers: any = {}; | |||||
params = {}; | |||||
data = {}; | |||||
} | |||||
@Injectable() | |||||
export class ApiGatewayService { | |||||
// Define the internal Subject we'll use to push the command count | |||||
private pendingCommandsSubject = new Subject<number>(); | |||||
private pendingCommandCount = 0; | |||||
// Provide the *public* Observable that clients can subscribe to | |||||
private pendingCommands$: Observable<number>; | |||||
constructor(private http: Http, private httpErrorHandler: HttpErrorHandlerService) { | |||||
this.pendingCommands$ = this.pendingCommandsSubject.asObservable(); | |||||
} | |||||
// I perform a GET request to the API, appending the given params | |||||
// as URL search parameters. Returns a stream. | |||||
get(url: string, params: any): Observable<Response> { | |||||
let options = new ApiGatewayOptions(); | |||||
options.method = RequestMethod.Get; | |||||
options.url = url; | |||||
options.params = params; | |||||
return this.request(options); | |||||
} | |||||
// I perform a POST request to the API. If both the params and data | |||||
// are present, the params will be appended as URL search parameters | |||||
// and the data will be serialized as a JSON payload. If only the | |||||
// data is present, it will be serialized as a JSON payload. Returns | |||||
// a stream. | |||||
post(url: string, data: any, params: any): Observable<Response> { | |||||
if (!data) { | |||||
data = params; | |||||
params = {}; | |||||
} | |||||
let options = new ApiGatewayOptions(); | |||||
options.method = RequestMethod.Post; | |||||
options.url = url; | |||||
options.params = params; | |||||
options.data = data; | |||||
return this.request(options); | |||||
} | |||||
private request(options: ApiGatewayOptions): Observable<any> { | |||||
options.method = (options.method || RequestMethod.Get); | |||||
options.url = (options.url || ''); | |||||
options.headers = (options.headers || {}); | |||||
options.params = (options.params || {}); | |||||
options.data = (options.data || {}); | |||||
this.interpolateUrl(options); | |||||
this.addXsrfToken(options); | |||||
this.addContentType(options); | |||||
// TODO add auth token when available | |||||
// this.addAuthToken(options); | |||||
let requestOptions = new RequestOptions(); | |||||
requestOptions.method = options.method; | |||||
requestOptions.url = options.url; | |||||
requestOptions.headers = options.headers; | |||||
requestOptions.search = this.buildUrlSearchParams(options.params); | |||||
requestOptions.body = JSON.stringify(options.data); | |||||
let isCommand = (options.method !== RequestMethod.Get); | |||||
if (isCommand) { | |||||
this.pendingCommandsSubject.next(++this.pendingCommandCount); | |||||
} | |||||
let stream = this.http.request(options.url, requestOptions) | |||||
.catch((error: any) => { | |||||
this.httpErrorHandler.handle(error); | |||||
return Observable.throw(error); | |||||
}) | |||||
.map(this.unwrapHttpValue) | |||||
.catch((error: any) => { | |||||
return Observable.throw(this.unwrapHttpError(error)); | |||||
}) | |||||
.finally(() => { | |||||
if (isCommand) { | |||||
this.pendingCommandsSubject.next(--this.pendingCommandCount); | |||||
} | |||||
}); | |||||
return stream; | |||||
} | |||||
private addContentType(options: ApiGatewayOptions): ApiGatewayOptions { | |||||
if (options.method !== RequestMethod.Get) { | |||||
options.headers['Content-Type'] = 'application/json; charset=UTF-8'; | |||||
} | |||||
return options; | |||||
} | |||||
private addAuthToken(options: ApiGatewayOptions): ApiGatewayOptions { | |||||
options.headers.Authorization = 'Bearer ' + JSON.parse(sessionStorage.getItem('accessToken')); | |||||
return options; | |||||
} | |||||
private extractValue(collection: any, key: string): any { | |||||
let value = collection[key]; | |||||
delete (collection[key]); | |||||
return value; | |||||
} | |||||
private addXsrfToken(options: ApiGatewayOptions): ApiGatewayOptions { | |||||
let xsrfToken = this.getXsrfCookie(); | |||||
if (xsrfToken) { | |||||
options.headers['X-XSRF-TOKEN'] = xsrfToken; | |||||
} | |||||
return options; | |||||
} | |||||
private getXsrfCookie(): string { | |||||
let matches = document.cookie.match(/\bXSRF-TOKEN=([^\s;]+)/); | |||||
try { | |||||
return (matches && decodeURIComponent(matches[1])); | |||||
} catch (decodeError) { | |||||
return (''); | |||||
} | |||||
} | |||||
private addCors(options: ApiGatewayOptions): ApiGatewayOptions { | |||||
options.headers['Access-Control-Allow-Origin'] = '*'; | |||||
return options; | |||||
} | |||||
private buildUrlSearchParams(params: any): URLSearchParams { | |||||
let searchParams = new URLSearchParams(); | |||||
for (let key in params) { | |||||
if (params.hasOwnProperty(key)) { | |||||
searchParams.append(key, params[key]); | |||||
} | |||||
} | |||||
return searchParams; | |||||
} | |||||
private interpolateUrl(options: ApiGatewayOptions): ApiGatewayOptions { | |||||
options.url = options.url.replace(/:([a-zA-Z]+[\w-]*)/g, ($0, token) => { | |||||
// Try to move matching token from the params collection. | |||||
if (options.params.hasOwnProperty(token)) { | |||||
return (this.extractValue(options.params, token)); | |||||
} | |||||
// Try to move matching token from the data collection. | |||||
if (options.data.hasOwnProperty(token)) { | |||||
return (this.extractValue(options.data, token)); | |||||
} | |||||
// If a matching value couldn't be found, just replace | |||||
// the token with the empty string. | |||||
return (''); | |||||
}); | |||||
// Clean up any repeating slashes. | |||||
options.url = options.url.replace(/\/{2,}/g, '/'); | |||||
// Clean up any trailing slashes. | |||||
options.url = options.url.replace(/\/+$/g, ''); | |||||
return options; | |||||
} | |||||
private unwrapHttpError(error: any): any { | |||||
try { | |||||
return (error.json()); | |||||
} catch (jsonError) { | |||||
return ({ | |||||
code: -1, | |||||
message: 'An unexpected error occurred.' | |||||
}); | |||||
} | |||||
} | |||||
private unwrapHttpValue(value: Response): any { | |||||
return (value.json()); | |||||
} | |||||
} |
@ -0,0 +1,23 @@ | |||||
import { Injectable } from '@angular/core'; | |||||
import { Observable } from 'rxjs/Rx'; | |||||
import { TranslateLoader } from 'ng2-translate/ng2-translate'; | |||||
import { MissingTranslationHandler, MissingTranslationHandlerParams } from 'ng2-translate/ng2-translate'; | |||||
import { ContentService } from './content.service'; | |||||
@Injectable() | |||||
export class ApiTranslationLoader implements TranslateLoader { | |||||
constructor(private cs: ContentService) { } | |||||
getTranslation(lang: string): Observable<any> { | |||||
return this.cs.get(lang); | |||||
} | |||||
} | |||||
@Injectable() | |||||
export class CustomMissingTranslationHandler implements MissingTranslationHandler { | |||||
handle(params: MissingTranslationHandlerParams) { | |||||
return params.key; | |||||
} | |||||
} |
@ -0,0 +1,37 @@ | |||||
import { Injectable } from '@angular/core'; | |||||
import { Router } from '@angular/router'; | |||||
import { DataService } from './data.service'; | |||||
import { User } from '../models/user.model'; | |||||
@Injectable() | |||||
export class AuthService { | |||||
constructor(private router: Router) { } | |||||
logout() { | |||||
sessionStorage.clear(); | |||||
this.router.navigate(['/login']); | |||||
} | |||||
isLoggedIn(): boolean { | |||||
return this.user(undefined) !== undefined; | |||||
} | |||||
user(user: User): User { | |||||
if (user) { | |||||
sessionStorage.setItem('user', JSON.stringify(user)); | |||||
} | |||||
let userData = JSON.parse(sessionStorage.getItem('user')); | |||||
if (userData) { | |||||
user = new User(userData.displayName, userData.roles); | |||||
} | |||||
return user ? user : undefined; | |||||
} | |||||
setAuth(res: any): void { | |||||
if (res && res.user) { | |||||
sessionStorage.setItem('user', JSON.stringify(res.user)); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
import { Injectable } from '@angular/core'; | |||||
import { DataService } from './data.service'; | |||||
@Injectable() | |||||
export class ContentService { | |||||
constructor(public dataService: DataService) { } | |||||
get(lang?: string): any { | |||||
return this.dataService.get('api/content?lang=' + (lang ? lang : 'en')); | |||||
} | |||||
} |
@ -0,0 +1,17 @@ | |||||
import { Injectable } from '@angular/core'; | |||||
import { ApiGatewayService } from './api-gateway.service'; | |||||
@Injectable() | |||||
export class DataService { | |||||
constructor(public http: ApiGatewayService) { } | |||||
get(url: string, params?: any) { | |||||
return this.http.get(url, undefined); | |||||
} | |||||
post(url: string, data: any, params?: any) { | |||||
return this.http.post(url, data, params); | |||||
} | |||||
} |
@ -0,0 +1,25 @@ | |||||
// CREDIT: | |||||
// The vast majority of this code came right from Ben Nadel's post: | |||||
// http://www.bennadel.com/blog/3047-creating-specialized-http-clients-in-angular-2-beta-8.htm | |||||
// | |||||
// My updates are mostly adapting it for Typescript: | |||||
// 1. Importing required modules | |||||
// 2. Adding type notations | |||||
// 3. Using the 'fat-arrow' syntax to properly scope in-line functions | |||||
// | |||||
import { Injectable } from '@angular/core'; | |||||
import { Router } from '@angular/router'; | |||||
@Injectable() | |||||
export class HttpErrorHandlerService { | |||||
constructor(private _router: Router) { } | |||||
handle(error: any) { | |||||
if (error.status === 401) { | |||||
sessionStorage.clear(); | |||||
// window.location.href = 'login'; | |||||
this._router.navigate(['Login']); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,13 @@ | |||||
import { Injectable } from '@angular/core'; | |||||
@Injectable() | |||||
export class NotificationService { | |||||
printSuccessMessage(message: string) { | |||||
console.log(message); | |||||
} | |||||
printErrorMessage(message: string) { | |||||
console.error(message); | |||||
} | |||||
} |
@ -0,0 +1,25 @@ | |||||
import { Injectable } from '@angular/core'; | |||||
import { Router } from '@angular/router'; | |||||
@Injectable() | |||||
export class UtilityService { | |||||
private _router: Router; | |||||
constructor(router: Router) { | |||||
this._router = router; | |||||
} | |||||
convertDateTime(date: Date) { | |||||
let _formattedDate = new Date(date.toString()); | |||||
return _formattedDate.toDateString(); | |||||
} | |||||
navigate(path: string) { | |||||
this._router.navigate([path]); | |||||
} | |||||
navigateToSignIn() { | |||||
this.navigate('/login'); | |||||
} | |||||
} |
@ -0,0 +1,86 @@ | |||||
import { NgModule, ModuleWithProviders } from '@angular/core'; | |||||
import { CommonModule } from '@angular/common'; | |||||
import { FormsModule, ReactiveFormsModule, FormBuilder } from '@angular/forms'; | |||||
import { RouterModule } from '@angular/router'; | |||||
import { HttpModule, JsonpModule } from '@angular/http'; | |||||
import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; | |||||
import { TranslateModule, TranslateLoader } from 'ng2-translate/ng2-translate'; | |||||
import { PageHeadingComponent } from './directives/page-heading.directive'; | |||||
import { DynamicFormComponent } from './forms/dynamic-form.component'; | |||||
import { DynamicFormControlComponent } from './forms/dynamic-form-control.component'; | |||||
import { ErrorMessageComponent } from './forms/error-message.component'; | |||||
import { ErrorSummaryComponent } from './forms/error-summary.component'; | |||||
import { FormControlService } from './forms/form-control.service'; | |||||
import { HeaderComponent } from './layout/header.component'; | |||||
import { FooterComponent } from './layout/footer.component'; | |||||
// Services | |||||
import { DataService } from './services/data.service'; | |||||
import { ApiGatewayService } from './services/api-gateway.service'; | |||||
import { AuthService } from './services/auth.service'; | |||||
import { HttpErrorHandlerService } from './services/http-error-handler.service'; | |||||
import { ApiTranslationLoader } from './services/api-translation-loader.service'; | |||||
import { ContentService } from './services/content.service'; | |||||
import { UtilityService } from './services/utility.service'; | |||||
import { UppercasePipe } from './pipes/uppercase.pipe'; | |||||
@NgModule({ | |||||
imports: [ | |||||
CommonModule, | |||||
FormsModule, | |||||
ReactiveFormsModule, | |||||
RouterModule, | |||||
NgbModule.forRoot(), | |||||
// No need to export as these modules don't expose any components/directive etc' | |||||
HttpModule, | |||||
JsonpModule, | |||||
TranslateModule.forRoot({ provide: TranslateLoader, useClass: ApiTranslationLoader }) | |||||
], | |||||
declarations: [ | |||||
DynamicFormComponent, | |||||
DynamicFormControlComponent, | |||||
ErrorMessageComponent, | |||||
ErrorSummaryComponent, | |||||
FooterComponent, | |||||
HeaderComponent, | |||||
PageHeadingComponent, | |||||
UppercasePipe | |||||
], | |||||
exports: [ | |||||
// Modules | |||||
CommonModule, | |||||
FormsModule, | |||||
ReactiveFormsModule, | |||||
RouterModule, | |||||
NgbModule, | |||||
TranslateModule, | |||||
// Providers, Components, directive, pipes | |||||
DynamicFormComponent, | |||||
DynamicFormControlComponent, | |||||
ErrorSummaryComponent, | |||||
ErrorMessageComponent, | |||||
FooterComponent, | |||||
HeaderComponent, | |||||
PageHeadingComponent, | |||||
UppercasePipe | |||||
] | |||||
}) | |||||
export class SharedModule { | |||||
static forRoot(): ModuleWithProviders { | |||||
return { | |||||
ngModule: SharedModule, | |||||
providers: [ | |||||
// Providers | |||||
HttpErrorHandlerService, | |||||
ApiGatewayService, | |||||
AuthService, | |||||
DataService, | |||||
ContentService, | |||||
FormControlService, | |||||
UtilityService | |||||
] | |||||
}; | |||||
} | |||||
} |
@ -0,0 +1,23 @@ | |||||
// Added parts of es6 which are necessary for your project or your browser support requirements. | |||||
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/set'; | |||||
import 'core-js/es6/weak-map'; | |||||
import 'core-js/es6/weak-set'; | |||||
import 'core-js/es6/typed'; | |||||
import 'core-js/es6/reflect'; | |||||
// see issue https://github.com/AngularClass/angular2-webpack-starter/issues/709 | |||||
// import 'core-js/es6/promise'; | |||||
import 'core-js/es7/reflect'; | |||||
import 'zone.js/dist/zone'; |
@ -0,0 +1,20 @@ | |||||
// For vendors for example jQuery, Lodash, angular2-jwt just import them here unless you plan on | |||||
// chunking vendors files for async loading. You would need to import the async loaded vendors | |||||
// at the entry point of the async loaded file. Also see custom-typings.d.ts as you also need to | |||||
// run `typings install x` where `x` is your module | |||||
// Angular 2 | |||||
import '@angular/platform-browser'; | |||||
import '@angular/platform-browser-dynamic'; | |||||
import '@angular/core'; | |||||
import '@angular/common'; | |||||
import '@angular/forms'; | |||||
import '@angular/http'; | |||||
import '@angular/router'; | |||||
// RxJS | |||||
import 'rxjs/add/operator/map'; | |||||
import 'rxjs/add/operator/mergeMap'; | |||||
import 'rxjs/add/operator/catch'; | |||||
import 'rxjs/add/operator/finally'; | |||||
import 'rxjs/add/observable/throw'; |
@ -0,0 +1,7 @@ | |||||
FROM microsoft/aspnetcore:1.0.1 | |||||
ENTRYPOINT ["dotnet", "eShopOnContainers.WebSPA.dll"] | |||||
ARG source=. | |||||
WORKDIR /app | |||||
ENV ASPNETCORE_URLS http://*:80 | |||||
EXPOSE 80 | |||||
COPY $source . |
@ -0,0 +1,27 @@ | |||||
using System.IO; | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.Extensions.Configuration; | |||||
namespace eShopConContainers.WebSPA | |||||
{ | |||||
public class Program | |||||
{ | |||||
public static void Main(string[] args) | |||||
{ | |||||
var config = new ConfigurationBuilder() | |||||
.SetBasePath(Directory.GetCurrentDirectory()) | |||||
.AddJsonFile("hosting.json", optional: true) | |||||
.Build(); | |||||
var host = new WebHostBuilder() | |||||
.UseKestrel() | |||||
.UseConfiguration(config) | |||||
.UseContentRoot(Directory.GetCurrentDirectory()) | |||||
.UseIISIntegration() | |||||
.UseStartup<Startup>() | |||||
.Build(); | |||||
host.Run(); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,18 @@ | |||||
{ | |||||
"iisSettings": { | |||||
"windowsAuthentication": false, | |||||
"anonymousAuthentication": true, | |||||
"iisExpress": { | |||||
"applicationUrl": "http://localhost:1250/", | |||||
"sslPort": 0 | |||||
} | |||||
}, | |||||
"profiles": { | |||||
"IIS Express": { | |||||
"commandName": "IISExpress", | |||||
"environmentVariables": { | |||||
"ASPNETCORE_ENVIRONMENT": "Development" | |||||
} | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,35 @@ | |||||
// For more information on enabling MVC for empty projects, visit http://go.microsoft.com/fwlink/?LinkID=397860 | |||||
using System.Linq; | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.AspNetCore.Mvc; | |||||
namespace eShopConContainers.WebSPA.Server.Controllers | |||||
{ | |||||
public class HomeController : Controller | |||||
{ | |||||
private readonly IHostingEnvironment _env; | |||||
public HomeController(IHostingEnvironment env) | |||||
{ | |||||
_env = env; | |||||
} | |||||
public IActionResult Index() | |||||
{ | |||||
ViewBag.HashedMain = GetHashedMainDotJs(); | |||||
return View(); | |||||
} | |||||
public string GetHashedMainDotJs() | |||||
{ | |||||
var basePath = _env.WebRootPath + "//dist//"; | |||||
var info = new System.IO.DirectoryInfo(basePath); | |||||
var file = info.GetFiles().Where(f => f.Name.StartsWith("main.") && !f.Name.EndsWith("bundle.map")).FirstOrDefault(); | |||||
return file.Name; | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,93 @@ | |||||
using System; | |||||
using Microsoft.AspNetCore.Antiforgery; | |||||
using Microsoft.AspNetCore.Builder; | |||||
using Microsoft.AspNetCore.Hosting; | |||||
using Microsoft.AspNetCore.Http; | |||||
using Microsoft.AspNetCore.SpaServices.Webpack; | |||||
using Microsoft.Extensions.Configuration; | |||||
using Microsoft.Extensions.DependencyInjection; | |||||
using Microsoft.Extensions.Logging; | |||||
using Newtonsoft.Json.Serialization; | |||||
namespace eShopConContainers.WebSPA | |||||
{ | |||||
public class Startup | |||||
{ | |||||
private IHostingEnvironment _hostingEnv; | |||||
public Startup(IHostingEnvironment env) | |||||
{ | |||||
_hostingEnv = env; | |||||
var builder = new ConfigurationBuilder() | |||||
.SetBasePath(env.ContentRootPath) | |||||
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) | |||||
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) | |||||
.AddEnvironmentVariables(); | |||||
if (env.IsDevelopment()) | |||||
{ | |||||
// For more details on using the user secret store see http://go.microsoft.com/fwlink/?LinkID=532709 | |||||
builder.AddUserSecrets(); | |||||
} | |||||
Configuration = builder.Build(); | |||||
} | |||||
public static IConfigurationRoot Configuration { get; set; } | |||||
// This method gets called by the runtime. Use this method to add services to the container. | |||||
// For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940 | |||||
public void ConfigureServices(IServiceCollection services) | |||||
{ | |||||
services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN"); | |||||
services.AddMvc() | |||||
.AddJsonOptions(options => | |||||
{ | |||||
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); | |||||
}); | |||||
} | |||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | |||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory, IAntiforgery antiforgery) | |||||
{ | |||||
if (env.IsDevelopment()) | |||||
{ | |||||
app.UseDeveloperExceptionPage(); | |||||
app.UseWebpackDevMiddleware(new WebpackDevMiddlewareOptions | |||||
{ | |||||
HotModuleReplacement = true, | |||||
ConfigFile = "config/webpack.config.js" | |||||
}); | |||||
} | |||||
// Configure XSRF middleware, This pattern is for SPA style applications where XSRF token is added on Index page | |||||
// load and passed back token on every subsequent async request | |||||
app.Use(async (context, next) => | |||||
{ | |||||
if (string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase)) | |||||
{ | |||||
var tokens = antiforgery.GetAndStoreTokens(context); | |||||
context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false }); | |||||
} | |||||
await next.Invoke(); | |||||
}); | |||||
app.UseStaticFiles(); | |||||
app.UseMvc(routes => | |||||
{ | |||||
routes.MapRoute( | |||||
name: "default", | |||||
template: "{controller=Home}/{action=Index}/{id?}"); | |||||
routes.MapSpaFallbackRoute( | |||||
name: "spa-fallback", | |||||
defaults: new { controller = "Home", action = "Index" }); | |||||
}); | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,20 @@ | |||||
<style> | |||||
div.app-spinner { | |||||
position: fixed; | |||||
top: 50%; | |||||
left: 50%; | |||||
} | |||||
</style> | |||||
<appc-app asp-prerender-webpack-config="config/webpack.config.js"> | |||||
<div class="app-spinner"> | |||||
<i class="fa fa-spinner fa-spin fa-5x" aria-hidden="true"></i> | |||||
</div> | |||||
</appc-app> | |||||
<script> | |||||
window.user = '@ViewBag.user'; | |||||
</script> | |||||
<script src="~/dist/vendor.js" asp-append-version="true"></script> | |||||
<script src="~/dist/@ViewBag.HashedMain" asp-append-version="true"></script> |
@ -0,0 +1,16 @@ | |||||
<!DOCTYPE html> | |||||
<html> | |||||
<head> | |||||
<meta charset="utf-8" /> | |||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |||||
<title>eShopConContainers.WebSPA</title> | |||||
<base href="/" /> | |||||
<link rel="stylesheet" href="~/dist/vendor.css" asp-append-version="true" /> | |||||
</head> | |||||
<body> | |||||
@RenderBody() | |||||
</body> | |||||
</html> |
@ -0,0 +1,3 @@ | |||||
@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers" | |||||
@addTagHelper "*, Microsoft.AspNetCore.SpaServices" |
@ -0,0 +1,3 @@ | |||||
@{ | |||||
Layout = "_Layout"; | |||||
} |
@ -0,0 +1,47 @@ | |||||
{ | |||||
"ConnectionStrings": { | |||||
"DefaultConnection": "Data Source=AspNetCore.db" | |||||
}, | |||||
"Logging": { | |||||
"IncludeScopes": false, | |||||
"LogLevel": { | |||||
"Default": "Debug", | |||||
"System": "Information", | |||||
"Microsoft": "Information" | |||||
} | |||||
}, | |||||
"Email": { | |||||
"From": "", | |||||
"Subject": "", | |||||
"SendGrid": { | |||||
"Username": "", | |||||
"Password": "" | |||||
} | |||||
}, | |||||
"Authentication": { | |||||
"Google": { | |||||
"ClientId": "", | |||||
"ClientSecret": "" | |||||
}, | |||||
"Facebook": { | |||||
"AppId": "", | |||||
"AppSecret": "" | |||||
}, | |||||
"Microsoft": { | |||||
"ClientId": "", | |||||
"ClientSecret": "" | |||||
}, | |||||
"Twitter": { | |||||
"ConsumerKey": "", | |||||
"ConsumerSecret": "" | |||||
}, | |||||
"Github": { | |||||
"ClientId": "", | |||||
"ClientSecret": "" | |||||
}, | |||||
"LinkedIn": { | |||||
"ClientId": "", | |||||
"ClientSecret": "" | |||||
} | |||||
} | |||||
} |
@ -0,0 +1,23 @@ | |||||
/** | |||||
* @author: @AngularClass | |||||
*/ | |||||
var path = require('path'); | |||||
// Helper functions | |||||
var ROOT = path.resolve(__dirname, '..'); | |||||
console.log('root directory:', root() + '\n'); | |||||
function hasProcessFlag(flag) { | |||||
return process.argv.join('').indexOf(flag) > -1; | |||||
} | |||||
function root(args) { | |||||
args = Array.prototype.slice.call(arguments, 0); | |||||
return path.join.apply(path, [ROOT].concat(args)); | |||||
} | |||||
exports.hasProcessFlag = hasProcessFlag; | |||||
exports.root = root; |
@ -0,0 +1,3 @@ | |||||
module.exports = { | |||||
devtool: 'cheap-module-source-map' | |||||
}; |
@ -0,0 +1,74 @@ | |||||
var path = require('path'); | |||||
var webpack = require('webpack'); | |||||
var merge = require('extendify')({ isDeep: true, arrays: 'concat' }); | |||||
var ExtractTextPlugin = require('extract-text-webpack-plugin'); | |||||
var extractCSS = new ExtractTextPlugin('styles.css'); | |||||
var ForkCheckerPlugin = require('awesome-typescript-loader').ForkCheckerPlugin; | |||||
var devConfig = require('./webpack.config.dev'); | |||||
var prodConfig = require('./webpack.config.prod'); | |||||
var isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Production'; | |||||
console.log("==========Dev Mode = " + isDevelopment + " ============" ) | |||||
module.exports = merge({ | |||||
resolve: { | |||||
extensions: ['.js', '.ts'] | |||||
}, | |||||
module: { | |||||
rules: [ | |||||
{ test: /\.ts$/, exclude: [/\.(spec|e2e)\.ts$/], loaders: ['awesome-typescript-loader?forkChecker=true ', 'angular2-template-loader'] }, | |||||
{ test: /\.html$/, loader: "html" }, | |||||
{ test: /\.css/, loader: extractCSS.extract(['css']) }, | |||||
{ test: /\.scss$/, loaders: ['raw-loader', 'sass-loader?sourceMap'] }, | |||||
{ test: /\.json$/, loader: 'json-loader' }, | |||||
{ | |||||
test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, | |||||
loader: "url?limit=10000&mimetype=application/font-woff" | |||||
}, { | |||||
test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, | |||||
loader: "url?limit=10000&mimetype=application/font-woff" | |||||
}, { | |||||
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, | |||||
loader: "url?limit=10000&mimetype=application/octet-stream" | |||||
}, { | |||||
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, | |||||
loader: "file" | |||||
}, { | |||||
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, | |||||
loader: "url?limit=10000&mimetype=image/svg+xml" | |||||
}, | |||||
{ | |||||
test: /\.(png|jpg|gif)$/, | |||||
loader: "file" | |||||
} | |||||
] | |||||
}, | |||||
entry: { | |||||
'main': './Client/main.ts' | |||||
}, | |||||
output: { | |||||
path: path.join(__dirname, '../wwwroot', 'dist'), | |||||
filename: '[name].js', | |||||
publicPath: '/dist/' | |||||
}, | |||||
profile: true, | |||||
plugins: [ | |||||
extractCSS, | |||||
new webpack.DllReferencePlugin({ | |||||
context: __dirname, | |||||
manifest: require('../wwwroot/dist/vendor-manifest.json') | |||||
}), | |||||
// To eliminate warning | |||||
// https://github.com/AngularClass/angular2-webpack-starter/issues/993 | |||||
new webpack.ContextReplacementPlugin( | |||||
/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, | |||||
__dirname | |||||
), | |||||
new ForkCheckerPlugin(), | |||||
new webpack.DefinePlugin({ | |||||
'process.env': { | |||||
'ENV': JSON.stringify(process.env.ASPNETCORE_ENVIRONMENT) | |||||
} | |||||
}) | |||||
] | |||||
}, isDevelopment ? devConfig : prodConfig); |
@ -0,0 +1,23 @@ | |||||
var webpack = require('webpack'); | |||||
const WebpackMd5Hash = require('webpack-md5-hash'); | |||||
module.exports = { | |||||
devtool: 'source-map', | |||||
output: { | |||||
filename: '[name].[chunkhash].bundle.js', | |||||
sourceMapFilename: '[name].[chunkhash].bundle.map', | |||||
chunkFilename: '[id].[chunkhash].chunk.js' | |||||
}, | |||||
plugins: [ | |||||
// new webpack.LoaderOptionsPlugin({ | |||||
// minimize: true, | |||||
// debug: false | |||||
// }), | |||||
new WebpackMd5Hash(), | |||||
new webpack.optimize.UglifyJsPlugin({ | |||||
beautify: false, | |||||
comments: false, | |||||
sourceMap: true | |||||
}) | |||||
] | |||||
}; |
@ -0,0 +1,73 @@ | |||||
var path = require('path'); | |||||
var webpack = require('webpack'); | |||||
var ExtractTextPlugin = require('extract-text-webpack-plugin'); | |||||
var extractCSS = new ExtractTextPlugin('vendor.css'); | |||||
var isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Development'; | |||||
module.exports = { | |||||
resolve: { | |||||
extensions: ['.js'] | |||||
}, | |||||
module: { | |||||
rules: [ | |||||
{ test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'url-loader?limit=100000' }, | |||||
{ test: /\.scss$/i, loader: extractCSS.extract(['css?minimize', 'sass']) }, | |||||
{ test: /\.json$/, loader: 'json-loader' } | |||||
] | |||||
}, | |||||
entry: { | |||||
// polyfills: [ | |||||
// 'core-js/es6/symbol', | |||||
// 'core-js/es6/object', | |||||
// 'core-js/es6/function', | |||||
// 'core-js/es6/parse-int', | |||||
// 'core-js/es6/parse-float', | |||||
// 'core-js/es6/number', | |||||
// 'core-js/es6/math', | |||||
// 'core-js/es6/string', | |||||
// 'core-js/es6/date', | |||||
// 'core-js/es6/array', | |||||
// 'core-js/es6/regexp', | |||||
// 'core-js/es6/map', | |||||
// 'core-js/es6/set', | |||||
// 'core-js/es6/reflect', | |||||
// 'core-js/es7/reflect', | |||||
// 'zone.js/dist/zone' | |||||
// ], | |||||
vendor: [ | |||||
'font-awesome/scss/font-awesome.scss', | |||||
'bootstrap/scss/bootstrap.scss', | |||||
'@angular/common', | |||||
'@angular/compiler', | |||||
'@angular/core', | |||||
'@angular/http', | |||||
'@angular/forms', | |||||
'@angular/platform-browser', | |||||
'@angular/platform-browser-dynamic', | |||||
'@angular/router' | |||||
] | |||||
}, | |||||
output: { | |||||
path: path.join(__dirname, '../wwwroot', 'dist'), | |||||
filename: '[name].js', | |||||
library: '[name]_[hash]', | |||||
}, | |||||
plugins: [ | |||||
extractCSS, | |||||
// To eliminate warning | |||||
// https://github.com/AngularClass/angular2-webpack-starter/issues/993 | |||||
new webpack.ContextReplacementPlugin( | |||||
/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/, | |||||
__dirname | |||||
), | |||||
new webpack.DllPlugin({ | |||||
path: path.join(__dirname, '../wwwroot', 'dist', '[name]-manifest.json'), | |||||
name: '[name]_[hash]' | |||||
}) | |||||
].concat(isDevelopment ? [] : [ | |||||
new webpack.optimize.UglifyJsPlugin({ | |||||
beautify: false, | |||||
comments: false | |||||
}) | |||||
]) | |||||
}; |
@ -0,0 +1,78 @@ | |||||
version: '2' | |||||
services: | |||||
webspa: | |||||
image: eshop/webspa | |||||
build: | |||||
context: . | |||||
dockerfile: Dockerfile | |||||
environment: | |||||
- CatalogUrl=http://catalog.api | |||||
- OrderingUrl=http://ordering.api | |||||
ports: | |||||
- "5104:80" | |||||
depends_on: | |||||
- catalog.api | |||||
- identity.data | |||||
catalog.api: | |||||
image: eshop/catalog.api | |||||
environment: | |||||
- ConnectionString=Server=catalog.data;Initial Catalog=CatalogData;User Id=sa;Password=Pass@word | |||||
expose: | |||||
- "80" | |||||
ports: | |||||
- "5101:80" | |||||
depends_on: | |||||
- catalog.data | |||||
catalog.data: | |||||
image: eshop/mssql-server-private-preview | |||||
environment: | |||||
- SA_PASSWORD=Pass@word | |||||
- ACCEPT_EULA=Y | |||||
ports: | |||||
- "5434:1433" | |||||
ordering.api: | |||||
image: eshop/ordering.api | |||||
environment: | |||||
- ConnectionString=Server=ordering.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word | |||||
ports: | |||||
- "5102:80" | |||||
# (Go to Production): For secured/final deployment, remove Ports mapping and | |||||
# leave just the internal expose section | |||||
# expose: | |||||
# - "80" | |||||
extra_hosts: | |||||
- "CESARDLBOOKVHD:10.0.75.1" | |||||
depends_on: | |||||
- ordering.data | |||||
ordering.data: | |||||
image: eshop/ordering.data.sqlserver.linux | |||||
ports: | |||||
- "5432:1433" | |||||
identity.data: | |||||
image: eshop/mssql-server-private-preview | |||||
environment: | |||||
- SA_PASSWORD=Pass@word | |||||
- ACCEPT_EULA=Y | |||||
ports: | |||||
- "5433:1433" | |||||
basket.api: | |||||
image: eshop/basket.api | |||||
environment: | |||||
- ConnectionString=basket.data | |||||
build: | |||||
context: . | |||||
dockerfile: Dockerfile | |||||
ports: | |||||
- "5103:80" | |||||
depends_on: | |||||
- basket.data | |||||
basket.data: | |||||
image: redis |
@ -0,0 +1,17 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | |||||
<PropertyGroup> | |||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion> | |||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath> | |||||
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked> | |||||
</PropertyGroup> | |||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" /> | |||||
<PropertyGroup Label="Globals"> | |||||
<ProjectGuid>9842db3a-1391-48c7-a49c-2fabd0a18ac2</ProjectGuid> | |||||
<RootNamespace>eShopOnContainers.WebSPA</RootNamespace> | |||||
</PropertyGroup> | |||||
<PropertyGroup> | |||||
<SchemaVersion>2.0</SchemaVersion> | |||||
</PropertyGroup> | |||||
<Import Project="$(VSToolsPath)\DotNet.Web\Microsoft.DotNet.Web.targets" Condition="'$(VSToolsPath)' != ''" /> | |||||
</Project> |
@ -0,0 +1,3 @@ | |||||
{ | |||||
"server.urls": "http://localhost:5000;http://localhost:5001" | |||||
} |
@ -0,0 +1,109 @@ | |||||
{ | |||||
"name": "eshopaspnetnetcoredockerspa", | |||||
"version": "0.0.0", | |||||
"private": true, | |||||
"keywords": [ | |||||
"aspnetcore", | |||||
"entityframework core", | |||||
"angular2", | |||||
"webpack2", | |||||
"typescript2", | |||||
"bootstrap4", | |||||
"docker" | |||||
], | |||||
"author": { | |||||
"name": "Microsoft", | |||||
"email": "cesardl@microsoft.com" | |||||
}, | |||||
"scripts": { | |||||
"rimraf": "rimraf", | |||||
"tslint": "tslint", | |||||
"typedoc": "typedoc", | |||||
"typings": "typings", | |||||
"webpack": "webpack", | |||||
"clean": "npm cache clean && npm run rimraf -- node_modules doc typings coverage wwwroot/dist", | |||||
"clean:dist": "npm run rimraf -- wwwroot/dist", | |||||
"preclean:install": "npm run clean", | |||||
"clean:install": "npm set progress=false && npm install", | |||||
"preclean:start": "npm run clean", | |||||
"clean:start": "npm start", | |||||
"build:vendor": "node node_modules/webpack/bin/webpack.js --config config/webpack.config.vendor.js", | |||||
"build:main": "node node_modules/webpack/bin/webpack.js --config config/webpack.config.js", | |||||
"setdev": "set ASPNETCORE_ENVIRONMENT=Development", | |||||
"setprod": "set ASPNETCORE_ENVIRONMENT=Production", | |||||
"build:dev": "npm run setdev && npm run clean:dist && npm run build:vendor && npm run build:main", | |||||
"build:prod": "npm run setprod && npm run clean:dist && npm run build:vendor && npm run build:main", | |||||
"lint": "npm run tslint \"Client/**/*.ts\"", | |||||
"docs": "npm run typedoc -- --options typedoc.json --exclude '**/*.spec.ts' ./Client/", | |||||
"version": "npm run build", | |||||
}, | |||||
"dependencies": { | |||||
"@angular/common": "2.1.2", | |||||
"@angular/compiler": "2.1.2", | |||||
"@angular/compiler-cli": "2.1.2", | |||||
"@angular/core": "2.1.2", | |||||
"@angular/forms": "2.1.2", | |||||
"@angular/http": "2.1.2", | |||||
"@angular/platform-browser": "2.1.2", | |||||
"@angular/platform-browser-dynamic": "2.1.2", | |||||
"@angular/platform-server": "2.1.2", | |||||
"@angular/router": "3.1.2", | |||||
"@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.11", | |||||
"aspnet-prerendering": "1.0.7", | |||||
"aspnet-webpack": "1.0.24", | |||||
"bootstrap": "4.0.0-alpha.5", | |||||
"core-js": "2.4.1", | |||||
"font-awesome": "4.6.3", | |||||
"isomorphic-fetch": "2.2.1", | |||||
"ng2-translate": "4.0.0", | |||||
"normalize.css": "5.0.0", | |||||
"preboot": "4.5.2", | |||||
"rxjs": "5.0.0-beta.12", | |||||
"zone.js": "0.6.26" | |||||
}, | |||||
"devDependencies": { | |||||
"@types/core-js": "0.9.34", | |||||
"@types/hammerjs": "2.0.33", | |||||
"@types/jasmine": "2.5.35", | |||||
"@types/node": "6.0.45", | |||||
"@types/protractor": "1.5.20", | |||||
"@types/selenium-webdriver": "2.44.26", | |||||
"@types/sinon": "1.16.31", | |||||
"@types/source-map": "0.1.28", | |||||
"@types/uglify-js": "2.6.28", | |||||
"@types/webpack": "1.12.35", | |||||
"angular2-template-loader": "0.6.0", | |||||
"awesome-typescript-loader": "2.2.4", | |||||
"codelyzer": "1.0.0-beta.3", | |||||
"copy-webpack-plugin": "^4.0.0", | |||||
"css": "2.2.1", | |||||
"css-loader": "0.25.0", | |||||
"es6-promise": "3.2.1", | |||||
"es6-promise-loader": "1.0.2", | |||||
"expose-loader": "0.7.1", | |||||
"extendify": "1.0.0", | |||||
"extract-text-webpack-plugin": "2.0.0-beta.4", | |||||
"file-loader": "0.9.0", | |||||
"html-loader": "0.4.4", | |||||
"html-webpack-plugin": "^2.24.1", | |||||
"json-loader": "0.5.4", | |||||
"node-sass": "3.9.3", | |||||
"parse5": "2.1.5", | |||||
"raw-loader": "0.5.1", | |||||
"rimraf": "2.5.4", | |||||
"sass-loader": "4.0.2", | |||||
"source-map-loader": "0.1.5", | |||||
"style-loader": "0.13.1", | |||||
"ts-helpers": "1.1.1", | |||||
"ts-node": "1.4.3", | |||||
"tslint": "3.15.1", | |||||
"tslint-loader": "2.1.5", | |||||
"typedoc": "0.5.0", | |||||
"typescript": "2.0.6", | |||||
"url-loader": "0.5.7", | |||||
"webpack": "2.1.0-beta.25", | |||||
"webpack-externals-plugin": "1.0.0", | |||||
"webpack-hot-middleware": "2.13.0", | |||||
"webpack-md5-hash": "0.0.5" | |||||
} | |||||
} |
@ -0,0 +1,116 @@ | |||||
{ | |||||
"userSecretsId": "aspnetcorespa-c23d27a4-eb88-4b18-9b77-2a93f3b15119", | |||||
"dependencies": { | |||||
"Microsoft.NETCore.App": { | |||||
"version": "1.0.0", | |||||
"type": "platform" | |||||
}, | |||||
"Microsoft.Extensions.Configuration.UserSecrets": "1.0.0", | |||||
"Microsoft.AspNetCore.Authentication.Cookies": "1.0.0", | |||||
"Microsoft.AspNetCore.Diagnostics": "1.0.0", | |||||
"Microsoft.AspNetCore.Mvc": "1.0.1", | |||||
"Microsoft.AspNetCore.Cors": "1.0.0", | |||||
"Microsoft.AspNetCore.Antiforgery": "1.0.1", | |||||
"Microsoft.AspNetCore.Authorization": "1.0.0", | |||||
"Newtonsoft.Json": "9.0.1", | |||||
"Webpack": "3.0.0", | |||||
"Microsoft.AspNetCore.AngularServices": "1.0.0-beta-000014", | |||||
"Microsoft.AspNetCore.Razor.Tools": { | |||||
"version": "1.0.0-preview2-final", | |||||
"type": "build" | |||||
}, | |||||
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0", | |||||
"Microsoft.AspNetCore.Server.Kestrel": "1.0.0", | |||||
"Microsoft.AspNetCore.StaticFiles": "1.0.0", | |||||
"Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0", | |||||
"Microsoft.Extensions.Configuration.Json": "1.0.0", | |||||
"Microsoft.Extensions.Logging": "1.0.0", | |||||
"Microsoft.Extensions.Logging.Console": "1.0.0", | |||||
"Microsoft.Extensions.Logging.Debug": "1.0.0", | |||||
"Microsoft.VisualStudio.Web.CodeGeneration.Tools": { | |||||
"version": "1.0.0-preview2-final", | |||||
"type": "build" | |||||
}, | |||||
"Microsoft.VisualStudio.Web.CodeGenerators.Mvc": { | |||||
"version": "1.0.0-preview2-final", | |||||
"type": "build" | |||||
}, | |||||
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0" | |||||
}, | |||||
"tools": { | |||||
"Microsoft.DotNet.Watcher.Tools": { | |||||
"version": "1.0.0-*", | |||||
"imports": "portable-net451+win8" | |||||
}, | |||||
"Microsoft.AspNetCore.Razor.Tools": { | |||||
"version": "1.0.0-preview2-final", | |||||
"imports": "portable-net45+win8+dnxcore50" | |||||
}, | |||||
"Microsoft.AspNetCore.Server.IISIntegration.Tools": { | |||||
"version": "1.0.0-preview2-final", | |||||
"imports": "portable-net45+win8+dnxcore50" | |||||
}, | |||||
"Microsoft.Extensions.SecretManager.Tools": { | |||||
"version": "1.0.0-preview2-final", | |||||
"imports": "portable-net45+win8+dnxcore50" | |||||
}, | |||||
"Microsoft.VisualStudio.Web.CodeGeneration.Tools": { | |||||
"version": "1.0.0-preview2-final", | |||||
"imports": [ | |||||
"portable-net45+win8+dnxcore50", | |||||
"portable-net45+win8" | |||||
] | |||||
} | |||||
}, | |||||
"frameworks": { | |||||
"netcoreapp1.0": { | |||||
"imports": [ | |||||
"dotnet5.6", | |||||
"portable-net45+win8" | |||||
] | |||||
} | |||||
}, | |||||
"buildOptions": { | |||||
"emitEntryPoint": true, | |||||
"preserveCompilationContext": true, | |||||
"compile": { | |||||
"exclude": [ | |||||
"node_modules", | |||||
"Client" | |||||
] | |||||
}, | |||||
"debugType": "portable" | |||||
}, | |||||
"runtimeOptions": { | |||||
"configProperties": { | |||||
"System.GC.Server": true | |||||
} | |||||
}, | |||||
"publishOptions": { | |||||
"include": [ | |||||
"appsettings.json", | |||||
"Client", | |||||
"typings", | |||||
"Views", | |||||
"tsconfig.json", | |||||
"tsd.json", | |||||
"web.config", | |||||
"config", | |||||
"wwwroot", | |||||
"dockerfile" | |||||
] | |||||
}, | |||||
"scripts": { | |||||
// "prepublish": [ | |||||
// "npm install", | |||||
// "node node_modules/webpack/bin/webpack.js --config config/webpack.config.vendor.js", | |||||
// "node node_modules/webpack/bin/webpack.js --config config/webpack.config.js" | |||||
// ], | |||||
"postpublish": [ | |||||
"dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" | |||||
] | |||||
}, | |||||
"tooling": { | |||||
"defaultNamespace": "eShopOnContainers.SPA" | |||||
} | |||||
} |
@ -0,0 +1,42 @@ | |||||
{ | |||||
"compilerOptions": { | |||||
"target": "es5", | |||||
"module": "commonjs", | |||||
"moduleResolution": "node", | |||||
"declaration": false, | |||||
"emitDecoratorMetadata": true, | |||||
"experimentalDecorators": true, | |||||
"allowSyntheticDefaultImports": true, | |||||
"sourceMap": true, | |||||
"strictNullChecks": false, | |||||
"baseUrl": "./src", | |||||
"paths": {}, | |||||
"lib": [ | |||||
"dom", | |||||
"es6" | |||||
], | |||||
"types": [ | |||||
"hammerjs", | |||||
"jasmine", | |||||
"node", | |||||
"protractor", | |||||
"selenium-webdriver", | |||||
"source-map", | |||||
"uglify-js", | |||||
"webpack" | |||||
] | |||||
}, | |||||
"exclude": [ | |||||
"node_modules", | |||||
"wwwroot" | |||||
], | |||||
"awesomeTypescriptLoaderOptions": { | |||||
"forkChecker": true, | |||||
"useWebpackText": true | |||||
}, | |||||
"compileOnSave": false, | |||||
"buildOnSave": false, | |||||
"atom": { | |||||
"rewriteTsconfig": false | |||||
} | |||||
} |
@ -0,0 +1,178 @@ | |||||
{ | |||||
"rulesDirectory": [ | |||||
"node_modules/codelyzer" | |||||
], | |||||
"rules": { | |||||
"directive-selector-name": [ | |||||
true, | |||||
"camelCase" | |||||
], | |||||
"component-selector-name": [ | |||||
true, | |||||
"kebab-case" | |||||
], | |||||
"directive-selector-type": [ | |||||
true, | |||||
"attribute" | |||||
], | |||||
"component-selector-type": [ | |||||
true, | |||||
"element" | |||||
], | |||||
"directive-selector-prefix": [ | |||||
true, | |||||
"appd" | |||||
], | |||||
"component-selector-prefix": [ | |||||
true, | |||||
"appc" | |||||
], | |||||
"use-input-property-decorator": true, | |||||
"use-output-property-decorator": true, | |||||
"use-host-property-decorator": true, | |||||
"no-attribute-parameter-decorator": true, | |||||
"no-input-rename": true, | |||||
"no-output-rename": true, | |||||
"no-forward-ref": true, | |||||
"use-life-cycle-interface": true, | |||||
"use-pipe-transform-interface": true, | |||||
"pipe-naming": [ | |||||
true, | |||||
"camelCase", | |||||
"appf" | |||||
], | |||||
"component-class-suffix": true, | |||||
"directive-class-suffix": true, | |||||
"import-destructuring-spacing": true, | |||||
"member-access": false, | |||||
"member-ordering": [ | |||||
true, | |||||
"public-before-private", | |||||
"static-before-instance", | |||||
"variables-before-functions" | |||||
], | |||||
"no-any": false, | |||||
"no-inferrable-types": false, | |||||
"no-internal-module": true, | |||||
"no-var-requires": false, | |||||
"typedef": false, | |||||
"typedef-whitespace": [ | |||||
true, | |||||
{ | |||||
"call-signature": "nospace", | |||||
"index-signature": "nospace", | |||||
"parameter": "nospace", | |||||
"property-declaration": "nospace", | |||||
"variable-declaration": "nospace" | |||||
}, | |||||
{ | |||||
"call-signature": "space", | |||||
"index-signature": "space", | |||||
"parameter": "space", | |||||
"property-declaration": "space", | |||||
"variable-declaration": "space" | |||||
} | |||||
], | |||||
"ban": false, | |||||
"curly": false, | |||||
"forin": true, | |||||
"label-position": true, | |||||
"label-undefined": true, | |||||
"no-arg": true, | |||||
"no-bitwise": true, | |||||
"no-conditional-assignment": 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-null-keyword": true, | |||||
"no-shadowed-variable": true, | |||||
"no-string-literal": true, | |||||
"no-switch-case-fall-through": true, | |||||
"no-unreachable": true, | |||||
"no-unused-expression": true, | |||||
"no-unused-variable": false, | |||||
"no-use-before-declare": true, | |||||
"no-var-keyword": true, | |||||
"radix": true, | |||||
"switch-default": true, | |||||
"triple-equals": [ | |||||
true, | |||||
"allow-null-check" | |||||
], | |||||
"use-strict": [ | |||||
true, | |||||
"check-module" | |||||
], | |||||
"eofline": true, | |||||
"indent": [ | |||||
true, | |||||
"spaces" | |||||
], | |||||
"max-line-length": [ | |||||
true, | |||||
200 | |||||
], | |||||
"no-require-imports": false, | |||||
"no-trailing-whitespace": true, | |||||
"object-literal-sort-keys": false, | |||||
"trailing-comma": [ | |||||
true, | |||||
{ | |||||
"multiline": "never", | |||||
"singleline": "never" | |||||
} | |||||
], | |||||
"align": false, | |||||
"class-name": true, | |||||
"comment-format": [ | |||||
true, | |||||
"check-space" | |||||
], | |||||
"interface-name": false, | |||||
"jsdoc-format": true, | |||||
"no-consecutive-blank-lines": false, | |||||
"no-constructor-vars": false, | |||||
"one-line": [ | |||||
true, | |||||
"check-open-brace", | |||||
"check-catch", | |||||
"check-else", | |||||
"check-finally", | |||||
"check-whitespace" | |||||
], | |||||
"quotemark": [ | |||||
true, | |||||
"single", | |||||
"avoid-escape" | |||||
], | |||||
"semicolon": [ | |||||
true, | |||||
"always" | |||||
], | |||||
"variable-name": [ | |||||
true, | |||||
"check-format", | |||||
"allow-leading-underscore", | |||||
"ban-keywords" | |||||
], | |||||
"whitespace": [ | |||||
true, | |||||
"check-branch", | |||||
"check-decl", | |||||
"check-operator", | |||||
"check-separator", | |||||
"check-type" | |||||
] | |||||
} | |||||
} |
@ -0,0 +1,15 @@ | |||||
{ | |||||
"mode": "modules", | |||||
"out": "doc", | |||||
"theme": "default", | |||||
"ignoreCompilerErrors": "true", | |||||
"experimentalDecorators": "true", | |||||
"emitDecoratorMetadata": "true", | |||||
"target": "ES5", | |||||
"moduleResolution": "node", | |||||
"preserveConstEnums": "true", | |||||
"stripInternal": "true", | |||||
"suppressExcessPropertyErrors": "true", | |||||
"suppressImplicitAnyIndexErrors": "true", | |||||
"module": "commonjs" | |||||
} |
@ -0,0 +1,14 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<configuration> | |||||
<!-- | |||||
Configure your application settings in appsettings.json. Learn more at https://go.microsoft.com/fwlink/?LinkId=786380 | |||||
--> | |||||
<system.webServer> | |||||
<handlers> | |||||
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified"/> | |||||
</handlers> | |||||
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" forwardWindowsAuthToken="false"/> | |||||
</system.webServer> | |||||
</configuration> |
@ -0,0 +1,9 @@ | |||||
<?xml version="1.0" encoding="utf-8"?> | |||||
<configuration> | |||||
<system.webServer> | |||||
<handlers> | |||||
<add name="httpPlatformHandler" path="*" verb="*" modules="httpPlatformHandler" resourceType="Unspecified"/> | |||||
</handlers> | |||||
<httpPlatform processPath="%DNX_PATH%" arguments="%DNX_ARGS%" stdoutLogEnabled="false"/> | |||||
</system.webServer> | |||||
</configuration> |