From a40b49f2ede6c2a6ec1697a7c0dd02c27d5fcdbb Mon Sep 17 00:00:00 2001 From: sbwalker Date: Thu, 8 Feb 2024 15:47:25 -0500 Subject: [PATCH] implement RenderModeBoundary --- .../Modules/Admin/RecycleBin/Index.razor | 12 +- .../Modules/Admin/UserProfile/Index.razor | 6 +- .../Modules/Controls/ModuleMessage.razor | 6 +- Oqtane.Client/Modules/HtmlText/Settings.razor | 4 +- Oqtane.Client/Modules/ModuleBase.cs | 10 +- .../Themes/Controls/Theme/Login.razor | 15 +- .../Themes/Controls/Theme/LoginBase.cs | 85 ++++++---- .../Themes/Controls/Theme/UserProfile.razor | 14 +- .../Containers/ContainerSettings.razor | 4 +- Oqtane.Client/UI/ModuleInstance.razor | 118 +------------- Oqtane.Client/UI/RenderModeBoundary.razor | 149 ++++++++++++++++++ Oqtane.Server/Components/App.razor | 4 +- 12 files changed, 248 insertions(+), 179 deletions(-) create mode 100644 Oqtane.Client/UI/RenderModeBoundary.razor diff --git a/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor b/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor index 1d88dcf8..91cf3669 100644 --- a/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor +++ b/Oqtane.Client/Modules/Admin/RecycleBin/Index.razor @@ -140,7 +140,7 @@ else { try { - ModuleInstance.ShowProgressIndicator(); + ShowProgressIndicator(); foreach (Page page in _pages.Where(item => item.IsDeleted)) { await PageService.DeletePageAsync(page.PageId); @@ -149,7 +149,7 @@ else await logger.LogInformation("Pages Permanently Deleted"); await Load(); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); StateHasChanged(); NavigationManager.NavigateTo(NavigateUrl()); } @@ -157,7 +157,7 @@ else { await logger.LogError(ex, "Error Permanently Deleting Pages {Error}", ex.Message); AddModuleMessage(ex.Message, MessageType.Error); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); } } @@ -199,21 +199,21 @@ else { try { - ModuleInstance.ShowProgressIndicator(); + ShowProgressIndicator(); foreach (Module module in _modules.Where(item => item.IsDeleted).ToList()) { await PageModuleService.DeletePageModuleAsync(module.PageModuleId); } await logger.LogInformation("Modules Permanently Deleted"); await Load(); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); StateHasChanged(); } catch (Exception ex) { await logger.LogError(ex, "Error Permanently Deleting Modules {Error}", ex.Message); AddModuleMessage(Localizer["Error.Modules.Delete"], MessageType.Error); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); } } private void OnPageChangePage(int page) diff --git a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor index 0f5dad7b..24d5cf6a 100644 --- a/Oqtane.Client/Modules/Admin/UserProfile/Index.razor +++ b/Oqtane.Client/Modules/Admin/UserProfile/Index.razor @@ -596,7 +596,7 @@ { try { - ModuleInstance.ShowProgressIndicator(); + ShowProgressIndicator(); foreach(var Notification in notifications) { if (!Notification.IsDeleted) @@ -612,7 +612,7 @@ } await logger.LogInformation("Notifications Permanently Deleted"); await LoadNotificationsAsync(); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); StateHasChanged(); } @@ -620,7 +620,7 @@ { await logger.LogError(ex, "Error Deleting Notifications {Error}", ex.Message); AddModuleMessage(ex.Message, MessageType.Error); - ModuleInstance.HideProgressIndicator(); + HideProgressIndicator(); } } diff --git a/Oqtane.Client/Modules/Controls/ModuleMessage.razor b/Oqtane.Client/Modules/Controls/ModuleMessage.razor index f4f00027..82034165 100644 --- a/Oqtane.Client/Modules/Controls/ModuleMessage.razor +++ b/Oqtane.Client/Modules/Controls/ModuleMessage.razor @@ -10,7 +10,10 @@ { @((MarkupString)"  ")View Details } - +
+ + +
} @@ -58,6 +61,5 @@ private void DismissModal() { _message = ""; - StateHasChanged(); } } diff --git a/Oqtane.Client/Modules/HtmlText/Settings.razor b/Oqtane.Client/Modules/HtmlText/Settings.razor index bc1004a3..f08074c1 100644 --- a/Oqtane.Client/Modules/HtmlText/Settings.razor +++ b/Oqtane.Client/Modules/HtmlText/Settings.razor @@ -40,7 +40,7 @@ } catch (Exception ex) { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); + AddModuleMessage(ex.Message, MessageType.Error); } } @@ -55,7 +55,7 @@ } catch (Exception ex) { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); + AddModuleMessage(ex.Message, MessageType.Error); } } } diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index 403f7fb3..e6582ffd 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -37,7 +37,7 @@ namespace Oqtane.Modules protected Module ModuleState { get; set; } [Parameter] - public ModuleInstance ModuleInstance { get; set; } + public RenderModeBoundary RenderModeBoundary { get; set; } // optional interface properties public virtual SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.View; } set { } } // default security @@ -274,22 +274,22 @@ namespace Oqtane.Modules public void AddModuleMessage(string message, MessageType type, string position) { ClearModuleMessage(); - ModuleInstance.AddModuleMessage(message, type, position); + RenderModeBoundary.AddModuleMessage(message, type, position); } public void ClearModuleMessage() { - ModuleInstance.AddModuleMessage("", MessageType.Undefined); + RenderModeBoundary.AddModuleMessage("", MessageType.Undefined); } public void ShowProgressIndicator() { - ModuleInstance.ShowProgressIndicator(); + RenderModeBoundary.ShowProgressIndicator(); } public void HideProgressIndicator() { - ModuleInstance.HideProgressIndicator(); + RenderModeBoundary.HideProgressIndicator(); } public void SetModuleTitle(string title) diff --git a/Oqtane.Client/Themes/Controls/Theme/Login.razor b/Oqtane.Client/Themes/Controls/Theme/Login.razor index ce27baaa..b5908ef9 100644 --- a/Oqtane.Client/Themes/Controls/Theme/Login.razor +++ b/Oqtane.Client/Themes/Controls/Theme/Login.razor @@ -9,12 +9,23 @@ ... - + @if (PageState.Runtime == Runtime.Hybrid) + { + + } + else + { +
+ + + +
+ }
@if (ShowLogin) { - + @SharedLocalizer["Login"] } diff --git a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs index 4a61cb04..fc41f565 100644 --- a/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs +++ b/Oqtane.Client/Themes/Controls/Theme/LoginBase.cs @@ -21,30 +21,65 @@ namespace Oqtane.Themes.Controls [Inject] public IJSRuntime jsRuntime { get; set; } [Inject] public IServiceProvider ServiceProvider { get; set; } - protected void LoginUser() + private bool allowexternallogin; + private bool allowsitelogin; + protected string loginurl; + protected string logouturl; + protected string returnurl; + + protected override void OnParametersSet() { - var allowexternallogin = (SettingService.GetSetting(PageState.Site.Settings, "ExternalLogin:ProviderType", "") != "") ? true : false; - var allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true")); - - var returnurl = ""; - if (!PageState.QueryString.ContainsKey("returnurl")) - { - returnurl = WebUtility.UrlEncode(PageState.Route.PathAndQuery); // remember current url - } - else - { - returnurl = PageState.QueryString["returnurl"]; // use existing value - } + allowexternallogin = (SettingService.GetSetting(PageState.Site.Settings, "ExternalLogin:ProviderType", "") != "") ? true : false; + allowsitelogin = bool.Parse(SettingService.GetSetting(PageState.Site.Settings, "LoginOptions:AllowSiteLogin", "true")); + // set login url if (allowexternallogin && !allowsitelogin) { // external login - NavigationManager.NavigateTo(Utilities.TenantUrl(PageState.Alias, "/pages/external?returnurl=" + returnurl), true); + loginurl = Utilities.TenantUrl(PageState.Alias, "/pages/external"); } else { // local login - NavigationManager.NavigateTo(NavigateUrl("login", "?returnurl=" + returnurl)); + loginurl = NavigateUrl("login"); + } + + if (!PageState.QueryString.ContainsKey("returnurl")) + { + // remember current url + loginurl += "?returnurl=" + WebUtility.UrlEncode(PageState.Route.PathAndQuery); + } + else + { + // use existing value + loginurl = "?returnurl=" + PageState.QueryString["returnurl"]; + } + + // set logout url + logouturl = Utilities.TenantUrl(PageState.Alias, "/pages/logout/"); + + // verify anonymous users can access current page + if (UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList) && Utilities.IsPageModuleVisible(PageState.Page.EffectiveDate, PageState.Page.ExpiryDate)) + { + returnurl = PageState.Route.PathAndQuery; + } + else + { + returnurl = PageState.Alias.Path; + } + } + + protected void LoginUser() + { + if (allowexternallogin && !allowsitelogin) + { + // external login + NavigationManager.NavigateTo(loginurl, true); + } + else + { + // local login + NavigationManager.NavigateTo(loginurl); } } @@ -52,30 +87,20 @@ namespace Oqtane.Themes.Controls { await LoggingService.Log(PageState.Alias, PageState.Page.PageId, null, PageState.User?.UserId, GetType().AssemblyQualifiedName, "Logout", LogFunction.Security, LogLevel.Information, null, "User Logout For Username {Username}", PageState.User?.Username); - Route route = new Route(PageState.Uri.AbsoluteUri, PageState.Alias.Path); - var url = route.PathAndQuery; - - // verify if anonymous users can access page - if (!UserSecurity.IsAuthorized(null, PermissionNames.View, PageState.Page.PermissionList) || !Utilities.IsPageModuleVisible(PageState.Page.EffectiveDate, PageState.Page.ExpiryDate)) - { - url = PageState.Alias.Path; - } - - - if (PageState.Runtime == Shared.Runtime.Hybrid) + if (PageState.Runtime == Runtime.Hybrid) { // hybrid apps utilize an interactive logout await UserService.LogoutUserAsync(PageState.User); var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider)); authstateprovider.NotifyAuthenticationChanged(); - NavigationManager.NavigateTo(url, true); + NavigationManager.NavigateTo(returnurl, true); } - else + else // this condition is only valid for legacy Login button inheriting from LoginBase { // post to the Logout page to complete the logout process - var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, returnurl = url }; + var fields = new { __RequestVerificationToken = SiteState.AntiForgeryToken, returnurl = returnurl }; var interop = new Interop(jsRuntime); - await interop.SubmitForm(Utilities.TenantUrl(PageState.Alias, "/pages/logout/"), fields); + await interop.SubmitForm(logouturl, fields); } } } diff --git a/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor b/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor index 850e28c3..69abd0e8 100644 --- a/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor +++ b/Oqtane.Client/Themes/Controls/Theme/UserProfile.razor @@ -11,12 +11,12 @@ ... - + @context.User.Identity.Name @if (ShowRegister && PageState.Site.AllowRegistration) { - + @Localizer["Register"] } @@ -33,16 +33,6 @@ { _returnurl = WebUtility.UrlEncode(PageState.Route.PathAndQuery); } - - private void RegisterUser() - { - NavigationManager.NavigateTo(NavigateUrl("register", "returnurl=" + _returnurl)); - } - - private void UpdateProfile() - { - NavigationManager.NavigateTo(NavigateUrl("profile", "returnurl=" + _returnurl)); - } } diff --git a/Oqtane.Client/Themes/OqtaneTheme/Containers/ContainerSettings.razor b/Oqtane.Client/Themes/OqtaneTheme/Containers/ContainerSettings.razor index b0c7774f..e96fdb7a 100644 --- a/Oqtane.Client/Themes/OqtaneTheme/Containers/ContainerSettings.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Containers/ContainerSettings.razor @@ -83,7 +83,7 @@ } catch (Exception ex) { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); + AddModuleMessage(ex.Message, MessageType.Error); } } @@ -100,7 +100,7 @@ } catch (Exception ex) { - ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error); + AddModuleMessage(ex.Message, MessageType.Error); } } } diff --git a/Oqtane.Client/UI/ModuleInstance.razor b/Oqtane.Client/UI/ModuleInstance.razor index 71143fc3..450fe7ef 100644 --- a/Oqtane.Client/UI/ModuleInstance.razor +++ b/Oqtane.Client/UI/ModuleInstance.razor @@ -1,127 +1,19 @@ @namespace Oqtane.UI -@inject IStringLocalizer Localizer -@inject ILogService LoggingService -@inherits ErrorBoundary +@inject SiteState SiteState -@if (CurrentException is null) +@if (ModuleState.RenderMode == RenderModes.Static) { - if (_message != "" && _messagePosition == "top") - { - - } - @if (ModuleType != null) - { - - @if (_progressIndicator) - { -
- } - } - if (_message != "" && _messagePosition == "bottom") - { - - } + } -else +else { - @if (!string.IsNullOrEmpty(_error)) - { - - } + } @code { - private string _message; - private string _error; - private MessageType _messageType; - private string _messagePosition; - private bool _progressIndicator = false; - - private Type ModuleType { get; set; } - private IDictionary ModuleParameters { get; set; } - [CascadingParameter] protected PageState PageState { get; set; } [CascadingParameter] private Module ModuleState { get; set; } - - private ModuleMessage ModuleMessage { get; set; } - - protected override bool ShouldRender() - { - return PageState?.RenderId == ModuleState?.RenderId; - } - - protected override void OnParametersSet() - { - _message = ""; - if (ShouldRender()) - { - if (!string.IsNullOrEmpty(ModuleState.ModuleType)) - { - ModuleType = Type.GetType(ModuleState.ModuleType); - if (ModuleType != null) - { - ModuleParameters = new Dictionary { { "ModuleInstance", this } }; - return; - } - // module does not exist with typename specified - _message = string.Format(Localizer["Error.Module.InvalidName"], Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0)); - _messageType = MessageType.Error; - _messagePosition = "top"; - } - else - { - _message = string.Format(Localizer["Error.Module.InvalidType"], ModuleState.ModuleDefinitionName); - _messageType = MessageType.Error; - _messagePosition = "top"; - } - } - } - - public void AddModuleMessage(string message, MessageType type) - { - AddModuleMessage(message, type, "top"); - } - - public void AddModuleMessage(string message, MessageType type, string position) - { - _message = message; - _messageType = type; - _messagePosition = position; - _progressIndicator = false; - StateHasChanged(); - } - - public void ShowProgressIndicator() - { - _progressIndicator = true; - StateHasChanged(); - } - - public void HideProgressIndicator() - { - _progressIndicator = false; - StateHasChanged(); - } - - protected override async Task OnErrorAsync(Exception exception) - { - // retrieve friendly localized error - _error = Localizer["Error.Module.Exception"]; - // log error - string category = GetType().AssemblyQualifiedName; - string feature = Utilities.GetTypeNameLastSegment(category, 1); - await LoggingService.Log(null, ModuleState.PageId, ModuleState.ModuleId, PageState.User?.UserId, category, feature, LogFunction.Other, LogLevel.Error, exception, "An Unexpected Error Has Occurred In {ModuleDefinitionName}: {Error}", ModuleState.ModuleDefinitionName, exception.Message); - await base.OnErrorAsync(exception); - return; - } - - public new void Recover() - { - _error = ""; - base.Recover(); - } - } diff --git a/Oqtane.Client/UI/RenderModeBoundary.razor b/Oqtane.Client/UI/RenderModeBoundary.razor new file mode 100644 index 00000000..d02df5f1 --- /dev/null +++ b/Oqtane.Client/UI/RenderModeBoundary.razor @@ -0,0 +1,149 @@ +@namespace Oqtane.UI +@inject SiteState SiteStateService +@inject IStringLocalizer Localizer +@inject ILogService LoggingService +@inherits ErrorBoundary + +@if (CurrentException is null) +{ + @if (ModuleType != null) + { + + + @if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "top") + { + + } + + @if (_progressIndicator) + { +
+ } + @if (!string.IsNullOrEmpty(_messageContent) && _messagePosition == "bottom") + { + + } +
+
+ } +} +else +{ + @if (!string.IsNullOrEmpty(_error)) + { + + } +} + +@code { + private Type ModuleType { get; set; } + private IDictionary ModuleParameters { get; set; } + + private string _messageContent; + private MessageType _messageType; + private string _messagePosition; + private bool _progressIndicator = false; + private string _error; + + [Parameter] + public SiteState SiteState { get; set; } + + [Parameter] + public PageState PageState { get; set; } + + [Parameter] + public Module ModuleState { get; set; } + + RenderFragment DynamicComponent { get; set; } + + protected override bool ShouldRender() + { + return PageState?.RenderId == ModuleState?.RenderId; + } + + protected override void OnParametersSet() + { + _messageContent = ""; + + if (ShouldRender()) + { + if (!string.IsNullOrEmpty(ModuleState.ModuleType)) + { + ModuleType = Type.GetType(ModuleState.ModuleType); + if (ModuleType != null) + { + // repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary) + SiteStateService.Alias = SiteState.Alias; + SiteStateService.AntiForgeryToken = SiteState.AntiForgeryToken; + SiteStateService.AuthorizationToken = SiteState.AuthorizationToken; + SiteStateService.RemoteIPAddress = SiteState.RemoteIPAddress; + SiteStateService.IsPrerendering = SiteState.IsPrerendering; + + ModuleParameters = new Dictionary { { "RenderModeBoundary", this } }; + } + else + { + // module does not exist with typename specified + _messageContent = string.Format(Localizer["Error.Module.InvalidName"], Utilities.GetTypeNameLastSegment(ModuleState.ModuleType, 0)); + _messageType = MessageType.Error; + _messagePosition = "top"; + } + } + else + { + _messageContent = string.Format(Localizer["Error.Module.InvalidType"], ModuleState.ModuleDefinitionName); + _messageType = MessageType.Error; + _messagePosition = "top"; + } + } + } + + public void AddModuleMessage(string message, MessageType type) + { + AddModuleMessage(message, type, "top"); + } + + public void AddModuleMessage(string message, MessageType type, string position) + { + _messageContent = message; + _messageType = type; + _messagePosition = position; + _progressIndicator = false; + StateHasChanged(); + } + + public void ShowProgressIndicator() + { + _progressIndicator = true; + StateHasChanged(); + } + + public void HideProgressIndicator() + { + _progressIndicator = false; + StateHasChanged(); + } + + private void DismissMessage() + { + _messageContent = ""; + } + + protected override async Task OnErrorAsync(Exception exception) + { + // retrieve friendly localized error + _error = Localizer["Error.Module.Exception"]; + // log error + string category = GetType().AssemblyQualifiedName; + string feature = Utilities.GetTypeNameLastSegment(category, 1); + await LoggingService.Log(null, ModuleState.PageId, ModuleState.ModuleId, PageState.User?.UserId, category, feature, LogFunction.Other, LogLevel.Error, exception, "An Unexpected Error Has Occurred In {ModuleDefinitionName}: {Error}", ModuleState.ModuleDefinitionName, exception.Message); + await base.OnErrorAsync(exception); + return; + } + + public new void Recover() + { + _error = ""; + base.Recover(); + } +} \ No newline at end of file diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index f7526324..8e6ca4c0 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -53,7 +53,7 @@ } else { - + } @((MarkupString)_headResources) @@ -66,7 +66,7 @@ } else { - + }