mirror of https://github.com/abpframework/abp.git
141 changed files with 2545 additions and 1032 deletions
@ -0,0 +1,4 @@ |
|||
ui-angular: |
|||
- npm/ng-packs/**/* |
|||
- templates/app/angular/**/* |
|||
- templates/module/angular/**/* |
|||
@ -0,0 +1,17 @@ |
|||
name: "Pull Request Labeler" |
|||
on: |
|||
pull_request: |
|||
paths: |
|||
- npm/ng-packs/**/* |
|||
- templates/app/angular/**/* |
|||
- templates/module/angular/**/* |
|||
branches: |
|||
- master |
|||
- dev |
|||
jobs: |
|||
labeler: |
|||
runs-on: ubuntu-18.04 |
|||
steps: |
|||
- uses: actions/labeler@v2 |
|||
with: |
|||
repo-token: "${{ secrets.GITHUB_TOKEN }}" |
|||
@ -1,14 +1,18 @@ |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar.LanguageSwitch |
|||
@using System.Linq |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Basic.Themes.Basic.Components.Toolbar.LanguageSwitch |
|||
@model LanguageSwitchViewComponentModel |
|||
<div class="dropdown"> |
|||
<a class="nav-link dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
|||
@Model.CurrentLanguage.DisplayName |
|||
</a> |
|||
@if (Model.OtherLanguages.Any()) |
|||
{ |
|||
<div class="dropdown"> |
|||
<a class="nav-link dropdown-toggle" href="#" role="button" id="dropdownMenuLink" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> |
|||
@Model.CurrentLanguage.DisplayName |
|||
</a> |
|||
|
|||
<div class="dropdown-menu dropdown-menu-right border-0 shadow-sm" aria-labelledby="dropdownMenuLink"> |
|||
@foreach (var language in Model.OtherLanguages) |
|||
{ |
|||
<a class="dropdown-item" href="/Abp/Languages/Switch?culture=@(language.CultureName)&uiCulture=@(language.UiCultureName)&returnUrl=@Context.Request.Path">@language.DisplayName</a> |
|||
} |
|||
</div> |
|||
</div> |
|||
<div class="dropdown-menu dropdown-menu-right border-0 shadow-sm" aria-labelledby="dropdownMenuLink"> |
|||
@foreach (var language in Model.OtherLanguages) |
|||
{ |
|||
<a class="dropdown-item" href="/Abp/Languages/Switch?culture=@(language.CultureName)&uiCulture=@(language.UiCultureName)&returnUrl=@Context.Request.Path">@language.DisplayName</a> |
|||
} |
|||
</div> |
|||
</div> |
|||
} |
|||
|
|||
@ -0,0 +1,49 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc.ModelBinding; |
|||
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Logging; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding |
|||
{ |
|||
public class AbpDateTimeModelBinder : IModelBinder |
|||
{ |
|||
private readonly Type _type; |
|||
private readonly SimpleTypeModelBinder _simpleTypeModelBinder; |
|||
private readonly IClock _clock; |
|||
|
|||
public AbpDateTimeModelBinder(ModelBinderProviderContext context) |
|||
{ |
|||
_type = context.Metadata.ModelType; |
|||
_clock = context.Services.GetRequiredService<IClock>(); |
|||
_simpleTypeModelBinder = new SimpleTypeModelBinder(context.Metadata.ModelType, |
|||
context.Services.GetRequiredService<ILoggerFactory>()); |
|||
} |
|||
|
|||
public async Task BindModelAsync(ModelBindingContext bindingContext) |
|||
{ |
|||
await _simpleTypeModelBinder.BindModelAsync(bindingContext); |
|||
|
|||
if (!bindingContext.Result.IsModelSet) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (_type == typeof(DateTime)) |
|||
{ |
|||
var dateTime = (DateTime) bindingContext.Result.Model; |
|||
bindingContext.Result = ModelBindingResult.Success(_clock.Normalize(dateTime)); |
|||
} |
|||
else |
|||
{ |
|||
var dateTime = (DateTime?) bindingContext.Result.Model; |
|||
if (dateTime != null) |
|||
{ |
|||
bindingContext.Result = ModelBindingResult.Success(_clock.Normalize(dateTime.Value)); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using Microsoft.AspNetCore.Mvc.ModelBinding; |
|||
using Microsoft.AspNetCore.Mvc.ModelBinding.Metadata; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding |
|||
{ |
|||
public class AbpDateTimeModelBinderProvider : IModelBinderProvider |
|||
{ |
|||
public IModelBinder GetBinder(ModelBinderProviderContext context) |
|||
{ |
|||
if (context.Metadata.ModelType != typeof(DateTime) && |
|||
context.Metadata.ModelType != typeof(DateTime?)) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
if (context.Metadata.ContainerType == null) |
|||
{ |
|||
if (context.Metadata is DefaultModelMetadata defaultModelMetadata && |
|||
defaultModelMetadata.Attributes.Attributes.All(x => x.GetType() != typeof(DisableDateTimeNormalizationAttribute))) |
|||
{ |
|||
return new AbpDateTimeModelBinder(context); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
var dateNormalizationDisabledForClass = |
|||
context.Metadata.ContainerType.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true); |
|||
|
|||
var dateNormalizationDisabledForProperty = context.Metadata.ContainerType |
|||
.GetProperty(context.Metadata.PropertyName) |
|||
?.IsDefined(typeof(DisableDateTimeNormalizationAttribute), true); |
|||
|
|||
if (!dateNormalizationDisabledForClass && |
|||
dateNormalizationDisabledForProperty != null && |
|||
!dateNormalizationDisabledForProperty.Value) |
|||
{ |
|||
return new AbpDateTimeModelBinder(context); |
|||
} |
|||
} |
|||
|
|||
return null; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
using JetBrains.Annotations; |
|||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.ValueConverters |
|||
{ |
|||
public class AbpDateTimeValueConverter : ValueConverter<DateTime?, DateTime?> |
|||
{ |
|||
public AbpDateTimeValueConverter(IClock clock, [CanBeNull] ConverterMappingHints mappingHints = null) |
|||
: base( |
|||
x => x.HasValue ? clock.Normalize(x.Value) : x, |
|||
x => x.HasValue ? clock.Normalize(x.Value) : x, mappingHints) |
|||
{ |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,61 @@ |
|||
using System; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding |
|||
{ |
|||
[Route("api/model-Binding-test")] |
|||
public class ModelBindingController : AbpController |
|||
{ |
|||
[HttpGet("DateTimeKind")] |
|||
public string DateTimeKind(DateTime input) |
|||
{ |
|||
return input.Kind.ToString().ToLower(); |
|||
} |
|||
|
|||
[HttpGet("NullableDateTimeKind")] |
|||
public string NullableDateTimeKind(DateTime? input) |
|||
{ |
|||
return input.Value.Kind.ToString().ToLower(); |
|||
} |
|||
|
|||
[HttpGet("DisableDateTimeNormalizationDateTimeKind")] |
|||
public string DisableDateTimeNormalizationDateTimeKind([DisableDateTimeNormalization]DateTime input) |
|||
{ |
|||
return input.Kind.ToString().ToLower(); |
|||
} |
|||
|
|||
[HttpGet("DisableDateTimeNormalizationNullableDateTimeKind")] |
|||
public string DisableDateTimeNormalizationNullableDateTimeKind([DisableDateTimeNormalization]DateTime? input) |
|||
{ |
|||
return input.Value.Kind.ToString().ToLower(); |
|||
} |
|||
|
|||
[HttpGet("ComplexTypeDateTimeKind")] |
|||
public string ComplexTypeDateTimeKind(GetDateTimeKindModel input) |
|||
{ |
|||
return input.Time1.Kind.ToString().ToLower() + "_" + |
|||
input.Time2.Kind.ToString().ToLower() + "_" + |
|||
input.Time3.Value.Kind.ToString().ToLower() + "_" + |
|||
input.InnerModel.Time4.Kind.ToString().ToLower(); |
|||
} |
|||
} |
|||
|
|||
public class GetDateTimeKindModel |
|||
{ |
|||
[DisableDateTimeNormalization] |
|||
public DateTime Time1 { get; set; } |
|||
|
|||
public DateTime Time2 { get; set; } |
|||
|
|||
public DateTime? Time3 { get; set; } |
|||
|
|||
public GetDateTimeKindInnerModel InnerModel { get; set; } |
|||
|
|||
[DisableDateTimeNormalization] |
|||
public class GetDateTimeKindInnerModel |
|||
{ |
|||
public DateTime Time4 { get; set; } |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,100 @@ |
|||
using System; |
|||
using System.Net; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Hosting; |
|||
using Shouldly; |
|||
using Volo.Abp.Timing; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.ModelBinding |
|||
{ |
|||
public abstract class ModelBindingController_Tests : AspNetCoreMvcTestBase |
|||
{ |
|||
protected DateTimeKind DateTimeKind { get; set; } |
|||
|
|||
protected override void ConfigureServices(HostBuilderContext context, IServiceCollection services) |
|||
{ |
|||
services.Configure<AbpClockOptions>(x => x.Kind = DateTimeKind); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task DateTimeKind_Test() |
|||
{ |
|||
var response = await Client.GetAsync("/api/model-Binding-test/DateTimeKind?input=2010-01-01T00:00:00Z"); |
|||
|
|||
response.StatusCode.ShouldBe(HttpStatusCode.OK); |
|||
var resultAsString = await response.Content.ReadAsStringAsync(); |
|||
resultAsString.ShouldBe(DateTimeKind.ToString().ToLower()); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task NullableDateTimeKind_Test() |
|||
{ |
|||
var response = |
|||
await Client.GetAsync("/api/model-Binding-test/NullableDateTimeKind?input=2010-01-01T00:00:00Z"); |
|||
|
|||
response.StatusCode.ShouldBe(HttpStatusCode.OK); |
|||
var resultAsString = await response.Content.ReadAsStringAsync(); |
|||
resultAsString.ShouldBe(DateTimeKind.ToString().ToLower()); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task DisableDateTimeNormalizationDateTimeKind_Test() |
|||
{ |
|||
var response = |
|||
await Client.GetAsync( |
|||
"/api/model-Binding-test/DisableDateTimeNormalizationDateTimeKind?input=2010-01-01T00:00:00Z"); |
|||
|
|||
response.StatusCode.ShouldBe(HttpStatusCode.OK); |
|||
var resultAsString = await response.Content.ReadAsStringAsync(); |
|||
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local.
|
|||
resultAsString.ShouldBe(DateTimeKind.Local.ToString().ToLower()); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task DisableDateTimeNormalizationNullableDateTimeKind_Test() |
|||
{ |
|||
var response = |
|||
await Client.GetAsync( |
|||
"/api/model-Binding-test/DisableDateTimeNormalizationNullableDateTimeKind?input=2010-01-01T00:00:00Z"); |
|||
|
|||
response.StatusCode.ShouldBe(HttpStatusCode.OK); |
|||
var resultAsString = await response.Content.ReadAsStringAsync(); |
|||
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local.
|
|||
resultAsString.ShouldBe(DateTimeKind.Local.ToString().ToLower()); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task ComplexTypeDateTimeKind_Test() |
|||
{ |
|||
var response = await Client.GetAsync("/api/model-Binding-test/ComplexTypeDateTimeKind?" + |
|||
"Time1=2010-01-01T00:00:00Z&" + |
|||
"Time2=2010-01-01T00:00:00Z&" + |
|||
"Time3=2010-01-01T00:00:00Z&" + |
|||
"InnerModel.Time4=2010-01-01T00:00:00Z"); |
|||
|
|||
response.StatusCode.ShouldBe(HttpStatusCode.OK); |
|||
var resultAsString = await response.Content.ReadAsStringAsync(); |
|||
//Time parameter(2010-01-01T00:00:00Z) with time zone information, so the default Kind is Local.
|
|||
resultAsString.ShouldBe( |
|||
$"local_{DateTimeKind.ToString().ToLower()}_{DateTimeKind.ToString().ToLower()}_local"); |
|||
} |
|||
} |
|||
|
|||
public class ModelBindingController_Utc_Tests : ModelBindingController_Tests |
|||
{ |
|||
public ModelBindingController_Utc_Tests() |
|||
{ |
|||
DateTimeKind = DateTimeKind.Utc; |
|||
} |
|||
} |
|||
|
|||
public class ModelBindingController_Local_Tests : ModelBindingController_Tests |
|||
{ |
|||
public ModelBindingController_Local_Tests() |
|||
{ |
|||
DateTimeKind = DateTimeKind.Local; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using Volo.Abp.TestApp.Testing; |
|||
|
|||
namespace Volo.Abp.EntityFrameworkCore.ValueConverters |
|||
{ |
|||
public class AbpDateTimeValueConverter_Tests : AbpDateTimeValueConverter_Tests<AbpEntityFrameworkCoreTestModule> |
|||
{ |
|||
|
|||
} |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.EntityFrameworkCore; |
|||
using Volo.Abp.Domain.Repositories.EntityFrameworkCore; |
|||
using Volo.Abp.EntityFrameworkCore; |
|||
using Volo.Abp.TestApp.Domain; |
|||
|
|||
namespace Volo.Abp.TestApp.EntityFrameworkCore |
|||
{ |
|||
public class PersonRepository : EfCoreRepository<TestAppDbContext, Person, Guid>, IPersonRepository |
|||
{ |
|||
public PersonRepository(IDbContextProvider<TestAppDbContext> dbContextProvider) |
|||
: base(dbContextProvider) |
|||
{ |
|||
} |
|||
|
|||
public async Task<PersonView> GetViewAsync(string name) |
|||
{ |
|||
return await DbContext.PersonView.Where(x => x.Name == name).FirstOrDefaultAsync(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using System; |
|||
using Volo.Abp.Domain.Entities.Auditing; |
|||
|
|||
namespace Volo.Abp.TestApp.Domain |
|||
{ |
|||
public class District : CreationAuditedEntity |
|||
{ |
|||
public Guid CityId { get; private set; } |
|||
|
|||
public string Name { get; private set; } |
|||
|
|||
public int Population { get; set; } |
|||
|
|||
private District() |
|||
{ |
|||
|
|||
} |
|||
|
|||
public District(Guid cityId, string name, int population = 0) |
|||
{ |
|||
CityId = cityId; |
|||
Name = name; |
|||
} |
|||
|
|||
public override object[] GetKeys() |
|||
{ |
|||
return new Object[] {CityId, Name}; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,13 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Text; |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace Volo.Abp.TestApp.Domain |
|||
{ |
|||
public interface IPersonRepository : IBasicRepository<Person, Guid> |
|||
{ |
|||
Task<PersonView> GetViewAsync(string name); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
using Volo.Abp.Timing; |
|||
|
|||
namespace Volo.Abp.TestApp.Domain |
|||
{ |
|||
public class PersonView |
|||
{ |
|||
public string Name { get; set; } |
|||
|
|||
public DateTime CreationTime { get; set; } |
|||
|
|||
public DateTime? Birthday { get; set; } |
|||
|
|||
[DisableDateTimeNormalization] |
|||
public DateTime? LastActive { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,73 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Shouldly; |
|||
using Volo.Abp.Domain.Repositories; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.TestApp.Domain; |
|||
using Volo.Abp.Timing; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.TestApp.Testing |
|||
{ |
|||
public abstract class AbpDateTimeValueConverter_Tests<TStartupModule> : TestAppTestBase<TStartupModule> |
|||
where TStartupModule : IAbpModule |
|||
{ |
|||
private readonly IPersonRepository _personRepository; |
|||
|
|||
protected AbpDateTimeValueConverter_Tests() |
|||
{ |
|||
_personRepository = GetRequiredService<IPersonRepository>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_Test() |
|||
{ |
|||
var personId = Guid.Parse("4125582e-d100-4c27-aa84-e4de85830dca"); |
|||
await _personRepository.InsertAsync(new Person(personId, "bob lee", 18) |
|||
{ |
|||
Birthday = DateTime.Parse("2020-01-01 00:00:00"), |
|||
LastActive = DateTime.Parse("2020-01-01 00:00:00"), |
|||
}, true); |
|||
|
|||
var person = await _personRepository.GetAsync(personId); |
|||
|
|||
person.ShouldNotBeNull(); |
|||
person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc); |
|||
|
|||
person.Birthday.ShouldNotBeNull(); |
|||
person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc); |
|||
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
|||
|
|||
//LastActive DisableDateTimeNormalization
|
|||
person.LastActive.ShouldNotBeNull(); |
|||
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified); |
|||
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task DateTime_Kind_Should_Be_Normalized_To_UTC_View_Test() |
|||
{ |
|||
var personName = "bob lee"; |
|||
await _personRepository.InsertAsync(new Person(Guid.NewGuid(), personName, 18) |
|||
{ |
|||
Birthday = DateTime.Parse("2020-01-01 00:00:00"), |
|||
LastActive = DateTime.Parse("2020-01-01 00:00:00"), |
|||
}, true); |
|||
|
|||
var person = await _personRepository.GetViewAsync(personName); |
|||
|
|||
person.ShouldNotBeNull(); |
|||
person.CreationTime.Kind.ShouldBe(DateTimeKind.Utc); |
|||
|
|||
person.Birthday.ShouldNotBeNull(); |
|||
person.Birthday.Value.Kind.ShouldBe(DateTimeKind.Utc); |
|||
person.Birthday.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
|||
|
|||
//LastActive DisableDateTimeNormalization
|
|||
person.LastActive.ShouldNotBeNull(); |
|||
person.LastActive.Value.Kind.ShouldBe(DateTimeKind.Unspecified); |
|||
person.LastActive.Value.ToString("yyy-MM-dd HH:mm:ss").ShouldBe("2020-01-01 00:00:00"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
{ |
|||
"culture": "tr", |
|||
"texts": { |
|||
"Volo.IdentityServer:DuplicateIdentityResourceName": "Identity Resource adı zaten mevcut: {Name}", |
|||
"Volo.IdentityServer:DuplicateApiResourceName": "Api Resource adı zaten mevcut: {Name}", |
|||
"Volo.IdentityServer:DuplicateClientId": "ClientId already zaten mevcut: {ClientId}" |
|||
} |
|||
} |
|||
@ -1,31 +1,68 @@ |
|||
import { Directive, ElementRef, Input, OnDestroy, OnInit, Optional, Renderer2 } from '@angular/core'; |
|||
import { |
|||
Directive, |
|||
ElementRef, |
|||
Input, |
|||
OnDestroy, |
|||
OnInit, |
|||
Renderer2, |
|||
ViewContainerRef, |
|||
TemplateRef, |
|||
Optional, |
|||
SimpleChanges, |
|||
OnChanges, |
|||
} from '@angular/core'; |
|||
import { Store } from '@ngxs/store'; |
|||
import { ConfigState } from '../states'; |
|||
import { takeUntilDestroy } from '../utils'; |
|||
import { Subscription } from 'rxjs'; |
|||
|
|||
@Directive({ |
|||
selector: '[abpPermission]', |
|||
}) |
|||
export class PermissionDirective implements OnInit, OnDestroy { |
|||
export class PermissionDirective implements OnInit, OnDestroy, OnChanges { |
|||
@Input('abpPermission') condition: string; |
|||
|
|||
constructor(@Optional() private elRef: ElementRef, private renderer: Renderer2, private store: Store) {} |
|||
subscription: Subscription; |
|||
|
|||
constructor( |
|||
private elRef: ElementRef, |
|||
private renderer: Renderer2, |
|||
private store: Store, |
|||
@Optional() private templateRef: TemplateRef<any>, |
|||
private vcRef: ViewContainerRef, |
|||
) {} |
|||
|
|||
private check() { |
|||
if (this.subscription) { |
|||
this.subscription.unsubscribe(); |
|||
} |
|||
|
|||
this.subscription = this.store |
|||
.select(ConfigState.getGrantedPolicy(this.condition)) |
|||
.pipe(takeUntilDestroy(this)) |
|||
.subscribe(isGranted => { |
|||
if (this.templateRef && isGranted) { |
|||
this.vcRef.clear(); |
|||
this.vcRef.createEmbeddedView(this.templateRef); |
|||
} else if (this.templateRef && !isGranted) { |
|||
this.vcRef.clear(); |
|||
} else if (!isGranted && !this.templateRef) { |
|||
this.renderer.removeChild((this.elRef.nativeElement as HTMLElement).parentElement, this.elRef.nativeElement); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
ngOnInit() { |
|||
if (this.condition) { |
|||
this.store |
|||
.select(ConfigState.getGrantedPolicy(this.condition)) |
|||
.pipe(takeUntilDestroy(this)) |
|||
.subscribe(isGranted => { |
|||
if (!isGranted) { |
|||
this.renderer.removeChild( |
|||
(this.elRef.nativeElement as HTMLElement).parentElement, |
|||
this.elRef.nativeElement, |
|||
); |
|||
} |
|||
}); |
|||
if (this.templateRef && !this.condition) { |
|||
this.vcRef.createEmbeddedView(this.templateRef); |
|||
} |
|||
} |
|||
|
|||
ngOnDestroy(): void {} |
|||
|
|||
ngOnChanges({ condition }: SimpleChanges) { |
|||
if ((condition || { currentValue: null }).currentValue) { |
|||
this.check(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,13 @@ |
|||
export {}; |
|||
|
|||
declare global { |
|||
interface Date { |
|||
toLocalISOString(): string; |
|||
} |
|||
} |
|||
|
|||
Date.prototype.toLocalISOString = function(this: Date): string { |
|||
const timezoneOffset = this.getTimezoneOffset(); |
|||
|
|||
return new Date(this.getTime() - timezoneOffset * 60000).toISOString(); |
|||
}; |
|||
@ -1,4 +1,4 @@ |
|||
<div #container id="abp-error" class="error"> |
|||
<div #container id="abp-http-error-container" class="error" [style.backgroundColor]="backgroundColor"> |
|||
<button *ngIf="!hideCloseIcon" id="abp-close-button" type="button" class="close mr-2" (click)="destroy()"> |
|||
<span aria-hidden="true">×</span> |
|||
</button> |
|||
@ -1,7 +1,6 @@ |
|||
.error { |
|||
position: fixed; |
|||
top: 0; |
|||
background-color: #fff; |
|||
width: 100vw; |
|||
height: 100vh; |
|||
z-index: 999999; |
|||
@ -1,30 +1,34 @@ |
|||
<ng-container *ngIf="visible"> |
|||
<div id="modal-container" class="modal show {{ modalClass }}" tabindex="-1" role="dialog"> |
|||
<div class="modal-backdrop" [@fade]="isModalOpen" (click)="close()"></div> |
|||
<div |
|||
id="abp-modal-dialog" |
|||
class="modal-dialog modal-{{ size }}" |
|||
role="document" |
|||
[class.modal-dialog-centered]="centered" |
|||
[@dialog]="isModalOpen" |
|||
#abpModalContent |
|||
> |
|||
<div id="abp-modal-content" class="modal-content"> |
|||
<div id="abp-modal-header" class="modal-header"> |
|||
<ng-container *ngTemplateOutlet="abpHeader"></ng-container> |
|||
|
|||
<button id="abp-modal-close-button" type="button" class="close" aria-label="Close" (click)="close()"> |
|||
<span aria-hidden="true">×</span> |
|||
</button> |
|||
</div> |
|||
<div id="abp-modal-body" class="modal-body"> |
|||
<ng-container *ngTemplateOutlet="abpBody"></ng-container> |
|||
</div> |
|||
<div id="abp-modal-footer" class="modal-footer"> |
|||
<ng-container *ngTemplateOutlet="abpFooter"></ng-container> |
|||
</div> |
|||
<div |
|||
*ngIf="visible" |
|||
[@fade]="isModalOpen" |
|||
id="modal-container" |
|||
class="modal show {{ modalClass }}" |
|||
tabindex="-1" |
|||
role="dialog" |
|||
> |
|||
<div class="modal-backdrop" (click)="close()"></div> |
|||
<div |
|||
id="abp-modal-dialog" |
|||
class="modal-dialog modal-{{ size }}" |
|||
role="document" |
|||
[class.modal-dialog-centered]="centered" |
|||
#abpModalContent |
|||
> |
|||
<div id="abp-modal-content" class="modal-content"> |
|||
<div id="abp-modal-header" class="modal-header"> |
|||
<ng-container *ngTemplateOutlet="abpHeader"></ng-container> |
|||
|
|||
<button id="abp-modal-close-button" type="button" class="close" aria-label="Close" (click)="close()"> |
|||
<span aria-hidden="true">×</span> |
|||
</button> |
|||
</div> |
|||
<div id="abp-modal-body" class="modal-body"> |
|||
<ng-container *ngTemplateOutlet="abpBody"></ng-container> |
|||
</div> |
|||
<div id="abp-modal-footer" class="modal-footer"> |
|||
<ng-container *ngTemplateOutlet="abpFooter"></ng-container> |
|||
</div> |
|||
</div> |
|||
<ng-content></ng-content> |
|||
</div> |
|||
</ng-container> |
|||
<ng-content></ng-content> |
|||
</div> |
|||
|
|||
@ -0,0 +1,46 @@ |
|||
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; |
|||
import { SortOrderIconComponent } from '../components/sort-order-icon/sort-order-icon.component'; |
|||
|
|||
describe('SortOrderIconComponent', () => { |
|||
let spectator: SpectatorHost<SortOrderIconComponent>; |
|||
let component: SortOrderIconComponent; |
|||
const createHost = createHostFactory(SortOrderIconComponent); |
|||
|
|||
beforeEach(() => { |
|||
spectator = createHost( |
|||
'<abp-sort-order-icon key="testKey" [(selectedSortKey)]="selectedSortKey" [(order)]="order"></abp-sort-order-icon>', |
|||
{ |
|||
hostProps: { |
|||
selectedSortKey: '', |
|||
order: '', |
|||
}, |
|||
}, |
|||
); |
|||
component = spectator.component; |
|||
}); |
|||
|
|||
test('should have correct icon class when selectedSortKey and sortKey are the same', () => { |
|||
const newKey = 'testKey'; |
|||
component.sort(newKey); |
|||
expect(component.selectedSortKey).toBe(newKey); |
|||
expect(component.order).toBe('asc'); |
|||
expect(component.icon).toBe('fa-sort-asc'); |
|||
}); |
|||
|
|||
test("shouldn't have any icon class when sortKey and selectedSortKey are different", () => { |
|||
const newKey = 'otherKey'; |
|||
component.sort(newKey); |
|||
expect(component.selectedSortKey).toBe(newKey); |
|||
expect(component.order).toBe('asc'); |
|||
expect(component.icon).toBe(''); |
|||
}); |
|||
|
|||
test('should change order correctly when sort function called', () => { |
|||
component.sort('testKey'); |
|||
expect(component.order).toBe('asc'); |
|||
component.sort('testKey'); |
|||
expect(component.order).toBe('desc'); |
|||
component.sort('testKey'); |
|||
expect(component.order).toBe(''); |
|||
}); |
|||
}); |
|||
@ -0,0 +1,2 @@ |
|||
cd ../applications/AuthServer.Host |
|||
dotnet run |
|||
@ -0,0 +1,2 @@ |
|||
cd ../microservices/IdentityService.Host |
|||
dotnet run |
|||
@ -0,0 +1,2 @@ |
|||
cd ../microservices/BloggingService.Host |
|||
dotnet run |
|||
@ -0,0 +1,2 @@ |
|||
cd ../microservices/ProductService.Host |
|||
dotnet run |
|||
@ -0,0 +1,2 @@ |
|||
cd ../gateways/InternalGateway.Host |
|||
dotnet run |
|||
@ -0,0 +1,2 @@ |
|||
cd ../gateways/BackendAdminAppGateway.Host |
|||
dotnet run |
|||
@ -0,0 +1,2 @@ |
|||
cd ../gateways/PublicWebSiteGateway.Host |
|||
dotnet run |
|||
@ -0,0 +1,2 @@ |
|||
cd ../applications/BackendAdminApp.Host |
|||
dotnet run |
|||
@ -0,0 +1,2 @@ |
|||
cd ../applications/PublicWebSite.Host |
|||
dotnet run |
|||
@ -0,0 +1,2 @@ |
|||
cd ../applications/ConsoleClientDemo |
|||
dotnet run |
|||
@ -0,0 +1,19 @@ |
|||
# Run the Microservice Demo Solution |
|||
|
|||
This folder contains PowerShell files to run the system: |
|||
|
|||
* **__Run_All_Application.ps1**: Runs all the applications in one click. |
|||
* **__Run_Browser.ps1**: Opens all the UIs of the applications in Google Chrome browser. |
|||
|
|||
Other files runs the individual applications. |
|||
|
|||
> This files are only tested in Windows 10. |
|||
|
|||
### Pre-Requirements |
|||
|
|||
- [SQL Server](https://www.microsoft.com/en-us/sql-server/sql-server-downloads) 2015+ (can be [express edition](https://www.microsoft.com/en-us/sql-server/sql-server-editions-express)) |
|||
- [Redis](https://redis.io/download) 5.0+ |
|||
- [RabbitMQ](https://www.rabbitmq.com/install-windows.html) 3.7.11+ |
|||
- [MongoDB](https://www.mongodb.com/download-center) 4.0+ |
|||
- [ElasticSearch](https://www.elastic.co/downloads/elasticsearch) 6.6+ |
|||
- [Kibana](https://www.elastic.co/downloads/kibana) 6.6+ (optional, recommended to see logs) |
|||
@ -0,0 +1,9 @@ |
|||
start powershell .\01_AuthServer.ps1 |
|||
start powershell .\02_IdentityService.ps1 |
|||
start powershell .\03_BloggingService.ps1 |
|||
start powershell .\04_ProductService.ps1 |
|||
start powershell .\05_InternalGateway.ps1 |
|||
start powershell .\06_BackendAdminAppGateway.ps1 |
|||
start powershell .\07_PublicWebSiteGateway.ps1 |
|||
start powershell .\08_BackendAdminApp.ps1 |
|||
start powershell .\09_PublicWebSite.ps1 |
|||
@ -0,0 +1 @@ |
|||
start chrome http://localhost:64999,http://localhost:63568,http://localhost:62157,http://localhost:60244,http://localhost:65129/swagger,http://localhost:65115/swagger,http://localhost:64897/swagger,http://localhost:51954,http://localhost:53435 |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue