mirror of https://github.com/abpframework/abp.git
61 changed files with 571 additions and 173 deletions
@ -0,0 +1,43 @@ |
|||
using System; |
|||
using Microsoft.AspNetCore.Components; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly |
|||
{ |
|||
public class AbpWebAssemblyConventionalRegistrar : ConventionalRegistrarBase |
|||
{ |
|||
public override void AddType(IServiceCollection services, Type type) |
|||
{ |
|||
if (IsConventionalRegistrationDisabled(type)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
if (!IsComponent(type)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
var serviceTypes = ExposedServiceExplorer.GetExposedServices(type); |
|||
|
|||
TriggerServiceExposing(services, type, serviceTypes); |
|||
|
|||
foreach (var serviceType in serviceTypes) |
|||
{ |
|||
services.Add( |
|||
ServiceDescriptor.Describe( |
|||
serviceType, |
|||
type, |
|||
ServiceLifetime.Transient |
|||
) |
|||
); |
|||
} |
|||
} |
|||
|
|||
private static bool IsComponent(Type type) |
|||
{ |
|||
return typeof(ComponentBase).IsAssignableFrom(type); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using System.Collections.ObjectModel; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
|||
{ |
|||
public class AlertList : ObservableCollection<AlertMessage> |
|||
{ |
|||
public void Add(AlertType type, string text, string title = null, bool dismissible = true) |
|||
{ |
|||
Add(new AlertMessage(type, text, title, dismissible)); |
|||
} |
|||
|
|||
public void Info(string text, string title = null, bool dismissible = true) |
|||
{ |
|||
Add(new AlertMessage(AlertType.Info, text, title, dismissible)); |
|||
} |
|||
|
|||
public void Warning(string text, string title = null, bool dismissible = true) |
|||
{ |
|||
Add(new AlertMessage(AlertType.Warning, text, title, dismissible)); |
|||
} |
|||
|
|||
public void Danger(string text, string title = null, bool dismissible = true) |
|||
{ |
|||
Add(new AlertMessage(AlertType.Danger, text, title, dismissible)); |
|||
} |
|||
|
|||
public void Success(string text, string title = null, bool dismissible = true) |
|||
{ |
|||
Add(new AlertMessage(AlertType.Success, text, title, dismissible)); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,14 @@ |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
|||
{ |
|||
public class AlertManager : IAlertManager, IScopedDependency |
|||
{ |
|||
public AlertList Alerts { get; } |
|||
|
|||
public AlertManager() |
|||
{ |
|||
Alerts = new AlertList(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
|||
{ |
|||
public class AlertMessage |
|||
{ |
|||
[NotNull] |
|||
public string Text |
|||
{ |
|||
get => _text; |
|||
set => _text = Check.NotNullOrWhiteSpace(value, nameof(value)); |
|||
} |
|||
private string _text; |
|||
|
|||
public AlertType Type { get; set; } |
|||
|
|||
[CanBeNull] |
|||
public string Title { get; set; } |
|||
|
|||
public bool Dismissible { get; set; } |
|||
|
|||
public AlertMessage(AlertType type, [NotNull] string text, string title = null, bool dismissible = true) |
|||
{ |
|||
Type = type; |
|||
Text = Check.NotNullOrWhiteSpace(text, nameof(text)); |
|||
Title = title; |
|||
Dismissible = dismissible; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,15 @@ |
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
|||
{ |
|||
public enum AlertType |
|||
{ |
|||
Default, |
|||
Primary, |
|||
Secondary, |
|||
Success, |
|||
Danger, |
|||
Warning, |
|||
Info, |
|||
Light, |
|||
Dark |
|||
} |
|||
} |
|||
@ -0,0 +1,7 @@ |
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly.Alerts |
|||
{ |
|||
public interface IAlertManager |
|||
{ |
|||
AlertList Alerts { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
using System; |
|||
using Microsoft.AspNetCore.Components; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Components.WebAssembly |
|||
{ |
|||
public class ServiceProviderComponentActivator : IComponentActivator |
|||
{ |
|||
public IServiceProvider ServiceProvider { get; } |
|||
|
|||
public ServiceProviderComponentActivator(IServiceProvider serviceProvider) |
|||
{ |
|||
ServiceProvider = serviceProvider; |
|||
} |
|||
|
|||
public IComponent CreateInstance(Type componentType) |
|||
{ |
|||
var instance = ServiceProvider.GetService(componentType); |
|||
|
|||
if (instance == null) |
|||
{ |
|||
instance = Activator.CreateInstance(componentType); |
|||
} |
|||
|
|||
if (!(instance is IComponent component)) |
|||
{ |
|||
throw new ArgumentException($"The type {componentType.FullName} does not implement {nameof(IComponent)}.", nameof(componentType)); |
|||
} |
|||
|
|||
return component; |
|||
} |
|||
} |
|||
} |
|||
@ -1,3 +1,3 @@ |
|||
@using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components |
|||
@using Volo.Abp.Ui.Branding |
|||
@inject IBrandingProvider BrandingProvider |
|||
<a class="navbar-brand" href="~/">@BrandingProvider.AppName</a> |
|||
<a class="navbar-brand" href="~/">@BrandingProvider.AppName</a> |
|||
|
|||
@ -1,13 +0,0 @@ |
|||
using Volo.Abp.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components |
|||
{ |
|||
public class DefaultBrandingProvider : IBrandingProvider, ITransientDependency |
|||
{ |
|||
public virtual string AppName => "MyApplication"; |
|||
|
|||
public virtual string LogoUrl => null; |
|||
|
|||
public virtual string LogoReverseUrl => null; |
|||
} |
|||
} |
|||
@ -1,17 +0,0 @@ |
|||
namespace Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Components |
|||
{ |
|||
public interface IBrandingProvider |
|||
{ |
|||
string AppName { get; } |
|||
|
|||
/// <summary>
|
|||
/// Logo on white background
|
|||
/// </summary>
|
|||
string LogoUrl { get; } |
|||
|
|||
/// <summary>
|
|||
/// Logo on dark background
|
|||
/// </summary>
|
|||
string LogoReverseUrl { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
using Volo.Abp.AspNetCore.Components.WebAssembly.Alerts; |
|||
|
|||
namespace Volo.Abp.BlazoriseUI.Components |
|||
{ |
|||
internal class AlertWrapper |
|||
{ |
|||
public AlertMessage AlertMessage { get; set; } |
|||
public bool IsVisible { get; set; } |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
@foreach (var alert in Alerts) |
|||
{ |
|||
<Alert Visible="@alert.IsVisible" Dismisable="@alert.AlertMessage.Dismissible" Color="@GetAlertColor(alert.AlertMessage.Type)"> |
|||
@if (!string.IsNullOrEmpty(alert.AlertMessage.Title)) |
|||
{ |
|||
<Heading Size="HeadingSize.Is4" Class="alert-heading"> |
|||
@alert.AlertMessage.Title |
|||
@if (alert.AlertMessage.Dismissible) |
|||
{ |
|||
<CloseButton Clicked="() => alert.IsVisible = false" /> |
|||
} |
|||
</Heading> |
|||
} |
|||
<Paragraph>@alert.AlertMessage.Text</Paragraph> |
|||
</Alert> |
|||
} |
|||
@ -0,0 +1,83 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Collections.Specialized; |
|||
using System.Linq; |
|||
using Blazorise; |
|||
using Microsoft.AspNetCore.Components; |
|||
using Microsoft.AspNetCore.Components.Routing; |
|||
using Volo.Abp.AspNetCore.Components.WebAssembly.Alerts; |
|||
|
|||
namespace Volo.Abp.BlazoriseUI.Components |
|||
{ |
|||
public partial class PageAlert : ComponentBase, IDisposable |
|||
{ |
|||
private List<AlertWrapper> Alerts = new List<AlertWrapper>(); |
|||
|
|||
[Inject] |
|||
protected IAlertManager AlertManager { get; set; } |
|||
|
|||
[Inject] |
|||
protected NavigationManager NavigationManager { get; set; } |
|||
|
|||
protected override void OnInitialized() |
|||
{ |
|||
base.OnInitialized(); |
|||
NavigationManager.LocationChanged += NavigationManager_LocationChanged; |
|||
AlertManager.Alerts.CollectionChanged += Alerts_CollectionChanged; |
|||
|
|||
Alerts.AddRange(AlertManager.Alerts.Select(t => new AlertWrapper |
|||
{ |
|||
AlertMessage = t, |
|||
IsVisible = true |
|||
})); |
|||
} |
|||
|
|||
//Since Blazor WASM doesn't support scoped dependency, we need to clear alerts on each location changed event.
|
|||
private void NavigationManager_LocationChanged(object sender, LocationChangedEventArgs e) |
|||
{ |
|||
AlertManager.Alerts.Clear(); |
|||
Alerts.Clear(); |
|||
} |
|||
|
|||
private void Alerts_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) |
|||
{ |
|||
if (e.Action == NotifyCollectionChangedAction.Add) |
|||
{ |
|||
foreach (var item in e.NewItems) |
|||
{ |
|||
Alerts.Add(new AlertWrapper |
|||
{ |
|||
AlertMessage = (AspNetCore.Components.WebAssembly.Alerts.AlertMessage)item, |
|||
IsVisible = true |
|||
}); |
|||
} |
|||
} |
|||
StateHasChanged(); |
|||
} |
|||
|
|||
protected virtual Color GetAlertColor(AlertType alertType) |
|||
{ |
|||
var color = alertType switch |
|||
{ |
|||
AlertType.Info => Color.Info, |
|||
AlertType.Success => Color.Success, |
|||
AlertType.Warning => Color.Warning, |
|||
AlertType.Danger => Color.Danger, |
|||
AlertType.Dark => Color.Dark, |
|||
AlertType.Default => Color.None, |
|||
AlertType.Light => Color.Light, |
|||
AlertType.Primary => Color.Primary, |
|||
AlertType.Secondary => Color.Secondary, |
|||
_ => Color.None, |
|||
}; |
|||
|
|||
return color; |
|||
} |
|||
|
|||
public void Dispose() |
|||
{ |
|||
NavigationManager.LocationChanged -= NavigationManager_LocationChanged; |
|||
AlertManager.Alerts.CollectionChanged -= Alerts_CollectionChanged; |
|||
} |
|||
} |
|||
} |
|||
@ -1,9 +1,11 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.MultiTenancy |
|||
{ |
|||
public interface ITenantResolveContributor |
|||
{ |
|||
string Name { get; } |
|||
|
|||
void Resolve(ITenantResolveContext context); |
|||
Task ResolveAsync(ITenantResolveContext context); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -1,10 +1,11 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.MultiTenancy |
|||
{ |
|||
public abstract class TenantResolveContributorBase : ITenantResolveContributor |
|||
{ |
|||
public abstract string Name { get; } |
|||
|
|||
//TODO: We can make this async
|
|||
public abstract void Resolve(ITenantResolveContext context); |
|||
public abstract Task ResolveAsync(ITenantResolveContext context); |
|||
} |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,75 @@ |
|||
using System.Linq; |
|||
using System.Security.Claims; |
|||
using System.Threading.Tasks; |
|||
using IdentityModel; |
|||
using Microsoft.AspNetCore.Identity; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Identity; |
|||
|
|||
namespace Volo.Abp.IdentityServer.AspNetIdentity |
|||
{ |
|||
public class AbpUserClaimsFactory<TUser> : IUserClaimsPrincipalFactory<TUser> |
|||
where TUser : class |
|||
{ |
|||
private readonly IObjectAccessor<IUserClaimsPrincipalFactory<TUser>> _inner; |
|||
private readonly UserManager<TUser> _userManager; |
|||
|
|||
public AbpUserClaimsFactory(IObjectAccessor<IUserClaimsPrincipalFactory<TUser>> inner, |
|||
UserManager<TUser> userManager) |
|||
{ |
|||
_inner = inner; |
|||
_userManager = userManager; |
|||
} |
|||
|
|||
public async Task<ClaimsPrincipal> CreateAsync(TUser user) |
|||
{ |
|||
var principal = await _inner.Value.CreateAsync(user); |
|||
var identity = principal.Identities.First(); |
|||
|
|||
if (!identity.HasClaim(x => x.Type == JwtClaimTypes.Subject)) |
|||
{ |
|||
var sub = await _userManager.GetUserIdAsync(user); |
|||
identity.AddIfNotContains(new Claim(JwtClaimTypes.Subject, sub)); |
|||
} |
|||
|
|||
var username = await _userManager.GetUserNameAsync(user); |
|||
var usernameClaim = identity.FindFirst(claim => |
|||
claim.Type == _userManager.Options.ClaimsIdentity.UserNameClaimType && claim.Value == username); |
|||
if (usernameClaim != null) |
|||
{ |
|||
identity.RemoveClaim(usernameClaim); |
|||
identity.AddIfNotContains(new Claim(JwtClaimTypes.PreferredUserName, username)); |
|||
} |
|||
|
|||
if (!identity.HasClaim(x => x.Type == JwtClaimTypes.Name)) |
|||
{ |
|||
identity.AddIfNotContains(new Claim(JwtClaimTypes.Name, username)); |
|||
} |
|||
|
|||
if (_userManager.SupportsUserEmail) |
|||
{ |
|||
var email = await _userManager.GetEmailAsync(user); |
|||
if (!string.IsNullOrWhiteSpace(email)) |
|||
{ |
|||
identity.AddIfNotContains(new Claim(JwtClaimTypes.Email, email)); |
|||
identity.AddIfNotContains(new Claim(JwtClaimTypes.EmailVerified, |
|||
await _userManager.IsEmailConfirmedAsync(user) ? "true" : "false", ClaimValueTypes.Boolean)); |
|||
} |
|||
} |
|||
|
|||
if (_userManager.SupportsUserPhoneNumber) |
|||
{ |
|||
var phoneNumber = await _userManager.GetPhoneNumberAsync(user); |
|||
if (!string.IsNullOrWhiteSpace(phoneNumber)) |
|||
{ |
|||
identity.AddIfNotContains(new Claim(JwtClaimTypes.PhoneNumber, phoneNumber)); |
|||
identity.AddIfNotContains(new Claim(JwtClaimTypes.PhoneNumberVerified, |
|||
await _userManager.IsPhoneNumberConfirmedAsync(user) ? "true" : "false", |
|||
ClaimValueTypes.Boolean)); |
|||
} |
|||
} |
|||
|
|||
return principal; |
|||
} |
|||
} |
|||
} |
|||
@ -1,18 +1 @@ |
|||
#blazor-error-ui { |
|||
background: lightyellow; |
|||
bottom: 0; |
|||
box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2); |
|||
display: none; |
|||
left: 0; |
|||
padding: 0.6rem 1.25rem 0.7rem 1.25rem; |
|||
position: fixed; |
|||
width: 100%; |
|||
z-index: 1000; |
|||
} |
|||
|
|||
#blazor-error-ui .dismiss { |
|||
cursor: pointer; |
|||
position: absolute; |
|||
right: 0.75rem; |
|||
top: 0.5rem; |
|||
} |
|||
|
|||
Loading…
Reference in new issue