diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/AbpSettingManagementBlazorMudBlazorModule.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/AbpSettingManagementBlazorMudBlazorModule.cs index a5ddb14976..ed57edea53 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/AbpSettingManagementBlazorMudBlazorModule.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/AbpSettingManagementBlazorMudBlazorModule.cs @@ -7,6 +7,7 @@ using Volo.Abp.Mapperly; using Volo.Abp.Modularity; using Volo.Abp.SettingManagement.Blazor.MudBlazor.Menus; using Volo.Abp.SettingManagement.Blazor.MudBlazor.Settings; +using Microsoft.Extensions.DependencyInjection; using Volo.Abp.SettingManagement.Localization; using Volo.Abp.UI.Navigation; diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/ISettingComponentContributor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/ISettingComponentContributor.cs new file mode 100644 index 0000000000..b81cd7f78d --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/ISettingComponentContributor.cs @@ -0,0 +1,10 @@ +using System.Threading.Tasks; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor; + +public interface ISettingComponentContributor +{ + Task ConfigureAsync(SettingComponentCreationContext context); + + Task CheckPermissionsAsync(SettingComponentCreationContext context); +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Menus/SettingManagementMenuContributor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Menus/SettingManagementMenuContributor.cs new file mode 100644 index 0000000000..477f719a21 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Menus/SettingManagementMenuContributor.cs @@ -0,0 +1,63 @@ +using System.Linq; +using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using Volo.Abp.Features; +using Volo.Abp.SettingManagement.Localization; +using Volo.Abp.UI.Navigation; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor.Menus; + +public class SettingManagementMenuContributor : IMenuContributor +{ + public async Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name == StandardMenus.Main) + { + await ConfigureMainMenuAsync(context); + } + } + + private async Task ConfigureMainMenuAsync(MenuConfigurationContext context) + { + var settingManagementPageOptions = context.ServiceProvider.GetRequiredService>().Value; + var settingPageCreationContext = new SettingComponentCreationContext(context.ServiceProvider); + if (!settingManagementPageOptions.Contributors.Any() || + !(await CheckAnyOfPagePermissionsGranted(settingManagementPageOptions, settingPageCreationContext)) + ) + { + return; + } + + var l = context.GetLocalizer(); + + /* This may happen if MVC UI is being used in the same application. + * In this case, we are removing the MVC setting management UI. */ + context.Menu.GetAdministration().TryRemoveMenuItem(SettingManagementMenus.GroupName); + + context.Menu + .GetAdministration() + .AddItem( + new ApplicationMenuItem( + SettingManagementMenus.GroupName, + l["Settings"], + "~/setting-management", + icon: "fa fa-cog" + ).RequireFeatures(SettingManagementFeatures.Enable) + ); + } + + protected virtual async Task CheckAnyOfPagePermissionsGranted( + SettingManagementComponentOptions settingManagementComponentOptions, + SettingComponentCreationContext settingComponentCreationContext) + { + foreach (var contributor in settingManagementComponentOptions.Contributors) + { + if (await contributor.CheckPermissionsAsync(settingComponentCreationContext)) + { + return true; + } + } + return false; + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Menus/SettingManagementMenus.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Menus/SettingManagementMenus.cs new file mode 100644 index 0000000000..8c773725e7 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Menus/SettingManagementMenus.cs @@ -0,0 +1,6 @@ +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor.Menus; + +public class SettingManagementMenus +{ + public const string GroupName = "SettingManagement"; +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor new file mode 100644 index 0000000000..d747102064 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor @@ -0,0 +1,121 @@ +@using Volo.Abp.SettingManagement.Localization +@using MudBlazor +@inherits Volo.Abp.AspNetCore.Components.AbpComponentBase + +@if (EmailSettings != null) +{ + + + + + + + + + + + + + + @bind-Value="@EmailSettings.SmtpPort" + Label="@L["SmtpPort"]" + Variant="Variant.Outlined" /> + + + + + + + + @if (!EmailSettings.SmtpUseDefaultCredentials) + { + + + + + + + + + + } + + + + + + @if (HasSendTestEmailPermission) + { + + @L["SendTestEmail"] + + } + + @L["Save"] + + + + + + @if (HasSendTestEmailPermission) + { + + + @L["SendTestEmail"] + + + + + + + + + + + @L["Cancel"] + @L["Send"] + + + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor.cs new file mode 100644 index 0000000000..7bb2d548f6 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/EmailSettingGroup/EmailSettingGroupViewComponent.razor.cs @@ -0,0 +1,195 @@ +using System; +using System.ComponentModel.DataAnnotations; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using MudBlazor; +using Volo.Abp.AspNetCore.Components.Messages; +using Volo.Abp.AspNetCore.Components.Web.Configuration; +using Volo.Abp.Auditing; +using Volo.Abp.Authorization.Permissions; +using Volo.Abp.SettingManagement.Localization; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor.Pages.SettingManagement.EmailSettingGroup; + +public partial class EmailSettingGroupViewComponent +{ + [Inject] + protected IEmailSettingsAppService EmailSettingsAppService { get; set; } = default!; + + [Inject] + protected IPermissionChecker PermissionChecker { get; set; } = default!; + + [Inject] + private ICurrentApplicationConfigurationCacheResetService CurrentApplicationConfigurationCacheResetService { get; set; } = default!; + + [Inject] + protected IUiMessageService UiMessageService { get; set; } = default!; + + [Inject] + protected ISnackbar Snackbar { get; set; } = default!; + + protected UpdateEmailSettingsViewModel? EmailSettings; + + protected SendTestEmailViewModel SendTestEmailInput = new(); + + protected MudForm? _emailFormRef; + protected MudForm? _testEmailFormRef; + + protected bool _sendTestEmailDialogVisible; + + protected bool HasSendTestEmailPermission { get; set; } + + public EmailSettingGroupViewComponent() + { + ObjectMapperContext = typeof(AbpSettingManagementBlazorMudBlazorModule); + LocalizationResource = typeof(AbpSettingManagementResource); + } + + protected async override Task OnInitializedAsync() + { + try + { + EmailSettings = ObjectMapper.Map(await EmailSettingsAppService.GetAsync()); + HasSendTestEmailPermission = await PermissionChecker.IsGrantedAsync(SettingManagementPermissions.EmailingTest); + SendTestEmailInput = new SendTestEmailViewModel(); + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + protected virtual async Task UpdateSettingsAsync() + { + try + { + if (_emailFormRef != null && !await _emailFormRef.Validate()) + { + return; + } + + if (EmailSettings == null) + { + return; + } + + await EmailSettingsAppService.UpdateAsync(ObjectMapper.Map(EmailSettings)); + + await CurrentApplicationConfigurationCacheResetService.ResetAsync(); + + Snackbar.Add(L["SavedSuccessfully"], Severity.Success); + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + protected virtual async Task OpenSendTestEmailDialogAsync() + { + try + { + if (_testEmailFormRef != null) + { + await _testEmailFormRef.ResetAsync(); + } + var emailSettings = await EmailSettingsAppService.GetAsync(); + SendTestEmailInput = new SendTestEmailViewModel + { + SenderEmailAddress = emailSettings.DefaultFromAddress, + TargetEmailAddress = CurrentUser.Email, + Subject = L["TestEmailSubject", new Random().Next(1000, 9999)], + Body = L["TestEmailBody"] + }; + + _sendTestEmailDialogVisible = true; + await InvokeAsync(StateHasChanged); + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + protected virtual Task CloseSendTestEmailDialogAsync() + { + _sendTestEmailDialogVisible = false; + return InvokeAsync(StateHasChanged); + } + + protected virtual async Task SendTestEmailAsync() + { + try + { + if (_testEmailFormRef != null && !await _testEmailFormRef.Validate()) + { + return; + } + + await EmailSettingsAppService.SendTestEmailAsync(ObjectMapper.Map(SendTestEmailInput)); + + Snackbar.Add(L["SentSuccessfully"], Severity.Success); + + await CloseSendTestEmailDialogAsync(); + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + public class UpdateEmailSettingsViewModel + { + [MaxLength(256)] + [Display(Name = "SmtpHost")] + public string? SmtpHost { get; set; } + + [Range(1, 65535)] + [Display(Name = "SmtpPort")] + public int SmtpPort { get; set; } + + [MaxLength(1024)] + [Display(Name = "SmtpUserName")] + public string? SmtpUserName { get; set; } + + [MaxLength(1024)] + [DataType(DataType.Password)] + [DisableAuditing] + [Display(Name = "SmtpPassword")] + public string? SmtpPassword { get; set; } + + [MaxLength(1024)] + [Display(Name = "SmtpDomain")] + public string? SmtpDomain { get; set; } + + [Display(Name = "SmtpEnableSsl")] + public bool SmtpEnableSsl { get; set; } + + [Display(Name = "SmtpUseDefaultCredentials")] + public bool SmtpUseDefaultCredentials { get; set; } + + [MaxLength(1024)] + [Required] + [Display(Name = "DefaultFromAddress")] + public string? DefaultFromAddress { get; set; } + + [MaxLength(1024)] + [Required] + [Display(Name = "DefaultFromDisplayName")] + public string? DefaultFromDisplayName { get; set; } + } + + public class SendTestEmailViewModel + { + [Required] + public string? SenderEmailAddress { get; set; } + + [Required] + public string? TargetEmailAddress { get; set; } + + [Required] + public string? Subject { get; set; } + + public string? Body { get; set; } + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor new file mode 100644 index 0000000000..ad3e7c9510 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor @@ -0,0 +1,41 @@ +@page "/setting-management" +@using Microsoft.AspNetCore.Authorization +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Components +@using Volo.Abp.Features +@attribute [Authorize] +@attribute [RequiresFeature(SettingManagementFeatures.Enable)] +@using Microsoft.Extensions.Localization +@using Volo.Abp.UI.Navigation.Localization.Resource +@inject IStringLocalizer LUiNavigation + +@* ************************* PAGE HEADER ************************* *@ + + + + + @if (!string.IsNullOrEmpty(SelectedGroup)) + { + + @foreach (var group in SettingComponentCreationContext.Groups) + { + +
+ @{ + SettingItemRenders.Add(builder => + { + builder.OpenComponent(0, group.ComponentType); + builder.CloseComponent(); + }); + } + + @SettingItemRenders.Last() +
+
+ } +
+ } +
+
diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor.cs new file mode 100644 index 0000000000..a85d2433fe --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/SettingManagement.razor.cs @@ -0,0 +1,60 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.Localization; +using Microsoft.Extensions.Options; +using Volo.Abp.BlazoriseUI; +using Volo.Abp.SettingManagement.Localization; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor.Pages.SettingManagement; + +public partial class SettingManagement +{ + [Inject] + protected IServiceProvider ServiceProvider { get; set; } = default!; + + protected SettingComponentCreationContext SettingComponentCreationContext { get; set; } = default!; + + [Inject] + protected IOptions _options { get; set; } = default!; + + [Inject] + protected IStringLocalizer L { get; set; } = default!; + + protected SettingManagementComponentOptions Options => _options.Value; + + protected List SettingItemRenders { get; set; } = new List(); + + protected string? SelectedGroup; + protected List BreadcrumbItems = new List(); + + protected int _activeTabIndex = 0; + + protected async override Task OnInitializedAsync() + { + BreadcrumbItems.Add(new BreadcrumbItem(LUiNavigation["Menu:Administration"].Value)); + BreadcrumbItems.Add(new BreadcrumbItem(L["Menu:Settings"].Value)); + + SettingComponentCreationContext = new SettingComponentCreationContext(ServiceProvider); + + foreach (var contributor in Options.Contributors) + { + await contributor.ConfigureAsync(SettingComponentCreationContext); + } + SettingComponentCreationContext.Normalize(); + SettingItemRenders.Clear(); + + if (SelectedGroup.IsNullOrEmpty() && SettingComponentCreationContext.Groups.Any()) + { + SelectedGroup = GetNormalizedString(SettingComponentCreationContext.Groups.First().Id); + _activeTabIndex = 0; + } + } + + protected virtual string GetNormalizedString(string value) + { + return value.Replace('.', '_'); + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/TimeZoneSettingGroup/TimeZoneSettingGroupViewComponent.razor b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/TimeZoneSettingGroup/TimeZoneSettingGroupViewComponent.razor new file mode 100644 index 0000000000..e244220bbb --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/TimeZoneSettingGroup/TimeZoneSettingGroupViewComponent.razor @@ -0,0 +1,35 @@ +@using Volo.Abp.SettingManagement.Localization +@using MudBlazor +@inherits Volo.Abp.AspNetCore.Components.AbpComponentBase + +@if (TimezoneSettings != null) +{ + + + + + @foreach (var item in TimezoneSettings.TimeZoneItems) + { + @item.Name + } + + @L["TimezoneHelpText"] + + + + + + @L["Save"] + + + + +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/TimeZoneSettingGroup/TimeZoneSettingGroupViewComponent.razor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/TimeZoneSettingGroup/TimeZoneSettingGroupViewComponent.razor.cs new file mode 100644 index 0000000000..90481994e7 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Pages/SettingManagement/TimeZoneSettingGroup/TimeZoneSettingGroupViewComponent.razor.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using MudBlazor; +using Volo.Abp.AspNetCore.Components.Messages; +using Volo.Abp.AspNetCore.Components.Web.Configuration; +using Volo.Abp.SettingManagement.Localization; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor.Pages.SettingManagement.TimeZoneSettingGroup; + +public partial class TimeZoneSettingGroupViewComponent +{ + [Inject] + protected ITimeZoneSettingsAppService TimeZoneSettingsAppService { get; set; } = default!; + + [Inject] + private ICurrentApplicationConfigurationCacheResetService CurrentApplicationConfigurationCacheResetService { get; set; } = default!; + + [Inject] + protected IUiMessageService UiMessageService { get; set; } = default!; + + [Inject] + protected ISnackbar Snackbar { get; set; } = default!; + + protected UpdateTimezoneSettingsViewModel? TimezoneSettings; + + public TimeZoneSettingGroupViewComponent() + { + ObjectMapperContext = typeof(AbpSettingManagementBlazorMudBlazorModule); + LocalizationResource = typeof(AbpSettingManagementResource); + } + + protected async override Task OnInitializedAsync() + { + TimezoneSettings = new UpdateTimezoneSettingsViewModel() + { + Timezone = await TimeZoneSettingsAppService.GetAsync(), + TimeZoneItems = await TimeZoneSettingsAppService.GetTimezonesAsync() + }; + } + + protected virtual async Task OnSelectedValueChangedAsync(string? timezone) + { + if (TimezoneSettings != null) + { + TimezoneSettings.Timezone = timezone; + } + await InvokeAsync(StateHasChanged); + } + + protected virtual async Task UpdateSettingsAsync() + { + try + { + if (TimezoneSettings == null) + { + return; + } + + await TimeZoneSettingsAppService.UpdateAsync(TimezoneSettings.Timezone); + await CurrentApplicationConfigurationCacheResetService.ResetAsync(); + Snackbar.Add(L["SavedSuccessfully"], Severity.Success); + } + catch (Exception ex) + { + await HandleErrorAsync(ex); + } + } + + public class UpdateTimezoneSettingsViewModel + { + public string? Timezone { get; set; } + + public List? TimeZoneItems { get; set; } + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingComponentCreationContext.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingComponentCreationContext.cs new file mode 100644 index 0000000000..b032b09841 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingComponentCreationContext.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.DependencyInjection; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor; + +public class SettingComponentCreationContext : IServiceProviderAccessor +{ + public IServiceProvider ServiceProvider { get; } + + public List Groups { get; private set; } + + public SettingComponentCreationContext(IServiceProvider serviceProvider) + { + ServiceProvider = serviceProvider; + + Groups = new List(); + } + + public void Normalize() + { + Order(); + } + + private void Order() + { + Groups = Groups.OrderBy(item => item.Order).ThenBy(item => item.DisplayName).ToList(); + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingComponentGroup.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingComponentGroup.cs new file mode 100644 index 0000000000..9755b410b1 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingComponentGroup.cs @@ -0,0 +1,40 @@ +using System; +using JetBrains.Annotations; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor; + +public class SettingComponentGroup +{ + public const int DefaultOrder = 1000; + + public string Id { + get => _id; + set => _id = Check.NotNullOrWhiteSpace(value, nameof(Id)); + } + private string _id = string.Empty; + + public string DisplayName { + get => _displayName; + set => _displayName = Check.NotNullOrWhiteSpace(value, nameof(DisplayName)); + } + private string _displayName = string.Empty; + + public Type ComponentType { + get => _componentType; + set => _componentType = Check.NotNull(value, nameof(ComponentType)); + } + private Type _componentType = null!; + + public object? Parameter { get; set; } + + public int Order { get; set; } + + public SettingComponentGroup([NotNull] string id, [NotNull] string displayName, [NotNull] Type componentType, object? parameter = null, int order = DefaultOrder) + { + Id = id; + DisplayName = displayName; + ComponentType = componentType; + Parameter = parameter; + Order = order; + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingManagementBlazorMudBlazorMappers.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingManagementBlazorMudBlazorMappers.cs new file mode 100644 index 0000000000..89b9b23de6 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingManagementBlazorMudBlazorMappers.cs @@ -0,0 +1,30 @@ +using Riok.Mapperly.Abstractions; +using Volo.Abp.Mapperly; +using static Volo.Abp.SettingManagement.Blazor.MudBlazor.Pages.SettingManagement.EmailSettingGroup.EmailSettingGroupViewComponent; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor; + +[Mapper] +public partial class UpdateEmailSettingsViewModelToUpdateEmailSettingsDtoMapper : MapperBase +{ + public override partial UpdateEmailSettingsDto Map(UpdateEmailSettingsViewModel source); + + public override partial void Map(UpdateEmailSettingsViewModel source, UpdateEmailSettingsDto destination); +} + + +[Mapper] +public partial class EmailSettingsDtoToUpdateEmailSettingsViewModelMapper : MapperBase +{ + public override partial UpdateEmailSettingsViewModel Map(EmailSettingsDto source); + + public override partial void Map(EmailSettingsDto source, UpdateEmailSettingsViewModel destination); +} + +[Mapper] +public partial class SendTestEmailViewModelToSendTestEmailInputMapper : MapperBase +{ + public override partial SendTestEmailInput Map(SendTestEmailViewModel source); + + public override partial void Map(SendTestEmailViewModel source, SendTestEmailInput destination); +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingManagementComponentOptions.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingManagementComponentOptions.cs new file mode 100644 index 0000000000..7e5e473c3d --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/SettingManagementComponentOptions.cs @@ -0,0 +1,13 @@ +using System.Collections.Generic; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor; + +public class SettingManagementComponentOptions +{ + public List Contributors { get; } + + public SettingManagementComponentOptions() + { + Contributors = new List(); + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Settings/EmailingPageContributor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Settings/EmailingPageContributor.cs new file mode 100644 index 0000000000..bdb204e698 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Settings/EmailingPageContributor.cs @@ -0,0 +1,62 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Volo.Abp.Features; +using Volo.Abp.MultiTenancy; +using Volo.Abp.SettingManagement.Blazor.MudBlazor.Pages.SettingManagement.EmailSettingGroup; +using Volo.Abp.SettingManagement.Localization; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor.Settings; + +public class EmailingPageContributor : ISettingComponentContributor +{ + public async Task ConfigureAsync(SettingComponentCreationContext context) + { + if (!await CheckPermissionsInternalAsync(context)) + { + return; + } + + var l = context.ServiceProvider.GetRequiredService>(); + context.Groups.Add( + new SettingComponentGroup( + "Volo.Abp.SettingManagement", + l["Menu:Emailing"], + typeof(EmailSettingGroupViewComponent) + ) + ); + } + + public async Task CheckPermissionsAsync(SettingComponentCreationContext context) + { + return await CheckPermissionsInternalAsync(context); + } + + private async Task CheckPermissionsInternalAsync(SettingComponentCreationContext context) + { + if (!await CheckFeatureAsync(context)) + { + return false; + } + + var authorizationService = context.ServiceProvider.GetRequiredService(); + + return await authorizationService.IsGrantedAsync(SettingManagementPermissions.Emailing); + } + + private async Task CheckFeatureAsync(SettingComponentCreationContext context) + { + var currentTenant = context.ServiceProvider.GetRequiredService(); + + if (!currentTenant.IsAvailable) + { + return true; + } + + var featureCheck = context.ServiceProvider.GetRequiredService(); + + return await featureCheck.IsEnabledAsync(SettingManagementFeatures.AllowChangingEmailSettings); + + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Settings/TimeZonePageContributor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Settings/TimeZonePageContributor.cs new file mode 100644 index 0000000000..6f812bd6e1 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/Settings/TimeZonePageContributor.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Volo.Abp.Features; +using Volo.Abp.SettingManagement.Blazor.MudBlazor.Pages.SettingManagement.TimeZoneSettingGroup; +using Volo.Abp.SettingManagement.Localization; +using Volo.Abp.Timing; + +namespace Volo.Abp.SettingManagement.Blazor.MudBlazor.Settings; + +public class TimeZonePageContributor : ISettingComponentContributor +{ + public async Task ConfigureAsync(SettingComponentCreationContext context) + { + var l = context.ServiceProvider.GetRequiredService>(); + if (await CheckPermissionsAsync(context)) + { + context.Groups.Add( + new SettingComponentGroup( + "Volo.Abp.TimeZone", + l["Menu:TimeZone"], + typeof(TimeZoneSettingGroupViewComponent) + ) + ); + } + } + + public async Task CheckPermissionsAsync(SettingComponentCreationContext context) + { + var authorizationService = context.ServiceProvider.GetRequiredService(); + + return context.ServiceProvider.GetRequiredService().SupportsMultipleTimezone + && await authorizationService.IsGrantedAsync(SettingManagementPermissions.TimeZone); + } +} diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/_Imports.razor b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/_Imports.razor new file mode 100644 index 0000000000..4e91324cd8 --- /dev/null +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Blazor.MudBlazor/_Imports.razor @@ -0,0 +1,4 @@ +@using Microsoft.AspNetCore.Components.Web +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor +@using MudBlazor +@using Volo.Abp.MudBlazorUI diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/AbpTenantManagementBlazorMudBlazorMapperlyMappers.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/AbpTenantManagementBlazorMudBlazorMapperlyMappers.cs new file mode 100644 index 0000000000..83b1474647 --- /dev/null +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/AbpTenantManagementBlazorMudBlazorMapperlyMappers.cs @@ -0,0 +1,16 @@ +using Riok.Mapperly.Abstractions; +using Volo.Abp.Mapperly; + +namespace Volo.Abp.TenantManagement.Blazor.MudBlazor; + +[Mapper] +[MapExtraProperties] +public partial class TenantDtoToTenantUpdateDtoMapper + : MapperBase +{ + [MapperIgnoreSource(nameof(TenantDto.Id))] + public override partial TenantUpdateDto Map(TenantDto source); + + [MapperIgnoreSource(nameof(TenantDto.Id))] + public override partial void Map(TenantDto source, TenantUpdateDto destination); +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/AbpTenantManagementBlazorMudBlazorModule.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/AbpTenantManagementBlazorMudBlazorModule.cs index 4a698f6a40..2427eb0083 100644 --- a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/AbpTenantManagementBlazorMudBlazorModule.cs +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/AbpTenantManagementBlazorMudBlazorModule.cs @@ -9,6 +9,7 @@ using Volo.Abp.Modularity; using Volo.Abp.ObjectExtending; using Volo.Abp.ObjectExtending.Modularity; using Volo.Abp.TenantManagement.Blazor.MudBlazor.Navigation; +using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor; using Volo.Abp.TenantManagement.Localization; using Volo.Abp.Threading; using Volo.Abp.UI.Navigation; diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Navigation/TenantManagementBlazorMenuContributor.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Navigation/TenantManagementBlazorMenuContributor.cs new file mode 100644 index 0000000000..04540c85a6 --- /dev/null +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Navigation/TenantManagementBlazorMenuContributor.cs @@ -0,0 +1,36 @@ +using System.Threading.Tasks; +using Volo.Abp.TenantManagement.Localization; +using Volo.Abp.UI.Navigation; +using Volo.Abp.Authorization.Permissions; + +namespace Volo.Abp.TenantManagement.Blazor.MudBlazor.Navigation; + +public class TenantManagementBlazorMenuContributor : IMenuContributor +{ + public virtual Task ConfigureMenuAsync(MenuConfigurationContext context) + { + if (context.Menu.Name != StandardMenus.Main) + { + return Task.CompletedTask; + } + + var administrationMenu = context.Menu.GetAdministration(); + + var l = context.GetLocalizer(); + + var tenantManagementMenuItem = new ApplicationMenuItem( + TenantManagementMenuNames.GroupName, + l["Menu:TenantManagement"], + icon: "fa fa-users" + ); + administrationMenu.AddItem(tenantManagementMenuItem); + + tenantManagementMenuItem.AddItem(new ApplicationMenuItem( + TenantManagementMenuNames.Tenants, + l["Tenants"], + url: "~/tenant-management/tenants" + ).RequirePermissions(TenantManagementPermissions.Tenants.Default)); + + return Task.CompletedTask; + } +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Navigation/TenantManagementMenuNames.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Navigation/TenantManagementMenuNames.cs new file mode 100644 index 0000000000..2f5dda85fa --- /dev/null +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Navigation/TenantManagementMenuNames.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.TenantManagement.Blazor.MudBlazor.Navigation; + +public class TenantManagementMenuNames +{ + public const string GroupName = "TenantManagement"; + + public const string Tenants = GroupName + ".Tenants"; +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor new file mode 100644 index 0000000000..6149079618 --- /dev/null +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor @@ -0,0 +1,99 @@ +@page "/tenant-management/tenants" +@attribute [Authorize(TenantManagementPermissions.Tenants.Default)] +@using Microsoft.AspNetCore.Authorization +@using Volo.Abp.FeatureManagement.Blazor.MudBlazor.Components +@using Microsoft.AspNetCore.Components.Forms +@using Volo.Abp.TenantManagement.Localization +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.Components +@using Volo.Abp.MudBlazorUI.Components.ObjectExtending +@using Volo.Abp.AspNetCore.Components.Web +@using Microsoft.Extensions.Localization +@using Volo.Abp.UI.Navigation.Localization.Resource +@inject IStringLocalizer LUiNavigation +@inherits AbpMudCrudPageBase + + + + + + + + + +@* ************************* CREATE MODAL ************************* *@ +@if (HasCreatePermission) +{ + + + @L["NewTenant"] + + + + + + + + + + + @L["Cancel"] + @L["Save"] + + +} + +@* ************************* EDIT MODAL ************************* *@ +@if (HasUpdatePermission) +{ + + + @L["Edit"] + + + + + + + + + @L["Cancel"] + @L["Save"] + + +} + +@if (HasManageFeaturesPermission) +{ + +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor.cs b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor.cs new file mode 100644 index 0000000000..eafa1c2af1 --- /dev/null +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/Pages/TenantManagement/TenantManagement.razor.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Microsoft.AspNetCore.Authorization; +using MudBlazor; +using Volo.Abp.AspNetCore.Components.Web.Extensibility.EntityActions; +using Volo.Abp.AspNetCore.Components.Web.Extensibility.TableColumns; +using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor.PageToolbars; +using Volo.Abp.BlazoriseUI; +using Volo.Abp.FeatureManagement.Blazor.MudBlazor.Components; +using Volo.Abp.ObjectExtending; +using Volo.Abp.TenantManagement.Localization; +using Volo.Abp.MudBlazorUI; + +namespace Volo.Abp.TenantManagement.Blazor.MudBlazor.Pages.TenantManagement; + +public partial class TenantManagement +{ + protected const string FeatureProviderName = "T"; + + protected bool HasManageFeaturesPermission; + protected string? ManageFeaturesPolicyName; + + protected FeatureManagementModal? FeatureManagementModal; + + protected bool ShowPassword { get; set; } + + protected PageToolbar Toolbar { get; } = new(); + + protected List TenantManagementTableColumns => TableColumns.Get(); + + private MudForm? _createFormRef; + private MudForm? _editFormRef; + + public TenantManagement() + { + LocalizationResource = typeof(AbpTenantManagementResource); + ObjectMapperContext = typeof(AbpTenantManagementBlazorMudBlazorModule); + + CreatePolicyName = TenantManagementPermissions.Tenants.Create; + UpdatePolicyName = TenantManagementPermissions.Tenants.Update; + DeletePolicyName = TenantManagementPermissions.Tenants.Delete; + + ManageFeaturesPolicyName = TenantManagementPermissions.Tenants.ManageFeatures; + } + + protected override ValueTask SetBreadcrumbItemsAsync() + { + BreadcrumbItems.Add(new BreadcrumbItem(LUiNavigation["Menu:Administration"].Value)); + BreadcrumbItems.Add(new BreadcrumbItem(L["Menu:TenantManagement"].Value)); + BreadcrumbItems.Add(new BreadcrumbItem(L["Tenants"].Value)); + return base.SetBreadcrumbItemsAsync(); + } + + protected override async Task SetPermissionsAsync() + { + await base.SetPermissionsAsync(); + + HasManageFeaturesPermission = await AuthorizationService.IsGrantedAsync(ManageFeaturesPolicyName!); + } + + protected override string GetDeleteConfirmationMessage(TenantDto entity) + { + return string.Format(L["TenantDeletionConfirmationMessage"], entity.Name); + } + + protected override ValueTask SetToolbarItemsAsync() + { + Toolbar.AddMudButton(L["NewTenant"], + OpenCreateDialogAsync, + icon: Icons.Material.Filled.Add.ToString(), + requiredPolicyName: CreatePolicyName); + + return base.SetToolbarItemsAsync(); + } + + protected override ValueTask SetEntityActionsAsync() + { + EntityActions + .Get() + .AddRange(new EntityAction[] + { + new EntityAction + { + Text = L["Edit"], + Visible = (data) => HasUpdatePermission, + Clicked = async (data) => { await OpenEditDialogAsync(data.As()); } + }, + new EntityAction + { + Text = L["Features"], + Visible = (data) => HasManageFeaturesPermission, + Clicked = async (data) => + { + var tenant = data.As(); + if (FeatureManagementModal != null) + { + await FeatureManagementModal.OpenAsync(FeatureProviderName, tenant.Id.ToString(), tenant.Name); + } + } + }, + new EntityAction + { + Text = L["Delete"], + Visible = (data) => HasDeletePermission, + Clicked = async (data) => await DeleteEntityAsync(data.As()), + ConfirmationMessage = (data) => GetDeleteConfirmationMessage(data.As()) + } + }); + + return base.SetEntityActionsAsync(); + } + + protected override async ValueTask SetTableColumnsAsync() + { + TenantManagementTableColumns + .AddRange(new TableColumn[] + { + new TableColumn + { + Title = L["Actions"], + Actions = EntityActions.Get(), + }, + new TableColumn + { + Title = L["TenantName"], + Sortable = true, + Data = nameof(TenantDto.Name), + }, + }); + + TenantManagementTableColumns.AddRange(await GetExtensionTableColumnsAsync( + TenantManagementModuleExtensionConsts.ModuleName, + TenantManagementModuleExtensionConsts.EntityNames.Tenant)); + + await base.SetTableColumnsAsync(); + } + + protected virtual void TogglePasswordVisibility() + { + ShowPassword = !ShowPassword; + } + + protected override async Task CreateEntityAsync() + { + if (_createFormRef != null && !await _createFormRef.Validate()) + { + return; + } + await base.CreateEntityAsync(); + } + + protected override async Task UpdateEntityAsync() + { + if (_editFormRef != null && !await _editFormRef.Validate()) + { + return; + } + await base.UpdateEntityAsync(); + } +} diff --git a/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/_Imports.razor b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/_Imports.razor new file mode 100644 index 0000000000..4e91324cd8 --- /dev/null +++ b/modules/tenant-management/src/Volo.Abp.TenantManagement.Blazor.MudBlazor/_Imports.razor @@ -0,0 +1,4 @@ +@using Microsoft.AspNetCore.Components.Web +@using Volo.Abp.AspNetCore.Components.Web.Theming.MudBlazor +@using MudBlazor +@using Volo.Abp.MudBlazorUI