diff --git a/docs/en/UI/Angular/Custom-Setting-Page.md b/docs/en/UI/Angular/Custom-Setting-Page.md index 0f39c70f1a..e4ee6d45c2 100644 --- a/docs/en/UI/Angular/Custom-Setting-Page.md +++ b/docs/en/UI/Angular/Custom-Setting-Page.md @@ -1,39 +1,34 @@ # Custom Setting Page -There are several settings tabs from different modules. You can add custom settings page to your project in 3 steps. +There are several settings tabs from different modules. You can add a custom setting page to your project. -1. Create a Component +1. Create a component with the following command: -```js -import { Select } from '@ngxs/store'; -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-your-custom-settings', - template: ` - custom-settings works! - `, -}) -export class YourCustomSettingsComponent { - // Your component logic -} +```bash +yarn ng generate component my-settings ``` -2. Add the `YourCustomSettingsComponent` to `declarations` and the `entryComponents` arrays in the `AppModule`. - -3. Open the `app.component.ts` and add the below content to the `ngOnInit` +2. Open the `app.component.ts` and modify the file as shown below: ```js -import { addSettingTab } from '@abp/ng.theme.shared'; -// ... - -ngOnInit() { - addSettingTab({ - component: YourCustomSettingsComponent, - name: 'Type here the setting tab title (you can type a localization key, e.g: AbpAccount::Login', - order: 4, - requiredPolicy: 'type here a policy key' - }); +import { Component } from '@angular/core'; +import { SettingTabsService } from '@abp/ng.core'; // imported SettingTabsService +import { MySettingsComponent } from './my-settings/my-settings.component'; // imported MySettingsComponent + +@Component(/* component metadata */) +export class AppComponent { + constructor(private settingTabs: SettingTabsService) // injected MySettingsComponent + { + // added below + settingTabs.add([ + { + name: 'MySettings', + order: 1, + requiredPolicy: 'policy key here', + component: MySettingsComponent, + }, + ]); + } } ``` diff --git a/docs/en/UI/Angular/images/custom-settings.png b/docs/en/UI/Angular/images/custom-settings.png index 05dd3f695a..dc40ad3fa9 100644 Binary files a/docs/en/UI/Angular/images/custom-settings.png and b/docs/en/UI/Angular/images/custom-settings.png differ diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs index e8477f20e9..6abcc70f0d 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/Domain/Repositories/MongoDB/MongoDbRepository.cs @@ -19,7 +19,8 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { public class MongoDbRepository : RepositoryBase, - IMongoDbRepository + IMongoDbRepository, + IMongoQueryable where TMongoDbContext : IAbpMongoDbContext where TEntity : class, IEntity { @@ -167,7 +168,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB } public override async Task FindAsync( - Expression> predicate, + Expression> predicate, bool includeDetails = true, CancellationToken cancellationToken = default) { @@ -322,6 +323,35 @@ namespace Volo.Abp.Domain.Repositories.MongoDB { throw new AbpDbConcurrencyException("Database operation expected to affect 1 row but actually affected 0 row. Data may have been modified or deleted since entities were loaded. This exception has been thrown on optimistic concurrency check."); } + + /// + /// IMongoQueryable + /// + /// + public QueryableExecutionModel GetExecutionModel() + { + return GetMongoQueryable().GetExecutionModel(); + } + + /// + /// IMongoQueryable + /// + /// + /// + public IAsyncCursor ToCursor(CancellationToken cancellationToken = new CancellationToken()) + { + return GetMongoQueryable().ToCursor(cancellationToken); + } + + /// + /// IMongoQueryable + /// + /// + /// + public Task> ToCursorAsync(CancellationToken cancellationToken = new CancellationToken()) + { + return GetMongoQueryable().ToCursorAsync(cancellationToken); + } } public class MongoDbRepository @@ -331,7 +361,7 @@ namespace Volo.Abp.Domain.Repositories.MongoDB where TEntity : class, IEntity { public IMongoDbRepositoryFilterer RepositoryFilterer { get; set; } - + public MongoDbRepository(IMongoDbContextProvider dbContextProvider) : base(dbContextProvider) { @@ -376,4 +406,4 @@ namespace Volo.Abp.Domain.Repositories.MongoDB return RepositoryFilterer.CreateEntityFilter(entity, withConcurrencyStamp, concurrencyStamp); } } -} \ No newline at end of file +} diff --git a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs index 206c4add39..a8dc34e83a 100644 --- a/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs +++ b/framework/src/Volo.Abp.MongoDB/Volo/Abp/MongoDB/MongoDbAsyncQueryableProvider.cs @@ -8,6 +8,7 @@ using Volo.Abp.DependencyInjection; using Volo.Abp.Linq; using MongoDB.Driver; using MongoDB.Driver.Linq; +using Volo.Abp.DynamicProxy; namespace Volo.Abp.MongoDB { @@ -15,12 +16,12 @@ namespace Volo.Abp.MongoDB { public bool CanExecute(IQueryable queryable) { - return queryable.Provider.GetType().Namespace?.StartsWith("MongoDB") ?? false; + return ProxyHelper.UnProxy(queryable) is IMongoQueryable; } - protected IMongoQueryable GetMongoQueryable(IQueryable queryable) + protected virtual IMongoQueryable GetMongoQueryable(IQueryable queryable) { - return (IMongoQueryable) queryable; + return ProxyHelper.UnProxy(queryable).As>(); } public Task ContainsAsync(IQueryable queryable, T item, CancellationToken cancellationToken = default) diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/MongoDbAsyncQueryableProvider_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/MongoDbAsyncQueryableProvider_Tests.cs new file mode 100644 index 0000000000..ae9be03d57 --- /dev/null +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/MongoDbAsyncQueryableProvider_Tests.cs @@ -0,0 +1,76 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using Shouldly; +using Volo.Abp.Domain.Repositories; +using Volo.Abp.TestApp.Domain; +using Volo.Abp.TestApp.Testing; +using Volo.Abp.Uow; +using Xunit; + +namespace Volo.Abp.MongoDB.Repositories +{ + [Collection(MongoTestCollection.Name)] + public class MongoDbAsyncQueryableProvider_Tests : TestAppTestBase + { + private readonly IUnitOfWorkManager _unitOfWorkManager; + private readonly IRepository _personRepository; + private readonly MongoDbAsyncQueryableProvider _mongoDbAsyncQueryableProvider; + + public MongoDbAsyncQueryableProvider_Tests() + { + _unitOfWorkManager = GetRequiredService(); + _personRepository = GetRequiredService>(); + _mongoDbAsyncQueryableProvider = GetRequiredService(); + } + + [Fact] + public void CanExecute() + { + _mongoDbAsyncQueryableProvider.CanExecute(_personRepository).ShouldBeTrue(); + _mongoDbAsyncQueryableProvider.CanExecute(_personRepository.WithDetails()).ShouldBeTrue(); + } + + [Fact] + public async Task FirstOrDefaultAsync() + { + using (var uow = _unitOfWorkManager.Begin()) + { + (await _mongoDbAsyncQueryableProvider.FirstOrDefaultAsync(_personRepository.Where(p => p.Name == "Douglas"))).ShouldNotBeNull(); + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task AnyAsync() + { + using (var uow = _unitOfWorkManager.Begin()) + { + (await _mongoDbAsyncQueryableProvider.AnyAsync(_personRepository, p => p.Name == "Douglas")).ShouldBeTrue(); + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task CountAsync() + { + using (var uow = _unitOfWorkManager.Begin()) + { + (await _mongoDbAsyncQueryableProvider.CountAsync(_personRepository.Where(p => p.Name == "Douglas"))).ShouldBeGreaterThan(0); + await uow.CompleteAsync(); + } + } + + [Fact] + public async Task LongCountAsync() + { + using (var uow = _unitOfWorkManager.Begin()) + { + (await _mongoDbAsyncQueryableProvider.LongCountAsync(_personRepository)).ShouldBeGreaterThan(0); + await uow.CompleteAsync(); + } + } + + //More MongoDbAsyncQueryableProvider's method test. + } +} diff --git a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs index dd441bd99d..09b1551e3d 100644 --- a/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs +++ b/framework/test/Volo.Abp.MongoDB.Tests/Volo/Abp/MongoDB/Repositories/Repository_Basic_Tests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Threading.Tasks; +using MongoDB.Driver.Linq; using Shouldly; using Volo.Abp.TestApp; using Volo.Abp.TestApp.Domain; @@ -12,6 +13,15 @@ namespace Volo.Abp.MongoDB.Repositories [Collection(MongoTestCollection.Name)] public class Repository_Basic_Tests : Repository_Basic_Tests { + [Fact] + public void ToMongoQueryable_Test() + { + ((IMongoQueryable) PersonRepository).ShouldNotBeNull(); + PersonRepository.As>().ShouldNotBeNull(); + ((IMongoQueryable) PersonRepository.Where(p => p.Name == "Douglas")).ShouldNotBeNull(); + PersonRepository.Where(p => p.Name == "Douglas").As>().ShouldNotBeNull(); + } + [Fact] public async Task Linq_Queries() { diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index 8815a0a157..0d20f447d9 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -58,6 +58,7 @@ $projects = ( "framework/src/Volo.Abp.BackgroundWorkers.Quartz", "framework/src/Volo.Abp.BlobStoring", "framework/src/Volo.Abp.BlobStoring.FileSystem", + "framework/src/Volo.Abp.BlobStoring.Azure", "framework/src/Volo.Abp.Caching", "framework/src/Volo.Abp.Caching.StackExchangeRedis", "framework/src/Volo.Abp.Castle.Core", @@ -250,4 +251,4 @@ $projects = ( "modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.Domain.Shared", "modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.EntityFrameworkCore", "modules/blob-storing-database/src/Volo.Abp.BlobStoring.Database.MongoDB" -) \ No newline at end of file +)