diff --git a/.gitignore b/.gitignore
index 75d3a4bd2..d7f16d65c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@
*.user
*.userosscache
*.sln.docstates
+.vscode/
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
diff --git a/cli-linux/build-bits-linux.sh b/cli-linux/build-bits-linux.sh
old mode 100644
new mode 100755
index e99df361b..7cda26d8c
--- a/cli-linux/build-bits-linux.sh
+++ b/cli-linux/build-bits-linux.sh
@@ -1,18 +1,17 @@
-
-projectList=(
- "/src/Services/Catalog/Catalog.API"
- "/src/Services/Basket/Basket.API"
- "/src/Services/Ordering/Ordering.API"
- "/src/Services/Identity/Identity.API"
- "/src/Web/WebMVC"
- "/src/Web/WebSPA"
- "/src/Web/WebStatus
+#!/bin/bash
+declare -a projectList=(
+ '../src/Services/Catalog/Catalog.API'
+ '../src/Services/Basket/Basket.API'
+ '../src/Services/Ordering/Ordering.API'
+ '../src/Services/Identity/Identity.API'
+ '../src/Web/WebMVC'
+ '../src/Web/WebSPA'
+ '../src/Web/WebStatus'
)
# Build SPA app
-pushd $(pwd)/src/Web/WebSPA
-npm rebuild node-sass
-npm run build:prod
+# pushd $(pwd)../src/Web/WebSPA
+# npm run build:prod
for project in "${projectList[@]}"
do
@@ -28,13 +27,13 @@ do
done
# remove old docker images:
-#images=$(docker images --filter=reference="eshop/*" -q)
-#if [ -n "$images" ]; then
-# docker rm $(docker ps -a -q) -f
-# echo "Deleting eShop images in local Docker repo"
-# echo $images
-# docker rmi $(docker images --filter=reference="eshop/*" -q) -f
-#fi
+images=$(docker images --filter=reference="eshop/*" -q)
+if [ -n "$images" ]; then
+ docker rm $(docker ps -a -q) -f
+ echo "Deleting eShop images in local Docker repo"
+ echo $images
+ docker rmi $(docker images --filter=reference="eshop/*" -q) -f
+fi
# No need to build the images, docker build or docker compose will
# do that using the images and containers defined in the docker-compose.yml file.
diff --git a/docker-compose.ci.build.yml b/docker-compose.ci.build.yml
index ef9705c8e..546b7690f 100644
--- a/docker-compose.ci.build.yml
+++ b/docker-compose.ci.build.yml
@@ -6,5 +6,5 @@ services:
volumes:
- .:/src
working_dir: /src
- command: /bin/bash -c "pushd ./src/Web/WebSPA && npm rebuild node-sass && pushd ./../../.. && dotnet restore ./eShopOnContainers-ServicesAndWebApps.sln && dotnet publish ./eShopOnContainers-ServicesAndWebApps.sln -c Release -o ./obj/Docker/publish"
+ command: /bin/bash -c "dotnet restore ./eShopOnContainers-ServicesAndWebApps.sln && dotnet publish ./eShopOnContainers-ServicesAndWebApps.sln -c Release -o ./obj/Docker/publish"
diff --git a/src/Web/WebMVC/wwwroot/css/site.min.css b/src/Web/WebMVC/wwwroot/css/site.min.css
index 4d03fa783..f5fc90999 100644
--- a/src/Web/WebMVC/wwwroot/css/site.min.css
+++ b/src/Web/WebMVC/wwwroot/css/site.min.css
@@ -1 +1 @@
-.esh-app-footer{background-color:#000;border-top:1px solid #eee;margin-top:2.5rem;padding-bottom:2.5rem;padding-top:2.5rem;width:100%}.esh-app-footer-brand{height:50px;width:230px}.esh-app-footer-text{color:#83d01b;line-height:50px;text-align:right;width:100%}@font-face{font-family:Montserrat;font-weight:400;src:url("../fonts/Montserrat-Regular.eot?") format("eot"),url("../fonts/Montserrat-Regular.woff") format("woff"),url("../fonts/Montserrat-Regular.ttf") format("truetype"),url("../fonts/Montserrat-Regular.svg#Montserrat") format("svg")}@font-face{font-family:Montserrat;font-weight:700;src:url("../fonts/Montserrat-Bold.eot?") format("eot"),url("../fonts/Montserrat-Bold.woff") format("woff"),url("../fonts/Montserrat-Bold.ttf") format("truetype"),url("../fonts/Montserrat-Bold.svg#Montserrat") format("svg")}html,body{font-family:Montserrat,sans-serif;font-size:16px;font-weight:400;z-index:10}*,*::after,*::before{box-sizing:border-box}.preloading{color:#00a69c;display:block;font-size:1.5rem;left:50%;position:fixed;top:50%;transform:translate(-50%,-50%)}select::-ms-expand{display:none}@media screen and (min-width:992px){.form-input{max-width:360px;width:360px}}.form-input{border-radius:0;height:45px;padding:10px}.form-input-small{max-width:100px !important}.form-input-medium{width:150px !important}.alert{padding-left:0}.alert-danger{background-color:transparent;border:0;color:#fb0d0d;font-size:12px}a,a:active,a:hover,a:visited{color:#000;text-decoration:none;transition:color .35s}a:hover,a:active{color:#75b918;transition:color .35s}.esh-basket{min-height:80vh}.esh-basket-titles{padding-bottom:1rem;padding-top:2rem}.esh-basket-titles--clean{padding-bottom:0;padding-top:0}.esh-basket-title{text-transform:uppercase}.esh-basket-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-basket-items--border:last-of-type{border-color:transparent}.esh-basket-item{font-size:1rem;font-weight:300}.esh-basket-item--middle{line-height:8rem}@media screen and (max-width:1024px){.esh-basket-item--middle{line-height:1rem}}.esh-basket-item--mark{color:#00a69c}.esh-basket-image{height:8rem}.esh-basket-input{line-height:1rem;width:100%}.esh-basket-checkout{border:none;border-radius:0;background-color:#83d01b;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s}.esh-basket-checkout:hover{background-color:#4a760f;transition:all .35s}.esh-basket-margin12{margin-left:12px}.esh-basketstatus{cursor:pointer;display:inline-block;float:right;position:relative;transition:all .35s}.esh-basketstatus.is-disabled{opacity:.5;pointer-events:none}.esh-basketstatus-image{height:36px;margin-top:.5rem}.esh-basketstatus-badge{background-color:#83d01b;border-radius:50%;color:#fff;display:block;height:1.5rem;left:50%;position:absolute;text-align:center;top:0;transform:translateX(-38%);transition:all .35s;width:1.5rem}.esh-basketstatus:hover .esh-basketstatus-badge{background-color:transparent;color:#75b918;transition:all .35s}.esh-catalog-hero{background-image:url("../images/main_banner.png");background-size:cover;height:260px;width:100%}.esh-catalog-title{position:relative;top:74.28571px}.esh-catalog-filters{background-color:#00a69c;height:65px}.esh-catalog-filter{background-color:transparent;border-color:#00d9cc;color:#fff;cursor:pointer;margin-right:1rem;margin-top:.5rem;outline-color:#83d01b;padding-bottom:0;padding-left:.5rem;padding-right:.5rem;padding-top:1.5rem;min-width:140px;-webkit-appearance:none}.esh-catalog-filter option{background-color:#00a69c}.esh-catalog-label{display:inline-block;position:relative;z-index:0}.esh-catalog-label::before{color:rgba(255,255,255,.5);content:attr(data-title);font-size:.65rem;margin-top:.65rem;margin-left:.5rem;position:absolute;text-transform:uppercase;z-index:1}.esh-catalog-label::after{background-image:url("../images/arrow-down.png");height:7px;content:'';position:absolute;right:1.5rem;top:2.5rem;width:10px;z-index:1}.esh-catalog-send{background-color:#83d01b;color:#fff;cursor:pointer;font-size:1rem;transform:translateY(.5rem);padding:.5rem;transition:all .35s}.esh-catalog-send:hover{background-color:#4a760f;transition:all .35s}.esh-catalog-items{margin-top:1rem}.esh-catalog-item{text-align:center;margin-bottom:1.5rem;width:33%;display:inline-block;float:none !important}@media screen and (max-width:1024px){.esh-catalog-item{width:50%}}@media screen and (max-width:768px){.esh-catalog-item{width:100%}}.esh-catalog-thumbnail{max-width:370px;width:100%}.esh-catalog-button{background-color:#83d01b;border:none;color:#fff;cursor:pointer;font-size:1rem;height:3rem;margin-top:1rem;transition:all .35s;width:80%}.esh-catalog-button.is-disabled{opacity:.5;pointer-events:none}.esh-catalog-button:hover{background-color:#4a760f;transition:all .35s}.esh-catalog-name{font-size:1rem;font-weight:300;margin-top:.5rem;text-align:center;text-transform:uppercase}.esh-catalog-price{text-align:center;font-weight:900;font-size:28px}.esh-catalog-price::before{content:'$'}.esh-orders{min-height:80vh;overflow-x:hidden}.esh-orders-header{background-color:#00a69c;height:4rem}.esh-orders-back{color:rgba(255,255,255,.4);line-height:4rem;text-transform:uppercase;text-decoration:none;transition:color .35s}.esh-orders-back:hover{color:#fff;transition:color .35s}.esh-orders-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders-title{text-transform:uppercase}.esh-orders-items{height:2rem;line-height:2rem;position:relative}.esh-orders-items:nth-of-type(2n+1):before{background-color:#eef;content:'';height:100%;left:0;margin-left:-100vw;position:absolute;top:0;width:200vw;z-index:-1}.esh-orders-item{font-weight:300}.esh-orders-item--hover{opacity:0;pointer-events:none}.esh-orders-items:hover .esh-orders-item--hover{opacity:1;pointer-events:all}.esh-orders-link{color:#83d01b;text-decoration:none;transition:color .35s}.esh-orders-link:hover{color:#75b918;transition:color .35s}.esh-orders_detail{min-height:80vh}.esh-orders_detail-section{padding:1rem 0}.esh-orders_detail-section--right{text-align:right}.esh-orders_detail-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders_detail-title{text-transform:uppercase}.esh-orders_detail-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-orders_detail-items--border:last-of-type{border-color:transparent}.esh-orders_detail-item{font-size:1rem;font-weight:300}.esh-orders_detail-item--middle{line-height:8rem}@media screen and (max-width:768px){.esh-orders_detail-item--middle{line-height:1rem}}.esh-orders_detail-item--mark{color:#83d01b}.esh-orders_detail-image{height:8rem}.esh-orders_new{min-height:80vh}.esh-orders_new-header{background-color:#00a69c;height:4rem}.esh-orders_new-back{color:rgba(255,255,255,.4);line-height:4rem;text-decoration:none;text-transform:uppercase;transition:color .35s}.esh-orders_new-back:hover{color:#fff;transition:color .35s}.esh-orders_new-section{padding:1rem 0}.esh-orders_new-section--right{text-align:right}.esh-orders_new-placeOrder{background-color:#83d01b;border:0;border-radius:0;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s}.esh-orders_new-placeOrder:hover{background-color:#4a760f;transition:all .35s}.esh-orders_new-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders_new-title{font-size:1.25rem;text-transform:uppercase}.esh-orders_new-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-orders_new-items--border:last-of-type{border-color:transparent}.esh-orders_new-item{font-size:1rem;font-weight:300}.esh-orders_new-item--middle{line-height:8rem}@media screen and (max-width:768px){.esh-orders_new-item--middle{line-height:1rem}}.esh-orders_new-item--mark{color:#83d01b}.esh-orders_new-image{height:8rem}.esh-header{background-color:#00a69c;height:4rem}.esh-header-back{color:rgba(255,255,255,.5) !important;line-height:4rem;text-transform:uppercase;text-decoration:none;transition:color .35s}.esh-header-back:hover{color:#fff !important;transition:color .35s}.esh-identity{line-height:3rem;position:relative;text-align:right}.esh-identity-section{display:inline-block;width:100%}.esh-identity-name{display:inline-block}.esh-identity-name--upper{text-transform:uppercase}@media screen and (max-width:768px){.esh-identity-name{font-size:.85rem}}.esh-identity-image{display:inline-block}.esh-identity-drop{background:#fff;height:0;min-width:14rem;right:0;overflow:hidden;padding:.5rem;position:absolute;top:2.5rem;transition:height .35s}.esh-identity:hover .esh-identity-drop{border:1px solid #eee;height:7rem;transition:height .35s}.esh-identity-item{cursor:pointer;display:block;transition:color .35s}.esh-identity-item:hover{color:#75b918;transition:color .35s}.esh-pager-wrapper{padding-top:1rem;text-align:center}.esh-pager-item{margin:0 5vw}.esh-pager-item--navigable{display:inline-block;cursor:pointer}.esh-pager-item--navigable.is-disabled{opacity:0;pointer-events:none}.esh-pager-item--navigable:hover{color:#83d01b}@media screen and (max-width:1280px){.esh-pager-item{font-size:.85rem}}@media screen and (max-width:1024px){.esh-pager-item{margin:0 4vw}}
\ No newline at end of file
+.esh-app-footer{background-color:#000;border-top:1px solid #eee;margin-top:2.5rem;padding-bottom:2.5rem;padding-top:2.5rem;width:100%}.esh-app-footer-brand{height:50px;width:230px}.esh-app-footer-text{color:#83d01b;line-height:50px;text-align:right;width:100%}@font-face{font-family:Montserrat;font-weight:400;src:url("../fonts/Montserrat-Regular.eot?") format("eot"),url("../fonts/Montserrat-Regular.woff") format("woff"),url("../fonts/Montserrat-Regular.ttf") format("truetype"),url("../fonts/Montserrat-Regular.svg#Montserrat") format("svg")}@font-face{font-family:Montserrat;font-weight:700;src:url("../fonts/Montserrat-Bold.eot?") format("eot"),url("../fonts/Montserrat-Bold.woff") format("woff"),url("../fonts/Montserrat-Bold.ttf") format("truetype"),url("../fonts/Montserrat-Bold.svg#Montserrat") format("svg")}html,body{font-family:Montserrat,sans-serif;font-size:16px;font-weight:400;z-index:10}*,*::after,*::before{box-sizing:border-box}.preloading{color:#00a69c;display:block;font-size:1.5rem;left:50%;position:fixed;top:50%;transform:translate(-50%,-50%)}select::-ms-expand{display:none}@media screen and (min-width:992px){.form-input{max-width:360px;width:360px}}.form-input{border-radius:0;height:45px;padding:10px}.form-input-small{max-width:100px !important}.form-input-medium{width:150px !important}.alert{padding-left:0}.alert-danger{background-color:transparent;border:0;color:#fb0d0d;font-size:12px}a,a:active,a:hover,a:visited{color:#000;text-decoration:none;transition:color .35s}a:hover,a:active{color:#75b918;transition:color .35s}.esh-basket{min-height:80vh}.esh-basket-titles{padding-bottom:1rem;padding-top:2rem}.esh-basket-titles--clean{padding-bottom:0;padding-top:0}.esh-basket-title{text-transform:uppercase}.esh-basket-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-basket-items--border:last-of-type{border-color:transparent}.esh-basket-item{font-size:1rem;font-weight:300}.esh-basket-item--middle{line-height:8rem}@media screen and (max-width:1024px){.esh-basket-item--middle{line-height:1rem}}.esh-basket-item--mark{color:#00a69c}.esh-basket-image{height:8rem}.esh-basket-input{line-height:1rem;width:100%}.esh-basket-checkout{border:none;border-radius:0;background-color:#83d01b;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s}.esh-basket-checkout:hover{background-color:#4a760f;transition:all .35s}.esh-basket-margin12{margin-left:12px}.esh-basketstatus{cursor:pointer;display:inline-block;float:right;position:relative;transition:all .35s}.esh-basketstatus.is-disabled{opacity:.5;pointer-events:none}.esh-basketstatus-image{height:36px;margin-top:.5rem}.esh-basketstatus-badge{background-color:#83d01b;border-radius:50%;color:#fff;display:block;height:1.5rem;left:50%;position:absolute;text-align:center;top:0;transform:translateX(-38%);transition:all .35s;width:1.5rem}.esh-basketstatus:hover .esh-basketstatus-badge{background-color:transparent;color:#75b918;transition:all .35s}.esh-catalog-hero{background-image:url("../images/main_banner.png");background-size:cover;height:260px;width:100%}.esh-catalog-title{position:relative;top:74.28571px}.esh-catalog-filters{background-color:#00a69c;height:65px}.esh-catalog-filter{background-color:transparent;border-color:#00d9cc;color:#fff;cursor:pointer;margin-right:1rem;margin-top:.5rem;outline-color:#83d01b;padding-bottom:0;padding-left:.5rem;padding-right:.5rem;padding-top:1.5rem;min-width:140px;-webkit-appearance:none}.esh-catalog-filter option{background-color:#00a69c}.esh-catalog-label{display:inline-block;position:relative;z-index:0}.esh-catalog-label::before{color:rgba(255,255,255,.5);content:attr(data-title);font-size:.65rem;margin-top:.65rem;margin-left:.5rem;position:absolute;text-transform:uppercase;z-index:1}.esh-catalog-label::after{background-image:url("../images/arrow-down.png");height:7px;content:'';position:absolute;right:1.5rem;top:2.5rem;width:10px;z-index:1}.esh-catalog-send{background-color:#83d01b;color:#fff;cursor:pointer;font-size:1rem;transform:translateY(.5rem);padding:.5rem;transition:all .35s}.esh-catalog-send:hover{background-color:#4a760f;transition:all .35s}.esh-catalog-items{margin-top:1rem}.esh-catalog-item{text-align:center;margin-bottom:1.5rem;width:33%;display:inline-block;float:none !important}@media screen and (max-width:1024px){.esh-catalog-item{width:50%}}@media screen and (max-width:768px){.esh-catalog-item{width:100%}}.esh-catalog-thumbnail{max-width:370px;width:100%}.esh-catalog-button{background-color:#83d01b;border:none;color:#fff;cursor:pointer;font-size:1rem;height:3rem;margin-top:1rem;transition:all .35s;width:80%}.esh-catalog-button.is-disabled{opacity:.5;pointer-events:none}.esh-catalog-button:hover{background-color:#4a760f;transition:all .35s}.esh-catalog-name{font-size:1rem;font-weight:300;margin-top:.5rem;text-align:center;text-transform:uppercase}.esh-catalog-price{text-align:center;font-weight:900;font-size:28px}.esh-catalog-price::before{content:'$'}.esh-orders{min-height:80vh;overflow-x:hidden}.esh-orders-header{background-color:#00a69c;height:4rem}.esh-orders-back{color:rgba(255,255,255,.4);line-height:4rem;text-transform:uppercase;text-decoration:none;transition:color .35s}.esh-orders-back:hover{color:#fff;transition:color .35s}.esh-orders-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders-title{text-transform:uppercase}.esh-orders-items{height:2rem;line-height:2rem;position:relative}.esh-orders-items:nth-of-type(2n+1):before{background-color:#eef;content:'';height:100%;left:0;margin-left:-100vw;position:absolute;top:0;width:200vw;z-index:-1}.esh-orders-item{font-weight:300}.esh-orders-item--hover{opacity:0;pointer-events:none}.esh-orders-items:hover .esh-orders-item--hover{opacity:1;pointer-events:all}.esh-orders-link{color:#83d01b;text-decoration:none;transition:color .35s}.esh-orders-link:hover{color:#75b918;transition:color .35s}.esh-orders_new{min-height:80vh}.esh-orders_new-header{background-color:#00a69c;height:4rem}.esh-orders_new-back{color:rgba(255,255,255,.4);line-height:4rem;text-decoration:none;text-transform:uppercase;transition:color .35s}.esh-orders_new-back:hover{color:#fff;transition:color .35s}.esh-orders_new-section{padding:1rem 0}.esh-orders_new-section--right{text-align:right}.esh-orders_new-placeOrder{background-color:#83d01b;border:0;border-radius:0;color:#fff;display:inline-block;font-size:1rem;font-weight:400;margin-top:1rem;padding:1rem 1.5rem;text-align:center;text-transform:uppercase;transition:all .35s}.esh-orders_new-placeOrder:hover{background-color:#4a760f;transition:all .35s}.esh-orders_new-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders_new-title{font-size:1.25rem;text-transform:uppercase}.esh-orders_new-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-orders_new-items--border:last-of-type{border-color:transparent}.esh-orders_new-item{font-size:1rem;font-weight:300}.esh-orders_new-item--middle{line-height:8rem}@media screen and (max-width:768px){.esh-orders_new-item--middle{line-height:1rem}}.esh-orders_new-item--mark{color:#83d01b}.esh-orders_new-image{height:8rem}.esh-orders_detail{min-height:80vh}.esh-orders_detail-section{padding:1rem 0}.esh-orders_detail-section--right{text-align:right}.esh-orders_detail-titles{padding-bottom:1rem;padding-top:2rem}.esh-orders_detail-title{text-transform:uppercase}.esh-orders_detail-items--border{border-bottom:1px solid #eee;padding:.5rem 0}.esh-orders_detail-items--border:last-of-type{border-color:transparent}.esh-orders_detail-item{font-size:1rem;font-weight:300}.esh-orders_detail-item--middle{line-height:8rem}@media screen and (max-width:768px){.esh-orders_detail-item--middle{line-height:1rem}}.esh-orders_detail-item--mark{color:#83d01b}.esh-orders_detail-image{height:8rem}.esh-identity{line-height:3rem;position:relative;text-align:right}.esh-identity-section{display:inline-block;width:100%}.esh-identity-name{display:inline-block}.esh-identity-name--upper{text-transform:uppercase}@media screen and (max-width:768px){.esh-identity-name{font-size:.85rem}}.esh-identity-image{display:inline-block}.esh-identity-drop{background:#fff;height:0;min-width:14rem;right:0;overflow:hidden;padding:.5rem;position:absolute;top:2.5rem;transition:height .35s}.esh-identity:hover .esh-identity-drop{border:1px solid #eee;height:7rem;transition:height .35s}.esh-identity-item{cursor:pointer;display:block;transition:color .35s}.esh-identity-item:hover{color:#75b918;transition:color .35s}.esh-header{background-color:#00a69c;height:4rem}.esh-header-back{color:rgba(255,255,255,.5) !important;line-height:4rem;text-transform:uppercase;text-decoration:none;transition:color .35s}.esh-header-back:hover{color:#fff !important;transition:color .35s}.esh-pager-wrapper{padding-top:1rem;text-align:center}.esh-pager-item{margin:0 5vw}.esh-pager-item--navigable{display:inline-block;cursor:pointer}.esh-pager-item--navigable.is-disabled{opacity:0;pointer-events:none}.esh-pager-item--navigable:hover{color:#83d01b}@media screen and (max-width:1280px){.esh-pager-item{font-size:.85rem}}@media screen and (max-width:1024px){.esh-pager-item{margin:0 4vw}}
\ No newline at end of file
diff --git a/src/Web/WebSPA/.angular-cli.json b/src/Web/WebSPA/.angular-cli.json
new file mode 100644
index 000000000..131f2897c
--- /dev/null
+++ b/src/Web/WebSPA/.angular-cli.json
@@ -0,0 +1,58 @@
+{
+ "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
+ "project": {
+ "name": "WebSPA"
+ },
+ "apps": [
+ {
+ "root": "Client",
+ "outDir": "wwwroot",
+ "assets": [
+ "assets",
+ "favicon.ico"
+ ],
+ "index": "index.html",
+ "main": "main.ts",
+ "polyfills": "polyfills.ts",
+ "test": "test.ts",
+ "tsconfig": "tsconfig.app.json",
+ "testTsconfig": "tsconfig.spec.json",
+ "prefix": "app",
+ "styles": [
+ "globals.scss",
+ "../node_modules/bootstrap/scss/bootstrap.scss"
+ ],
+ "scripts": [],
+ "environmentSource": "environments/environment.ts",
+ "environments": {
+ "dev": "environments/environment.ts",
+ "prod": "environments/environment.prod.ts"
+ }
+ }
+ ],
+ "e2e": {
+ "protractor": {
+ "config": "./protractor.conf.js"
+ }
+ },
+ "lint": [
+ {
+ "project": "Client/tsconfig.app.json"
+ },
+ {
+ "project": "Client/tsconfig.spec.json"
+ },
+ {
+ "project": "e2e/tsconfig.e2e.json"
+ }
+ ],
+ "test": {
+ "karma": {
+ "config": "./karma.conf.js"
+ }
+ },
+ "defaults": {
+ "styleExt": "scss",
+ "component": {}
+ }
+}
diff --git a/src/Web/WebSPA/.gitignore b/src/Web/WebSPA/.gitignore
index 280332f79..a4cb1babf 100644
--- a/src/Web/WebSPA/.gitignore
+++ b/src/Web/WebSPA/.gitignore
@@ -177,10 +177,7 @@ ClientBin/
*.publishsettings
node_modules/
bower_components/
-**/wwwroot/tmp/
-**/wwwroot/*.bundle.map
-**/wwwroot/*.js
-/wwwroot/dist/
+wwwroot/
orleans.codegen.cs
diff --git a/src/Web/WebSPA/Client/assets/.gitkeep b/src/Web/WebSPA/Client/assets/.gitkeep
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/Web/WebSPA/Client/images/arrow-down.png b/src/Web/WebSPA/Client/assets/images/arrow-down.png
similarity index 100%
rename from src/Web/WebSPA/Client/images/arrow-down.png
rename to src/Web/WebSPA/Client/assets/images/arrow-down.png
diff --git a/src/Web/WebSPA/Client/images/arrow-right.svg b/src/Web/WebSPA/Client/assets/images/arrow-right.svg
similarity index 100%
rename from src/Web/WebSPA/Client/images/arrow-right.svg
rename to src/Web/WebSPA/Client/assets/images/arrow-right.svg
diff --git a/src/Web/WebSPA/Client/images/brand.png b/src/Web/WebSPA/Client/assets/images/brand.png
similarity index 100%
rename from src/Web/WebSPA/Client/images/brand.png
rename to src/Web/WebSPA/Client/assets/images/brand.png
diff --git a/src/Web/WebSPA/Client/images/brand_dark.png b/src/Web/WebSPA/Client/assets/images/brand_dark.png
similarity index 100%
rename from src/Web/WebSPA/Client/images/brand_dark.png
rename to src/Web/WebSPA/Client/assets/images/brand_dark.png
diff --git a/src/Web/WebSPA/Client/images/cart.png b/src/Web/WebSPA/Client/assets/images/cart.png
similarity index 100%
rename from src/Web/WebSPA/Client/images/cart.png
rename to src/Web/WebSPA/Client/assets/images/cart.png
diff --git a/src/Web/WebSPA/Client/images/logout.png b/src/Web/WebSPA/Client/assets/images/logout.png
similarity index 100%
rename from src/Web/WebSPA/Client/images/logout.png
rename to src/Web/WebSPA/Client/assets/images/logout.png
diff --git a/src/Web/WebSPA/Client/images/main_banner.png b/src/Web/WebSPA/Client/assets/images/main_banner.png
similarity index 100%
rename from src/Web/WebSPA/Client/images/main_banner.png
rename to src/Web/WebSPA/Client/assets/images/main_banner.png
diff --git a/src/Web/WebSPA/Client/images/main_banner_text.png b/src/Web/WebSPA/Client/assets/images/main_banner_text.png
similarity index 100%
rename from src/Web/WebSPA/Client/images/main_banner_text.png
rename to src/Web/WebSPA/Client/assets/images/main_banner_text.png
diff --git a/src/Web/WebSPA/Client/images/my_orders.png b/src/Web/WebSPA/Client/assets/images/my_orders.png
similarity index 100%
rename from src/Web/WebSPA/Client/images/my_orders.png
rename to src/Web/WebSPA/Client/assets/images/my_orders.png
diff --git a/src/Web/WebSPA/Client/custom-typings.d.ts b/src/Web/WebSPA/Client/custom-typings.d.ts
deleted file mode 100644
index 8e46a4e30..000000000
--- a/src/Web/WebSPA/Client/custom-typings.d.ts
+++ /dev/null
@@ -1,2 +0,0 @@
-// Extra variables that live on Global that will be replaced by webpack DefinePlugin
-// declare var process: any;
diff --git a/src/Web/WebSPA/Client/environments/environment.prod.ts b/src/Web/WebSPA/Client/environments/environment.prod.ts
new file mode 100644
index 000000000..3612073bc
--- /dev/null
+++ b/src/Web/WebSPA/Client/environments/environment.prod.ts
@@ -0,0 +1,3 @@
+export const environment = {
+ production: true
+};
diff --git a/src/Web/WebSPA/Client/environments/environment.ts b/src/Web/WebSPA/Client/environments/environment.ts
new file mode 100644
index 000000000..b7f639aec
--- /dev/null
+++ b/src/Web/WebSPA/Client/environments/environment.ts
@@ -0,0 +1,8 @@
+// The file contents for the current environment will overwrite these during build.
+// The build system defaults to the dev environment which uses `environment.ts`, but if you do
+// `ng build --env=prod` then `environment.prod.ts` will be used instead.
+// The list of which env maps to which file can be found in `.angular-cli.json`.
+
+export const environment = {
+ production: false
+};
diff --git a/src/Web/WebSPA/wwwroot/favicon.ico b/src/Web/WebSPA/Client/favicon.ico
similarity index 100%
rename from src/Web/WebSPA/wwwroot/favicon.ico
rename to src/Web/WebSPA/Client/favicon.ico
diff --git a/src/Web/WebSPA/Client/globals.scss b/src/Web/WebSPA/Client/globals.scss
index fde578e3d..e69b955dc 100644
--- a/src/Web/WebSPA/Client/globals.scss
+++ b/src/Web/WebSPA/Client/globals.scss
@@ -1,3 +1,4 @@
+/* You can add global styles to this file, and also import other style files */
@import './modules/variables';
$dist: './fonts/Montserrat-Regular';
diff --git a/src/Web/WebSPA/Client/index.html b/src/Web/WebSPA/Client/index.html
new file mode 100644
index 000000000..5d9432f70
--- /dev/null
+++ b/src/Web/WebSPA/Client/index.html
@@ -0,0 +1,18 @@
+
+
+
+
+ eShopConContainers.WebSPA
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Web/WebSPA/Client/main.ts b/src/Web/WebSPA/Client/main.ts
index ff50b8628..1f87381f8 100644
--- a/src/Web/WebSPA/Client/main.ts
+++ b/src/Web/WebSPA/Client/main.ts
@@ -1,23 +1,11 @@
-import './polyfills';
-
-import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
-import { AppModule } from './modules/app.module';
+import { AppModule } from './modules/app.module';
+import { environment } from './environments/environment';
-if (process.env.ENV === 'Development') {
- // Development
-} else {
- // Production
+if (environment.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();
-}
diff --git a/src/Web/WebSPA/Client/modules/app.component.html b/src/Web/WebSPA/Client/modules/app.component.html
index bd50dc066..14e322e61 100644
--- a/src/Web/WebSPA/Client/modules/app.component.html
+++ b/src/Web/WebSPA/Client/modules/app.component.html
@@ -4,7 +4,7 @@
@@ -28,7 +28,7 @@
-
+
diff --git a/src/Web/WebSPA/Client/modules/app.component.ts b/src/Web/WebSPA/Client/modules/app.component.ts
index 00abe4ad4..37bba914b 100644
--- a/src/Web/WebSPA/Client/modules/app.component.ts
+++ b/src/Web/WebSPA/Client/modules/app.component.ts
@@ -13,12 +13,12 @@ import { ConfigurationService } from './shared/services/configuration.service';
*/
@Component({
- selector: 'esh-app.esh-app',
+ selector: 'esh-app',
styleUrls: ['./app.component.scss'],
templateUrl: './app.component.html'
})
export class AppComponent implements OnInit {
- private Authenticated: boolean = false;
+ Authenticated: boolean = false;
subscription: Subscription;
constructor(private titleService: Title, private securityService: SecurityService, private configurationService: ConfigurationService) {
diff --git a/src/Web/WebSPA/Client/modules/basket/basket-status/basket-status.component.html b/src/Web/WebSPA/Client/modules/basket/basket-status/basket-status.component.html
index 7509a2281..b15127a60 100644
--- a/src/Web/WebSPA/Client/modules/basket/basket-status/basket-status.component.html
+++ b/src/Web/WebSPA/Client/modules/basket/basket-status/basket-status.component.html
@@ -3,7 +3,7 @@
[routerLink]="['basket']">
-
+
{{badge}}
diff --git a/src/Web/WebSPA/Client/modules/catalog/catalog.component.html b/src/Web/WebSPA/Client/modules/catalog/catalog.component.html
index c0aa46ad5..d3c40af62 100644
--- a/src/Web/WebSPA/Client/modules/catalog/catalog.component.html
+++ b/src/Web/WebSPA/Client/modules/catalog/catalog.component.html
@@ -16,7 +16,7 @@
-
+
diff --git a/src/Web/WebSPA/Client/modules/catalog/catalog.component.scss b/src/Web/WebSPA/Client/modules/catalog/catalog.component.scss
index 663215ff6..9158bf858 100644
--- a/src/Web/WebSPA/Client/modules/catalog/catalog.component.scss
+++ b/src/Web/WebSPA/Client/modules/catalog/catalog.component.scss
@@ -4,7 +4,7 @@
$banner-height: 260px;
&-hero {
- background-image: url('../../images/main_banner.png');
+ background-image: url('../../assets/images/main_banner.png');
background-size: cover;
height: $banner-height;
width: 100%;
@@ -61,7 +61,7 @@
}
&::after {
- background-image: url('../../images/arrow-down.png');
+ background-image: url('../../assets/images/arrow-down.png');
content: '';
height: 7px; //png height
position: absolute;
diff --git a/src/Web/WebSPA/Client/modules/orders/orders-detail/orders-detail.component.ts b/src/Web/WebSPA/Client/modules/orders/orders-detail/orders-detail.component.ts
index 31da11594..c9c5c79c0 100644
--- a/src/Web/WebSPA/Client/modules/orders/orders-detail/orders-detail.component.ts
+++ b/src/Web/WebSPA/Client/modules/orders/orders-detail/orders-detail.component.ts
@@ -1,6 +1,6 @@
-import { Component, OnInit } from '@angular/core';
-import { OrdersService } from '../orders.service';
-import { IOrder } from '../../shared/models/order.model';
+import { Component, OnInit } from '@angular/core';
+import { OrdersService } from '../orders.service';
+import { IOrderDetail } from '../../shared/models/order-detail.model';
import { ActivatedRoute } from '@angular/router';
@Component({
@@ -9,7 +9,7 @@ import { ActivatedRoute } from '@angular/router';
templateUrl: './orders-detail.component.html'
})
export class OrdersDetailComponent implements OnInit {
- order = {}; // new order
+ public order: IOrderDetail = {};
constructor(private service: OrdersService, private route: ActivatedRoute) { }
@@ -27,5 +27,4 @@ export class OrdersDetailComponent implements OnInit {
console.log(this.order);
});
}
-}
-
+}
\ No newline at end of file
diff --git a/src/Web/WebSPA/Client/modules/orders/orders-new/orders-new.component.ts b/src/Web/WebSPA/Client/modules/orders/orders-new/orders-new.component.ts
index 8f8a10eb0..4f6f82a9f 100644
--- a/src/Web/WebSPA/Client/modules/orders/orders-new/orders-new.component.ts
+++ b/src/Web/WebSPA/Client/modules/orders/orders-new/orders-new.component.ts
@@ -13,10 +13,10 @@ import { Router } from '@angular/router';
templateUrl: './orders-new.component.html'
})
export class OrdersNewComponent implements OnInit {
- private newOrderForm: FormGroup; // new order form
- private isOrderProcessing: Boolean;
- private errorReceived: Boolean;
- private order: IOrder;
+ newOrderForm: FormGroup; // new order form
+ isOrderProcessing: boolean;
+ errorReceived: boolean;
+ order: IOrder;
constructor(private service: OrdersService, fb: FormBuilder, private router: Router) {
// Obtain user profile information
diff --git a/src/Web/WebSPA/Client/modules/orders/orders.service.ts b/src/Web/WebSPA/Client/modules/orders/orders.service.ts
index 24991056a..355670cdd 100644
--- a/src/Web/WebSPA/Client/modules/orders/orders.service.ts
+++ b/src/Web/WebSPA/Client/modules/orders/orders.service.ts
@@ -4,6 +4,7 @@ import { Response } from '@angular/http';
import { DataService } from '../shared/services/data.service';
import { IOrder } from '../shared/models/order.model';
import { IOrderItem } from '../shared/models/orderItem.model';
+import { IOrderDetail } from "../shared/models/order-detail.model";
import { SecurityService } from '../shared/services/security.service';
import { ConfigurationService } from '../shared/services/configuration.service';
import { BasketWrapperService } from '../shared/services/basket.wrapper.service';
@@ -35,7 +36,7 @@ export class OrdersService {
});
}
- getOrder(id: number): Observable {
+ getOrder(id: number): Observable {
let url = this.ordersUrl + '/api/v1/orders/' + id;
return this.service.get(url).map((response: Response) => {
diff --git a/src/Web/WebSPA/Client/modules/shared/components/identity/identity.html b/src/Web/WebSPA/Client/modules/shared/components/identity/identity.html
index f15dda395..9dce33adc 100644
--- a/src/Web/WebSPA/Client/modules/shared/components/identity/identity.html
+++ b/src/Web/WebSPA/Client/modules/shared/components/identity/identity.html
@@ -12,7 +12,7 @@
*ngIf="authenticated">
{{userName}}
-
+
My orders
-
+
Log Out
-
+
diff --git a/src/Web/WebSPA/Client/modules/shared/components/identity/identity.ts b/src/Web/WebSPA/Client/modules/shared/components/identity/identity.ts
index 606249c0a..505cdc05d 100644
--- a/src/Web/WebSPA/Client/modules/shared/components/identity/identity.ts
+++ b/src/Web/WebSPA/Client/modules/shared/components/identity/identity.ts
@@ -10,7 +10,7 @@ import { SecurityService } from '../../services/security.service';
styleUrls: ['./identity.scss']
})
export class Identity implements OnInit {
- private authenticated: boolean = false;
+ authenticated: boolean = false;
private subscription: Subscription;
private userName: string = '';
diff --git a/src/Web/WebSPA/Client/modules/shared/models/order-detail.model.ts b/src/Web/WebSPA/Client/modules/shared/models/order-detail.model.ts
new file mode 100644
index 000000000..25a869f9c
--- /dev/null
+++ b/src/Web/WebSPA/Client/modules/shared/models/order-detail.model.ts
@@ -0,0 +1,14 @@
+import {IOrderItem} from './orderItem.model';
+
+export interface IOrderDetail {
+ ordernumber: string;
+ status: string;
+ street: string;
+ date: Date;
+ city: number;
+ state: string;
+ zipcode: string;
+ country: number;
+ total: number;
+ orderitems: IOrderItem[];
+}
diff --git a/src/Web/WebSPA/Client/modules/shared/shared.module.ts b/src/Web/WebSPA/Client/modules/shared/shared.module.ts
index 64441396f..da7667df6 100644
--- a/src/Web/WebSPA/Client/modules/shared/shared.module.ts
+++ b/src/Web/WebSPA/Client/modules/shared/shared.module.ts
@@ -16,6 +16,10 @@ import { StorageService } from './services/storage.service';
import { Pager } from './components/pager/pager';
import { Header } from './components/header/header';
import { Identity } from './components/identity/identity';
+import { PageNotFoundComponent } from './components/page-not-found/page-not-found.component';
+
+// Pipes:
+import { UppercasePipe } from './pipes/uppercase.pipe';
@NgModule({
imports: [
@@ -31,7 +35,9 @@ import { Identity } from './components/identity/identity';
declarations: [
Pager,
Header,
- Identity
+ Identity,
+ PageNotFoundComponent,
+ UppercasePipe
],
exports: [
// Modules
@@ -43,7 +49,9 @@ import { Identity } from './components/identity/identity';
// Providers, Components, directive, pipes
Pager,
Header,
- Identity
+ Identity,
+ PageNotFoundComponent,
+ UppercasePipe
]
})
export class SharedModule {
diff --git a/src/Web/WebSPA/Client/polyfills.ts b/src/Web/WebSPA/Client/polyfills.ts
index 2cdf1a036..53bdaf1b8 100644
--- a/src/Web/WebSPA/Client/polyfills.ts
+++ b/src/Web/WebSPA/Client/polyfills.ts
@@ -1,23 +1,68 @@
-// 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';
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ * 2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ * file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE9, IE10 and IE11 requires all of the following polyfills. **/
+// import 'core-js/es6/symbol';
+// import 'core-js/es6/object';
+// import 'core-js/es6/function';
+// import 'core-js/es6/parse-int';
+// import 'core-js/es6/parse-float';
+// import 'core-js/es6/number';
+// import 'core-js/es6/math';
+// import 'core-js/es6/string';
+// import 'core-js/es6/date';
+// import 'core-js/es6/array';
+// import 'core-js/es6/regexp';
+// import 'core-js/es6/map';
+// import 'core-js/es6/set';
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js'; // Run `npm install --save classlist.js`.
+/** IE10 and IE11 requires the following to support `@angular/animation`. */
+// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+
+/** Evergreen browsers require these. **/
+import 'core-js/es6/reflect';
import 'core-js/es7/reflect';
-import 'zone.js/dist/zone';
+
+
+/** ALL Firefox browsers require the following to support `@angular/animation`. **/
+// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
+
+
+
+/***************************************************************************************************
+ * Zone JS is required by Angular itself.
+ */
+import 'zone.js/dist/zone'; // Included with Angular CLI.
+
+
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
+
+/**
+ * Date, currency, decimal and percent pipes.
+ * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10
+ */
+// import 'intl'; // Run `npm install --save intl`.
diff --git a/src/Web/WebSPA/Client/test.ts b/src/Web/WebSPA/Client/test.ts
new file mode 100644
index 000000000..9bf72267e
--- /dev/null
+++ b/src/Web/WebSPA/Client/test.ts
@@ -0,0 +1,32 @@
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/long-stack-trace-zone';
+import 'zone.js/dist/proxy.js';
+import 'zone.js/dist/sync-test';
+import 'zone.js/dist/jasmine-patch';
+import 'zone.js/dist/async-test';
+import 'zone.js/dist/fake-async-test';
+import { getTestBed } from '@angular/core/testing';
+import {
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any.
+declare var __karma__: any;
+declare var require: any;
+
+// Prevent Karma from running prematurely.
+__karma__.loaded = function () {};
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+ BrowserDynamicTestingModule,
+ platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
+// Finally, start Karma to run the tests.
+__karma__.start();
diff --git a/src/Web/WebSPA/Client/tsconfig.app.json b/src/Web/WebSPA/Client/tsconfig.app.json
new file mode 100644
index 000000000..5e2507db5
--- /dev/null
+++ b/src/Web/WebSPA/Client/tsconfig.app.json
@@ -0,0 +1,13 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../out-tsc/app",
+ "module": "es2015",
+ "baseUrl": "",
+ "types": []
+ },
+ "exclude": [
+ "test.ts",
+ "**/*.spec.ts"
+ ]
+}
diff --git a/src/Web/WebSPA/Client/tsconfig.spec.json b/src/Web/WebSPA/Client/tsconfig.spec.json
new file mode 100644
index 000000000..510e3f1fd
--- /dev/null
+++ b/src/Web/WebSPA/Client/tsconfig.spec.json
@@ -0,0 +1,20 @@
+{
+ "extends": "../tsconfig.json",
+ "compilerOptions": {
+ "outDir": "../out-tsc/spec",
+ "module": "commonjs",
+ "target": "es5",
+ "baseUrl": "",
+ "types": [
+ "jasmine",
+ "node"
+ ]
+ },
+ "files": [
+ "test.ts"
+ ],
+ "include": [
+ "**/*.spec.ts",
+ "**/*.d.ts"
+ ]
+}
diff --git a/src/Web/WebSPA/Client/typings.d.ts b/src/Web/WebSPA/Client/typings.d.ts
new file mode 100644
index 000000000..ef5c7bd62
--- /dev/null
+++ b/src/Web/WebSPA/Client/typings.d.ts
@@ -0,0 +1,5 @@
+/* SystemJS module definition */
+declare var module: NodeModule;
+interface NodeModule {
+ id: string;
+}
diff --git a/src/Web/WebSPA/Client/vendor.ts b/src/Web/WebSPA/Client/vendor.ts
deleted file mode 100644
index 4f40d6b4a..000000000
--- a/src/Web/WebSPA/Client/vendor.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-// 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';
diff --git a/src/Web/WebSPA/Server/Controllers/HomeController.cs b/src/Web/WebSPA/Server/Controllers/HomeController.cs
index 7e78cd41a..3bb021943 100644
--- a/src/Web/WebSPA/Server/Controllers/HomeController.cs
+++ b/src/Web/WebSPA/Server/Controllers/HomeController.cs
@@ -1,6 +1,5 @@
// 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;
using Microsoft.Extensions.Options;
@@ -18,23 +17,6 @@ namespace eShopConContainers.WebSPA.Server.Controllers
_env = env;
_settings = settings;
}
-
- 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;
- }
-
public IActionResult Configuration()
{
return Json(_settings.Value);
diff --git a/src/Web/WebSPA/Startup.cs b/src/Web/WebSPA/Startup.cs
index a572f7961..f06cb8ee1 100644
--- a/src/Web/WebSPA/Startup.cs
+++ b/src/Web/WebSPA/Startup.cs
@@ -1,16 +1,15 @@
using System;
+using System.IO;
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 Microsoft.Extensions.HealthChecks;
using Newtonsoft.Json.Serialization;
using eShopOnContainers.WebSPA;
-using Microsoft.Extensions.HealthChecks;
-using System.Threading.Tasks;
namespace eShopConContainers.WebSPA
{
@@ -76,29 +75,34 @@ namespace eShopConContainers.WebSPA
// 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.Use(async (context, next) =>
{
- if (string.Equals(context.Request.Path.Value, "/", StringComparison.OrdinalIgnoreCase))
+ await next();
+
+ // If there's no available file and the request doesn't contain an extension, we're probably trying to access a page.
+ // Rewrite request to use app root
+ if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value) && !context.Request.Path.Value.StartsWith("/api"))
{
- var tokens = antiforgery.GetAndStoreTokens(context);
- context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false });
+ context.Request.Path = "/index.html";
+ context.Response.StatusCode = 200; // Make sure we update the status code, otherwise it returns 404
+ await next();
}
- await next.Invoke();
});
+ app.UseDefaultFiles();
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" });
- });
+ app.UseMvcWithDefaultRoute();
}
}
}
diff --git a/src/Web/WebSPA/Views/Home/Index.cshtml b/src/Web/WebSPA/Views/Home/Index.cshtml
deleted file mode 100644
index 931ef55c7..000000000
--- a/src/Web/WebSPA/Views/Home/Index.cshtml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Web/WebSPA/Views/Shared/_Layout.cshtml b/src/Web/WebSPA/Views/Shared/_Layout.cshtml
deleted file mode 100644
index c7d974e27..000000000
--- a/src/Web/WebSPA/Views/Shared/_Layout.cshtml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
- eShopConContainers.WebSPA
-
-
-
-
-
- @RenderBody()
-
-
-
\ No newline at end of file
diff --git a/src/Web/WebSPA/Views/_ViewImports.cshtml b/src/Web/WebSPA/Views/_ViewImports.cshtml
deleted file mode 100644
index 1c0d391f9..000000000
--- a/src/Web/WebSPA/Views/_ViewImports.cshtml
+++ /dev/null
@@ -1,3 +0,0 @@
-
-@addTagHelper "*, Microsoft.AspNetCore.Mvc.TagHelpers"
-@addTagHelper "*, Microsoft.AspNetCore.SpaServices"
diff --git a/src/Web/WebSPA/Views/_ViewStart.cshtml b/src/Web/WebSPA/Views/_ViewStart.cshtml
deleted file mode 100644
index 820a2f6e0..000000000
--- a/src/Web/WebSPA/Views/_ViewStart.cshtml
+++ /dev/null
@@ -1,3 +0,0 @@
-@{
- Layout = "_Layout";
-}
diff --git a/src/Web/WebSPA/WebSPA.csproj b/src/Web/WebSPA/WebSPA.csproj
index d5161d753..33412407a 100644
--- a/src/Web/WebSPA/WebSPA.csproj
+++ b/src/Web/WebSPA/WebSPA.csproj
@@ -22,21 +22,9 @@
PreserveNewest
-
- PreserveNewest
-
-
- PreserveNewest
-
-
- PreserveNewest
-
PreserveNewest
-
- PreserveNewest
-
PreserveNewest
@@ -51,7 +39,6 @@
-
diff --git a/src/Web/WebSPA/config/helpers.js b/src/Web/WebSPA/config/helpers.js
deleted file mode 100644
index 9d37e78a8..000000000
--- a/src/Web/WebSPA/config/helpers.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/**
- * @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;
diff --git a/src/Web/WebSPA/config/webpack.config.dev.js b/src/Web/WebSPA/config/webpack.config.dev.js
deleted file mode 100644
index d87a27ee4..000000000
--- a/src/Web/WebSPA/config/webpack.config.dev.js
+++ /dev/null
@@ -1,3 +0,0 @@
-module.exports = {
- //devtool: 'cheap-module-source-map'
-};
diff --git a/src/Web/WebSPA/config/webpack.config.js b/src/Web/WebSPA/config/webpack.config.js
deleted file mode 100644
index 2bf3a804d..000000000
--- a/src/Web/WebSPA/config/webpack.config.js
+++ /dev/null
@@ -1,77 +0,0 @@
-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 CopyWebpackPlugin = require('copy-webpack-plugin');
-var isDevelopment = process.env.ASPNETCORE_ENVIRONMENT === 'Development';
-
-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', 'angular2-router-loader']
- },
- { test: /\.html$/, loader: "html" },
- { test: /\.scss$/, loader: 'exports-loader?module.exports.toString()!css-loader!sass-loader' },
- { test: /\.json$/, loader: 'json-loader' },
- {
- test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
- loader: "file-loader"
- }, {
- test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
- loader: "file-loader"
- }, {
- test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
- loader: "file-loader"
- }, {
- test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
- loader: "file-loader"
- },
- {
- test: /\.(png|jpg|gif|svg)$/,
- loader: "file-loader?name=images/[name].[ext]"
- }
- ]
- },
- 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)
- }
- }),
- new CopyWebpackPlugin([
- { from: 'Client/fonts', to: 'fonts' }
- ])
- ]
-}, isDevelopment ? devConfig : prodConfig);
diff --git a/src/Web/WebSPA/config/webpack.config.prod.js b/src/Web/WebSPA/config/webpack.config.prod.js
deleted file mode 100644
index 95277c818..000000000
--- a/src/Web/WebSPA/config/webpack.config.prod.js
+++ /dev/null
@@ -1,23 +0,0 @@
-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
- })
- ]
-};
diff --git a/src/Web/WebSPA/config/webpack.config.vendor.js b/src/Web/WebSPA/config/webpack.config.vendor.js
deleted file mode 100644
index 9009e8ba6..000000000
--- a/src/Web/WebSPA/config/webpack.config.vendor.js
+++ /dev/null
@@ -1,74 +0,0 @@
-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',
- './Client/globals.scss'
- ]
- },
- 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
- })
- ])
-};
diff --git a/src/Web/WebSPA/package.json b/src/Web/WebSPA/package.json
index b863e2f1c..003f220ac 100644
--- a/src/Web/WebSPA/package.json
+++ b/src/Web/WebSPA/package.json
@@ -16,90 +16,51 @@
"email": "cesardl@microsoft.com"
},
"scripts": {
+ "ng": "ng",
"rimraf": "rimraf",
- "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",
- "version": "npm run build",
+ "clean": "npm cache clean && npm run rimraf -- node_modules doc typings coverage wwwroot",
+ "start": "ng serve",
+ "build:dev": "ng build",
+ "build:prod": "ng build --prod --aot --extract-css",
"lint:sass": "sass-lint -c .sass-lint.yml Client/**/*.scss --verbose",
"lint:ts": "tslint -c tslint.json Client/**/*.ts"
},
"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",
+ "@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",
+ "@ng-bootstrap/ng-bootstrap": "1.0.0-alpha.22",
"bootstrap": "4.0.0-alpha.5",
- "core-js": "2.4.1",
+ "core-js": "^2.4.1",
"file-loader": "0.9.0",
"font-awesome": "4.6.3",
"isomorphic-fetch": "2.2.1",
"normalize.css": "5.0.0",
"preboot": "4.5.2",
- "rxjs": "5.0.0-beta.12",
- "zone.js": "0.6.26"
+ "rxjs": "^5.1.0",
+ "zone.js": "^0.8.4"
},
"devDependencies": {
+ "@angular/cli": "1.0.0",
+ "@angular/compiler-cli": "^4.0.0",
+ "@types/jasmine": "2.5.38",
+ "@types/node": "~6.0.60",
"@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-router-loader": "0.3.4",
- "angular2-template-loader": "0.6.0",
- "awesome-typescript-loader": "2.2.4",
- "codelyzer": "1.0.0-beta.3",
- "copy-webpack-plugin": "4.0.1",
- "css": "2.2.1",
- "css-loader": "0.25.0",
- "es6-promise": "3.2.1",
- "es6-promise-loader": "1.0.2",
- "exports-loader": "0.6.3",
- "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": "4.5.0",
- "parse5": "2.1.5",
- "rimraf": "2.5.4",
+ "codelyzer": "~2.0.0",
"sass-lint": "1.10.2",
- "sass-loader": "4.0.2",
"ts-helpers": "1.1.1",
- "ts-node": "1.4.3",
- "tslint": "3.15.1",
+ "ts-node": "~2.0.0",
+ "tslint": "~4.5.0",
"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"
+ "typescript": "~2.2.0",
+ "url-loader": "0.5.7"
}
}
diff --git a/src/Web/WebSPA/tsconfig.json b/src/Web/WebSPA/tsconfig.json
index e04adfb21..a35a8ee3a 100644
--- a/src/Web/WebSPA/tsconfig.json
+++ b/src/Web/WebSPA/tsconfig.json
@@ -1,42 +1,20 @@
{
+ "compileOnSave": false,
"compilerOptions": {
- "target": "es5",
- "module": "commonjs",
- "moduleResolution": "node",
+ "outDir": "./dist/out-tsc",
+ "baseUrl": "src",
+ "sourceMap": true,
"declaration": false,
+ "moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
- "allowSyntheticDefaultImports": true,
- "sourceMap": true,
- "strictNullChecks": false,
- "baseUrl": "./src",
- "paths": {},
- "lib": [
- "dom",
- "es6"
+ "target": "es5",
+ "typeRoots": [
+ "node_modules/@types"
],
- "types": [
- "hammerjs",
- "jasmine",
- "node",
- "protractor",
- "selenium-webdriver",
- "source-map",
- "uglify-js",
- "webpack"
+ "lib": [
+ "es2016",
+ "dom"
]
- },
- "exclude": [
- "node_modules",
- "wwwroot"
- ],
- "awesomeTypescriptLoaderOptions": {
- "forkChecker": true,
- "useWebpackText": true
- },
- "compileOnSave": false,
- "buildOnSave": false,
- "atom": {
- "rewriteTsconfig": false
}
-}
\ No newline at end of file
+}
diff --git a/src/Web/WebSPA/wwwroot/web.config b/src/Web/WebSPA/wwwroot/web.config
deleted file mode 100644
index e70a7778d..000000000
--- a/src/Web/WebSPA/wwwroot/web.config
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
-
-
-
-
-
-