Browse Source

Merge remote-tracking branch 'abpframework/dev' into docs

pull/4914/head
liangshiwei 6 years ago
parent
commit
4ba37c9e2a
  1. 38
      .github/lock.yml
  2. 15
      .github/stale.yml
  3. 11
      .github/workflows/angular.yml
  4. 12
      docs/en/API/Application-Configuration.md
  5. 2
      docs/en/Authorization.md
  6. 2
      docs/en/Background-Workers-Quartz.md
  7. 2
      docs/en/Best-Practices/Application-Services.md
  8. 2
      docs/en/Blob-Storing-Database.md
  9. 2
      docs/en/Entity-Framework-Core-Migrations.md
  10. 2
      docs/en/Modules/Docs.md
  11. 2
      docs/en/Startup-Templates/Module.md
  12. 46
      docs/en/Tutorials/Part-1.md
  13. 2
      docs/en/Tutorials/Part-10.md
  14. 77
      docs/en/Tutorials/Part-8.md
  15. 5
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmApplicationType.cs
  16. 17
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs
  17. 15
      framework/src/Volo.Abp.Core/System/Collections/Generic/AbpListExtensions.cs
  18. 2
      framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs
  19. 1
      framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs
  20. 11
      framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs
  21. 15
      framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs
  22. 25
      framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs
  23. 3
      framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PeopleAppService_Tests.cs
  24. 18
      framework/test/Volo.Abp.Core.Tests/System/Collections/Generic/AbpListExtensions_Tests.cs
  25. 6
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs
  26. 90
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/StringValueTypeJsonConverter.cs
  27. 6
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/UpdateFeatureDto.cs
  28. 4
      modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs
  29. 1
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs
  30. 80
      modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs
  31. 4
      modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs
  32. 4
      modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs
  33. 25
      modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo.Abp.Users.EntityFrameworkCore.Tests.csproj
  34. 2
      modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo.Abp.Users.EntityFrameworkCore.Tests.csproj.DotSettings
  35. 7
      modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo/Abp/Users/EntityFrameworkCore/AbpUserRepository_Tests.cs
  36. 38
      modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo/Abp/Users/EntityFrameworkCore/AbpUsersEntityFrameworkCoreTestModule.cs
  37. 7
      modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo/Abp/Users/EntityFrameworkCore/ExternalUserLookupService_Tests.cs
  38. 7
      modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo/Abp/Users/EntityFrameworkCore/LocalUserLookupService_Tests.cs
  39. 25
      modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj
  40. 8
      modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUserRepository_Tests.cs
  41. 31
      modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUsersMongoDbTestModule.cs
  42. 8
      modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/ExternalUserLookupService_Tests.cs
  43. 8
      modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/LocalUserLookupService_Tests.cs
  44. 22
      modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoDbFixture.cs
  45. 10
      modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoTestCollection.cs
  46. 31
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj
  47. 2
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj.DotSettings
  48. 53
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUserRepository_Tests.cs
  49. 27
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersExternalTestData.cs
  50. 17
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersLocalTestData.cs
  51. 14
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestBase.cs
  52. 29
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestDataBuilder.cs
  53. 34
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestsSharedModule.cs
  54. 77
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/ExternalUserLookupService_Tests.cs
  55. 28
      modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/LocalUserLookupService_Tests.cs
  56. 4
      npm/ng-packs/package.json
  57. 3
      npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts
  58. 6
      npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts
  59. 40
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.html
  60. 33
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts
  61. 20
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts
  62. 10
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.html
  63. 27
      npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts
  64. 2
      npm/ng-packs/packages/theme-shared/package.json

38
.github/lock.yml

@ -0,0 +1,38 @@
# Configuration for Lock Threads - https://github.com/dessant/lock-threads-app
# Number of days of inactivity before a closed issue or pull request is locked
daysUntilLock: 30
# Skip issues and pull requests created before a given timestamp. Timestamp must
# follow ISO 8601 (`YYYY-MM-DD`). Set to `false` to disable
skipCreatedBefore: false
# Issues and pull requests with these labels will be ignored. Set to `[]` to disable
exemptLabels: []
# Label to add before locking, such as `outdated`. Set to `false` to disable
lockLabel: false
# Comment to post before locking. Set to `false` to disable
lockComment: >
This thread has been automatically locked since there has not been
any recent activity after it was closed. Please open a new issue for
related bugs.
# Assign `resolved` as the reason for locking. Set to `false` to disable
setLockReason: true
# Limit to only `issues` or `pulls`
# only: issues
# Optionally, specify configuration settings just for `issues` or `pulls`
# issues:
# exemptLabels:
# - help-wanted
# lockLabel: outdated
# pulls:
# daysUntilLock: 30
# Repository to extend settings from
# _extends: repo

15
.github/stale.yml

@ -0,0 +1,15 @@
# Number of days of inactivity before an issue becomes stale
daysUntilStale: 60
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Set to true to ignore issues in a milestone (defaults to false)
exemptMilestones: true
# Label to use when marking an issue as stale
staleLabel: inactive
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs. Thank you
for your contributions.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false

11
.github/workflows/angular.yml

@ -3,15 +3,6 @@ on:
pull_request:
paths:
- 'npm/ng-packs/**'
branches:
#- master
- dev
push:
paths:
- 'npm/ng-packs/**'
branches:
#- master
- dev
jobs:
build-test-lint:
runs-on: ubuntu-18.04
@ -19,6 +10,6 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: '10.x'
node-version: '12.x'
- run: yarn && yarn ci
working-directory: npm/ng-packs

12
docs/en/API/Application-Configuration.md

@ -2,12 +2,12 @@
ABP Framework provides a pre-built and standard endpoint that contains some useful information about the application/service. Here, the list of some fundamental information at this endpoint:
* [Localization](Localization.md) values, supported and the current language of the application.
* Available and granted [policies](Authorization.md) (permissions) for the current user.
* [Setting](Settings.md) values for the current user.
* Info about the [current user](CurrentUser.md) (like id and user name).
* Info about the current [tenant](Multi-Tenancy.md) (like id and name).
* [Time zone](Timing.md) information for the current user and the [clock](Timing.md) type of the application.
* [Localization](../Localization.md) values, supported and the current language of the application.
* Available and granted [policies](../Authorization.md) (permissions) for the current user.
* [Setting](../Settings.md) values for the current user.
* Info about the [current user](../CurrentUser.md) (like id and user name).
* Info about the current [tenant](../Multi-Tenancy.md) (like id and name).
* [Time zone](../Timing.md) information for the current user and the [clock](Timing.md) type of the application.
## HTTP API

2
docs/en/Authorization.md

@ -284,8 +284,6 @@ You may need to check a policy/permission on the client side. For ASP.NET Core M
abp.auth.isGranted('MyPermissionName');
```
See [abp.auth](UI/AspNetCore/JavaScript-API/Index.md) API documentation for details.
## Permission Management
Permission management is normally done by an admin user using the permission management modal:

2
docs/en/Background-Workers-Quartz.md

@ -1,6 +1,6 @@
# Quartz Background Worker Manager
[Quartz](https://www.quartz-scheduler.net/) is an advanced background worker manager. You can integrate Quartz with the ABP Framework to use it instead of the [default background worker manager](Background-Worker.md). ABP simply integrates quartz.
[Quartz](https://www.quartz-scheduler.net/) is an advanced background worker manager. You can integrate Quartz with the ABP Framework to use it instead of the [default background worker manager](Background-Workers.md). ABP simply integrates quartz.
## Installation

2
docs/en/Best-Practices/Application-Services.md

@ -206,7 +206,7 @@ This method votes a question and returns the current score of the question.
#### Extra Properties
* **Do** use either `MapExtraPropertiesTo` extension method ([see](Object-Extensions.md)) or configure the object mapper (`MapExtraProperties`) to allow application developers to be able to extend the objects and services.
* **Do** use either `MapExtraPropertiesTo` extension method ([see](../Object-Extensions.md)) or configure the object mapper (`MapExtraProperties`) to allow application developers to be able to extend the objects and services.
#### Manipulating / Deleting Entities

2
docs/en/Blob-Storing-Database.md

@ -27,7 +27,7 @@ This command adds all the NuGet packages to corresponding layers of your solutio
Here, all the NuGet packages defined by this provider;
* [Volo.Abp.BlobStoring.Database.Domain.Shared](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Domain.Shared)
* [Volo.Abp.BlobStoring.Database.Domain.Shared](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Database.Domain.Shared)
* [Volo.Abp.BlobStoring.Database.Domain](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Database.Domain)
* [Volo.Abp.BlobStoring.Database.EntityFrameworkCore](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Database.EntityFrameworkCore)
* [Volo.Abp.BlobStoring.Database.MongoDB](https://www.nuget.org/packages/Volo.Abp.BlobStoring.Database.MongoDB)

2
docs/en/Entity-Framework-Core-Migrations.md

@ -2,7 +2,7 @@
This document begins by **introducing the default structure** provided by [the application startup template](Startup-Templates/Application.md) and **discusses various scenarios** you may want to implement for your own application.
> This document is for who want to fully understand and customize the database structure comes with [the application startup template](Startup-Templates/Application.md). If you simply want to create entities and manage your code first migrations, just follow [the startup tutorials](Tutorials/Index.md).
> This document is for who want to fully understand and customize the database structure comes with [the application startup template](Startup-Templates/Application.md). If you simply want to create entities and manage your code first migrations, just follow [the startup tutorials](Tutorials/Part-1.md).
### Source Code

2
docs/en/Modules/Docs.md

@ -613,7 +613,7 @@ Configure<DocsElasticSearchOptions>(options =>
The `Index` is automatically created after the application starts if the `Index` does not exist.
`DefaultElasticClientProvider` is responsible for creating `IElasticClient`. By default, it reads Elastic Search's `Url` from `IConfiguration`.
If your `IElasticClient` needs additional configuration, please use override `IElasticClientProvider` service and replace it in the [dependency injection](Dependency-Injection.md) system.
If your `IElasticClient` needs additional configuration, please use override `IElasticClientProvider` service and replace it in the [dependency injection](../Dependency-Injection.md) system.
```
{

2
docs/en/Startup-Templates/Module.md

@ -56,7 +56,7 @@ An `IssueType` enum and an `IssueConsts` class (which may have some constant fie
### .Domain Project
This is the domain layer of the solution. It mainly contains [entities, aggregate roots](../Entities.md), [domain services](../Domain-Services.md), [value types](../Value-Types.md), [repository interfaces](../Repositories.md) and other domain objects.
This is the domain layer of the solution. It mainly contains [entities, aggregate roots](../Entities.md), [domain services](../Domain-Services.md), value types, [repository interfaces](../Repositories.md) and other domain objects.
An `Issue` entity, an `IssueManager` domain service and an `IIssueRepository` interface are good candidates for this project.

46
docs/en/Tutorials/Part-1.md

@ -233,32 +233,30 @@ namespace Acme.BookStore
public async Task SeedAsync(DataSeedContext context)
{
if (await _bookRepository.GetCountAsync() > 0)
if (await _bookRepository.GetCountAsync() <= 0)
{
return;
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
}
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
}
}
}

2
docs/en/Tutorials/Part-10.md

@ -80,7 +80,7 @@ This is a typical migration problem and the decision depends on your case;
* You can do it programmatically on data migration or seed phase.
* You can manually handle it on the database.
We prefer to delete the database {{if DB=="EF"}}(run the `Drop-Database` in the *Package Manager Console*){{end}} since this is just an example project and data loss is not important. Since this topic is not related to the ABP Framework, we don't go deeper for all the scenarios.
We prefer to **delete the database** {{if DB=="EF"}}(run the `Drop-Database` in the *Package Manager Console*){{end}} since this is just an example project and data loss is not important. Since this topic is not related to the ABP Framework, we don't go deeper for all the scenarios.
{{if DB=="EF"}}

77
docs/en/Tutorials/Part-8.md

@ -439,50 +439,51 @@ namespace Acme.BookStore
public async Task SeedAsync(DataSeedContext context)
{
if (await _bookRepository.GetCountAsync() > 0)
if (await _bookRepository.GetCountAsync() <= 0)
{
return;
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
}
// ADDED SEED DATA FOR AUTHORS
await _authorRepository.InsertAsync(
await _authorManager.CreateAsync(
"George Orwell",
new DateTime(1903, 06, 25),
"Orwell produced literary criticism and poetry, fiction and polemical journalism; and is best known for the allegorical novella Animal Farm (1945) and the dystopian novel Nineteen Eighty-Four (1949)."
)
);
await _authorRepository.InsertAsync(
await _authorManager.CreateAsync(
"Douglas Adams",
new DateTime(1952, 03, 11),
"Douglas Adams was an English author, screenwriter, essayist, humorist, satirist and dramatist. Adams was an advocate for environmentalism and conservation, a lover of fast cars, technological innovation and the Apple Macintosh, and a self-proclaimed 'radical atheist'."
)
);
await _bookRepository.InsertAsync(
new Book
{
Name = "1984",
Type = BookType.Dystopia,
PublishDate = new DateTime(1949, 6, 8),
Price = 19.84f
},
autoSave: true
);
if (await _authorRepository.GetCountAsync() <= 0)
{
await _authorRepository.InsertAsync(
await _authorManager.CreateAsync(
"George Orwell",
new DateTime(1903, 06, 25),
"Orwell produced literary criticism and poetry, fiction and polemical journalism; and is best known for the allegorical novella Animal Farm (1945) and the dystopian novel Nineteen Eighty-Four (1949)."
)
);
await _bookRepository.InsertAsync(
new Book
{
Name = "The Hitchhiker's Guide to the Galaxy",
Type = BookType.ScienceFiction,
PublishDate = new DateTime(1995, 9, 27),
Price = 42.0f
},
autoSave: true
);
await _authorRepository.InsertAsync(
await _authorManager.CreateAsync(
"Douglas Adams",
new DateTime(1952, 03, 11),
"Douglas Adams was an English author, screenwriter, essayist, humorist, satirist and dramatist. Adams was an advocate for environmentalism and conservation, a lover of fast cars, technological innovation and the Apple Macintosh, and a self-proclaimed 'radical atheist'."
)
);
}
}
}
}

5
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/NpmApplicationType.cs

@ -5,6 +5,7 @@ namespace Volo.Abp.Cli.ProjectModification
[Flags]
public enum NpmApplicationType
{
Mvc = 1
Mvc = 1,
Angular = 2
}
}
}

17
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/SolutionModuleAdder.cs

@ -39,7 +39,7 @@ namespace Volo.Abp.Cli.ProjectModification
EfCoreMigrationAdder efCoreMigrationAdder,
DerivedClassFinder derivedClassFinder,
ProjectNpmPackageAdder projectNpmPackageAdder,
NpmGlobalPackagesChecker npmGlobalPackagesChecker,
NpmGlobalPackagesChecker npmGlobalPackagesChecker,
IRemoteServiceExceptionHandler remoteServiceExceptionHandler,
SourceCodeDownloadService sourceCodeDownloadService,
SolutionFileModifier solutionFileModifier,
@ -159,7 +159,7 @@ namespace Volo.Abp.Cli.ProjectModification
{
Directory.Delete(demoFolder, true);
}
var hostFolder = Path.Combine(targetModuleFolder, "host");
if (Directory.Exists(hostFolder))
{
@ -186,7 +186,9 @@ namespace Volo.Abp.Cli.ProjectModification
await ProjectNugetPackageAdder.AddAsync(targetProjectFile, nugetPackage);
}
if (!module.NpmPackages.IsNullOrEmpty())
var mvcNpmPackages = module.NpmPackages?.Where(p => p.ApplicationType.HasFlag(NpmApplicationType.Mvc)).ToList();
if (!mvcNpmPackages.IsNullOrEmpty())
{
var targetProjects = ProjectFinder.FindNpmTargetProjectFile(projectFiles);
if (targetProjects.Any())
@ -195,8 +197,7 @@ namespace Volo.Abp.Cli.ProjectModification
foreach (var targetProject in targetProjects)
{
foreach (var npmPackage in module.NpmPackages.Where(p =>
p.ApplicationType.HasFlag(NpmApplicationType.Mvc)))
foreach (var npmPackage in mvcNpmPackages)
{
await ProjectNpmPackageAdder.AddAsync(Path.GetDirectoryName(targetProject), npmPackage);
}
@ -222,7 +223,7 @@ namespace Volo.Abp.Cli.ProjectModification
}
var dbMigrationsProject = projectFiles.FirstOrDefault(p => p.EndsWith(".DbMigrations.csproj"));
if (dbMigrationsProject == null)
{
Logger.LogDebug("Solution doesn't have a \".DbMigrations\" project.");
@ -241,7 +242,7 @@ namespace Volo.Abp.Cli.ProjectModification
if (addedNewBuilder && !skipDbMigrations)
{
EfCoreMigrationAdder.AddMigration(dbMigrationsProject, module.Name, startupProject);
EfCoreMigrationAdder.AddMigration(dbMigrationsProject, module.Name, startupProject);
}
}
@ -274,4 +275,4 @@ namespace Volo.Abp.Cli.ProjectModification
.Any(p => p.EndsWith(".IdentityServer") || p.EndsWith(".HttpApi.Host"));
}
}
}
}

15
framework/src/Volo.Abp.Core/System/Collections/Generic/AbpListExtensions.cs

@ -9,6 +9,14 @@ namespace System.Collections.Generic
/// </summary>
public static class AbpListExtensions
{
public static void InsertRange<T>(this IList<T> source, int index, IEnumerable<T> items)
{
foreach (var item in items)
{
source.Insert(index++, item);
}
}
public static int FindIndex<T>(this IList<T> source, Predicate<T> selector)
{
for (var i = 0; i < source.Count; ++i)
@ -182,7 +190,7 @@ namespace System.Collections.Generic
/// <param name="getDependencies">Function to resolve the dependencies</param>
/// <returns>
/// Returns a new list ordered by dependencies.
/// If A depends on B, then B will come before than A in the resulting list.
/// If A depends on B, then B will come before than A in the resulting list.
/// </returns>
public static List<T> SortByDependencies<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> getDependencies)
{
@ -202,14 +210,15 @@ namespace System.Collections.Generic
}
/// <summary>
///
///
/// </summary>
/// <typeparam name="T">The type of the members of values.</typeparam>
/// <param name="item">Item to resolve</param>
/// <param name="getDependencies">Function to resolve the dependencies</param>
/// <param name="sorted">List with the sortet items</param>
/// <param name="visited">Dictionary with the visited items</param>
private static void SortByDependenciesVisit<T>(T item, Func<T, IEnumerable<T>> getDependencies, List<T> sorted, Dictionary<T, bool> visited)
private static void SortByDependenciesVisit<T>(T item, Func<T, IEnumerable<T>> getDependencies, List<T> sorted,
Dictionary<T, bool> visited)
{
bool inProcess;
var alreadyVisited = visited.TryGetValue(item, out inProcess);

2
framework/src/Volo.Abp.EntityFrameworkCore/Volo/Abp/EntityFrameworkCore/EntityHistory/EntityHistoryHelper.cs

@ -242,7 +242,7 @@ namespace Volo.Abp.EntityFrameworkCore.EntityHistory
}
}
if (IsBaseAuditProperty(propertyInfo, entityType))
if (propertyInfo != null && IsBaseAuditProperty(propertyInfo, entityType))
{
return false;
}

1
framework/src/Volo.Abp.Http.Client/Volo/Abp/Http/Client/DynamicProxying/DynamicHttpProxyInterceptor.cs

@ -17,7 +17,6 @@ using Volo.Abp.Http.Modeling;
using Volo.Abp.Http.ProxyScripting.Generators;
using Volo.Abp.Json;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
using Volo.Abp.Threading;
using Volo.Abp.Tracing;

11
framework/src/Volo.Abp.Json/Volo/Abp/Json/AbpJsonModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.Modularity;
using Volo.Abp.Json.Newtonsoft;
using Volo.Abp.Modularity;
using Volo.Abp.Timing;
namespace Volo.Abp.Json
@ -6,6 +7,12 @@ namespace Volo.Abp.Json
[DependsOn(typeof(AbpTimingModule))]
public class AbpJsonModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpNewtonsoftJsonSerializerOptions>(options =>
{
options.Converters.Add<AbpJsonIsoDateTimeConverter>();
});
}
}
}

15
framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/AbpNewtonsoftJsonSerializerOptions.cs

@ -0,0 +1,15 @@
using Newtonsoft.Json;
using Volo.Abp.Collections;
namespace Volo.Abp.Json.Newtonsoft
{
public class AbpNewtonsoftJsonSerializerOptions
{
public ITypeList<JsonConverter> Converters { get; }
public AbpNewtonsoftJsonSerializerOptions()
{
Converters = new TypeList<JsonConverter>();
}
}
}

25
framework/src/Volo.Abp.Json/Volo/Abp/Json/Newtonsoft/NewtonsoftJsonSerializer.cs

@ -1,4 +1,8 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Volo.Abp.DependencyInjection;
@ -7,14 +11,19 @@ namespace Volo.Abp.Json.Newtonsoft
{
public class NewtonsoftJsonSerializer : IJsonSerializer, ITransientDependency
{
private readonly AbpJsonIsoDateTimeConverter _dateTimeConverter;
private static readonly CamelCaseExceptDictionaryKeysResolver SharedCamelCaseExceptDictionaryKeysResolver =
new CamelCaseExceptDictionaryKeysResolver();
public NewtonsoftJsonSerializer(AbpJsonIsoDateTimeConverter dateTimeConverter)
protected List<JsonConverter> Converters { get; }
public NewtonsoftJsonSerializer(
IOptions<AbpNewtonsoftJsonSerializerOptions> options,
IServiceProvider serviceProvider)
{
_dateTimeConverter = dateTimeConverter;
Converters = options.Value
.Converters
.Select(c => (JsonConverter) serviceProvider.GetRequiredService(c))
.ToList();
}
public string Serialize(object obj, bool camelCase = true, bool indented = false)
@ -36,8 +45,8 @@ namespace Volo.Abp.Json.Newtonsoft
{
var settings = new JsonSerializerSettings();
settings.Converters.Insert(0, _dateTimeConverter);
settings.Converters.InsertRange(0, Converters);
if (camelCase)
{
settings.ContractResolver = SharedCamelCaseExceptDictionaryKeysResolver;
@ -47,7 +56,7 @@ namespace Volo.Abp.Json.Newtonsoft
{
settings.Formatting = Formatting.Indented;
}
return settings;
}
@ -63,4 +72,4 @@ namespace Volo.Abp.Json.Newtonsoft
}
}
}
}
}

3
framework/test/Volo.Abp.AspNetCore.Mvc.Tests/Volo/Abp/AspNetCore/Mvc/PeopleAppService_Tests.cs

@ -83,7 +83,6 @@ namespace Volo.Abp.AspNetCore.Mvc
(await _personRepository.FindAsync(resultDto.Id)).ShouldNotBeNull();
}
[Fact]
public async Task Update_Test()
{
@ -170,4 +169,4 @@ namespace Volo.Abp.AspNetCore.Mvc
douglas.Phones.Any(p => p.Number == firstPhone.Number).ShouldBeFalse();
}
}
}
}

18
framework/test/Volo.Abp.Core.Tests/System/Collections/Generic/AbpListExtensions_Tests.cs

@ -7,6 +7,20 @@ namespace System.Collections.Generic
{
public class AbpListExtensions_Tests
{
[Fact]
public void InsertRange()
{
var list = Enumerable.Range(1, 3).ToList();
list.InsertRange(1, new[] {7, 8, 9});
list[0].ShouldBe(1);
list[1].ShouldBe(7);
list[2].ShouldBe(8);
list[3].ShouldBe(9);
list[4].ShouldBe(2);
list[5].ShouldBe(3);
}
[Fact]
public void InsertAfter()
{
@ -191,7 +205,7 @@ namespace System.Collections.Generic
{
var list = RandomHelper
.GenerateRandomizedList(new char[] {'A', 'B', 'C', 'D', 'E', 'F', 'G'});
list = list.SortByDependencies(c => dependencies[c]);
foreach (var dependency in dependencies)
@ -204,4 +218,4 @@ namespace System.Collections.Generic
}
}
}
}
}

6
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/AbpFeatureManagementApplicationContractsModule.cs

@ -1,4 +1,5 @@
using Volo.Abp.Application;
using Volo.Abp.Json.Newtonsoft;
using Volo.Abp.Modularity;
using Volo.Abp.VirtualFileSystem;
@ -16,6 +17,11 @@ namespace Volo.Abp.FeatureManagement
{
options.FileSets.AddEmbedded<AbpFeatureManagementApplicationContractsModule>();
});
Configure<AbpNewtonsoftJsonSerializerOptions>(options =>
{
options.Converters.Add<StringValueTypeJsonConverter>();
});
}
}
}

90
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/StringValueTypeJsonConverter.cs

@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Validation.StringValues;
namespace Volo.Abp.FeatureManagement
{
public class StringValueTypeJsonConverter : JsonConverter, ITransientDependency
{
public override bool CanWrite => false;
public override bool CanConvert(Type objectType)
{
return objectType == typeof(IStringValueType);
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("This method should not be called to write (since CanWrite is false).");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType != JsonToken.StartObject)
{
return null;
}
var jsonObject = JObject.Load(reader);
var stringValue = CreateStringValueTypeByName(jsonObject, jsonObject["name"].ToString());
foreach (var o in serializer.Deserialize<Dictionary<string, object>>(
new JsonTextReader(new StringReader(jsonObject["properties"].ToString()))))
{
stringValue[o.Key] = o.Value;
}
stringValue.Validator = CreateValueValidatorByName(jsonObject["validator"], jsonObject["validator"]["name"].ToString());
foreach (var o in serializer.Deserialize<Dictionary<string, object>>(
new JsonTextReader(new StringReader(jsonObject["validator"]["properties"].ToString()))))
{
stringValue.Validator[o.Key] = o.Value;
}
return stringValue;
}
protected virtual IStringValueType CreateStringValueTypeByName(JObject jObject, string name)
{
if (name == "SelectionStringValueType")
{
var selectionStringValueType = new SelectionStringValueType();
if (jObject["itemSource"].HasValues)
{
selectionStringValueType.ItemSource = new StaticSelectionStringValueItemSource(jObject["itemSource"]["items"]
.Select(item => new LocalizableSelectionStringValueItem()
{
Value = item["value"].ToString(),
DisplayText = new LocalizableStringInfo(item["displayText"]["resourceName"].ToString(), item["displayText"]["name"].ToString())
}).ToArray());
}
return selectionStringValueType;
}
return name switch
{
"FreeTextStringValueType" => new FreeTextStringValueType(),
"ToggleStringValueType" => new ToggleStringValueType(),
_ => throw new ArgumentException($"{nameof(IStringValueType)} named {name} was not found!")
};
}
protected virtual IValueValidator CreateValueValidatorByName(JToken jObject, string name)
{
return name switch
{
"NULL" => new AlwaysValidValueValidator(),
"BOOLEAN" => new BooleanValueValidator(),
"NUMERIC" => new NumericValueValidator(),
"STRING" => new StringValueValidator(),
_ => throw new ArgumentException($"{nameof(IValueValidator)} named {name} was not found!")
};
}
}
}

6
modules/feature-management/src/Volo.Abp.FeatureManagement.Application.Contracts/Volo/Abp/FeatureManagement/UpdateFeatureDto.cs

@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Volo.Abp.FeatureManagement
namespace Volo.Abp.FeatureManagement
{
public class UpdateFeatureDto
{

4
modules/feature-management/src/Volo.Abp.FeatureManagement.Application/Volo/Abp/FeatureManagement/FeatureAppService.cs

@ -1,13 +1,9 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using JetBrains.Annotations;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options;
using Volo.Abp.Application.Services;
using Volo.Abp.Features;
namespace Volo.Abp.FeatureManagement

1
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/FeatureAppService_Tests.cs

@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using NSubstitute;

80
modules/feature-management/test/Volo.Abp.FeatureManagement.Application.Tests/Volo/Abp/FeatureManagement/StringValueJsonConverter_Tests.cs

@ -0,0 +1,80 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Shouldly;
using Volo.Abp.Json;
using Volo.Abp.Validation.StringValues;
using Xunit;
namespace Volo.Abp.FeatureManagement
{
public class StringValueJsonConverter_Tests : FeatureManagementApplicationTestBase
{
private readonly IJsonSerializer _jsonSerializer;
public StringValueJsonConverter_Tests()
{
_jsonSerializer = GetRequiredService<IJsonSerializer>();
}
[Fact]
public void Should_Serialize_And_Deserialize()
{
var featureListDto = new FeatureListDto
{
Features = new List<FeatureDto>
{
new FeatureDto
{
ValueType = new FreeTextStringValueType
{
Validator = new BooleanValueValidator()
}
},
new FeatureDto
{
ValueType = new SelectionStringValueType
{
ItemSource = new StaticSelectionStringValueItemSource(
new LocalizableSelectionStringValueItem
{
Value = "TestValue",
DisplayText = new LocalizableStringInfo("TestResourceName", "TestName")
}),
Validator = new AlwaysValidValueValidator()
}
},
new FeatureDto
{
ValueType = new ToggleStringValueType
{
Validator = new NumericValueValidator
{
MaxValue = 1000,
MinValue = 10
}
}
}
}
};
var serialized = _jsonSerializer.Serialize(featureListDto, indented: true);
var featureListDto2 = _jsonSerializer.Deserialize<FeatureListDto>(serialized);
featureListDto2.Features[0].ValueType.ShouldBeOfType<FreeTextStringValueType>();
featureListDto2.Features[0].ValueType.Validator.ShouldBeOfType<BooleanValueValidator>();
featureListDto2.Features[1].ValueType.ShouldBeOfType<SelectionStringValueType>();
featureListDto2.Features[1].ValueType.Validator.ShouldBeOfType<AlwaysValidValueValidator>();
featureListDto2.Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldBeOfType<LocalizableSelectionStringValueItem[]>();
featureListDto2.Features[1].ValueType.As<SelectionStringValueType>().ItemSource.Items.ShouldContain(x =>
x.Value == "TestValue" && x.DisplayText.ResourceName == "TestResourceName" &&
x.DisplayText.Name == "TestName");
featureListDto2.Features[2].ValueType.ShouldBeOfType<ToggleStringValueType>();
featureListDto2.Features[2].ValueType.Validator.ShouldBeOfType<NumericValueValidator>();
featureListDto2.Features[2].ValueType.Validator.As<NumericValueValidator>().MaxValue.ShouldBe(1000);
featureListDto2.Features[2].ValueType.Validator.As<NumericValueValidator>().MinValue.ShouldBe(10);
}
}
}

4
modules/identity/src/Volo.Abp.Identity.EntityFrameworkCore/Volo/Abp/Identity/EntityFrameworkCore/EFCoreIdentitySecurityLogRepository.cs

@ -95,8 +95,8 @@ namespace Volo.Abp.Identity.EntityFrameworkCore
string correlationId = null)
{
return DbSet.AsNoTracking()
.WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime)
.WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime >= endTime)
.WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime.Value)
.WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime < endTime.Value.AddDays(1).Date)
.WhereIf(!applicationName.IsNullOrWhiteSpace(), securityLog => securityLog.ApplicationName == applicationName)
.WhereIf(!identity.IsNullOrWhiteSpace(), securityLog => securityLog.Identity == identity)
.WhereIf(!action.IsNullOrWhiteSpace(), securityLog => securityLog.Action == action)

4
modules/identity/src/Volo.Abp.Identity.MongoDB/Volo/Abp/Identity/MongoDB/MongoIdentitySecurityLogRepository.cs

@ -101,8 +101,8 @@ namespace Volo.Abp.Identity.MongoDB
string correlationId = null)
{
return GetMongoQueryable()
.WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime)
.WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime >= endTime)
.WhereIf(startTime.HasValue, securityLog => securityLog.CreationTime >= startTime.Value)
.WhereIf(endTime.HasValue, securityLog => securityLog.CreationTime < endTime.Value.AddDays(1).Date)
.WhereIf(!applicationName.IsNullOrWhiteSpace(),
securityLog => securityLog.ApplicationName == applicationName)
.WhereIf(!identity.IsNullOrWhiteSpace(), securityLog => securityLog.Identity == identity)

25
modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo.Abp.Users.EntityFrameworkCore.Tests.csproj

@ -1,25 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AssemblyName>Volo.Abp.Users.EntityFrameworkCore.Tests</AssemblyName>
<PackageId>Volo.Abp.Users.EntityFrameworkCore.Tests</PackageId>
<LangVersion>latest</LangVersion>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Users.EntityFrameworkCore\Volo.Abp.Users.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\..\test\Volo.Abp.Users.Tests.Shared\Volo.Abp.Users.Tests.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="3.1.4" />
</ItemGroup>
</Project>

2
modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo.Abp.Users.EntityFrameworkCore.Tests.csproj.DotSettings

@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary>

7
modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo/Abp/Users/EntityFrameworkCore/AbpUserRepository_Tests.cs

@ -1,7 +0,0 @@
namespace Volo.Abp.Users.EntityFrameworkCore
{
public class AbpUserRepository_Tests : AbpUserRepository_Tests<AbpUsersEntityFrameworkCoreTestModule>
{
}
}

38
modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo/Abp/Users/EntityFrameworkCore/AbpUsersEntityFrameworkCoreTestModule.cs

@ -1,38 +0,0 @@
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;
using Volo.Abp.Uow;
namespace Volo.Abp.Users.EntityFrameworkCore
{
[DependsOn(
typeof(AbpUsersTestsSharedModule),
typeof(AbpUsersEntityFrameworkCoreModule)
)]
public class AbpUsersEntityFrameworkCoreTestModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddEntityFrameworkInMemoryDatabase();
var databaseName = Guid.NewGuid().ToString();
services.Configure<AbpDbContextOptions>(options =>
{
options.Configure(context =>
{
context.DbContextOptions.UseInMemoryDatabase(databaseName);
});
});
services.Configure<AbpUnitOfWorkDefaultOptions>(options =>
{
options.TransactionBehavior = UnitOfWorkTransactionBehavior.Disabled; //EF in-memory database does not support transactions
});
services.AddAssemblyOf<AbpUsersEntityFrameworkCoreTestModule>();
}
}
}

7
modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo/Abp/Users/EntityFrameworkCore/ExternalUserLookupService_Tests.cs

@ -1,7 +0,0 @@
namespace Volo.Abp.Users.EntityFrameworkCore
{
public class ExternalUserLookupService_Tests : ExternalUserLookupService_Tests<AbpUsersEntityFrameworkCoreTestModule>
{
}
}

7
modules/users/test/Volo.Abp.Users.EntityFrameworkCore.Tests/Volo/Abp/Users/EntityFrameworkCore/LocalUserLookupService_Tests.cs

@ -1,7 +0,0 @@
namespace Volo.Abp.Users.EntityFrameworkCore
{
public class LocalUserLookupService_Tests : LocalUserLookupService_Tests<AbpUsersEntityFrameworkCoreTestModule>
{
}
}

25
modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo.Abp.Users.MongoDB.Tests.csproj

@ -1,25 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AssemblyName>Volo.Abp.Users.MongoDB.Tests</AssemblyName>
<PackageId>Volo.Abp.Users.MongoDB.Tests</PackageId>
<LangVersion>latest</LangVersion>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Users.MongoDB\Volo.Abp.Users.MongoDB.csproj" />
<ProjectReference Include="..\..\test\Volo.Abp.Users.Tests.Shared\Volo.Abp.Users.Tests.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="Mongo2Go" Version="2.2.12" />
</ItemGroup>
</Project>

8
modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUserRepository_Tests.cs

@ -1,8 +0,0 @@
namespace Volo.Abp.Users.MongoDB
{
[Collection(MongoTestCollection.Name)]
public class AbpUserRepository_Tests : AbpUserRepository_Tests<AbpUsersMongoDbTestModule>
{
}
}

31
modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/AbpUsersMongoDbTestModule.cs

@ -1,31 +0,0 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using Mongo2Go;
using Volo.Abp.Data;
using Volo.Abp.Modularity;
namespace Volo.Abp.Users.MongoDB
{
[DependsOn(
typeof(AbpUsersMongoDbModule),
typeof(AbpUsersTestsSharedModule)
)]
public class AbpUsersMongoDbTestModule : AbpModule
{
private static readonly MongoDbRunner MongoDbRunner = MongoDbRunner.Start();
public override void ConfigureServices(IServiceCollection services)
{
var connectionString = MongoDbFixture.ConnectionString.EnsureEndsWith('/') +
"Db_" +
Guid.NewGuid().ToString("N");
Configure<AbpDbConnectionOptions>(options =>
{
options.ConnectionStrings.Default = connectionString;
});
services.AddAssemblyOf<AbpUsersMongoDbTestModule>();
}
}
}

8
modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/ExternalUserLookupService_Tests.cs

@ -1,8 +0,0 @@
namespace Volo.Abp.Users.MongoDB
{
[Collection(MongoTestCollection.Name)]
public class ExternalUserLookupService_Tests : ExternalUserLookupService_Tests<AbpUsersMongoDbTestModule>
{
}
}

8
modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/LocalUserLookupService_Tests.cs

@ -1,8 +0,0 @@
namespace Volo.Abp.Users.MongoDB
{
[Collection(MongoTestCollection.Name)]
public class LocalUserLookupService_Tests : LocalUserLookupService_Tests<AbpUsersMongoDbTestModule>
{
}
}

22
modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoDbFixture.cs

@ -1,22 +0,0 @@
using System;
using Mongo2Go;
namespace Volo.Abp.Users.MongoDB
{
public class MongoDbFixture : IDisposable
{
private static readonly MongoDbRunner MongoDbRunner;
public static readonly string ConnectionString;
static MongoDbFixture()
{
MongoDbRunner = MongoDbRunner.Start();
ConnectionString = MongoDbRunner.ConnectionString;
}
public void Dispose()
{
MongoDbRunner?.Dispose();
}
}
}

10
modules/users/test/Volo.Abp.Users.MongoDB.Tests/Volo/Abp/Users/MongoDB/MongoTestCollection.cs

@ -1,10 +0,0 @@
using Xunit;
namespace Volo.Abp.Users.MongoDB
{
[CollectionDefinition(Name)]
public class MongoTestCollection : ICollectionFixture<MongoDbFixture>
{
public const string Name = "MongoDB Collection";
}
}

31
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj

@ -1,31 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AssemblyName>Volo.Abp.Users.Tests.Shared</AssemblyName>
<PackageId>Volo.Abp.Users.Tests.Shared</PackageId>
<LangVersion>latest</LangVersion>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateAssemblyConfigurationAttribute>false</GenerateAssemblyConfigurationAttribute>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<GenerateAssemblyProductAttribute>false</GenerateAssemblyProductAttribute>
<RootNamespace />
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Volo.Abp.Users.Domain\Volo.Abp.Users.Domain.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.Autofac\Volo.Abp.Autofac.csproj" />
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.TestBase\Volo.Abp.TestBase.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.9.0" />
<PackageReference Include="NSubstitute" Version="4.2.1" />
<PackageReference Include="Shouldly" Version="3.0.2" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.extensibility.execution" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
</ItemGroup>
</Project>

2
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo.Abp.Users.Tests.Shared.csproj.DotSettings

@ -1,2 +0,0 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/CodeInspection/CSharpLanguageProject/LanguageLevel/@EntryValue">CSharp71</s:String></wpf:ResourceDictionary>

53
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUserRepository_Tests.cs

@ -1,53 +0,0 @@
using System;
using System.Linq;
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.Users
{
public abstract class AbpUserRepository_Tests<TStartupModule> : AbpUsersTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly AbpUsersLocalTestData _localTestData;
private readonly IAbpUserRepository _userRepository;
protected AbpUserRepository_Tests()
{
_userRepository = GetRequiredService<IAbpUserRepository>();
_localTestData = GetRequiredService<AbpUsersLocalTestData>();
}
[Fact]
public async Task FindAsync()
{
var john = await _userRepository.FindAsync(_localTestData.John.Id);
john.ShouldNotBeNull();
john.UserName.ShouldBe(_localTestData.John.UserName);
//Undefined user
(await _userRepository.FindAsync(Guid.NewGuid())).ShouldBeNull();
}
[Fact]
public async Task FindByUserNameAsync()
{
var john = await _userRepository.FindByUserNameAsync(_localTestData.John.UserName);
john.ShouldNotBeNull();
john.Id.ShouldBe(_localTestData.John.Id);
//Undefined user
(await _userRepository.FindByUserNameAsync("undefined-user")).ShouldBeNull();
}
[Fact]
public async Task GetListAsync()
{
(await _userRepository.GetListAsync(new Guid[0])).Any().ShouldBeFalse();
(await _userRepository.GetListAsync(new[] { _localTestData.John.Id })).Count.ShouldBe(1);
(await _userRepository.GetListAsync(new[] { _localTestData.John.Id, _localTestData.David.Id })).Count.ShouldBe(2);
(await _userRepository.GetListAsync(new[] { _localTestData.John.Id, _localTestData.David.Id, Guid.NewGuid() })).Count.ShouldBe(2);
}
}
}

27
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersExternalTestData.cs

@ -1,27 +0,0 @@
using System;
using System.Collections.Generic;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Users
{
public class AbpUsersExternalTestData : ISingletonDependency
{
public IAbpUserData David { get; }
public IAbpUserData Neo { get; }
public AbpUsersExternalTestData(AbpUsersLocalTestData localTestData)
{
Neo = new AbpUserData(Guid.NewGuid(), "neo");
David = localTestData.David.ToAbpUserData();
}
public List<IAbpUserData> GetAllUsers()
{
return new List<IAbpUserData>
{
David,
Neo
};
}
}
}

17
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersLocalTestData.cs

@ -1,17 +0,0 @@
using System;
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Users
{
public class AbpUsersLocalTestData : ISingletonDependency
{
public AbpUser John { get; }
public AbpUser David { get; }
public AbpUsersLocalTestData()
{
John = new AbpUser(Guid.NewGuid(), "john");
David = new AbpUser(Guid.NewGuid(), "david", "david@abp.io");
}
}
}

14
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestBase.cs

@ -1,14 +0,0 @@
using Volo.Abp.Modularity;
using Volo.Abp.Testing;
namespace Volo.Abp.Users
{
public abstract class AbpUsersTestBase<TStartupModule> : AbpIntegratedTest<TStartupModule>
where TStartupModule : IAbpModule
{
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options)
{
options.UseAutofac();
}
}
}

29
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestDataBuilder.cs

@ -1,29 +0,0 @@
using Volo.Abp.DependencyInjection;
namespace Volo.Abp.Users
{
public class AbpUsersTestDataBuilder : ITransientDependency
{
private readonly IAbpUserRepository _userRepository;
private readonly AbpUsersLocalTestData _localTestData;
public AbpUsersTestDataBuilder(
IAbpUserRepository userRepository,
AbpUsersLocalTestData localTestData)
{
_userRepository = userRepository;
_localTestData = localTestData;
}
public void Build()
{
AddUsers();
}
private void AddUsers()
{
_userRepository.Insert(_localTestData.John);
_userRepository.Insert(_localTestData.David);
}
}
}

34
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/AbpUsersTestsSharedModule.cs

@ -1,34 +0,0 @@
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
namespace Volo.Abp.Users
{
[DependsOn(
typeof(AbpUsersDomainModule),
typeof(AbpTestBaseModule),
typeof(AbpAutofacModule)
)]
public class AbpUsersTestsSharedModule : AbpModule
{
public override void ConfigureServices(IServiceCollection services)
{
services.AddAssemblyOf<AbpUsersTestsSharedModule>();
}
public override void OnApplicationInitialization(ApplicationInitializationContext context)
{
SeedTestData(context);
}
private static void SeedTestData(ApplicationInitializationContext context)
{
using (var scope = context.ServiceProvider.CreateScope())
{
scope.ServiceProvider
.GetRequiredService<AbpUsersTestDataBuilder>()
.Build();
}
}
}
}

77
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/ExternalUserLookupService_Tests.cs

@ -1,77 +0,0 @@
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.Users
{
public abstract class ExternalUserLookupService_Tests<TStartupModule> : AbpUsersTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IAbpUserLookupService _lookupService;
private readonly AbpUsersLocalTestData _localTestData;
private readonly AbpUsersExternalTestData _externalTestData;
protected ExternalUserLookupService_Tests()
{
_lookupService = GetRequiredService<IAbpUserLookupService>();
_localTestData = GetRequiredService<AbpUsersLocalTestData>();
_externalTestData = GetRequiredService<AbpUsersExternalTestData>();
}
protected override void AfterAddApplication(IServiceCollection services)
{
services.AddTransient<IExternalAbpUserLookupServiceProvider, TestExternalAbpUserLookupServiceProvider>();
}
[Fact]
public async Task FindByUserNameAsync()
{
(await GetRequiredService<IAbpUserRepository>().FindByUserNameAsync(_localTestData.John.UserName)).ShouldNotBeNull();
(await _lookupService.FindByUserNameAsync("undefined-user")).ShouldBeNull();
(await _lookupService.FindByUserNameAsync(_localTestData.John.UserName)).ShouldBeNull(); //Because it's not available in the external provider. And this will delete the user!
(await _lookupService.FindByUserNameAsync(_localTestData.David.UserName)).ShouldNotBeNull();
(await _lookupService.FindByUserNameAsync(_externalTestData.Neo.UserName)).ShouldNotBeNull();
(await GetRequiredService<IAbpUserRepository>().FindByUserNameAsync(_localTestData.John.UserName)).ShouldBeNull();
}
[Fact]
public async Task FindByIdAsync()
{
(await GetRequiredService<IAbpUserRepository>().FindAsync(_localTestData.John.Id)).ShouldNotBeNull();
(await _lookupService.FindByIdAsync(Guid.NewGuid())).ShouldBeNull();
(await _lookupService.FindByIdAsync(_localTestData.John.Id)).ShouldBeNull(); //Because it's not available in the external provider. And this will delete the user!
(await _lookupService.FindByIdAsync(_localTestData.David.Id)).ShouldNotBeNull();
(await _lookupService.FindByIdAsync(_externalTestData.Neo.Id)).ShouldNotBeNull();
(await GetRequiredService<IAbpUserRepository>().FindAsync(_localTestData.John.Id)).ShouldBeNull();
}
public class TestExternalAbpUserLookupServiceProvider : IExternalAbpUserLookupServiceProvider
{
private readonly AbpUsersExternalTestData _externalTestData;
public TestExternalAbpUserLookupServiceProvider(AbpUsersExternalTestData externalTestData)
{
_externalTestData = externalTestData;
}
public Task<IAbpUserData> FindByIdAsync(Guid id, CancellationToken cancellationToken = default)
{
return Task.FromResult(_externalTestData.GetAllUsers().FirstOrDefault(u => u.Id == id));
}
public Task<IAbpUserData> FindByUserNameAsync(string userName, CancellationToken cancellationToken = default)
{
return Task.FromResult(_externalTestData.GetAllUsers().FirstOrDefault(u => u.UserName == userName));
}
}
}
}

28
modules/users/test/Volo.Abp.Users.Tests.Shared/Volo/Abp/Users/LocalUserLookupService_Tests.cs

@ -1,28 +0,0 @@
using System.Threading.Tasks;
using Shouldly;
using Volo.Abp.Modularity;
using Xunit;
namespace Volo.Abp.Users
{
public abstract class LocalUserLookupService_Tests<TStartupModule> : AbpUsersTestBase<TStartupModule>
where TStartupModule : IAbpModule
{
private readonly IAbpUserLookupService _lookupService;
private readonly AbpUsersLocalTestData _localTestData;
protected LocalUserLookupService_Tests()
{
_lookupService = GetRequiredService<IAbpUserLookupService>();
_localTestData = GetRequiredService<AbpUsersLocalTestData>();
}
[Fact]
public async Task FindByUserNameAsync()
{
(await _lookupService.FindByUserNameAsync(_localTestData.John.UserName)).ShouldNotBeNull();
(await _lookupService.FindByUserNameAsync(_localTestData.David.UserName)).ShouldNotBeNull();
(await _lookupService.FindByUserNameAsync("undefined-user")).ShouldBeNull();
}
}
}

4
npm/ng-packs/package.json

@ -16,7 +16,7 @@
"scripts:build": "cd scripts && yarn && yarn build",
"prepare:workspace": "yarn scripts:build --noInstall",
"ci": "yarn ng lint && yarn prepare:workspace && yarn ci:test && yarn ci:build",
"ci:test": "ng test --coverage=false",
"ci:test": "ng test --coverage=false --silent",
"ci:build": "cd scripts && yarn build:prod",
"lerna": "lerna",
"compile:ivy": "yarn ngcc --properties es2015 browser module main --first-only --create-ivy-entry-points --tsconfig './tsconfig.prod.json' --source node_modules --async false",
@ -51,7 +51,7 @@
"@fortawesome/fontawesome-free": "^5.13.0",
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
"@ngneat/spectator": "^5.11.0",
"@ngx-validate/core": "^0.0.9",
"@ngx-validate/core": "^0.0.10",
"@ngxs/devtools-plugin": "^3.6.2",
"@ngxs/logger-plugin": "^3.6.2",
"@ngxs/router-plugin": "^3.6.2",

3
npm/ng-packs/packages/core/src/lib/tests/initial-utils.spec.ts

@ -77,7 +77,8 @@ describe('InitialUtils', () => {
const injectorSpy = jest.spyOn(injector, 'get');
const store = spectator.inject(Store);
store.selectSnapshot.andCallFake(selector => selector({ SessionState: { language: 'tr' } }));
injectorSpy.mockReturnValue(store);
injectorSpy.mockReturnValueOnce(store);
injectorSpy.mockReturnValueOnce({ cultureNameToLocaleFileNameMapping: {} });
expect(typeof localeInitializer(injector)).toBe('function');
expect(await localeInitializer(injector)()).toBe('resolved');
});

6
npm/ng-packs/packages/core/src/lib/tests/localization.service.spec.ts

@ -1,3 +1,4 @@
import { CORE_OPTIONS } from '../tokens/options.token';
import { Router } from '@angular/router';
import { createServiceFactory, SpectatorService, SpyObject } from '@ngneat/spectator/jest';
import { Actions, Store } from '@ngxs/store';
@ -13,7 +14,10 @@ describe('LocalizationService', () => {
service: LocalizationService,
entryComponents: [],
mocks: [Store, Router],
providers: [{ provide: Actions, useValue: new Subject() }],
providers: [
{ provide: Actions, useValue: new Subject() },
{ provide: CORE_OPTIONS, useValue: { cultureNameToLocaleFileNameMapping: {} } },
],
});
beforeEach(() => {

40
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.html

@ -1,15 +1,13 @@
<div class="form-group" [abpPermission]="prop.permission" [ngSwitch]="getComponent(prop)">
<ng-template ngSwitchCase="input">
<label [htmlFor]="prop.id"
>{{ prop.displayName | abpLocalization }} {{ getAsterisk(prop, data) }}</label
>
<label [htmlFor]="prop.id">{{ prop.displayName | abpLocalization }} {{ asterisk }}</label>
<input
[id]="prop.id"
[formControlName]="prop.name"
[autocomplete]="prop.autocomplete"
[type]="getType(prop)"
[abpDisabled]="prop.disabled(data)"
[readonly]="prop.readonly(data)"
[abpDisabled]="disabled"
[readonly]="readonly"
class="form-control"
/>
</ng-template>
@ -19,28 +17,26 @@
<input
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="prop.disabled(data)"
[abpDisabled]="disabled"
type="checkbox"
class="custom-control-input"
/>
<label [htmlFor]="prop.id" class="custom-control-label"
>{{ prop.displayName | abpLocalization }} {{ getAsterisk(prop, data) }}</label
>{{ prop.displayName | abpLocalization }} {{ asterisk }}</label
>
</div>
</ng-template>
<ng-template ngSwitchCase="select">
<label [htmlFor]="prop.id"
>{{ prop.displayName | abpLocalization }} {{ getAsterisk(prop, data) }}</label
>
<label [htmlFor]="prop.id">{{ prop.displayName | abpLocalization }} {{ asterisk }}</label>
<select
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="prop.disabled(data)"
[abpDisabled]="disabled"
class="custom-select form-control"
>
<option
*ngFor="let option of prop.options(data) | async; trackBy: track.by('value')"
*ngFor="let option of options$ | async; trackBy: track.by('value')"
[ngValue]="option.value"
>{{ option.key }}</option
>
@ -48,9 +44,7 @@
</ng-template>
<ng-template ngSwitchCase="date">
<label [htmlFor]="prop.id"
>{{ prop.displayName | abpLocalization }} {{ getAsterisk(prop, data) }}</label
>
<label [htmlFor]="prop.id">{{ prop.displayName | abpLocalization }} {{ asterisk }}</label>
<input
[id]="prop.id"
[formControlName]="prop.name"
@ -64,28 +58,22 @@
</ng-template>
<ng-template ngSwitchCase="time">
<label [htmlFor]="prop.id"
>{{ prop.displayName | abpLocalization }} {{ getAsterisk(prop, data) }}</label
>
<label [htmlFor]="prop.id">{{ prop.displayName | abpLocalization }} {{ asterisk }}</label>
<ngb-timepicker [formControlName]="prop.name"></ngb-timepicker>
</ng-template>
<ng-template ngSwitchCase="dateTime">
<label [htmlFor]="prop.id"
>{{ prop.displayName | abpLocalization }} {{ getAsterisk(prop, data) }}</label
>
<label [htmlFor]="prop.id">{{ prop.displayName | abpLocalization }} {{ asterisk }}</label>
<abp-date-time-picker [prop]="prop"></abp-date-time-picker>
</ng-template>
<ng-template ngSwitchCase="textarea">
<label [htmlFor]="prop.id"
>{{ prop.displayName | abpLocalization }} {{ getAsterisk(prop, data) }}</label
>
<label [htmlFor]="prop.id">{{ prop.displayName | abpLocalization }} {{ asterisk }}</label>
<textarea
[id]="prop.id"
[formControlName]="prop.name"
[abpDisabled]="prop.disabled(data)"
[readonly]="prop.readonly(data)"
[abpDisabled]="disabled"
[readonly]="readonly"
class="form-control"
></textarea>
</ng-template>

33
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form-prop.component.ts

@ -1,14 +1,17 @@
import { TrackByService } from '@abp/ng.core';
import { ABP, TrackByService } from '@abp/ng.core';
import {
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Input,
Optional,
SimpleChanges,
SkipSelf,
OnChanges,
} from '@angular/core';
import { ControlContainer, Validators } from '@angular/forms';
import { ControlContainer, Validators, ValidatorFn } from '@angular/forms';
import { NgbDateAdapter, NgbTimeAdapter } from '@ng-bootstrap/ng-bootstrap';
import { Observable, of } from 'rxjs';
import { DateAdapter } from '../../adapters/date.adapter';
import { TimeAdapter } from '../../adapters/time.adapter';
import { ePropType } from '../../enums/props.enum';
@ -30,15 +33,23 @@ import { selfFactory } from '../../utils/factory.util';
{ provide: NgbTimeAdapter, useClass: TimeAdapter },
],
})
export class ExtensibleFormPropComponent {
export class ExtensibleFormPropComponent implements OnChanges {
@Input() data: PropData;
@Input() prop: FormProp;
options$: Observable<ABP.Option<any>[]> = of([]);
validators: ValidatorFn[] = [];
readonly: boolean;
disabled: boolean;
constructor(public readonly cdRef: ChangeDetectorRef, public readonly track: TrackByService) {}
getAsterisk(prop: FormProp, data: PropData): string {
return prop.validators(data).some(validator => validator === Validators.required) ? '*' : '';
get asterisk(): string {
return this.validators.some(validator => validator === Validators.required) ? '*' : '';
}
getComponent(prop: FormProp): string {
@ -77,4 +88,16 @@ export class ExtensibleFormPropComponent {
return 'hidden';
}
}
ngOnChanges({ prop }: SimpleChanges) {
const options = prop.currentValue.options;
const readonly = prop.currentValue.readonly;
const disabled = prop.currentValue.disabled;
const validators = prop.currentValue.validators;
if (options) this.options$ = options(this.data);
if (readonly) this.readonly = readonly(this.data);
if (disabled) this.disabled = disabled(this.data);
if (validators) this.validators = validators(this.data);
}
}

20
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-form/extensible-form.component.ts

@ -1,20 +1,16 @@
import { TrackByService } from '@abp/ng.core';
import {
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
Inject,
Input,
OnDestroy,
Optional,
QueryList,
SkipSelf,
ViewChildren,
} from '@angular/core';
import { ControlContainer, FormGroup } from '@angular/forms';
import { Subscription } from 'rxjs';
import { debounceTime } from 'rxjs/operators';
import { EXTRA_PROPERTIES_KEY } from '../../constants/extra-properties';
import { FormPropList } from '../../models/form-props';
import { ExtensionsService } from '../../services/extensions.service';
@ -35,7 +31,7 @@ import { ExtensibleFormPropComponent } from './extensible-form-prop.component';
},
],
})
export class ExtensibleFormComponent<R = any> implements AfterViewInit, OnDestroy {
export class ExtensibleFormComponent<R = any> {
@ViewChildren(ExtensibleFormPropComponent)
formProps: QueryList<ExtensibleFormPropComponent>;
@ -46,7 +42,6 @@ export class ExtensibleFormComponent<R = any> implements AfterViewInit, OnDestro
this.record = record;
}
private subscription = new Subscription();
extraPropertiesKey = EXTRA_PROPERTIES_KEY;
propList: FormPropList<R>;
record: R;
@ -66,17 +61,4 @@ export class ExtensibleFormComponent<R = any> implements AfterViewInit, OnDestro
private extensions: ExtensionsService,
@Inject(EXTENSIONS_IDENTIFIER) private identifier: string,
) {}
ngAfterViewInit() {
this.subscription.add(
this.form.statusChanges.pipe(debounceTime(0)).subscribe(() => {
this.formProps.forEach(prop => prop.cdRef.markForCheck());
this.cdRef.detectChanges();
}),
);
}
ngOnDestroy() {
this.subscription.unsubscribe();
}
}

10
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.html

@ -27,11 +27,11 @@
[sortable]="prop.sortable"
>
<ng-template let-row="row" let-i="index" ngx-datatable-cell-template>
<ng-container
*abpPropData="let data; fromList: propList; withRecord: row; atIndex: i"
[abpPermission]="prop.permission"
>
<div *ngIf="prop.visible(data)" [innerHTML]="getContent(prop, data) | async"></div>
<ng-container [abpPermission]="prop.permission">
<div
*ngIf="row['_' + prop.name].visible"
[innerHTML]="row['_' + prop.name].value | async"
></div>
</ng-container>
</ng-template>
</ngx-datatable-column>

27
npm/ng-packs/packages/theme-shared/extensions/src/lib/components/extensible-table/extensible-table.component.ts

@ -9,6 +9,11 @@ import {
LOCALE_ID,
TemplateRef,
TrackByFunction,
Type,
InjectionToken,
InjectFlags,
SimpleChanges,
OnChanges,
} from '@angular/core';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@ -25,7 +30,7 @@ const DEFAULT_ACTIONS_COLUMN_WIDTH = 150;
templateUrl: './extensible-table.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ExtensibleTableComponent<R = any> {
export class ExtensibleTableComponent<R = any> implements OnChanges {
@Input() actionsText: string;
@Input() data: R[];
@Input() list: ListService;
@ -35,6 +40,8 @@ export class ExtensibleTableComponent<R = any> {
}
@Input() actionsTemplate: TemplateRef<any>;
getInjected: <T>(token: Type<T> | InjectionToken<T>, notFoundValue?: T, flags?: InjectFlags) => T;
readonly columnWidths: number[];
readonly propList: EntityPropList<R>;
@ -42,6 +49,8 @@ export class ExtensibleTableComponent<R = any> {
readonly trackByFn: TrackByFunction<EntityProp<R>> = (_, item) => item.name;
constructor(@Inject(LOCALE_ID) private locale: string, injector: Injector) {
// tslint:disable-next-line
this.getInjected = injector.get.bind(injector);
const extensions = injector.get(ExtensionsService);
const name = injector.get(EXTENSIONS_IDENTIFIER);
this.propList = extensions.entityProps.get(name).props;
@ -85,4 +94,20 @@ export class ExtensibleTableComponent<R = any> {
}),
);
}
ngOnChanges({ data }: SimpleChanges) {
if (!data?.currentValue) return;
this.data = data.currentValue.map((record, index) => {
this.propList.forEach(prop => {
const propData = { getInjected: this.getInjected, record, index } as any;
record[`_${prop.value.name}`] = {
visible: prop.value.visible(propData),
value: this.getContent(prop.value, propData),
};
});
return record;
});
}
}

2
npm/ng-packs/packages/theme-shared/package.json

@ -10,7 +10,7 @@
"@abp/ng.core": "~3.0.4",
"@fortawesome/fontawesome-free": "^5.13.1",
"@ng-bootstrap/ng-bootstrap": "^6.1.0",
"@ngx-validate/core": "^0.0.9",
"@ngx-validate/core": "^0.0.10",
"@swimlane/ngx-datatable": "^17.0.0",
"bootstrap": "^4.5.0",
"chart.js": "^2.9.3",

Loading…
Cancel
Save