Browse Source

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

pull/2816/head
liangshiw 7 years ago
parent
commit
ccbcc96eac
  1. 2
      README.md
  2. 2
      abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json
  3. 316
      docs/en/AspNet-Boilerplate-Migration-Guide.md
  4. 1
      docs/en/Repositories.md
  5. 4
      framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationAdder.cs
  6. 12
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css
  7. 2
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.min.css
  8. 12
      modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss
  9. 3
      npm/get-version.js
  10. 2
      npm/ng-packs/package.json
  11. 2
      npm/ng-packs/packages/account/src/lib/account.module.ts
  12. 2
      npm/ng-packs/packages/core/src/lib/actions/config.actions.ts
  13. 7
      npm/ng-packs/packages/core/src/lib/utils/route-utils.ts
  14. 2
      npm/ng-packs/packages/identity/src/lib/identity.module.ts
  15. 2
      npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts
  16. 7
      npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts
  17. 8
      npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts
  18. 4
      npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts
  19. 2
      npm/ng-packs/packages/theme-shared/src/lib/tests/confirmation.service.spec.ts
  20. 1
      npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts
  21. 5
      npm/ng-packs/packages/theme-shared/src/lib/tests/modal.component.spec.ts
  22. 6
      npm/ng-packs/packages/theme-shared/src/lib/tests/table-sort.directive.spec.ts
  23. 2
      npm/ng-packs/packages/theme-shared/src/lib/tests/toaster.service.spec.ts
  24. 5
      npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts
  25. 15
      npm/ng-packs/scripts/package-lock.json
  26. 3
      npm/ng-packs/scripts/package.json
  27. 27
      npm/ng-packs/scripts/publish.ts
  28. 20
      npm/ng-packs/scripts/yarn.lock
  29. 5
      npm/package.json
  30. 29
      npm/preview-publish.ps1
  31. 10
      npm/publish.ps1
  32. 7
      npm/yarn.lock
  33. 50
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/Data/MyProjectNameDbMigrationService.cs
  34. 24
      templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/EntityFrameworkCore/EntityFrameworkCoreMyProjectNameDbSchemaMigrator.cs

2
README.md

@ -3,7 +3,7 @@
[![Build Status](http://vjenkins.dynu.net:5480/job/abp/badge/icon)](http://ci.volosoft.com:5480/blue/organizations/jenkins/abp/activity) [![Build Status](http://vjenkins.dynu.net:5480/job/abp/badge/icon)](http://ci.volosoft.com:5480/blue/organizations/jenkins/abp/activity)
[![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) [![NuGet](https://img.shields.io/nuget/v/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core) [![NuGet Download](https://img.shields.io/nuget/dt/Volo.Abp.Core.svg?style=flat-square)](https://www.nuget.org/packages/Volo.Abp.Core)
[![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.Core.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds) [![MyGet (with prereleases)](https://img.shields.io/myget/abp-nightly/vpre/Volo.Abp.svg?style=flat-square)](https://docs.abp.io/en/abp/latest/Nightly-Builds)
This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://blog.abp.io/abp/Abp-vNext-Announcement). This project is the next generation of the [ASP.NET Boilerplate](https://aspnetboilerplate.com/) web application framework. See [the announcement](https://blog.abp.io/abp/Abp-vNext-Announcement).

2
abp_io/AbpIoLocalization/AbpIoLocalization/Commercial/Localization/Resources/en.json

@ -28,6 +28,6 @@
"UserNameNotFound": "There is no user with username {0}", "UserNameNotFound": "There is no user with username {0}",
"SuccessfullyAddedToNewsletter": "Thanks you for subscribing to our newsletter!", "SuccessfullyAddedToNewsletter": "Thanks you for subscribing to our newsletter!",
"ManageProfile": "Manage your profile", "ManageProfile": "Manage your profile",
"EmailNotValid": "Email address is not valid!" "EmailNotValid": "Please enter a valid email address."
} }
} }

316
docs/en/AspNet-Boilerplate-Migration-Guide.md

@ -0,0 +1,316 @@
# ASP.NET Boilerplate v5+ to ABP Framework Migration
ABP Framework is **the successor** of the open source [ASP.NET Boilerplate](https://aspnetboilerplate.com/) framework. This guide aims to help you to **migrate your existing solutions** (you developed with the ASP.NET Boilerplate framework) to the ABP Framework.
## Introduction
**ASP.NET Boilerplate** is being **actively developed** [since 2013](https://github.com/aspnetboilerplate/aspnetboilerplate/graphs/contributors). It is loved, used and contributed by the community. It started as a side project of [a developer](http://halilibrahimkalkan.com/), but now it is officially maintained and improved by the company [Volosoft](https://volosoft.com/) in addition to the great community support.
ABP Framework has the same goal of the ASP.NET Boilerplate framework: **Don't Repeat Yourself**! It provides infrastructure, tools and startup templates to make a developer's life easier while developing enterprise software solutions.
See [the introduction blog post](https://blog.abp.io/abp/Abp-vNext-Announcement) if you wonder why we needed to re-write the ASP.NET Boilerplate framework.
### Should I Migrate?
No, you don't have to!
* ASP.NET Boilerplate is still in active development and maintenance.
* It also works on the latest ASP.NET Core and related libraries and tools. It is up to date.
However, if you want to take the advantage of the new ABP Framework [features](https://abp.io/features) and the new architecture opportunities (like support for NoSQL databases, microservice compatibility, advanced modularity), you can use this document as a guide.
### What About the ASP.NET Zero?
[ASP.NET Zero](https://aspnetzero.com/) is a commercial product developed by the core ASP.NET Boilerplate team, on top of the ASP.NET Boilerplate framework. It provides pre-built application [features](https://aspnetzero.com/Features), code generation tooling and a nice looking modern UI. It is trusted and used by thousands of companies from all around the World.
We have created the [ABP Commercial](https://commercial.abp.io/) as an alternative to the ASP.NET Zero. ABP Commercial is more modular and upgradeable compared to the ASP.NET Zero. It currently has less features compared to ASP.NET Zero, but the gap will be closed by the time (it also has some features don't exist in the ASP.NET Zero).
We think ASP.NET Zero is still a good choice while starting a new application. It is production ready and mature solution delivered as a full source code. It is being actively developed and we are constantly adding new features.
We don't suggest to migrate your ASP.NET Zero based solution to the ABP Commercial if;
* Your ASP.NET Zero solution is mature and it is in maintenance rather than a rapid development.
* You don't have enough development time to perform the migration.
* A monolithic solution fits in your business.
* You've customized existing ASP.NET Zero features too much based on your requirements.
We also suggest you to compare the features of two products based on your needs.
If you have an ASP.NET Zero based solution and want to migrate to the ABP Commercial, this guide will also help you.
## The Migration Progress
We've designed the ABP Framework by **getting the best parts** of the ASP.NET Boilerplate framework, so it will be familiar to you if you've developed ASP.NET Boilerplate based applications.
In the ASP.NET Boilerplate, we have not worked much on the UI side, but used some free themes (we've used [metronic theme](https://keenthemes.com/metronic/) for ASP.NET Zero on the other side). In the ABP Framework, we worked a lot on the UI side (especially for the MVC / Razor Pages UI, because Angular already has a good modular system of its own). So, the **most challenging part** of the migration will be the **User Interface** of your solution.
ABP Framework is (and ASP.NET Boilerplate was) designed based on the [Domain Driven Design](https://docs.abp.io/en/abp/latest/Domain-Driven-Design) patterns & principles and the startup templates are layered based on the DDD layers. So, this guide respects to that layering model and explains the migration layer by layer.
## Creating the Solution
First step of the migration is to create a new solution. We suggest you to create a fresh new project using [the startup templates](https://abp.io/get-started) (see [this document](https://docs.abp.io/en/commercial/latest/getting-started) for the ABP Commercial).
After creating the project and running the application, you can copy your code from your existing solution to the new solution step by step, layer by layer.
### About Pre-Built Modules
The startup projects for the ABP Framework use the [pre-built modules](https://docs.abp.io/en/abp/latest/Modules/Index) (not all of them, but the essentials) and themes as NuGet/NPM packages. So, you don't see the source code of the modules/themes in your solution. This has an advantage that you can easily update these packages when a new version is released. However, you can not easily customize them as their source code in your hands.
We suggest to continue to use these modules as package references, in this way you can get new features easily (see [abp update command](https://docs.abp.io/en/abp/latest/CLI#update)). In this case, you have a few options to customize or extend the functionality of the used modules;
* You can create your own entity and share the same database table with an entity in a used module. An example of this is the `AppUser` entity comes in the startup template.
* You can [replace](https://docs.abp.io/en/abp/latest/Dependency-Injection#replace-a-service) a domain service, application service, controller, page model or other types of services with your own implementation. We suggest you to inherit from the existing implementation and override the method you need.
* You can replace a `.cshtml` view, page, view component, partial view... with your own one using the [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System).
* You can override javascript, css, image or any other type of static files using the [Virtual File System](https://docs.abp.io/en/abp/latest/Virtual-File-System).
More extend/customization options will be developed and documented by the time. However, if you need to fully change the module implementation, it is best to add the [source code](https://github.com/abpframework/abp/tree/dev/modules) of the related module into your own solution and remove the package dependencies.
The source code of the modules and the themes are [MIT](https://opensource.org/licenses/MIT) licensed, you can fully own and customize it without any limitation (for the ABP Commercial, you can download the source code of a [module](https://commercial.abp.io/modules)/[theme](https://commercial.abp.io/themes) if you have a [license](https://commercial.abp.io/pricing) type that includes the source code).
## The Domain Layer
Most of your domain layer code will remain same, while you need to perform some minor changes in your domain objects.
### Aggregate Roots & Entities
The ABP Framework and the ASP.NET Boilerplate both have the `IEntity` and `IEntity<T>` interfaces and `Entity` and `Entity<T>` base classes to define entities but they have some differences.
If you have an entity in the ASP.NET Boilerplate application like that:
````csharp
public class Person : Entity //Default PK is int for the ASP.NET Boilerplate
{
...
}
````
Then your primary key (the `Id` property in the base class) is `int` which is the **default primary key** (PK) type for the ASP.NET Boilerplate. If you want to set another type of PK, you need to explicitly declare it:
````csharp
public class Person : Entity<Guid> //Set explicit PK in the ASP.NET Boilerplate
{
...
}
````
ABP Framework behaves differently and expects to **always explicitly set** the PK type:
````csharp
public class Person : Entity<Guid> //Set explicit PK in the ASP.NET Boilerplate
{
...
}
````
`Id` property (and the corresponding PK in the database) will be `Guid` in this case.
#### Composite Primary Keys
ABP Framework also has a non-generic `Entity` base class, but this time it has no `Id` property. Its purpose is to allow you to create entities with composite PKs. See [the documentation](https://docs.abp.io/en/abp/latest/Entities#entities-with-composite-keys) to learn more about the composite PKs.
#### Aggregate Root
It is best practice now to use the `AggregateRoot` base class instead of `Entity` for aggregate root entities. See [the documentation](https://docs.abp.io/en/abp/latest/Entities#aggregateroot-class) to learn more about the aggregate roots.
In opposite to the ASP.NET Boilerplate, the ABP Framework creates default repositories (`IRepository<T>`) **only for the aggregate roots**. It doesn't create for other types derived from the `Entity`.
If you still want to create default repositories for all entity types, find the *YourProjectName*EntityFrameworkCoreModule class in your solution and change `options.AddDefaultRepositories()` to `options.AddDefaultRepositories(includeAllEntities: true)` (it may be already like that for the application startup template).
#### Migrating the Existing Entities
We suggest & use the GUID as the PK type for all the ABP Framework modules. However, you can continue to use your existing PK types to migrate your database tables easier.
The challenging part will be the primary keys of the ASP.NET Boilerplate related entities, like Users, Roles, Tenants, Settings... etc. Our suggestion is to copy data from existing database to the new database tables using a tool or in a manual way (be careful about the foreign key values).
#### Documentation
See the documentation for details on the entities:
* [ASP.NET Boilerplate - Entity documentation](https://aspnetboilerplate.com/Pages/Documents/Entities)
* [ABP Framework - Entity documentation](https://docs.abp.io/en/abp/latest/Entities)
### Repositories
> ABP Framework creates default repositories (`IRepository<T>`) **only for the aggregate roots**. It doesn't create for other types derived from the `Entity`. See the "Aggregate Root" section above for more information.
The ABP Framework and the ASP.NET Boilerplate both have the default generic repository system, but has some differences.
#### Injecting the Repositories
In the ASP.NET Boilerplate, there are two default repository interfaces you can directly inject and use:
* `IRepository<TEntity>` (e.g. `IRepository<Person>`) is used for entities with `int` primary key (PK) which is the default PK type.
* `IRepository<TEntity, TKey>` (e.g. `IRepository<Person, Guid>`) is used for entities with other types of PKs.
ABP Framework doesn't have a default PK type, so you need to **explicitly declare the PK type** of your entity, like `IRepository<Person, int>` or `IRepository<Person, Guid>`.
ABP Framework also has the `IRepository<TEntity>` (without PK), but it is mostly used when your entity has a composite PK (because this repository has no methods work with the `Id` property). See [the documentation](https://docs.abp.io/en/abp/latest/Entities#entities-with-composite-keys) to learn more about the **composite PKs**.
#### Restricted Repositories
ABP Framework additionally provides a few repository interfaces:
* `IBasicRepository<TEntity, TKey>` has the same methods with the `IRepository` except it doesn't have `IQueryable` support. It can be useful if you don't want to expose complex querying code to the application layer. In this case, you typically want to create custom repositories to encapsulate the querying logic. It is also useful for database providers those don't support `IQueryable`.
* `IReadOnlyRepository<TEntity,TKey>` has the methods get data from the database, but doesn't contain any method change the database.
* `IReadOnlyBasicRepository<TEntity, TKey>` is similar to the read only repository but also doesn't support `IQueryable`.
All the interfaces also have versions without `TKey` (like ``IReadOnlyRepository<TEntity>`) those can be used for composite PKs just like explained above.
#### GetAll() vs IQueryable
ASP.NET Boilerplate's repository has a `GetAll()` method that is used to obtain an `IQueryable` object to execute LINQ on it. An example application service calls the `GetAll()` method:
````csharp
public class PersonAppService : ApplicationService, IPersonAppService
{
private readonly IRepository<Person, Guid> _personRepository;
public PersonAppService(IRepository<Person, Guid> personRepository)
{
_personRepository = personRepository;
}
public async Task DoIt()
{
var people = await _personRepository
.GetAll() //GetAll() returns IQueryable
.Where(p => p.BirthYear > 2000) //Use LINQ extension methods
.ToListAsync();
}
}
````
ABP Framework's repository doesn't have this method. Instead, it implements the `IQueryable` itself. So, you can directly use LINQ on the repository:
````csharp
public class PersonAppService : ApplicationService, IPersonAppService
{
private readonly IRepository<Person, Guid> _personRepository;
public PersonAppService(IRepository<Person, Guid> personRepository)
{
_personRepository = personRepository;
}
public async Task DoIt()
{
var people = await _personRepository
.Where(p => p.BirthYear > 2000) //Use LINQ extension methods
.ToListAsync();
}
}
````
> Note that in order to use the async LINQ extension methods (like `ToListAsync` here), you may need to depend on the database provider (like EF Core) since these methods are defined in the database provider package, they are not standard LINQ methods.
#### FirstOrDefault(predicate), Single()... Methods
ABP Framework repository has not such methods get predicate (expression) since the repository itself is `IQueryable` and all these methods are already standard LINQ extension methods those can be directly used.
However, it provides the following methods those can be used to query a single entity by its Id:
* `FindAsync(id)` returns the entity or null if not found.
* `GetAsync(id)` method returns the entity or throws an `EntityNotFoundException` (which causes HTTP 404 status code) if not found.
#### Sync vs Async
ABP Framework repository has no sync methods (like `Insert`). All the methods are async (like `InsertAsync`). So, if your application has sync repository method usages, convert them to async versions.
In general, ABP Framework forces you to completely use async everywhere, because mixing async & sync methods is not a recommended approach.
#### Documentation
See the documentation for details on the repositories:
* [ASP.NET Boilerplate - Repository documentation](https://aspnetboilerplate.com/Pages/Documents/Repositories)
* [ABP Framework - Repository documentation](https://docs.abp.io/en/abp/latest/Repositories)
### Domain Services
Your domain service logic mostly remains same on the migration. ABP Framework also defines the base `DomainService` class and the `IDomainService` interface just works like the ASP.NET Boilerplate.
## The Application Layer
Your application service logic remains similar on the migration. ABP Framework also defines the base `ApplicationService` class and the `IApplicationService` interface just works like the ASP.NET Boilerplate, but there are some differences in details.
### Declarative Authorization
ASP.NET Boilerplate has `AbpAuthorize` and `AbpMvcAuthorize` attributes for declarative authorization. Example usage:
````csharp
[AbpAuthorize("MyUserDeletionPermissionName")]
public async Task DeleteUserAsync(...)
{
...
}
````
ABP Framework doesn't has such a custom attribute. It uses the standard `Authorize` attribute in all layers.
````csharp
[Authorize("MyUserDeletionPermissionName")]
public async Task DeleteUserAsync(...)
{
...
}
````
This is possible with the better integration to the Microsoft Authorization Extensions libraries. See the Authorization section below for more information about the authorization system.
### CrudAppService and AsyncCrudAppService Classes
ASP.NET Boilerplate has `CrudAppService` (with sync service methods) and `AsyncCrudAppService` (with async service methods) classes.
ABP Framework only has the `CrudAppService` which actually has only the async methods (instead of sync methods).
ABP Framework's `CrudAppService` method signatures are slightly different than the old one. For example, old update method signature was ` Task<TEntityDto> UpdateAsync(TUpdateInput input) ` while the new one is ` Task<TGetOutputDto> UpdateAsync(TKey id, TUpdateInput input) `. The main difference is that it gets the Id of the updating entity as a separate parameter instead of including in the input DTO.
### Data Transfer Objects (DTOs)
There are similar base DTO classes (like `EntityDto`) in the ABP Framework too. So, you can find the corresponding DTO base class if you need.
#### Validation
You can continue to use the data annotation attributes to validate your DTOs just like in the ASP.NET Boilerplate.
ABP Framework doesn't include the ` ICustomValidate ` that does exists in the ASP.NET Boilerplate. Instead, you should implement the standard `IValidatableObject` interface for your custom validation logic.
## The Infrastructure Layer
### IAbpSession vs ICurrentUser and ICurrentTenant
ASP.NET Boilerplate's `IAbpSession` service is used to obtain the current user and tenant information, like ` UserId ` and `TenantId`.
ABP Framework doesn't have the same service. Instead, use `ICurrentUser` and `ICurrentTenant` services. These services are defined as base properties in some common classes (like `ApplicationService` and `AbpController`), so you generally don't need to manually inject them. They also have much properties compared to the `IAbpSession`.
### Authorization
ABP Framework extends the [ASP.NET Core Authorization](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/introduction) by adding **permissions** as auto [policies](https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies) and allowing the authorization system to be usable in the [application services](Application-Services.md) too.
#### AbpAutorize vs Autorize
Use the standard `[Autorize]` and `[AllowAnonymous]` attributes instead of ASP.NET Boilerplate's custom `[AbpAutorize]` and `[AbpAllowAnonymous]` attributes.
#### IPermissionChecker vs IAuthorizationService
Use the standard `IAuthorizationService` to check permissions instead of the ASP.NET Boilerplate's `IPermissionChecker` service. While `IPermissionChecker` also exists in the ABP Framework, it is used to explicitly use the permissions. Using `IAuthorizationService` is the recommended way since it covers other type of policy checks too.
#### AuthorizationProvider vs PermissionDefinitionProvider
You inherit from the `AuthorizationProvider` in the ASP.NET Boilerplate to define your permissions. ABP Framework replaces it by the `PermissionDefinitionProvider` base class. So, define your permissions by inheriting from the `PermissionDefinitionProvider` class.
### Unit of Work
TODO
### Multi-Tenancy
TODO
## Missing Features
The following features are not present for the ABP Framework. Here, a list of major missing features (and the related issue for that feature waiting on the ABP Framework GitHub repository):
* [Multi-Lingual Entities](https://aspnetboilerplate.com/Pages/Documents/Multi-Lingual-Entities) ([#1754](https://github.com/abpframework/abp/issues/1754))
Most of these features will eventually be implemented. However, you can implement them yourself if they are important for you. If you want, you can [contribute](Contribution/Index.md) to the framework by implementing these yourself.

1
docs/en/Repositories.md

@ -52,7 +52,6 @@ Generic Repositories provides some standard CRUD features out of the box:
* Provides `Update` and `Delete` methods to update or delete an entity by entity object or it's id. * Provides `Update` and `Delete` methods to update or delete an entity by entity object or it's id.
* Provides `Delete` method to delete multiple entities by a filter. * Provides `Delete` method to delete multiple entities by a filter.
* Implements `IQueryable<TEntity>`, so you can use LINQ and extension methods like `FirstOrDefault`, `Where`, `OrderBy`, `ToList` and so on... * Implements `IQueryable<TEntity>`, so you can use LINQ and extension methods like `FirstOrDefault`, `Where`, `OrderBy`, `ToList` and so on...
* Have **sync** and **async** versions for all methods.
### Basic Repositories ### Basic Repositories

4
framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectModification/EfCoreMigrationAdder.cs

@ -12,7 +12,7 @@ namespace Volo.Abp.Cli.ProjectModification
var moduleName = ParseModuleName(module); var moduleName = ParseModuleName(module);
var migrationName = "Added_" + moduleName + "_Module" + GetUniquePostFix(); var migrationName = "Added_" + moduleName + "_Module" + GetUniquePostFix();
CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(csprojFile) + "\" & dotnet ef migrations add " + migrationName + GetStartupProjectOption(startupProject)); CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(csprojFile) + "\" && dotnet ef migrations add " + migrationName + GetStartupProjectOption(startupProject));
if (updateDatabase) if (updateDatabase)
{ {
@ -22,7 +22,7 @@ namespace Volo.Abp.Cli.ProjectModification
protected void UpdateDatabase(string csprojFile, string startupProject) protected void UpdateDatabase(string csprojFile, string startupProject)
{ {
CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(csprojFile) + "\" & dotnet ef database update" + GetStartupProjectOption(startupProject)); CmdHelper.RunCmd("cd \"" + Path.GetDirectoryName(csprojFile) + "\" && dotnet ef database update" + GetStartupProjectOption(startupProject));
} }
protected virtual string ParseModuleName(string fullModuleName) protected virtual string ParseModuleName(string fullModuleName)

12
modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.css

@ -137,17 +137,17 @@
.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand strong { .docs-page .docs-sidebar .docs-top .navbar-logo .navbar-brand strong {
font-weight: 300; font-weight: 300;
text-transform: uppercase; text-transform: uppercase;
font-size: .9rem; font-size: .7em;
opacity: .6; } letter-spacing: 1px; }
.docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site { .docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site {
color: #000; color: #000;
opacity: .15; opacity: .65;
transition: .4s; transition: .2s;
font-size: .75rem; font-size: .8em;
font-weight: 300; } font-weight: 300; }
.docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site:hover { .docs-page .docs-sidebar .docs-top .navbar-logo .go-back-site:hover {
text-decoration: none; text-decoration: none;
opacity: .5; } opacity: 1; }
.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc { .docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc {
font-size: .85em; } font-size: .85em; }
.docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc strong { .docs-page .docs-sidebar .docs-top .navbar-logo .navbar-logo-desc strong {

2
modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.min.css

File diff suppressed because one or more lines are too long

12
modules/docs/src/Volo.Docs.Web/Pages/Documents/Shared/Styles/vs.scss

@ -233,21 +233,21 @@ body {
strong { strong {
font-weight: 300; font-weight: 300;
text-transform: uppercase; text-transform: uppercase;
font-size: .9rem; font-size: .7em;
opacity: .6; letter-spacing: 1px;
} }
} }
.go-back-site { .go-back-site {
color: #000; color: #000;
opacity: .15; opacity: .65;
transition: .4s; transition: .2s;
font-size: .75rem; font-size: .8em;
font-weight: 300; font-weight: 300;
&:hover { &:hover {
text-decoration: none; text-decoration: none;
opacity: .5; opacity: 1;
} }
} }

3
npm/get-version.js

@ -0,0 +1,3 @@
const fse = require("fs-extra");
console.log(fse.readJSONSync("package.json").version);

2
npm/ng-packs/package.json

@ -82,7 +82,7 @@
"protractor": "~5.4.0", "protractor": "~5.4.0",
"rxjs": "~6.4.0", "rxjs": "~6.4.0",
"snq": "^1.0.3", "snq": "^1.0.3",
"symlink-manager": "^1.4.1", "symlink-manager": "^1.4.2",
"ts-node": "~7.0.0", "ts-node": "~7.0.0",
"tsickle": "^0.37.0", "tsickle": "^0.37.0",
"tslint": "~5.20.0", "tslint": "~5.20.0",

2
npm/ng-packs/packages/account/src/lib/account.module.ts

@ -3,7 +3,6 @@ import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { NgModule, Provider } from '@angular/core'; import { NgModule, Provider } from '@angular/core';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core'; import { NgxValidateCoreModule } from '@ngx-validate/core';
import { TableModule } from 'primeng/table';
import { AccountRoutingModule } from './account-routing.module'; import { AccountRoutingModule } from './account-routing.module';
import { ChangePasswordComponent } from './components/change-password/change-password.component'; import { ChangePasswordComponent } from './components/change-password/change-password.component';
import { LoginComponent } from './components/login/login.component'; import { LoginComponent } from './components/login/login.component';
@ -29,7 +28,6 @@ import { AuthWrapperComponent } from './components/auth-wrapper/auth-wrapper.com
CoreModule, CoreModule,
AccountRoutingModule, AccountRoutingModule,
ThemeSharedModule, ThemeSharedModule,
TableModule,
NgbDropdownModule, NgbDropdownModule,
NgxValidateCoreModule, NgxValidateCoreModule,
], ],

2
npm/ng-packs/packages/core/src/lib/actions/config.actions.ts

@ -1,4 +1,4 @@
import { ABP } from '../models'; import { ABP } from '../models/common';
export class PatchRouteByName { export class PatchRouteByName {
static readonly type = '[Config] Patch Route By Name'; static readonly type = '[Config] Patch Route By Name';

7
npm/ng-packs/packages/core/src/lib/utils/route-utils.ts

@ -1,4 +1,4 @@
import { ABP } from '../models'; import { ABP } from '../models/common';
export function organizeRoutes( export function organizeRoutes(
routes: ABP.FullRoute[], routes: ABP.FullRoute[],
@ -33,7 +33,10 @@ export function organizeRoutes(
return filteredRoutes; return filteredRoutes;
} }
export function setChildRoute(routes: ABP.FullRoute[], parentNameArr: ABP.FullRoute[]): ABP.FullRoute[] { export function setChildRoute(
routes: ABP.FullRoute[],
parentNameArr: ABP.FullRoute[],
): ABP.FullRoute[] {
return routes.map(route => { return routes.map(route => {
if (route.children && route.children.length) { if (route.children && route.children.length) {
route.children = setChildRoute(route.children, parentNameArr); route.children = setChildRoute(route.children, parentNameArr);

2
npm/ng-packs/packages/identity/src/lib/identity.module.ts

@ -8,7 +8,6 @@ import { NgbTabsetModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { ThemeSharedModule } from '@abp/ng.theme.shared'; import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { UsersComponent } from './components/users/users.component'; import { UsersComponent } from './components/users/users.component';
import { PermissionManagementModule } from '@abp/ng.permission-management'; import { PermissionManagementModule } from '@abp/ng.permission-management';
import { TableModule } from 'primeng/table';
import { NgxValidateCoreModule } from '@ngx-validate/core'; import { NgxValidateCoreModule } from '@ngx-validate/core';
@NgModule({ @NgModule({
@ -19,7 +18,6 @@ import { NgxValidateCoreModule } from '@ngx-validate/core';
IdentityRoutingModule, IdentityRoutingModule,
NgbTabsetModule, NgbTabsetModule,
ThemeSharedModule, ThemeSharedModule,
TableModule,
NgbDropdownModule, NgbDropdownModule,
PermissionManagementModule, PermissionManagementModule,
NgxValidateCoreModule, NgxValidateCoreModule,

2
npm/ng-packs/packages/tenant-management/src/lib/tenant-management.module.ts

@ -3,7 +3,6 @@ import { ThemeSharedModule } from '@abp/ng.theme.shared';
import { NgModule, Provider } from '@angular/core'; import { NgModule, Provider } from '@angular/core';
import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxsModule } from '@ngxs/store'; import { NgxsModule } from '@ngxs/store';
import { TableModule } from 'primeng/table';
import { TenantsComponent } from './components/tenants/tenants.component'; import { TenantsComponent } from './components/tenants/tenants.component';
import { TenantManagementState } from './states/tenant-management.state'; import { TenantManagementState } from './states/tenant-management.state';
import { TenantManagementRoutingModule } from './tenant-management-routing.module'; import { TenantManagementRoutingModule } from './tenant-management-routing.module';
@ -17,7 +16,6 @@ import { NgxValidateCoreModule } from '@ngx-validate/core';
NgxsModule.forFeature([TenantManagementState]), NgxsModule.forFeature([TenantManagementState]),
NgxValidateCoreModule, NgxValidateCoreModule,
CoreModule, CoreModule,
TableModule,
ThemeSharedModule, ThemeSharedModule,
NgbDropdownModule, NgbDropdownModule,
FeatureManagementModule, FeatureManagementModule,

7
npm/ng-packs/packages/theme-basic/src/lib/components/application-layout/application-layout.component.ts

@ -1,10 +1,10 @@
import { import {
ABP, ABP,
ApplicationConfiguration, ApplicationConfiguration,
AuthService,
Config, Config,
ConfigState, ConfigState,
eLayoutType, eLayoutType,
GetAppConfiguration,
SessionState, SessionState,
SetLanguage, SetLanguage,
takeUntilDestroy, takeUntilDestroy,
@ -14,15 +14,11 @@ import {
AfterViewInit, AfterViewInit,
Component, Component,
OnDestroy, OnDestroy,
QueryList,
Renderer2, Renderer2,
TemplateRef, TemplateRef,
TrackByFunction, TrackByFunction,
ViewChild, ViewChild,
ViewChildren,
ElementRef,
} from '@angular/core'; } from '@angular/core';
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
import { Navigate, RouterState } from '@ngxs/router-plugin'; import { Navigate, RouterState } from '@ngxs/router-plugin';
import { Select, Store } from '@ngxs/store'; import { Select, Store } from '@ngxs/store';
import compare from 'just-compare'; import compare from 'just-compare';
@ -32,7 +28,6 @@ import snq from 'snq';
import { AddNavigationElement } from '../../actions'; import { AddNavigationElement } from '../../actions';
import { Layout } from '../../models/layout'; import { Layout } from '../../models/layout';
import { LayoutState } from '../../states'; import { LayoutState } from '../../states';
import { AuthService } from 'packages/core/src/lib/services/auth.service';
@Component({ @Component({
selector: 'abp-layout-application', selector: 'abp-layout-application',

8
npm/ng-packs/packages/theme-basic/src/lib/theme-basic.module.ts

@ -4,7 +4,6 @@ import { NgModule } from '@angular/core';
import { NgbCollapseModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; import { NgbCollapseModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core'; import { NgxValidateCoreModule } from '@ngx-validate/core';
import { NgxsModule } from '@ngxs/store'; import { NgxsModule } from '@ngxs/store';
import { ToastModule } from 'primeng/toast';
import { AccountLayoutComponent } from './components/account-layout/account-layout.component'; import { AccountLayoutComponent } from './components/account-layout/account-layout.component';
import { ApplicationLayoutComponent } from './components/application-layout/application-layout.component'; import { ApplicationLayoutComponent } from './components/application-layout/application-layout.component';
import { EmptyLayoutComponent } from './components/empty-layout/empty-layout.component'; import { EmptyLayoutComponent } from './components/empty-layout/empty-layout.component';
@ -21,7 +20,6 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
ThemeSharedModule, ThemeSharedModule,
NgbCollapseModule, NgbCollapseModule,
NgbDropdownModule, NgbDropdownModule,
ToastModule,
NgxValidateCoreModule, NgxValidateCoreModule,
NgxsModule.forFeature([LayoutState]), NgxsModule.forFeature([LayoutState]),
NgxValidateCoreModule.forRoot({ NgxValidateCoreModule.forRoot({
@ -29,9 +27,11 @@ export const LAYOUTS = [ApplicationLayoutComponent, AccountLayoutComponent, Empt
blueprints: { blueprints: {
email: 'AbpAccount::ThisFieldIsNotAValidEmailAddress.', email: 'AbpAccount::ThisFieldIsNotAValidEmailAddress.',
max: 'AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]', max: 'AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
maxlength: 'AbpAccount::ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthoOf{0}[{{ requiredLength }}]', maxlength:
'AbpAccount::ThisFieldMustBeAStringOrArrayTypeWithAMaximumLengthoOf{0}[{{ requiredLength }}]',
min: 'AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]', min: 'AbpAccount::ThisFieldMustBeBetween{0}And{1}[{{ min }},{{ max }}]',
minlength: 'AbpAccount::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}[{{ requiredLength }}]', minlength:
'AbpAccount::ThisFieldMustBeAStringOrArrayTypeWithAMinimumLengthOf{0}[{{ requiredLength }}]',
required: 'AbpAccount::ThisFieldIsRequired.', required: 'AbpAccount::ThisFieldIsRequired.',
passwordMismatch: 'AbpIdentity::Identity.PasswordConfirmationFailed', passwordMismatch: 'AbpIdentity::Identity.PasswordConfirmationFailed',
}, },

4
npm/ng-packs/packages/theme-shared/src/lib/handlers/error.handler.ts

@ -190,8 +190,8 @@ export class ErrorHandler {
if (body.details) { if (body.details) {
message = body.details; message = body.details;
title = body.message; title = body.message;
} else if (body.code) { } else if (body.message) {
title = body.code; title = DEFAULT_ERROR_MESSAGES.defaultError.title;
message = body.message; message = body.message;
} else { } else {
message = body.message || DEFAULT_ERROR_MESSAGES.defaultError.title; message = body.message || DEFAULT_ERROR_MESSAGES.defaultError.title;

2
npm/ng-packs/packages/theme-shared/src/lib/tests/confirmation.service.spec.ts

@ -3,7 +3,6 @@ import { Component } from '@angular/core';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { NgxsModule } from '@ngxs/store'; import { NgxsModule } from '@ngxs/store';
import { MessageService } from 'primeng/components/common/messageservice';
import { ConfirmationService } from '../services/confirmation.service'; import { ConfirmationService } from '../services/confirmation.service';
import { ThemeSharedModule } from '../theme-shared.module'; import { ThemeSharedModule } from '../theme-shared.module';
import { OAuthModule, OAuthService } from 'angular-oauth2-oidc'; import { OAuthModule, OAuthService } from 'angular-oauth2-oidc';
@ -24,7 +23,6 @@ describe('ConfirmationService', () => {
const createComponent = createComponentFactory({ const createComponent = createComponentFactory({
component: DummyComponent, component: DummyComponent,
imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot(), RouterTestingModule], imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot(), RouterTestingModule],
providers: [MessageService],
mocks: [OAuthService], mocks: [OAuthService],
}); });

1
npm/ng-packs/packages/theme-shared/src/lib/tests/error.handler.spec.ts

@ -6,7 +6,6 @@ import { createRoutingFactory, SpectatorRouting } from '@ngneat/spectator/jest';
import { NgxsModule, Store } from '@ngxs/store'; import { NgxsModule, Store } from '@ngxs/store';
import { DEFAULT_ERROR_MESSAGES, ErrorHandler } from '../handlers'; import { DEFAULT_ERROR_MESSAGES, ErrorHandler } from '../handlers';
import { ThemeSharedModule } from '../theme-shared.module'; import { ThemeSharedModule } from '../theme-shared.module';
import { MessageService } from 'primeng/components/common/messageservice';
import { RouterError, RouterDataResolved } from '@ngxs/router-plugin'; import { RouterError, RouterDataResolved } from '@ngxs/router-plugin';
import { NavigationError, ResolveEnd } from '@angular/router'; import { NavigationError, ResolveEnd } from '@angular/router';
import { OAuthModule, OAuthService } from 'angular-oauth2-oidc'; import { OAuthModule, OAuthService } from 'angular-oauth2-oidc';

5
npm/ng-packs/packages/theme-shared/src/lib/tests/modal.component.spec.ts

@ -1,8 +1,6 @@
import { LocalizationPipe } from '@abp/ng.core'; import { LocalizationPipe } from '@abp/ng.core';
import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest'; import { createHostFactory, SpectatorHost } from '@ngneat/spectator/jest';
import { Store } from '@ngxs/store'; import { Store } from '@ngxs/store';
import { MessageService } from 'primeng/components/common/messageservice';
import { ToastModule } from 'primeng/toast';
import { timer } from 'rxjs'; import { timer } from 'rxjs';
import { ButtonComponent, ConfirmationComponent, ModalComponent } from '../components'; import { ButtonComponent, ConfirmationComponent, ModalComponent } from '../components';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
@ -16,9 +14,8 @@ describe('ModalComponent', () => {
let disappearFn; let disappearFn;
const createHost = createHostFactory({ const createHost = createHostFactory({
component: ModalComponent, component: ModalComponent,
imports: [ToastModule, RouterTestingModule], imports: [RouterTestingModule],
declarations: [ConfirmationComponent, LocalizationPipe, ButtonComponent], declarations: [ConfirmationComponent, LocalizationPipe, ButtonComponent],
providers: [MessageService],
mocks: [Store], mocks: [Store],
}); });

6
npm/ng-packs/packages/theme-shared/src/lib/tests/table-sort.directive.spec.ts

@ -1,5 +1,4 @@
import { SpectatorDirective, createDirectiveFactory } from '@ngneat/spectator/jest'; import { SpectatorDirective, createDirectiveFactory } from '@ngneat/spectator/jest';
import { TableModule, Table } from 'primeng/table';
import { TableSortDirective } from '../directives/table-sort.directive'; import { TableSortDirective } from '../directives/table-sort.directive';
describe('TableSortDirective', () => { describe('TableSortDirective', () => {
@ -7,11 +6,12 @@ describe('TableSortDirective', () => {
let directive: TableSortDirective; let directive: TableSortDirective;
const createDirective = createDirectiveFactory({ const createDirective = createDirectiveFactory({
directive: TableSortDirective, directive: TableSortDirective,
imports: [TableModule],
}); });
beforeEach(() => { beforeEach(() => {
spectator = createDirective(`<p-table [value]="[1,4,2]" [abpTableSort]="{ order: 'asc' }"></p-table>`); spectator = createDirective(
`<p-table [value]="[1,4,2]" [abpTableSort]="{ order: 'asc' }"></p-table>`,
);
directive = spectator.directive; directive = spectator.directive;
}); });

2
npm/ng-packs/packages/theme-shared/src/lib/tests/toaster.service.spec.ts

@ -3,7 +3,6 @@ import { Component } from '@angular/core';
import { RouterTestingModule } from '@angular/router/testing'; import { RouterTestingModule } from '@angular/router/testing';
import { createComponentFactory, Spectator } from '@ngneat/spectator/jest'; import { createComponentFactory, Spectator } from '@ngneat/spectator/jest';
import { NgxsModule } from '@ngxs/store'; import { NgxsModule } from '@ngxs/store';
import { MessageService } from 'primeng/components/common/messageservice';
import { ToasterService } from '../services/toaster.service'; import { ToasterService } from '../services/toaster.service';
import { ThemeSharedModule } from '../theme-shared.module'; import { ThemeSharedModule } from '../theme-shared.module';
import { OAuthService } from 'angular-oauth2-oidc'; import { OAuthService } from 'angular-oauth2-oidc';
@ -24,7 +23,6 @@ describe('ToasterService', () => {
const createComponent = createComponentFactory({ const createComponent = createComponentFactory({
component: DummyComponent, component: DummyComponent,
imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot(), RouterTestingModule], imports: [CoreModule, ThemeSharedModule.forRoot(), NgxsModule.forRoot(), RouterTestingModule],
providers: [MessageService],
mocks: [OAuthService], mocks: [OAuthService],
}); });

5
npm/ng-packs/packages/theme-shared/src/lib/theme-shared.module.ts

@ -3,8 +3,6 @@ import { DatePipe } from '@angular/common';
import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core'; import { APP_INITIALIZER, Injector, ModuleWithProviders, NgModule } from '@angular/core';
import { NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap'; import { NgbDateParserFormatter } from '@ng-bootstrap/ng-bootstrap';
import { NgxValidateCoreModule } from '@ngx-validate/core'; import { NgxValidateCoreModule } from '@ngx-validate/core';
import { MessageService } from 'primeng/components/common/messageservice';
import { ToastModule } from 'primeng/toast';
import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component'; import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';
import { ButtonComponent } from './components/button/button.component'; import { ButtonComponent } from './components/button/button.component';
import { ChartComponent } from './components/chart/chart.component'; import { ChartComponent } from './components/chart/chart.component';
@ -40,7 +38,7 @@ export function appendScript(injector: Injector) {
} }
@NgModule({ @NgModule({
imports: [CoreModule, ToastModule, NgxValidateCoreModule], imports: [CoreModule, NgxValidateCoreModule],
declarations: [ declarations: [
BreadcrumbComponent, BreadcrumbComponent,
ButtonComponent, ButtonComponent,
@ -92,7 +90,6 @@ export class ThemeSharedModule {
deps: [Injector], deps: [Injector],
useFactory: appendScript, useFactory: appendScript,
}, },
{ provide: MessageService, useClass: MessageService },
{ provide: HTTP_ERROR_CONFIG, useValue: options.httpErrorConfig }, { provide: HTTP_ERROR_CONFIG, useValue: options.httpErrorConfig },
{ {
provide: 'HTTP_ERROR_CONFIG', provide: 'HTTP_ERROR_CONFIG',

15
npm/ng-packs/scripts/package-lock.json

@ -4,6 +4,15 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"@types/fs-extra": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.1.tgz",
"integrity": "sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/json5": { "@types/json5": {
"version": "0.0.29", "version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@ -463,9 +472,9 @@
} }
}, },
"commander": { "commander": {
"version": "4.0.1", "version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.0.1.tgz", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-IPF4ouhCP+qdlcmCedhxX4xiGBPyigb8v5NeUp+0LyhwLgxMqyp3S0vl7TAPfS/hiP7FC3caI/PB9lTmP8r1NA==" "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA=="
}, },
"component-emitter": { "component-emitter": {
"version": "1.3.0", "version": "1.3.0",

3
npm/ng-packs/scripts/package.json

@ -13,12 +13,13 @@
"author": "", "author": "",
"dependencies": { "dependencies": {
"babel-preset-node6": "^11.0.0", "babel-preset-node6": "^11.0.0",
"commander": "^4.0.1", "commander": "^4.1.1",
"execa": "^2.0.3", "execa": "^2.0.3",
"fs-extra": "^8.1.0", "fs-extra": "^8.1.0",
"prompt-confirm": "^2.0.4" "prompt-confirm": "^2.0.4"
}, },
"devDependencies": { "devDependencies": {
"@types/fs-extra": "^8.0.1",
"@types/node": "^13.1.2", "@types/node": "^13.1.2",
"esm": "^3.2.25", "esm": "^3.2.25",
"ts-node": "^8.5.4", "ts-node": "^8.5.4",

27
npm/ng-packs/scripts/publish.ts

@ -1,9 +1,23 @@
import execa from 'execa'; import execa from 'execa';
import fse from 'fs-extra'; import fse from 'fs-extra';
import program from 'commander';
program
.option(
'-v, --nextVersion <version>',
'next semantic version. Available versions: ["major", "minor", "patch", "premajor", "preminor", "prepatch", "prerelease", "or type a custom version"]',
)
.option('-p, --preview', 'publish with preview tag');
program.parse(process.argv);
const publish = async () => { const publish = async () => {
const versions = ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease']; const versions = ['major', 'minor', 'patch', 'premajor', 'preminor', 'prepatch', 'prerelease'];
let nextSemanticVersion = (process.argv[2] || '').toLowerCase();
if (!program.nextVersion) {
console.error('Please provide a version with --nextVersion attribute');
process.exit(1);
}
try { try {
await execa('yarn', ['install-new-dependencies'], { stdout: 'inherit' }); await execa('yarn', ['install-new-dependencies'], { stdout: 'inherit' });
@ -12,7 +26,7 @@ const publish = async () => {
await execa( await execa(
'yarn', 'yarn',
['lerna', 'version', nextSemanticVersion, '--yes', '--no-commit-hooks', '--skip-git'], ['lerna', 'version', program.nextVersion, '--yes', '--no-commit-hooks', '--skip-git'],
{ stdout: 'inherit', cwd: '../' }, { stdout: 'inherit', cwd: '../' },
); );
@ -26,7 +40,14 @@ const publish = async () => {
await execa( await execa(
'yarn', 'yarn',
['lerna', 'exec', '--', '"npm publish --registry https://registry.npmjs.org"'], [
'lerna',
'exec',
'--',
`"npm publish --registry https://registry.npmjs.org${
program.preview ? ' --tag preview' : ''
}"`,
],
{ {
stdout: 'inherit', stdout: 'inherit',
cwd: '../', cwd: '../',

20
npm/ng-packs/scripts/yarn.lock

@ -2,11 +2,23 @@
# yarn lockfile v1 # yarn lockfile v1
"@types/fs-extra@^8.0.1":
version "8.0.1"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.1.tgz#a2378d6e7e8afea1564e44aafa2e207dadf77686"
integrity sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==
dependencies:
"@types/node" "*"
"@types/json5@^0.0.29": "@types/json5@^0.0.29":
version "0.0.29" version "0.0.29"
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/node@*":
version "13.7.1"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.1.tgz#238eb34a66431b71d2aaddeaa7db166f25971a0d"
integrity sha512-Zq8gcQGmn4txQEJeiXo/KiLpon8TzAl0kmKH4zdWctPj05nWwp1ClMdAVEloqrQKfaC48PNLdgN/aVaLqUrluA==
"@types/node@^13.1.2": "@types/node@^13.1.2":
version "13.1.2" version "13.1.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.2.tgz#fe94285bf5e0782e1a9e5a8c482b1c34465fa385" resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.2.tgz#fe94285bf5e0782e1a9e5a8c482b1c34465fa385"
@ -412,10 +424,10 @@ collection-visit@^1.0.0:
map-visit "^1.0.0" map-visit "^1.0.0"
object-visit "^1.0.0" object-visit "^1.0.0"
commander@^4.0.1: commander@^4.1.1:
version "4.0.1" version "4.1.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-4.0.1.tgz#b67622721785993182e807f4883633e6401ba53c" resolved "https://registry.yarnpkg.com/commander/-/commander-4.1.1.tgz#9fd602bd936294e9e9ef46a3f4d6964044b18068"
integrity sha512-IPF4ouhCP+qdlcmCedhxX4xiGBPyigb8v5NeUp+0LyhwLgxMqyp3S0vl7TAPfS/hiP7FC3caI/PB9lTmP8r1NA== integrity sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==
component-emitter@^1.2.1: component-emitter@^1.2.1:
version "1.3.0" version "1.3.0"

5
npm/package.json

@ -1,4 +1,5 @@
{ {
"version": "2.1.0",
"scripts": { "scripts": {
"lerna": "lerna", "lerna": "lerna",
"gulp:app": "node run-gulp-script.js ../templates/app/aspnet-core", "gulp:app": "node run-gulp-script.js ../templates/app/aspnet-core",
@ -7,11 +8,13 @@
"update:templates": "node abp-package-update-script.js ../templates" "update:templates": "node abp-package-update-script.js ../templates"
}, },
"devDependencies": { "devDependencies": {
"@types/fs-extra": "^8.0.1",
"glob": "^7.1.5", "glob": "^7.1.5",
"lerna": "^3.18.4", "lerna": "^3.18.4",
"npm-check-updates": "^3.1.25" "npm-check-updates": "^3.1.25"
}, },
"dependencies": { "dependencies": {
"execa": "^3.4.0" "execa": "^3.4.0",
"fs-extra": "^8.1.0"
} }
} }

29
npm/preview-publish.ps1

@ -0,0 +1,29 @@
param(
[string]$Version
)
$NextVersion = $(node get-version.js) + '-preview' + (Get-Date).tostring(“yyyyMMdd”)
$rootFolder = (Get-Item -Path "./" -Verbose).FullName
if(-Not $Version) {
$Version = $NextVersion;
}
$commands = (
"cd ng-packs\scripts",
"npm install",
"npm run publish-packages -- --nextVersion $Version --preview",
"cd ../../",
"yarn",
"yarn lerna publish $Version --no-push --yes --no-git-reset --no-commit-hooks --no-git-tag-version --force-publish --dist-tag preview"
)
foreach ($command in $commands) {
Write-Host $command
Invoke-Expression $command
if($LASTEXITCODE -ne '0' -And $command -notlike '*cd *'){
Write-Host ("Process failed! " + $command)
Set-Location $rootFolder
exit $LASTEXITCODE
}
}

10
npm/publish.ps1

@ -2,17 +2,17 @@ param(
[string]$Version [string]$Version
) )
$NextVersion = $(node get-version.js)
$rootFolder = (Get-Item -Path "./" -Verbose).FullName
if(-Not $Version) { if(-Not $Version) {
echo 'Please pass a semantic version like this: ./publish.ps1 -Version patch' $Version = $NextVersion;
exit
} }
$rootFolder = (Get-Item -Path "./" -Verbose).FullName
$commands = ( $commands = (
"cd ng-packs\scripts", "cd ng-packs\scripts",
"npm install", "npm install",
"npm run publish-packages -- $Version", "npm run publish-packages -- --nextVersion $Version",
"cd ../../", "cd ../../",
"yarn", "yarn",
"yarn lerna publish $Version --no-push --yes --no-git-reset --no-commit-hooks --no-git-tag-version --force-publish", "yarn lerna publish $Version --no-push --yes --no-git-reset --no-commit-hooks --no-git-tag-version --force-publish",

7
npm/yarn.lock

@ -832,6 +832,13 @@
resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
"@types/fs-extra@^8.0.1":
version "8.0.1"
resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-8.0.1.tgz#a2378d6e7e8afea1564e44aafa2e207dadf77686"
integrity sha512-J00cVDALmi/hJOYsunyT52Hva5TnJeKP5yd1r+mH/ZU0mbYZflR0Z5kw5kITtKTRYMhm1JMClOFYdHnQszEvqw==
dependencies:
"@types/node" "*"
"@types/glob@^7.1.1": "@types/glob@^7.1.1":
version "7.1.1" version "7.1.1"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"

50
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.Domain/Data/MyProjectNameDbMigrationService.cs

@ -1,8 +1,12 @@
using System.Threading.Tasks; using System;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;
using Volo.Abp.TenantManagement;
namespace MyCompanyName.MyProjectName.Data namespace MyCompanyName.MyProjectName.Data
{ {
@ -12,13 +16,19 @@ namespace MyCompanyName.MyProjectName.Data
private readonly IDataSeeder _dataSeeder; private readonly IDataSeeder _dataSeeder;
private readonly IMyProjectNameDbSchemaMigrator _dbSchemaMigrator; private readonly IMyProjectNameDbSchemaMigrator _dbSchemaMigrator;
private readonly ITenantRepository _tenantRepository;
private readonly ICurrentTenant _currentTenant;
public MyProjectNameDbMigrationService( public MyProjectNameDbMigrationService(
IDataSeeder dataSeeder, IDataSeeder dataSeeder,
IMyProjectNameDbSchemaMigrator dbSchemaMigrator) IMyProjectNameDbSchemaMigrator dbSchemaMigrator,
ITenantRepository tenantRepository,
ICurrentTenant currentTenant)
{ {
_dataSeeder = dataSeeder; _dataSeeder = dataSeeder;
_dbSchemaMigrator = dbSchemaMigrator; _dbSchemaMigrator = dbSchemaMigrator;
_tenantRepository = tenantRepository;
_currentTenant = currentTenant;
Logger = NullLogger<MyProjectNameDbMigrationService>.Instance; Logger = NullLogger<MyProjectNameDbMigrationService>.Instance;
} }
@ -27,13 +37,43 @@ namespace MyCompanyName.MyProjectName.Data
{ {
Logger.LogInformation("Started database migrations..."); Logger.LogInformation("Started database migrations...");
Logger.LogInformation("Migrating database schema..."); await MigrateHostDatabaseAsync();
var i = 0;
var tenants = await _tenantRepository.GetListAsync();
foreach (var tenant in tenants)
{
i++;
using (_currentTenant.Change(tenant.Id))
{
Logger.LogInformation($"Migrating {tenant.Name} database schema... ({i} of {tenants.Count})");
await MigrateTenantDatabasesAsync(tenant);
Logger.LogInformation($"Successfully completed {tenant.Name} database migrations.");
}
}
Logger.LogInformation("Successfully completed database migrations.");
}
private async Task MigrateHostDatabaseAsync()
{
Logger.LogInformation("Migrating host database schema...");
await _dbSchemaMigrator.MigrateAsync(); await _dbSchemaMigrator.MigrateAsync();
Logger.LogInformation("Executing database seed..."); Logger.LogInformation("Executing host database seed...");
await _dataSeeder.SeedAsync(); await _dataSeeder.SeedAsync();
Logger.LogInformation("Successfully completed database migrations."); Logger.LogInformation("Successfully completed host database migrations.");
}
private async Task MigrateTenantDatabasesAsync(Tenant tenant)
{
Logger.LogInformation($"Migrating schema for {tenant.Name} database...");
await _dbSchemaMigrator.MigrateAsync();
Logger.LogInformation($"Executing {tenant.Name} tenant database seed...");
await _dataSeeder.SeedAsync(tenant.Id);
} }
} }
} }

24
templates/app/aspnet-core/src/MyCompanyName.MyProjectName.EntityFrameworkCore.DbMigrations/EntityFrameworkCore/EntityFrameworkCoreMyProjectNameDbSchemaMigrator.cs

@ -1,24 +1,36 @@
using System.Threading.Tasks; using System;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using MyCompanyName.MyProjectName.Data; using MyCompanyName.MyProjectName.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace MyCompanyName.MyProjectName.EntityFrameworkCore namespace MyCompanyName.MyProjectName.EntityFrameworkCore
{ {
[Dependency(ReplaceServices = true)] [Dependency(ReplaceServices = true)]
public class EntityFrameworkCoreMyProjectNameDbSchemaMigrator public class EntityFrameworkCoreMyProjectNameDbSchemaMigrator
: IMyProjectNameDbSchemaMigrator, ITransientDependency : IMyProjectNameDbSchemaMigrator, ITransientDependency
{ {
private readonly MyProjectNameMigrationsDbContext _dbContext; private readonly IServiceProvider _serviceProvider;
public EntityFrameworkCoreMyProjectNameDbSchemaMigrator(MyProjectNameMigrationsDbContext dbContext) public EntityFrameworkCoreMyProjectNameDbSchemaMigrator(
IServiceProvider serviceProvider)
{ {
_dbContext = dbContext; _serviceProvider = serviceProvider;
} }
public async Task MigrateAsync() public async Task MigrateAsync()
{ {
await _dbContext.Database.MigrateAsync(); /* We intentionally resolving the MyProjectNameMigrationsDbContext
* from IServiceProvider (instead of directly injecting it)
* to properly get the connection string of the current tenant in the
* current scope.
*/
await _serviceProvider
.GetRequiredService<MyProjectNameMigrationsDbContext>()
.Database
.MigrateAsync();
} }
} }
} }
Loading…
Cancel
Save