mirror of https://github.com/abpframework/abp.git
Browse Source
# Conflicts: # npm/ng-packs/packages/account/src/lib/components/manage-profile/manage-profile.component.ts # npm/ng-packs/packages/setting-management/config/src/lib/components/email-setting-group/email-setting-group.component.ts # npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/current-user.component.ts # npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/languages.component.ts # npm/ng-packs/packages/theme-basic/src/lib/components/nav-items/nav-items.component.ts # npm/ng-packs/packages/theme-basic/src/lib/handlers/lazy-style.handler.ts # npm/ng-packs/packages/theme-basic/src/lib/services/layout.service.ts # npm/ng-packs/packages/theme-shared/src/lib/directives/ngx-datatable-default.directive.tsfeature/ssr-migration-schematic
173 changed files with 1795 additions and 1179 deletions
@ -0,0 +1,28 @@ |
|||||
|
**It is going to get hotter with ABP’s Summer Campaign!** |
||||
|
|
||||
|
Since it’s summer time, we wanted to make it even hotter by announcing a summer campaign! From July 21 to 31 we are offering a 20% discount on all ABP licenses. Now is the best time to invest in ABP and start developing asp net applications faster without wasting your time with repetitive tasks. |
||||
|
|
||||
|
## Summer Campaign Terms |
||||
|
|
||||
|
Please review the following terms and conditions carefully. |
||||
|
|
||||
|
* This offer is available for extensions and new purchases. |
||||
|
* Developer seat purchases are also included to the campaign. |
||||
|
* Campaign is available from July 21st to July 31st. |
||||
|
* Discounts are valid on selected licenses only. |
||||
|
* This offer cannot be combined with other promotions or discounts. |
||||
|
|
||||
|
**Why Choose ABP?** |
||||
|
|
||||
|
ABP offers a powerful infrastructure, simplifying modern ASP.NET core development. It helps develop modern ASP.NET applications, including ASP.NET core MVC web applications, blazor front-end projects, and angular .NET Core solutions. |
||||
|
|
||||
|
-The core framework and pre-built modules are designed with microservice architecture in mind. |
||||
|
-ABP provides a module system that allows you to develop reusable application modules. |
||||
|
-Helps implement a DDD based layered architecture and build a maintainable code base. |
||||
|
-Easily manage SaaS applications with integrated multi-tenancy, from database to UI. |
||||
|
|
||||
|
**This Offer Ends July 31, So Hurry Up!** |
||||
|
|
||||
|
This summer campaign is running from July 21 to July 31, so don’t miss your chance. Now is the perfect opportunity to enhance your asp net web development with ABP and benefit from our exclusive features. |
||||
|
|
||||
|
Get Your Discount Now: [https://abp.io/pricing?utm_source=abpwebsite&utm_medium=referral&utm_campaign=summer25_blog](https://abp.io/pricing?utm_source=abpwebsite&utm_medium=referral&utm_campaign=summer25_blog) |
||||
@ -0,0 +1,221 @@ |
|||||
|
# Module Installer Projects |
||||
|
|
||||
|
Each ABP module includes an `.Installer` project (e.g., `Volo.Abp.Account.Installer`) that serves as a **Virtual File System container** for module installation and resource management. These projects are essential for the ABP CLI to understand and install modules properly. |
||||
|
|
||||
|
## Purpose of Installer Projects |
||||
|
|
||||
|
Installer projects have three main purposes: |
||||
|
|
||||
|
1. **Virtual File System Integration**: Register the module's embedded resources with ABP's Virtual File System |
||||
|
2. **Resource Packaging**: Package module metadata files (`.abpmdl` and `.abppkg`) as embedded resources |
||||
|
3. **CLI Integration**: Enable the ABP CLI to understand module structure and install modules automatically |
||||
|
|
||||
|
## Structure of Installer Projects |
||||
|
|
||||
|
### Project Files |
||||
|
|
||||
|
- **`{ModuleName}.Installer.csproj`**: References `Volo.Abp.VirtualFileSystem` and embeds module metadata files |
||||
|
- **`InstallationNotes.md`**: Documentation for the module |
||||
|
- **`Volo/Abp/{ModuleName}/Abp{ModuleName}InstallerModule.cs`**: The core module class that registers embedded resources |
||||
|
|
||||
|
### Example Installer Module |
||||
|
|
||||
|
```csharp |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
|
||||
|
namespace Volo.Abp.Account; |
||||
|
|
||||
|
[DependsOn(typeof(AbpVirtualFileSystemModule))] |
||||
|
public class AbpAccountInstallerModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
Configure<AbpVirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpAccountInstallerModule>(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### Project Configuration |
||||
|
|
||||
|
The `.csproj` file embeds module metadata as content: |
||||
|
|
||||
|
```xml |
||||
|
<Project Sdk="Microsoft.NET.Sdk"> |
||||
|
<PropertyGroup> |
||||
|
<TargetFramework>net9.0</TargetFramework> |
||||
|
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest> |
||||
|
<RootNamespace /> |
||||
|
</PropertyGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" /> |
||||
|
</ItemGroup> |
||||
|
|
||||
|
<ItemGroup> |
||||
|
<!-- Embed module definition file --> |
||||
|
<Content Include="..\..\Volo.Abp.Account.abpmdl"> |
||||
|
<Pack>true</Pack> |
||||
|
<PackagePath>content\</PackagePath> |
||||
|
</Content> |
||||
|
|
||||
|
<!-- Embed package definition files --> |
||||
|
<Content Include="..\..\**\*.abppkg*"> |
||||
|
<Pack>true</Pack> |
||||
|
<PackagePath>content\</PackagePath> |
||||
|
</Content> |
||||
|
</ItemGroup> |
||||
|
</Project> |
||||
|
``` |
||||
|
|
||||
|
## Module Metadata Files |
||||
|
|
||||
|
### `.abpmdl` (Module Definition) |
||||
|
|
||||
|
The module definition file describes the module's structure and packages: |
||||
|
|
||||
|
```json |
||||
|
{ |
||||
|
"folders": { |
||||
|
"items": { |
||||
|
"src": {}, |
||||
|
"test": {} |
||||
|
} |
||||
|
}, |
||||
|
"packages": { |
||||
|
"Volo.Abp.Account.Web": { |
||||
|
"path": "src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.abppkg", |
||||
|
"folder": "src" |
||||
|
}, |
||||
|
"Volo.Abp.Account.Application": { |
||||
|
"path": "src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.abppkg", |
||||
|
"folder": "src" |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
### `.abppkg` (Package Definition) |
||||
|
|
||||
|
Each package has a definition file that specifies its role: |
||||
|
|
||||
|
```json |
||||
|
{ |
||||
|
"role": "lib.application" |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
Common roles: |
||||
|
- `lib.application`: Application layer package |
||||
|
- `lib.mvc`: MVC/Web layer package |
||||
|
- `lib.domain`: Domain layer package |
||||
|
- `lib.domain-shared`: Shared domain layer package |
||||
|
- `lib.efcore`: Entity Framework Core package |
||||
|
|
||||
|
## How Installer Projects Work |
||||
|
|
||||
|
### 1. CLI Installation Process |
||||
|
|
||||
|
When you run `abp add-module Volo.Abp.Account`: |
||||
|
|
||||
|
1. **Download Installer Package**: CLI downloads `Volo.Abp.Account.Installer` from NuGet |
||||
|
2. **Read Module Definition**: CLI reads the embedded `.abpmdl` file to understand module structure |
||||
|
3. **Read Package Definitions**: CLI reads `.abppkg` files to understand package roles |
||||
|
4. **Install Packages**: CLI installs appropriate packages to correct project types based on roles |
||||
|
5. **Add Dependencies**: CLI adds module dependencies to project module classes |
||||
|
|
||||
|
### 2. Virtual File System Integration |
||||
|
|
||||
|
The `InstallerModule` registers itself with the Virtual File System: |
||||
|
|
||||
|
```csharp |
||||
|
options.FileSets.AddEmbedded<AbpAccountInstallerModule>(); |
||||
|
``` |
||||
|
|
||||
|
This makes embedded resources available at runtime and enables: |
||||
|
- Access to module metadata |
||||
|
- Resource file management |
||||
|
- Module configuration |
||||
|
|
||||
|
## Creating Installer Projects for New Modules |
||||
|
|
||||
|
### Required Files |
||||
|
|
||||
|
1. **Project File**: `{ModuleName}.Installer.csproj` |
||||
|
2. **Module Class**: `Abp{ModuleName}InstallerModule.cs` |
||||
|
3. **Documentation**: `InstallationNotes.md` |
||||
|
4. **Module Definition**: `{ModuleName}.abpmdl` (in module root) |
||||
|
5. **Package Definitions**: `{PackageName}.abppkg` (in each package) |
||||
|
|
||||
|
### Template Structure |
||||
|
|
||||
|
``` |
||||
|
modules/your-module/ |
||||
|
├── src/ |
||||
|
│ ├── Volo.Abp.YourModule.Installer/ |
||||
|
│ │ ├── Volo.Abp.YourModule.Installer.csproj |
||||
|
│ │ ├── InstallationNotes.md |
||||
|
│ │ └── Volo/ |
||||
|
│ │ └── Abp/ |
||||
|
│ │ └── YourModule/ |
||||
|
│ │ └── AbpYourModuleInstallerModule.cs |
||||
|
│ └── [other packages]/ |
||||
|
├── Volo.Abp.YourModule.abpmdl |
||||
|
└── [other module files] |
||||
|
``` |
||||
|
|
||||
|
### Package Definition Examples |
||||
|
|
||||
|
For different package types: |
||||
|
|
||||
|
```json |
||||
|
// Application package |
||||
|
{ "role": "lib.application" } |
||||
|
|
||||
|
// MVC package |
||||
|
{ "role": "lib.mvc" } |
||||
|
|
||||
|
// Domain package |
||||
|
{ "role": "lib.domain" } |
||||
|
|
||||
|
// EF Core package |
||||
|
{ "role": "lib.efcore" } |
||||
|
``` |
||||
|
|
||||
|
## Why Installer Projects Appear "Empty" |
||||
|
|
||||
|
Installer projects appear minimal because their primary function is infrastructure, not business logic: |
||||
|
|
||||
|
- **No Business Logic**: Business logic belongs in the actual module packages |
||||
|
- **Pure Infrastructure**: They only handle module installation and resource management |
||||
|
- **CLI Integration**: They enable automated module installation through the ABP CLI |
||||
|
- **Resource Management**: They package and distribute module metadata |
||||
|
|
||||
|
## Best Practices |
||||
|
|
||||
|
1. **Follow Naming Convention**: Use `{ModuleName}.Installer` for the project name |
||||
|
2. **Include Documentation**: Always provide `InstallationNotes.md` with module information |
||||
|
3. **Proper Dependencies**: Only depend on `Volo.Abp.VirtualFileSystem` |
||||
|
4. **Embed All Metadata**: Include both `.abpmdl` and `.abppkg` files |
||||
|
5. **Test Installation**: Verify your installer works with `abp add-module` command |
||||
|
|
||||
|
## Troubleshooting |
||||
|
|
||||
|
### Common Issues |
||||
|
|
||||
|
1. **Missing .abpmdl file**: Ensure the module definition file exists in the module root |
||||
|
2. **Missing .abppkg files**: Each package needs a definition file |
||||
|
3. **Incorrect roles**: Use appropriate roles for each package type |
||||
|
4. **CLI not finding module**: Verify the installer package is published to NuGet |
||||
|
|
||||
|
### Verification Steps |
||||
|
|
||||
|
1. Build the installer project: `dotnet build` |
||||
|
2. Check embedded resources: Verify `.abpmdl` and `.abppkg` files are embedded |
||||
|
3. Test CLI installation: `abp add-module YourModule` |
||||
|
4. Verify dependencies: Check that module dependencies are added correctly |
||||
|
|
||||
|
This installer system enables ABP's sophisticated module architecture, allowing for automated installation with proper dependency resolution and project type matching. |
||||
|
After Width: | Height: | Size: 68 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 68 KiB |
@ -0,0 +1,92 @@ |
|||||
|
using System; |
||||
|
using System.Diagnostics; |
||||
|
using System.Linq; |
||||
|
using System.Threading.Tasks; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Domain.Repositories; |
||||
|
using Volo.Abp.TestApp.Domain; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.EntityFrameworkCore; |
||||
|
|
||||
|
public class AbpEfCoreNavigationHelper_Tests : EntityFrameworkCoreTestBase |
||||
|
{ |
||||
|
private readonly IRepository<Blog, Guid> _blogRepository; |
||||
|
|
||||
|
public AbpEfCoreNavigationHelper_Tests() |
||||
|
{ |
||||
|
_blogRepository = GetRequiredService<IRepository<Blog, Guid>>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public async Task Performance_Test() |
||||
|
{ |
||||
|
//These time taken varies on different machines.
|
||||
|
//I used relatively large values, but it can also check for performance problem.
|
||||
|
var batchUpdateTime = TimeSpan.FromSeconds(30); |
||||
|
var queryTime = TimeSpan.FromSeconds(10); |
||||
|
|
||||
|
if (!Environment.GetEnvironmentVariable("GITHUB_ACTIONS").IsNullOrWhiteSpace()) |
||||
|
{ |
||||
|
batchUpdateTime = batchUpdateTime * 6; |
||||
|
queryTime = queryTime * 6; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
var stopWatch = Stopwatch.StartNew(); |
||||
|
await WithUnitOfWorkAsync(async () => |
||||
|
{ |
||||
|
for (var i = 0; i < 5 * 1000; i++) |
||||
|
{ |
||||
|
await _blogRepository.InsertAsync( |
||||
|
new Blog(Guid.NewGuid()) |
||||
|
{ |
||||
|
Name = "Blog" + i, |
||||
|
BlogPosts = |
||||
|
[ |
||||
|
new BlogPost(Guid.NewGuid()) |
||||
|
{ |
||||
|
Title = "Post" + i |
||||
|
} |
||||
|
] |
||||
|
}); |
||||
|
} |
||||
|
}); |
||||
|
stopWatch.Stop(); |
||||
|
stopWatch.Elapsed.ShouldBeLessThan(batchUpdateTime); |
||||
|
|
||||
|
|
||||
|
stopWatch.Restart(); |
||||
|
var blogs = await _blogRepository.GetListAsync(includeDetails: true); |
||||
|
blogs.Count.ShouldBe(5 * 1000); |
||||
|
blogs.SelectMany(x => x.BlogPosts).Count().ShouldBe(5 * 1000); |
||||
|
stopWatch.Stop(); |
||||
|
stopWatch.Elapsed.ShouldBeLessThan(queryTime); |
||||
|
|
||||
|
|
||||
|
var blogId = blogs.First().Id; |
||||
|
stopWatch.Restart(); |
||||
|
await WithUnitOfWorkAsync(async () => |
||||
|
{ |
||||
|
var blog = await _blogRepository.GetAsync(blogId); |
||||
|
blog.ShouldNotBeNull(); |
||||
|
for (var i = 0; i < 5 * 1000; i++) |
||||
|
{ |
||||
|
blog.BlogPosts.Add( |
||||
|
new BlogPost(Guid.NewGuid()) |
||||
|
{ |
||||
|
Title = "NewPost" + i |
||||
|
}); |
||||
|
} |
||||
|
await _blogRepository.UpdateAsync(blog); |
||||
|
}); |
||||
|
stopWatch.Stop(); |
||||
|
stopWatch.Elapsed.ShouldBeLessThan(batchUpdateTime); |
||||
|
|
||||
|
stopWatch.Restart(); |
||||
|
var blog = await _blogRepository.GetAsync(blogId); |
||||
|
blog.BlogPosts.Count.ShouldBe(5 * 1000 + 1); |
||||
|
stopWatch.Stop(); |
||||
|
stopWatch.Elapsed.ShouldBeLessThan(queryTime); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,31 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using Volo.Abp.Domain.Entities; |
||||
|
using Volo.Abp.Domain.Entities.Auditing; |
||||
|
|
||||
|
namespace Volo.Abp.TestApp.Domain; |
||||
|
|
||||
|
public class Blog : FullAuditedAggregateRoot<Guid> |
||||
|
{ |
||||
|
public Blog(Guid id) |
||||
|
: base(id) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public string Name { get; set; } |
||||
|
|
||||
|
public List<BlogPost> BlogPosts { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class BlogPost : Entity<Guid> |
||||
|
{ |
||||
|
public BlogPost(Guid id) |
||||
|
: base(id) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
public Guid BlogId { get; set; } |
||||
|
public Blog Blog { get; set; } |
||||
|
|
||||
|
public string Title { get; set; } |
||||
|
} |
||||
@ -1,3 +1,5 @@ |
|||||
## ABP Free Modules |
## ABP Free Modules |
||||
|
|
||||
These modules are free & open source. |
These modules are free & open source. |
||||
|
|
||||
|
For detailed information about module architecture and installer projects, see the [Module Installer Projects documentation](../docs/en/framework/architecture/modularity/installer-projects.md). |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace Volo.Abp.OpenIddict; |
||||
|
|
||||
|
public static class AbpOpenIddictErrors |
||||
|
{ |
||||
|
public const string AccountLocked = "account_locked"; |
||||
|
|
||||
|
public const string AccountInactive = "account_inactive"; |
||||
|
} |
||||
@ -0,0 +1,92 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Security.Claims; |
||||
|
using System.Text.Json.Nodes; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.AspNetCore.Authentication; |
||||
|
using Microsoft.AspNetCore.Mvc; |
||||
|
using Microsoft.IdentityModel.Tokens; |
||||
|
using OpenIddict.Abstractions; |
||||
|
using OpenIddict.Server.AspNetCore; |
||||
|
|
||||
|
namespace Volo.Abp.OpenIddict.Controllers; |
||||
|
|
||||
|
public partial class TokenController |
||||
|
{ |
||||
|
protected virtual async Task<IActionResult> HandleTokenExchangeGrantTypeAsync(OpenIddictRequest request) |
||||
|
{ |
||||
|
// Retrieve the claims principal stored in the subject token.
|
||||
|
//
|
||||
|
// Note: the principal may not represent a user (e.g if the token was issued during a client credentials token
|
||||
|
// request and represents a client application): developers are strongly encouraged to ensure that the user
|
||||
|
// and client identifiers are randomly generated so that a malicious client cannot impersonate a legit user.
|
||||
|
//
|
||||
|
// See https://datatracker.ietf.org/doc/html/rfc9068#SecurityConsiderations for more information.
|
||||
|
var result = await HttpContext.AuthenticateAsync(OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); |
||||
|
|
||||
|
// If available, retrieve the claims principal stored in the actor token.
|
||||
|
var actor = result.Properties?.GetParameter<ClaimsPrincipal>(OpenIddictServerAspNetCoreConstants.Properties.ActorTokenPrincipal); |
||||
|
|
||||
|
// Retrieve the user profile corresponding to the subject token.
|
||||
|
var user = await UserManager.FindByIdAsync(result.Principal!.GetClaim(OpenIddictConstants.Claims.Subject)!); |
||||
|
if (user is null) |
||||
|
{ |
||||
|
return Forbid( |
||||
|
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, |
||||
|
properties: new AuthenticationProperties(new Dictionary<string, string> |
||||
|
{ |
||||
|
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, |
||||
|
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The token is no longer valid." |
||||
|
})); |
||||
|
} |
||||
|
|
||||
|
// Ensure the user is still allowed to sign in.
|
||||
|
if (!await PreSignInCheckAsync(user)) |
||||
|
{ |
||||
|
return Forbid( |
||||
|
authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, |
||||
|
properties: new AuthenticationProperties(new Dictionary<string, string?> |
||||
|
{ |
||||
|
[OpenIddictServerAspNetCoreConstants.Properties.Error] = OpenIddictConstants.Errors.InvalidGrant, |
||||
|
[OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is no longer allowed to sign in." |
||||
|
})); |
||||
|
} |
||||
|
|
||||
|
// Note: whether the identity represents a delegated or impersonated access (or any other
|
||||
|
// model) is entirely up to the implementer: to support all scenarios, OpenIddict doesn't
|
||||
|
// enforce any specific constraint on the identity used for the sign-in operation and only
|
||||
|
// requires that the standard "act" and "may_act" claims be valid JSON objects if present.
|
||||
|
|
||||
|
// Clear the dynamic claims cache.
|
||||
|
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId); |
||||
|
|
||||
|
// Create a new ClaimsPrincipal containing the claims that
|
||||
|
// will be used to create an id_token, a token or a code.
|
||||
|
var principal = await SignInManager.CreateUserPrincipalAsync(user); |
||||
|
|
||||
|
// Note: IdentityModel doesn't support serializing ClaimsIdentity.Actor to the
|
||||
|
// standard "act" claim yet, which requires adding the "act" claim manually.
|
||||
|
//
|
||||
|
// For more information, see
|
||||
|
// https://github.com/AzureAD/azure-activedirectory-identitymodel-extensions-for-dotnet/pull/3219.
|
||||
|
if (!string.IsNullOrEmpty(actor?.GetClaim(OpenIddictConstants.Claims.Subject)) && |
||||
|
!string.Equals(principal.GetClaim(OpenIddictConstants.Claims.Subject), actor.GetClaim(OpenIddictConstants.Claims.Subject), StringComparison.Ordinal)) |
||||
|
{ |
||||
|
principal.SetClaim(OpenIddictConstants.Claims.Actor, new JsonObject |
||||
|
{ |
||||
|
[OpenIddictConstants.Claims.Subject] = actor.GetClaim(OpenIddictConstants.Claims.Subject) |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
// Note: in this sample, the granted scopes match the requested scope
|
||||
|
// but you may want to allow the user to uncheck specific scopes.
|
||||
|
// For that, simply restrict the list of scopes before calling SetScopes.
|
||||
|
principal.SetScopes(request.GetScopes()); |
||||
|
principal.SetResources(await GetResourcesAsync(request.GetScopes())); |
||||
|
|
||||
|
await OpenIddictClaimsPrincipalManager.HandleAsync(request, principal); |
||||
|
|
||||
|
// Returning a SignInResult will ask OpenIddict to issue the appropriate access/identity tokens.
|
||||
|
return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); |
||||
|
} |
||||
|
} |
||||
@ -1,8 +1,8 @@ |
|||||
import { Directive, TemplateRef } from '@angular/core'; |
import { Directive, TemplateRef, inject } from '@angular/core'; |
||||
|
|
||||
|
@Directive({ |
||||
|
selector: '[abpTreeExpandedIconTemplate],[abp-tree-expanded-icon-template]', |
||||
|
}) |
||||
|
export class ExpandedIconTemplateDirective {
template = inject<TemplateRef<any>>(TemplateRef); |
||||
|
|
||||
@Directive({ |
} |
||||
selector: '[abpTreeExpandedIconTemplate],[abp-tree-expanded-icon-template]', |
|
||||
}) |
|
||||
export class ExpandedIconTemplateDirective { |
|
||||
constructor(public template: TemplateRef<any>) {} |
|
||||
} |
|
||||
|
|||||
@ -1,8 +1,8 @@ |
|||||
import { Directive, TemplateRef } from '@angular/core'; |
import { Directive, TemplateRef, inject } from '@angular/core'; |
||||
|
|
||||
|
@Directive({ |
||||
|
selector: '[abpTreeNodeTemplate],[abp-tree-node-template]', |
||||
|
}) |
||||
|
export class TreeNodeTemplateDirective {
template = inject<TemplateRef<any>>(TemplateRef); |
||||
|
|
||||
@Directive({ |
} |
||||
selector: '[abpTreeNodeTemplate],[abp-tree-node-template]', |
|
||||
}) |
|
||||
export class TreeNodeTemplateDirective { |
|
||||
constructor(public template: TemplateRef<any>) {} |
|
||||
} |
|
||||
|
|||||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue