Browse Source

Merge branch 'dev'

pull/251/head
Ramón Tomás 7 years ago
parent
commit
0c6bb89d26
45 changed files with 417 additions and 150 deletions
  1. +5
    -1
      cli-windows/build-bits.ps1
  2. +7
    -6
      docker-compose.override.yml
  3. +7
    -6
      docker-compose.prod.yml
  4. +9
    -8
      docker-compose.yml
  5. +1
    -0
      k8s/conf_cloud.yml
  6. +1
    -0
      k8s/conf_local.yml
  7. +6
    -2
      k8s/deploy.ps1
  8. +18
    -3
      k8s/deployments.yaml
  9. +8
    -0
      src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs
  10. +0
    -5
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj
  11. +1
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.Core/project.json
  12. +63
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/MainApplication.cs
  13. +19
    -1
      src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/eShopOnContainers.TestRunner.Droid.csproj
  14. +3
    -0
      src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/packages.config
  15. +1
    -1
      src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs
  16. +9
    -4
      src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs
  17. +2
    -1
      src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs
  18. +5
    -6
      src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingStartupFilter.cs
  19. +3
    -8
      src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs
  20. +7
    -1
      src/Services/Basket/Basket.API/Program.cs
  21. +3
    -1
      src/Services/Basket/Basket.API/Startup.cs
  22. +0
    -1
      src/Services/Ordering/Ordering.API/Program.cs
  23. +56
    -23
      src/Web/WebMVC/Controllers/CartController.cs
  24. +1
    -1
      src/Web/WebMVC/Controllers/OrderController.cs
  25. +3
    -1
      src/Web/WebMVC/Startup.cs
  26. +13
    -4
      src/Web/WebMVC/ViewComponents/Cart.cs
  27. +14
    -2
      src/Web/WebMVC/ViewComponents/CartList.cs
  28. +9
    -0
      src/Web/WebMVC/Views/Catalog/Index.cshtml
  29. +19
    -8
      src/Web/WebMVC/Views/Shared/Components/Cart/Default.cshtml
  30. +75
    -55
      src/Web/WebMVC/Views/Shared/Components/CartList/Default.cshtml
  31. +1
    -0
      src/Web/WebMVC/WebMVC.csproj
  32. +7
    -0
      src/Web/WebMVC/wwwroot/css/_variables.scss
  33. +1
    -0
      src/Web/WebMVC/wwwroot/css/app.component.min.css
  34. +15
    -0
      src/Web/WebMVC/wwwroot/css/basket/basket-status/basket-status.component.css
  35. +1
    -0
      src/Web/WebMVC/wwwroot/css/basket/basket-status/basket-status.component.min.css
  36. +16
    -0
      src/Web/WebMVC/wwwroot/css/basket/basket-status/basket-status.component.scss
  37. +1
    -0
      src/Web/WebMVC/wwwroot/css/basket/basket.component.min.css
  38. +1
    -0
      src/Web/WebMVC/wwwroot/css/catalog/catalog.component.min.css
  39. +1
    -0
      src/Web/WebMVC/wwwroot/css/orders/orders-detail/orders-detail.component.min.css
  40. +1
    -0
      src/Web/WebMVC/wwwroot/css/orders/orders-new/orders-new.component.min.css
  41. +1
    -0
      src/Web/WebMVC/wwwroot/css/orders/orders.component.min.css
  42. +1
    -0
      src/Web/WebMVC/wwwroot/css/shared/components/header/header.min.css
  43. +1
    -0
      src/Web/WebMVC/wwwroot/css/shared/components/pager/pager.min.css
  44. BIN
      src/Web/WebMVC/wwwroot/images/cart-inoperative.png
  45. +1
    -1
      src/Web/WebStatus/Startup.cs

+ 5
- 1
cli-windows/build-bits.ps1 View File

@ -14,7 +14,11 @@ $projectPaths =
@{Path="$rootPath\src\Services\Identity\Identity.API";Prj="Identity.API.csproj"},
@{Path="$rootPath\src\Services\Catalog\Catalog.API";Prj="Catalog.API.csproj"},
@{Path="$rootPath\src\Services\Ordering\Ordering.API";Prj="Ordering.API.csproj"},
@{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"}
@{Path="$rootPath\src\Services\Basket\Basket.API";Prj="Basket.API.csproj"},
@{Path="$rootPath\src\Services\GracePeriod\GracePeriodManager";Prj="GracePeriodManager.csproj"},
@{Path="$rootPath\src\Services\Location\Locations.API";Prj="Locations.API.csproj"},
@{Path="$rootPath\src\Services\Marketing\Marketing.API";Prj="Marketing.API.csproj"},
@{Path="$rootPath\src\Services\Payment\Payment.API";Prj="Payment.API.csproj"},
@{Path="$rootPath\src\Web\WebStatus";Prj="WebStatus.csproj"}
$projectPaths | foreach {


+ 7
- 6
docker-compose.override.yml View File

@ -7,12 +7,6 @@ version: '2.1'
# An external IP or DNS name has to be used (instead localhost and the 10.0.75.1 IP) when testing the Web apps and the Xamarin apps from remote machines/devices using the same WiFi, for instance.
services:
graceperiodmanager:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
basket.api:
environment:
@ -83,6 +77,13 @@ services:
ports:
- "5110:80"
graceperiodmanager:
environment:
- ASPNETCORE_ENVIRONMENT=Development
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
webspa:
environment:
- ASPNETCORE_ENVIRONMENT=Development


+ 7
- 6
docker-compose.prod.yml View File

@ -12,12 +12,6 @@ version: '2.1'
# docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
services:
graceperiodmanager:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
basket.api:
environment:
@ -81,6 +75,13 @@ services:
ports:
- "5110:80"
graceperiodmanager:
environment:
- ASPNETCORE_ENVIRONMENT=Production
- ASPNETCORE_URLS=http://0.0.0.0:80
- ConnectionString=Server=sql.data;Database=Microsoft.eShopOnContainers.Services.OrderingDb;User Id=sa;Password=Pass@word
- EventBusConnection=${ESHOP_AZURE_SERVICE_BUS:-rabbitmq}
webspa:
environment:
- ASPNETCORE_ENVIRONMENT=Production


+ 9
- 8
docker-compose.yml View File

@ -1,14 +1,6 @@
version: '2.1'
services:
graceperiodmanager:
image: eshop/graceperiodmanager:${TAG:-latest}
build:
context: ./src/Services/GracePeriod/GracePeriodManager
dockerfile: Dockerfile
depends_on:
- sql.data
- rabbitmq
basket.api:
image: eshop/basket.api:${TAG:-latest}
@ -57,6 +49,15 @@ services:
- identity.api
- rabbitmq
graceperiodmanager:
image: eshop/graceperiodmanager:${TAG:-latest}
build:
context: ./src/Services/GracePeriod/GracePeriodManager
dockerfile: Dockerfile
depends_on:
- sql.data
- rabbitmq
webspa:
image: eshop/webspa:${TAG:-latest}
build:


+ 1
- 0
k8s/conf_cloud.yml View File

@ -30,6 +30,7 @@ data:
# GracePeriodManager entries
GracePeriodTime: "5" # Grace period duration (time when you can cancel order) in minutes
GracePeriodCheckUpdateTime: "60000" # Interval time to check new Order status (in milliseconds)
GracePeriodManagerBus: CONNECTION_STRING (NAME OF RABBITMQ CONTAINER OR Endpoint=sb://XXXX in case of using Azure)
# Global entries
UseAzureServiceBus: "TRUE" IF USE AZURE SB ("FALSE" FOR USING RABBITMQ)
keystore: REDIS CONNECTION STRING FOR KEYSTORE

+ 1
- 0
k8s/conf_local.yml View File

@ -23,5 +23,6 @@ data:
PaymentBus: rabbitmq
GracePeriodTime: "1"
GracePeriodCheckUpdateTime: "60000"
GracePeriodManagerBus: rabbitmq
UseAzureServiceBus: "False"
keystore: keystore-data

+ 6
- 2
k8s/deploy.ps1 View File

@ -63,7 +63,7 @@ if ($buildImages) {
docker-compose -p .. -f ../docker-compose.yml build
Write-Host "Pushing images to $registry/$dockerOrg..." -ForegroundColor Yellow
$services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus")
$services = ("basket.api", "catalog.api", "identity.api", "ordering.api", "marketing.api","payment.api","locations.api", "webmvc", "webspa", "webstatus", "graceperiodmanager")
foreach ($service in $services) {
$imageFqdn = if ($useDockerHub) {"$dockerOrg/${service}"} else {"$registry/$dockerOrg/${service}"}
@ -136,7 +136,7 @@ ExecKube -cmd 'create configmap urls `
--from-literal=BasketHealthCheckUrl=http://basket/hc `
--from-literal=CatalogUrl=http://$($externalDns)/catalog-api `
--from-literal=CatalogHealthCheckUrl=http://catalog/hc `
--from-literal=PicBaseUrl=http://$($externalDns)/catalog-api/api/v1/pic/ `
--from-literal=PicBaseUrl=http://$($externalDns)/catalog-api/api/v1/catalog/items/[0]/pic/ `
--from-literal=IdentityUrl=http://$($externalDns)/identity `
--from-literal=IdentityHealthCheckUrl=http://identity/hc `
--from-literal=OrderingUrl=http://ordering `
@ -147,10 +147,12 @@ ExecKube -cmd 'create configmap urls `
--from-literal=MvcClientCatalogUrl=http://catalog `
--from-literal=MvcClientBasketUrl=http://basket `
--from-literal=WebSpaHealthCheckUrl=http://webspa/hc `
--from-literal=MarketingHealthCheckUrl=http://marketing/hc `
--from-literal=SpaClientOrderingExternalUrl=http://$($externalDns)/ordering-api `
--from-literal=SpaClientCatalogExternalUrl=http://$($externalDns)/catalog-api `
--from-literal=SpaClientBasketExternalUrl=http://$($externalDns)/basket-api `
--from-literal=SpaClientIdentityExternalUrl=http://$($externalDns)/identity `
--from-literal=LocationsHealthCheckUrl=http://locations/hc `
--from-literal=SpaClientExternalUrl=http://$($externalDns)'
ExecKube -cmd 'label configmap urls app=eshop'
@ -180,6 +182,7 @@ ExecKube -cmd 'set image deployments/payment payment=${registryPath}${dockerOrg}
ExecKube -cmd 'set image deployments/webmvc webmvc=${registryPath}${dockerOrg}/webmvc:$imageTag'
ExecKube -cmd 'set image deployments/webstatus webstatus=${registryPath}${dockerOrg}/webstatus:$imageTag'
ExecKube -cmd 'set image deployments/webspa webspa=${registryPath}${dockerOrg}/webspa:$imageTag'
ExecKube -cmd 'set image deployments/graceperiodmanager graceperiodmanager=${registryPath}${dockerOrg}/graceperiodmanager:$imageTag'
Write-Host "Execute rollout..." -ForegroundColor Yellow
ExecKube -cmd 'rollout resume deployments/basket'
@ -192,6 +195,7 @@ ExecKube -cmd 'rollout resume deployments/payment'
ExecKube -cmd 'rollout resume deployments/webmvc'
ExecKube -cmd 'rollout resume deployments/webstatus'
ExecKube -cmd 'rollout resume deployments/webspa'
ExecKube -cmd 'rollout resume deployments/graceperiodmanager'
Write-Host "WebSPA is exposed at http://$externalDns, WebMVC at http://$externalDns/webmvc, WebStatus at http://$externalDns/webstatus" -ForegroundColor Yellow

+ 18
- 3
k8s/deployments.yaml View File

@ -74,7 +74,7 @@ spec:
- name: AzureStorageEnabled
valueFrom:
configMapKeyRef:
name: urls
name: externalcfg
key: CatalogAzureStorageEnabled
- name: EventBusConnection
valueFrom:
@ -185,8 +185,8 @@ spec:
template:
metadata:
labels:
app: graceperiodmanager
component: ordering
app: eshop
component: graceperiodmanager
spec:
containers:
- name: graceperiodmanager
@ -455,6 +455,16 @@ spec:
configMapKeyRef:
name: urls
key: OrderingHealthCheckUrl
- name: LocationsUrl
valueFrom:
configMapKeyRef:
name: urls
key: LocationsHealthCheckUrl
- name: MarketingUrl
valueFrom:
configMapKeyRef:
name: urls
key: MarketingHealthCheckUrl
- name: mvc
valueFrom:
configMapKeyRef:
@ -541,6 +551,11 @@ spec:
configMapKeyRef:
name: urls
key: OrderingHealthCheckUrl
- name: MarketingUrlHC
valueFrom:
configMapKeyRef:
name: urls
key: MarketingHealthCheckUrl
ports:
- containerPort: 80
imagePullSecrets:


+ 8
- 0
src/BuildingBlocks/Resilience/Resilience.Http/ResilientHttpClient.cs View File

@ -81,6 +81,14 @@ namespace Microsoft.eShopOnContainers.BuildingBlocks.Resilience.Http
var response = await _client.SendAsync(requestMessage);
// raise exception if HttpResponseCode 500
// needed for circuit breaker to track fails
if (response.StatusCode == HttpStatusCode.InternalServerError)
{
throw new HttpRequestException();
}
return await response.Content.ReadAsStringAsync();
});
}


+ 0
- 5
src/Mobile/eShopOnContainers/eShopOnContainers.Core/eShopOnContainers.Core.csproj View File

@ -290,11 +290,6 @@
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Reference Include="System.ComponentModel.Annotations">
<HintPath>..\..\..\..\..\..\..\..\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETPortable\v4.6\Profile\Profile44\System.ComponentModel.Annotations.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Views\CampaignDetailsView.xaml">
<Generator>MSBuild:UpdateDesignTimeXaml</Generator>


+ 1
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.Core/project.json View File

@ -10,6 +10,7 @@
"Newtonsoft.Json": "9.0.1",
"SlideOverKit": "2.1.4",
"Splat": "1.6.2",
"System.ComponentModel.Annotations": "4.3.0",
"Xam.Plugin.Geolocator": "3.0.4",
"Xam.Plugins.Settings": "2.6.0.12-beta",
"Xamarin.FFImageLoading": "2.2.9",


+ 63
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/MainApplication.cs View File

@ -0,0 +1,63 @@
using System;
using Android.App;
using Android.OS;
using Android.Runtime;
using Plugin.CurrentActivity;
namespace eShopOnContainers.TestRunner.Droid
{
//You can specify additional application information in this attribute
[Application]
public class MainApplication : Application, Application.IActivityLifecycleCallbacks
{
public MainApplication(IntPtr handle, JniHandleOwnership transer)
:base(handle, transer)
{
}
public override void OnCreate()
{
base.OnCreate();
RegisterActivityLifecycleCallbacks(this);
//A great place to initialize Xamarin.Insights and Dependency Services!
}
public override void OnTerminate()
{
base.OnTerminate();
UnregisterActivityLifecycleCallbacks(this);
}
public void OnActivityCreated(Activity activity, Bundle savedInstanceState)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityDestroyed(Activity activity)
{
}
public void OnActivityPaused(Activity activity)
{
}
public void OnActivityResumed(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivitySaveInstanceState(Activity activity, Bundle outState)
{
}
public void OnActivityStarted(Activity activity)
{
CrossCurrentActivity.Current.Activity = activity;
}
public void OnActivityStopped(Activity activity)
{
}
}
}

+ 19
- 1
src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/eShopOnContainers.TestRunner.Droid.csproj View File

@ -51,6 +51,21 @@
</Reference>
<Reference Include="Mono.Android" />
<Reference Include="mscorlib" />
<Reference Include="Plugin.CurrentActivity, Version=1.0.1.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Plugin.CurrentActivity.1.0.1\lib\MonoAndroid10\Plugin.CurrentActivity.dll</HintPath>
</Reference>
<Reference Include="Plugin.Geolocator, Version=3.0.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.dll</HintPath>
</Reference>
<Reference Include="Plugin.Geolocator.Abstractions, Version=3.0.4.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Xam.Plugin.Geolocator.3.0.4\lib\MonoAndroid10\Plugin.Geolocator.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Plugin.Permissions, Version=1.1.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.dll</HintPath>
</Reference>
<Reference Include="Plugin.Permissions.Abstractions, Version=1.1.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\..\..\..\packages\Plugin.Permissions.1.1.7\lib\MonoAndroid10\Plugin.Permissions.Abstractions.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Net.Http.Extensions, Version=2.2.29.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
@ -194,12 +209,15 @@
</ItemGroup>
<ItemGroup>
<Compile Include="MainActivity.cs" />
<Compile Include="MainApplication.cs" />
<Compile Include="Resources\Resource.Designer.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
<None Include="packages.config">
<SubType>Designer</SubType>
</None>
<None Include="Resources\AboutResources.txt" />
<None Include="Assets\AboutAssets.txt" />
</ItemGroup>


+ 3
- 0
src/Mobile/eShopOnContainers/eShopOnContainers.TestRunner.Droid/packages.config View File

@ -13,6 +13,8 @@
<package id="modernhttpclient" version="2.4.2" targetFramework="monoandroid60" />
<package id="NETStandard.Library" version="1.6.0" targetFramework="monoandroid60" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="monoandroid60" />
<package id="Plugin.CurrentActivity" version="1.0.1" targetFramework="monoandroid60" />
<package id="Plugin.Permissions" version="1.1.7" targetFramework="monoandroid60" />
<package id="SlideOverKit" version="2.1.4" targetFramework="monoandroid60" />
<package id="Splat" version="1.6.2" targetFramework="monoandroid60" />
<package id="System.AppContext" version="4.1.0" targetFramework="monoandroid60" />
@ -58,6 +60,7 @@
<package id="System.Threading.Timer" version="4.0.1" targetFramework="monoandroid60" />
<package id="System.Xml.ReaderWriter" version="4.0.11" targetFramework="monoandroid60" />
<package id="System.Xml.XDocument" version="4.0.11" targetFramework="monoandroid60" />
<package id="Xam.Plugin.Geolocator" version="3.0.4" targetFramework="monoandroid60" />
<package id="Xam.Plugins.Settings" version="2.6.0.12-beta" targetFramework="monoandroid60" />
<package id="Xamarin.Android.Support.Animated.Vector.Drawable" version="23.3.0" targetFramework="monoandroid70" />
<package id="Xamarin.Android.Support.Design" version="23.3.0" targetFramework="monoandroid70" />


src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingMiddlewareAppBuilderExtensions.cs → src/Services/Basket/Basket.API/Infrastructure/Exceptions/FailingMiddlewareAppBuilderExtensions.cs View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Infrastructure.Middlewares
namespace Basket.API.Infrastructure.Middlewares
{
public static class FailingMiddlewareAppBuilderExtensions
{

src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingMiddleware.cs → src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingMiddleware.cs View File

@ -4,7 +4,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Infrastructure.Middlewares
namespace Basket.API.Infrastructure.Middlewares
{
public class FailingMiddleware
{
@ -26,8 +26,7 @@ namespace Ordering.API.Infrastructure.Middlewares
return;
}
if (_mustFail)
if (MustFail(context))
{
context.Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError;
context.Response.ContentType = "text/plain";
@ -42,7 +41,7 @@ namespace Ordering.API.Infrastructure.Middlewares
private async Task ProcessConfigRequest(HttpContext context)
{
var enable = context.Request.Query.Keys.Any(k => k == "enable");
var disable = context.Request.Query.Keys.Any(k => k == "disable");
var disable = context.Request.Query.Keys.Any(k => k == "disable");
if (enable && disable)
{
@ -74,5 +73,11 @@ namespace Ordering.API.Infrastructure.Middlewares
await context.Response.WriteAsync(message);
}
private bool MustFail(HttpContext context)
{
return _mustFail &&
(_options.EndpointPaths.Any(x => x == context.Request.Path.Value)
|| _options.EndpointPaths.Count == 0);
}
}
}

src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingOptions.cs → src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingOptions.cs View File

@ -3,10 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Infrastructure.Middlewares
namespace Basket.API.Infrastructure.Middlewares
{
public class FailingOptions
{
public string ConfigPath = "/Failing";
public List<string> EndpointPaths { get; set; } = new List<string>();
}
}

src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingStartupFilter.cs → src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingStartupFilter.cs View File

@ -1,23 +1,22 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Ordering.API.Infrastructure.Middlewares
namespace Basket.API.Infrastructure.Middlewares
{
public class FailingStartupFilter : IStartupFilter
{
public FailingStartupFilter()
private readonly Action<FailingOptions> _options;
public FailingStartupFilter(Action<FailingOptions> optionsAction)
{
_options = optionsAction;
}
public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
{
return app =>
{
app.UseFailingMiddleware();
app.UseFailingMiddleware(_options);
next(app);
};
}

src/Services/Ordering/Ordering.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs → src/Services/Basket/Basket.API/Infrastructure/Middlewares/FailingWebHostBuilderExtensions.cs View File

@ -1,23 +1,18 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Ordering.API.Infrastructure.Middlewares;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Hosting
namespace Basket.API.Infrastructure.Middlewares
{
public static class WebHostBuildertExtensions
{
public static IWebHostBuilder UseFailing(this IWebHostBuilder builder, string path)
public static IWebHostBuilder UseFailing(this IWebHostBuilder builder, Action<FailingOptions> options)
{
builder.ConfigureServices(services =>
{
services.AddSingleton<IStartupFilter>(new FailingStartupFilter());
services.AddSingleton<IStartupFilter>(new FailingStartupFilter(options));
});
return builder;
}
}
}

+ 7
- 1
src/Services/Basket/Basket.API/Program.cs View File

@ -1,5 +1,7 @@
using Microsoft.AspNetCore.Builder;
using Basket.API.Infrastructure.Middlewares;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using System.Collections.Generic;
using System.IO;
namespace Microsoft.eShopOnContainers.Services.Basket.API
@ -10,6 +12,10 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
{
var host = new WebHostBuilder()
.UseKestrel()
.UseFailing(options =>
{
options.ConfigPath = "/Failing";
})
.UseHealthChecks("/hc")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()


+ 3
- 1
src/Services/Basket/Basket.API/Startup.cs View File

@ -58,7 +58,9 @@ namespace Microsoft.eShopOnContainers.Services.Basket.API
services.AddHealthChecks(checks =>
{
checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")));
checks.AddValueTaskCheck("HTTP Endpoint", () => new ValueTask<IHealthCheckResult>(HealthCheckResult.Healthy("Ok")),
TimeSpan.Zero //No cache for this HealthCheck, better just for demos
);
});
services.Configure<BasketSettings>(Configuration);


+ 0
- 1
src/Services/Ordering/Ordering.API/Program.cs View File

@ -10,7 +10,6 @@ namespace Microsoft.eShopOnContainers.Services.Ordering.API
{
var host = new WebHostBuilder()
.UseKestrel()
.UseFailing("/Failing")
.UseHealthChecks("/hc")
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()


+ 56
- 23
src/Web/WebMVC/Controllers/CartController.cs View File

@ -7,6 +7,7 @@ using Microsoft.eShopOnContainers.WebMVC.Services;
using Microsoft.eShopOnContainers.WebMVC.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication;
using Polly.CircuitBreaker;
namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
@ -26,47 +27,79 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
public async Task<IActionResult> Index()
{
var user = _appUserParser.Parse(HttpContext.User);
var vm = await _basketSvc.GetBasket(user);
try
{
var user = _appUserParser.Parse(HttpContext.User);
var vm = await _basketSvc.GetBasket(user);
return View(vm);
return View(vm);
}
catch (BrokenCircuitException)
{
// Catch error when Basket.api is in circuit-opened mode
HandleBrokenCircuitException();
}
return View();
}
[HttpPost]
public async Task<IActionResult> Index(Dictionary<string, int> quantities, string action)
{
var user = _appUserParser.Parse(HttpContext.User);
var basket = await _basketSvc.SetQuantities(user, quantities);
var vm = await _basketSvc.UpdateBasket(basket);
try
{
var user = _appUserParser.Parse(HttpContext.User);
var basket = await _basketSvc.SetQuantities(user, quantities);
var vm = await _basketSvc.UpdateBasket(basket);
if (action == "[ Checkout ]")
if (action == "[ Checkout ]")
{
var order = _basketSvc.MapBasketToOrder(basket);
return RedirectToAction("Create", "Order");
}
}
catch (BrokenCircuitException)
{
var order = _basketSvc.MapBasketToOrder(basket);
return RedirectToAction("Create", "Order");
// Catch error when Basket.api is in circuit-opened mode
HandleBrokenCircuitException();
}
return View(vm);
return View();
}
public async Task<IActionResult> AddToCart(CatalogItem productDetails)
{
if (productDetails.Id != null)
try
{
var user = _appUserParser.Parse(HttpContext.User);
var product = new BasketItem()
if (productDetails.Id != null)
{
Id = Guid.NewGuid().ToString(),
Quantity = 1,
ProductName = productDetails.Name,
PictureUrl = productDetails.PictureUri,
UnitPrice = productDetails.Price,
ProductId = productDetails.Id
};
await _basketSvc.AddItemToBasket(user, product);
var user = _appUserParser.Parse(HttpContext.User);
var product = new BasketItem()
{
Id = Guid.NewGuid().ToString(),
Quantity = 1,
ProductName = productDetails.Name,
PictureUrl = productDetails.PictureUri,
UnitPrice = productDetails.Price,
ProductId = productDetails.Id
};
await _basketSvc.AddItemToBasket(user, product);
}
return RedirectToAction("Index", "Catalog");
}
catch (BrokenCircuitException)
{
// Catch error when Basket.api is in circuit-opened mode
HandleBrokenCircuitException();
}
return RedirectToAction("Index", "Catalog");
}
private void HandleBrokenCircuitException()
{
TempData["BasketInoperativeMsg"] = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)";
}
}
}

+ 1
- 1
src/Web/WebMVC/Controllers/OrderController.cs View File

@ -56,7 +56,7 @@ namespace Microsoft.eShopOnContainers.WebMVC.Controllers
{
ModelState.AddModelError("Error", "It was not possible to create a new order, please try later on. (Business Msg Due to Circuit-Breaker)");
}
return View(model);
return View("Create", model);
}
public async Task<IActionResult> Cancel(string orderId)


+ 3
- 1
src/Web/WebMVC/Startup.cs View File

@ -40,7 +40,8 @@ namespace Microsoft.eShopOnContainers.WebMVC
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddMvc();
services.AddSession();
if (Configuration.GetValue<string>("IsClusterEnv") == bool.TrueString)
{
@ -104,6 +105,7 @@ namespace Microsoft.eShopOnContainers.WebMVC
app.UseExceptionHandler("/Catalog/Error");
}
app.UseSession();
app.UseStaticFiles();
app.UseCookieAuthentication(new CookieAuthenticationOptions


+ 13
- 4
src/Web/WebMVC/ViewComponents/Cart.cs View File

@ -6,6 +6,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Polly.CircuitBreaker;
namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
{
@ -17,11 +18,19 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
{
var itemsInCart = await ItemsInCartAsync(user);
var vm = new CartComponentViewModel()
var vm = new CartComponentViewModel();
try
{
ItemsCount = itemsInCart
};
var itemsInCart = await ItemsInCartAsync(user);
vm.ItemsCount = itemsInCart;
return View(vm);
}
catch (BrokenCircuitException)
{
// Catch error when Basket.api is in circuit-opened mode
ViewBag.IsBasketInoperative = true;
}
return View(vm);
}
private async Task<int> ItemsInCartAsync(ApplicationUser user)


+ 14
- 2
src/Web/WebMVC/ViewComponents/CartList.cs View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Polly.CircuitBreaker;
namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
{
@ -16,8 +17,19 @@ namespace Microsoft.eShopOnContainers.WebMVC.ViewComponents
public async Task<IViewComponentResult> InvokeAsync(ApplicationUser user)
{
var item = await GetItemsAsync(user);
return View(item);
var vm = new Basket();
try
{
vm = await GetItemsAsync(user);
return View(vm);
}
catch (BrokenCircuitException)
{
// Catch error when Basket.api is in circuit-opened mode
TempData["BasketInoperativeMsg"] = "Basket Service is inoperative, please try later on. (Business Msg Due to Circuit-Breaker)";
}
return View(vm);
}
private Task<Basket> GetItemsAsync(ApplicationUser user) => _cartSvc.GetBasket(user);


+ 9
- 0
src/Web/WebMVC/Views/Catalog/Index.cshtml View File

@ -23,6 +23,15 @@
</section>
<div class="container">
<div class="row">
<br />
@if(TempData.ContainsKey("BasketInoperativeMsg"))
{
<div class="alert alert-warning" role="alert">
&nbsp;@TempData["BasketInoperativeMsg"]
</div>
}
</div>
@if (Model.CatalogItems.Count() > 0)
{


+ 19
- 8
src/Web/WebMVC/Views/Shared/Components/Cart/Default.cshtml View File

@ -7,14 +7,25 @@
<a class="esh-basketstatus @Model.Disabled"
asp-area=""
asp-controller="Cart"
asp-action="Index">
<div class="esh-basketstatus-image">
<img src="~/images/cart.png" />
</div>
<div class="esh-basketstatus-badge">
@Model.ItemsCount
</div>
asp-action="Index">
@if (ViewBag.IsBasketInoperative == true)
{
<div class="esh-basketstatus-image">
<img src="~/images/cart-inoperative.png" />
</div>
<div class="esh-basketstatus-badge-inoperative">
X
</div>
}
else
{
<div class="esh-basketstatus-image">
<img src="~/images/cart.png" />
</div>
<div class="esh-basketstatus-badge">
@Model.ItemsCount
</div>
}
</a>


+ 75
- 55
src/Web/WebMVC/Views/Shared/Components/CartList/Default.cshtml View File

@ -5,67 +5,87 @@
}
<div class="container">
<article class="esh-basket-titles row">
<section class="esh-basket-title col-xs-3">Product</section>
<section class="esh-basket-title col-xs-3 hidden-lg-down"></section>
<section class="esh-basket-title col-xs-2">Price</section>
<section class="esh-basket-title col-xs-2">Quantity</section>
<section class="esh-basket-title col-xs-2">Cost</section>
</article>
@for (int i = 0; i < Model.Items.Count; i++)
@if (TempData.ContainsKey("BasketInoperativeMsg"))
{
<br />
<div class="alert alert-warning" role="alert">
&nbsp;@TempData["BasketInoperativeMsg"]
</div>
}
else
{
var item = Model.Items[i];
<article class="esh-basket-titles row">
<br />
@if (TempData.ContainsKey("BasketInoperativeMsg"))
{
<div class="alert alert-warning" role="alert">
&nbsp;@TempData["BasketInoperativeMsg"]
</div>
}
<article class="esh-basket-items row">
<div>
<section class="esh-basket-item esh-basket-item--middle col-lg-3 hidden-lg-down">
<img class="esh-basket-image" src="@item.PictureUrl" />
</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-3">@item.ProductName</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2">$ @item.UnitPrice.ToString("N2")</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2">
<input type="hidden" name="@("quantities[" + i +"].Key")" value="@item.Id" />
<input type="number" class="esh-basket-input" min="1" name="@("quantities[" + i +"].Value")" value="@item.Quantity" />
</section>
<section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-xs-2">$ @Math.Round(item.Quantity * item.UnitPrice, 2).ToString("N2")</section>
<section class="esh-basket-title col-xs-3">Product</section>
<section class="esh-basket-title col-xs-3 hidden-lg-down"></section>
<section class="esh-basket-title col-xs-2">Price</section>
<section class="esh-basket-title col-xs-2">Quantity</section>
<section class="esh-basket-title col-xs-2">Cost</section>
</article>
@for (int i = 0; i < Model.Items.Count; i++)
{
var item = Model.Items[i];
<article class="esh-basket-items row">
<div>
<section class="esh-basket-item esh-basket-item--middle col-lg-3 hidden-lg-down">
<img class="esh-basket-image" src="@item.PictureUrl" />
</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-3">@item.ProductName</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2">$ @item.UnitPrice.ToString("N2")</section>
<section class="esh-basket-item esh-basket-item--middle col-xs-2">
<input type="hidden" name="@("quantities[" + i +"].Key")" value="@item.Id" />
<input type="number" class="esh-basket-input" min="1" name="@("quantities[" + i +"].Value")" value="@item.Quantity" />
</section>
<section class="esh-basket-item esh-basket-item--middle esh-basket-item--mark col-xs-2">$ @Math.Round(item.Quantity * item.UnitPrice, 2).ToString("N2")</section>
</div>
<div class="row">
</div>
</article>
<div class="esh-basket-items--border row">
@if (item.OldUnitPrice != 0)
{
<div class="alert alert-warning esh-basket-margin12" role="alert">&nbsp;Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was $ @item.OldUnitPrice </div>
}
</div>
<div class="row">
<br />
}
</div>
</article>
<div class="container">
<article class="esh-basket-titles esh-basket-titles--clean row">
<section class="esh-basket-title col-xs-10"></section>
<section class="esh-basket-title col-xs-2">Total</section>
</article>
<div class="esh-basket-items--border row">
@if (item.OldUnitPrice != 0)
{
<div class="alert alert-warning esh-basket-margin12" role="alert">&nbsp;Note that the price of this article changed in our Catalog. The old price when you originally added it to the basket was $ @item.OldUnitPrice </div>
}
<article class="esh-basket-items row">
<section class="esh-basket-item col-xs-10"></section>
<section class="esh-basket-item esh-basket-item--mark col-xs-2">$ @Model.Total()</section>
</article>
<article class="esh-basket-items row">
<section class="esh-basket-item col-xs-7"></section>
<section class="esh-basket-item col-xs-2">
<button class="btn esh-basket-checkout" name="name" value="" type="submit">[ Update ]</button>
</section>
<section class="esh-basket-item col-xs-3">
<input type="submit"
class="btn esh-basket-checkout"
value="[ Checkout ]" name="action" />
</section>
</article>
</div>
<br/>
}
</div>
<div class="container">
<article class="esh-basket-titles esh-basket-titles--clean row">
<section class="esh-basket-title col-xs-10"></section>
<section class="esh-basket-title col-xs-2">Total</section>
</article>
<article class="esh-basket-items row">
<section class="esh-basket-item col-xs-10"></section>
<section class="esh-basket-item esh-basket-item--mark col-xs-2">$ @Model.Total()</section>
</article>
<article class="esh-basket-items row">
<section class="esh-basket-item col-xs-7"></section>
<section class="esh-basket-item col-xs-2">
<button class="btn esh-basket-checkout" name="name" value="" type="submit">[ Update ]</button>
</section>
<section class="esh-basket-item col-xs-3">
<input type="submit"
class="btn esh-basket-checkout"
value="[ Checkout ]" name="action" />
</section>
</article>
</div>

+ 1
- 0
src/Web/WebMVC/WebMVC.csproj View File

@ -41,6 +41,7 @@
<PackageReference Include="Microsoft.AspNetCore.Mvc" Version="1.1.3" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Session" Version="1.1.2" />
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="1.1.2" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.2" />


+ 7
- 0
src/Web/WebMVC/wwwroot/css/_variables.scss View File

@ -11,6 +11,13 @@ $color-secondary-darker: darken($color-secondary, 20%);
$color-secondary-bright: lighten($color-secondary, 10%);
$color-secondary-brighter: lighten($color-secondary, 20%);
$color-warning: #ff0000;
$color-warning-dark: darken($color-warning, 5%);
$color-warning-darker: darken($color-warning, 20%);
$color-warning-bright: lighten($color-warning, 10%);
$color-warning-brighter: lighten($color-warning, 20%);
$color-background-dark: #333333;
$color-background-darker: #000000;
$color-background-bright: #EEEEFF;


+ 1
- 0
src/Web/WebMVC/wwwroot/css/app.component.min.css View File

@ -0,0 +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;}

+ 15
- 0
src/Web/WebMVC/wwwroot/css/basket/basket-status/basket-status.component.css View File

@ -31,6 +31,21 @@
width: 1.5rem;
}
.esh-basketstatus-badge-inoperative {
background-color: #ff0000;
border-radius: 50%;
color: #FFFFFF;
display: block;
height: 1.5rem;
left: 50%;
position: absolute;
text-align: center;
top: 0;
transform: translateX(-38%);
transition: all 0.35s;
width: 1.5rem;
}
.esh-basketstatus:hover .esh-basketstatus-badge {
background-color: transparent;
color: #75b918;


+ 1
- 0
src/Web/WebMVC/wwwroot/css/basket/basket-status/basket-status.component.min.css View File

@ -0,0 +1 @@
.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-badge-inoperative{background-color:#f00;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;}

+ 16
- 0
src/Web/WebMVC/wwwroot/css/basket/basket-status/basket-status.component.scss View File

@ -33,6 +33,22 @@
width: $size;
}
&-badge-inoperative {
$size: 1.5rem;
background-color: $color-warning;
border-radius: 50%;
color: $color-foreground-brighter;
display: block;
height: $size;
left: 50%;
position: absolute;
text-align: center;
top: 0;
transform: translateX(-38%);
transition: all $animation-speed-default;
width: $size;
}
&:hover &-badge {
background-color: transparent;
color: $color-secondary-dark;


+ 1
- 0
src/Web/WebMVC/wwwroot/css/basket/basket.component.min.css View File

@ -0,0 +1 @@
.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-items-margin-left1{margin-left:1px;}.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{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-basket-checkout:hover{background-color:#4a760f;transition:all .35s;}

+ 1
- 0
src/Web/WebMVC/wwwroot/css/catalog/catalog.component.min.css View File

@ -0,0 +1 @@
.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{-webkit-appearance:none;background-color:transparent;border-color:#00d9cc;color:#fff;cursor:pointer;margin-right:1rem;margin-top:.5rem;min-width:140px;outline-color:#83d01b;padding-bottom:0;padding-left:.5rem;padding-right:.5rem;padding-top:1.5rem;}.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-left:.5rem;margin-top:.65rem;position:absolute;text-transform:uppercase;z-index:1;}.esh-catalog-label::after{background-image:url("../../images/arrow-down.png");content:'';height:7px;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;margin-top:-1.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{margin-bottom:1.5rem;text-align:center;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:0;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{font-size:28px;font-weight:900;text-align:center;}.esh-catalog-price::before{content:'$';}

+ 1
- 0
src/Web/WebMVC/wwwroot/css/orders/orders-detail/orders-detail.component.min.css View File

@ -0,0 +1 @@
.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;}

+ 1
- 0
src/Web/WebMVC/wwwroot/css/orders/orders-new/orders-new.component.min.css View File

@ -0,0 +1 @@
.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_new-alert{margin-top:10px;}

+ 1
- 0
src/Web/WebMVC/wwwroot/css/orders/orders.component.min.css View File

@ -0,0 +1 @@
.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-decoration:none;text-transform:uppercase;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;}

+ 1
- 0
src/Web/WebMVC/wwwroot/css/shared/components/header/header.min.css View File

@ -0,0 +1 @@
.esh-header{background-color:#00a69c;height:4rem;}.esh-header-back{color:rgba(255,255,255,.5);line-height:4rem;text-decoration:none;text-transform:uppercase;transition:color .35s;}.esh-header-back:hover{color:#fff;transition:color .35s;}

+ 1
- 0
src/Web/WebMVC/wwwroot/css/shared/components/pager/pager.min.css View File

@ -0,0 +1 @@
.esh-pager-wrapper{padding-top:1rem;text-align:center;}.esh-pager-item{margin:0 5vw;}.esh-pager-item.is-disabled{opacity:0;pointer-events:none;}.esh-pager-item--navigable{cursor:pointer;display:inline-block;}.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 2.5vw;}}

BIN
src/Web/WebMVC/wwwroot/images/cart-inoperative.png View File

Before After
Width: 43  |  Height: 37  |  Size: 948 B

+ 1
- 1
src/Web/WebStatus/Startup.cs View File

@ -39,7 +39,7 @@ namespace WebStatus
}
checks.AddUrlCheckIfNotNull(Configuration["OrderingUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["BasketUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["BasketUrl"], TimeSpan.Zero); //No cache for this HealthCheck, better just for demos
checks.AddUrlCheckIfNotNull(Configuration["CatalogUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["IdentityUrl"], TimeSpan.FromMinutes(minutes));
checks.AddUrlCheckIfNotNull(Configuration["LocationsUrl"], TimeSpan.FromMinutes(minutes));


Loading…
Cancel
Save