performance optimization to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries

This commit is contained in:
sbwalker 2024-07-16 16:21:35 -04:00
parent 98bdfd3dbe
commit 4d26468ede
15 changed files with 145 additions and 72 deletions

View File

@ -10,6 +10,7 @@
@inject IStringLocalizer<SharedResources> SharedLocalizer @inject IStringLocalizer<SharedResources> SharedLocalizer
@inject IPageModuleService PageModuleService @inject IPageModuleService PageModuleService
@inject IModuleService ModuleService @inject IModuleService ModuleService
@inject IPageService PageService
@if (_initialized) @if (_initialized)
{ {
@ -313,8 +314,9 @@
.Select(md => md.PageId) .Select(md => md.PageId)
.Distinct(); .Distinct();
// Filter and retrieve the corresponding pages // retrieve the pages which contain the module
_pagesWithModules = PageState.Pages var pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
_pagesWithModules = pages
.Where(pg => distinctPageIds.Contains(pg.PageId) && pg.IsDeleted == false) .Where(pg => distinctPageIds.Contains(pg.PageId) && pg.IsDeleted == false)
.ToList(); .ToList();

View File

@ -3,6 +3,7 @@
@inherits ModuleBase @inherits ModuleBase
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject IThemeService ThemeService @inject IThemeService ThemeService
@inject IPageService PageService
@inject IModuleService ModuleService @inject IModuleService ModuleService
@inject IPageModuleService PageModuleService @inject IPageModuleService PageModuleService
@inject IStringLocalizer<Settings> Localizer @inject IStringLocalizer<Settings> Localizer
@ -79,14 +80,13 @@
} }
else else
{ {
foreach (Page p in PageState.Pages) foreach (Page p in _pages)
{ {
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList)) if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList))
{ {
<option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option> <option value="@p.PageId">@(new string('-', p.Level * 2))@(p.Name)</option>
} }
} }
} }
</select> </select>
</div> </div>
@ -154,10 +154,12 @@
private DateTime modifiedon; private DateTime modifiedon;
private DateTime? _effectivedate = null; private DateTime? _effectivedate = null;
private DateTime? _expirydate = null; private DateTime? _expirydate = null;
private List<Page> _pages;
protected override void OnInitialized() protected override async Task OnInitializedAsync()
{ {
SetModuleTitle(Localizer["ModuleSettings.Title"]); SetModuleTitle(Localizer["ModuleSettings.Title"]);
_module = ModuleState.ModuleDefinition.Name; _module = ModuleState.ModuleDefinition.Name;
_title = ModuleState.Title; _title = ModuleState.Title;
_moduleSettingsTitle = Localizer["ModuleSettings.Heading"]; _moduleSettingsTitle = Localizer["ModuleSettings.Heading"];
@ -173,7 +175,7 @@
modifiedon = ModuleState.ModifiedOn; modifiedon = ModuleState.ModifiedOn;
_effectivedate = Utilities.UtcAsLocalDate(ModuleState.EffectiveDate); _effectivedate = Utilities.UtcAsLocalDate(ModuleState.EffectiveDate);
_expirydate = Utilities.UtcAsLocalDate(ModuleState.ExpiryDate); _expirydate = Utilities.UtcAsLocalDate(ModuleState.ExpiryDate);
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
if (ModuleState.ModuleDefinition != null) if (ModuleState.ModuleDefinition != null)
{ {

View File

@ -26,7 +26,7 @@
<div class="col-sm-9"> <div class="col-sm-9">
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required> <select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
<option value="-1">&lt;@Localizer["SiteRoot"]&gt;</option> <option value="-1">&lt;@Localizer["SiteRoot"]&gt;</option>
@foreach (Page page in PageState.Pages) @foreach (Page page in _pages)
{ {
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList)) if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
{ {
@ -213,6 +213,7 @@
private bool validated = false; private bool validated = false;
private List<ThemeControl> _themes = new List<ThemeControl>(); private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>(); private List<ThemeControl> _containers = new List<ThemeControl>();
private List<Page> _pages;
private int _pageId; private int _pageId;
private string _name; private string _name;
private string _parentid = "-1"; private string _parentid = "-1";
@ -243,6 +244,8 @@
{ {
try try
{ {
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
if (PageState.QueryString.ContainsKey("id")) if (PageState.QueryString.ContainsKey("id"))
{ {
_pageId = Int32.Parse(PageState.QueryString["id"]); _pageId = Int32.Parse(PageState.QueryString["id"]);
@ -263,7 +266,7 @@
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype); _containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
_containertype = PageState.Site.DefaultContainerType; _containertype = PageState.Site.DefaultContainerType;
_children = new List<Page>(); _children = new List<Page>();
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid)))) foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
{ {
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList)) if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{ {
@ -293,7 +296,7 @@
{ {
_parentid = (string)e.Value; _parentid = (string)e.Value;
_children = new List<Page>(); _children = new List<Page>();
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid)))) foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
{ {
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList)) if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{ {
@ -371,7 +374,7 @@
} }
else else
{ {
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == page.ParentId); Page parent = _pages.FirstOrDefault(item => item.PageId == page.ParentId);
if (parent.Path == string.Empty) if (parent.Path == string.Empty)
{ {
page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
@ -382,7 +385,6 @@
} }
} }
var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
if (_pages.Any(item => item.Path == page.Path)) if (_pages.Any(item => item.Path == page.Path))
{ {
AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning); AddModuleMessage(string.Format(Localizer["Message.Page.Exists"], _path), MessageType.Warning);
@ -402,11 +404,11 @@
page.Order = 0; page.Order = 0;
break; break;
case "<": case "<":
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); child = _pages.Where(item => item.PageId == _childid).FirstOrDefault();
page.Order = child.Order - 1; page.Order = child.Order - 1;
break; break;
case ">": case ">":
child = PageState.Pages.Where(item => item.PageId == _childid).FirstOrDefault(); child = _pages.Where(item => item.PageId == _childid).FirstOrDefault();
page.Order = child.Order + 1; page.Order = child.Order + 1;
break; break;
case ">>": case ">>":

View File

@ -31,7 +31,7 @@
<div class="col-sm-9"> <div class="col-sm-9">
<select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required> <select id="parent" class="form-select" value="@_parentid" @onchange="(e => ParentChanged(e))" required>
<option value="-1">&lt;@Localizer["SiteRoot"]&gt;</option> <option value="-1">&lt;@Localizer["SiteRoot"]&gt;</option>
@foreach (Page page in PageState.Pages) @foreach (Page page in _pages)
{ {
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList) && page.PageId != _pageId) if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList) && page.PageId != _pageId)
{ {
@ -302,6 +302,7 @@
private bool validated = false; private bool validated = false;
private List<ThemeControl> _themes = new List<ThemeControl>(); private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>(); private List<ThemeControl> _containers = new List<ThemeControl>();
private List<Page> _pages;
private int _pageId; private int _pageId;
private string _name; private string _name;
private string _currentparentid; private string _currentparentid;
@ -345,6 +346,7 @@
{ {
try try
{ {
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
_pageId = Int32.Parse(PageState.QueryString["id"]); _pageId = Int32.Parse(PageState.QueryString["id"]);
_page = await PageService.GetPageAsync(_pageId); _page = await PageService.GetPageAsync(_pageId);
_icons = await SystemService.GetIconsAsync(); _icons = await SystemService.GetIconsAsync();
@ -360,10 +362,10 @@
else else
{ {
_parentid = _page.ParentId.ToString(); _parentid = _page.ParentId.ToString();
_parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId); _parent = _pages.FirstOrDefault(item => item.PageId == _page.ParentId);
} }
_children = new List<Page>(); _children = new List<Page>();
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture)))) foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture))))
{ {
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList)) if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{ {
@ -447,7 +449,7 @@
{ {
_parentid = (string)e.Value; _parentid = (string)e.Value;
_children = new List<Page>(); _children = new List<Page>();
foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid)))) foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid))))
{ {
if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList)) if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{ {
@ -549,7 +551,7 @@
} }
else else
{ {
Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId); Page parent = _pages.FirstOrDefault(item => item.PageId == _page.ParentId);
if (parent.Path == string.Empty) if (parent.Path == string.Empty)
{ {
_page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); _page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path);
@ -560,7 +562,6 @@
} }
} }
var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
if (_pages.Any(item => item.Path == _page.Path && item.PageId != _page.PageId)) if (_pages.Any(item => item.Path == _page.Path && item.PageId != _page.PageId))
{ {
AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning); AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning);
@ -582,11 +583,11 @@
_page.Order = 0; _page.Order = 0;
break; break;
case "<": case "<":
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid); child = _pages.FirstOrDefault(item => item.PageId == _childid);
if (child != null) _page.Order = child.Order - 1; if (child != null) _page.Order = child.Order - 1;
break; break;
case ">": case ">":
child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid); child = _pages.FirstOrDefault(item => item.PageId == _childid);
if (child != null) _page.Order = child.Order + 1; if (child != null) _page.Order = child.Order + 1;
break; break;
case ">>": case ">>":

View File

@ -5,11 +5,11 @@
@inject IStringLocalizer<Index> Localizer @inject IStringLocalizer<Index> Localizer
@inject IStringLocalizer<SharedResources> SharedLocalizer @inject IStringLocalizer<SharedResources> SharedLocalizer
@if (PageState.Pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) @if (_pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin))
{ {
<ActionLink Action="Add" Text="Add Page" ResourceKey="AddPage" /> <ActionLink Action="Add" Text="Add Page" ResourceKey="AddPage" />
<Pager Items="@PageState.Pages.Where(item => !item.IsDeleted)" SearchProperties="Name"> <Pager Items="@_pages.Where(item => !item.IsDeleted)" SearchProperties="Name">
<Header> <Header>
<th style="width: 1px;">&nbsp;</th> <th style="width: 1px;">&nbsp;</th>
<th style="width: 1px;">&nbsp;</th> <th style="width: 1px;">&nbsp;</th>
@ -28,6 +28,21 @@
@code { @code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
private List<Page> _pages;
protected override async Task OnInitializedAsync()
{
try
{
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Pages {Error}", ex.Message);
AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error);
}
}
private async Task DeletePage(Page page) private async Task DeletePage(Page page)
{ {
try try

View File

@ -4,6 +4,7 @@
@using Microsoft.Extensions.DependencyInjection @using Microsoft.Extensions.DependencyInjection
@inject NavigationManager NavigationManager @inject NavigationManager NavigationManager
@inject ISiteService SiteService @inject ISiteService SiteService
@inject IPageService PageService
@inject ITenantService TenantService @inject ITenantService TenantService
@inject IDatabaseService DatabaseService @inject IDatabaseService DatabaseService
@inject IAliasService AliasService @inject IAliasService AliasService
@ -29,7 +30,7 @@
<div class="col-sm-9"> <div class="col-sm-9">
<select id="homepage" class="form-select" @bind="@_homepageid" required> <select id="homepage" class="form-select" @bind="@_homepageid" required>
<option value="-">&lt;@SharedLocalizer["Not Specified"]&gt;</option> <option value="-">&lt;@SharedLocalizer["Not Specified"]&gt;</option>
@foreach (Page page in PageState.Pages) @foreach (Page page in _pages)
{ {
if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone)) if (UserSecurity.ContainsRole(page.PermissionList, PermissionNames.View, RoleNames.Everyone))
{ {
@ -410,6 +411,7 @@
private bool _initialized = false; private bool _initialized = false;
private List<ThemeControl> _themes = new List<ThemeControl>(); private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>(); private List<ThemeControl> _containers = new List<ThemeControl>();
private List<Page> _pages;
private string _name = string.Empty; private string _name = string.Empty;
private string _homepageid = "-"; private string _homepageid = "-";
private string _isdeleted; private string _isdeleted;
@ -472,6 +474,8 @@
Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId); Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId);
if (site != null) if (site != null)
{ {
_pages = await PageService.GetPagesAsync(PageState.Site.SiteId);
_name = site.Name; _name = site.Name;
if (site.HomePageId != null) if (site.HomePageId != null)
{ {

View File

@ -138,4 +138,7 @@
<data name="EditPage.Text" xml:space="preserve"> <data name="EditPage.Text" xml:space="preserve">
<value>Edit</value> <value>Edit</value>
</data> </data>
<data name="Error.Page.Load" xml:space="preserve">
<value>Error Loading Pages</value>
</data>
</root> </root>

View File

@ -6,10 +6,26 @@
{ {
@if (PageState.RenderMode == RenderModes.Interactive) @if (PageState.RenderMode == RenderModes.Interactive)
{ {
<ModuleActionsInteractive PageState="@PageState" ModuleState="@ModuleState" /> <ModuleActionsInteractive PageState="@_moduleActionsPageState" ModuleState="@ModuleState" />
} }
else else
{ {
<ModuleActionsInteractive PageState="@PageState" ModuleState="@ModuleState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" /> <ModuleActionsInteractive PageState="@_moduleActionsPageState" ModuleState="@ModuleState" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
}
}
@code {
private ModuleActionsPageState _moduleActionsPageState;
protected override void OnParametersSet()
{
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
_moduleActionsPageState = new ModuleActionsPageState
{
Alias = PageState.Alias,
Page = PageState.Page,
User = PageState.User,
EditMode = PageState.EditMode
};
} }
} }

View File

@ -7,9 +7,7 @@ using Oqtane.Models;
using Oqtane.Security; using Oqtane.Security;
using Oqtane.Services; using Oqtane.Services;
using Oqtane.Shared; using Oqtane.Shared;
using Oqtane.UI;
using System.Net; using System.Net;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
// ReSharper disable UnassignedGetOnlyAutoProperty // ReSharper disable UnassignedGetOnlyAutoProperty
@ -24,7 +22,7 @@ namespace Oqtane.Themes.Controls
[Inject] public IModuleService ModuleService { get; set; } [Inject] public IModuleService ModuleService { get; set; }
[Inject] public IStringLocalizer<ModuleActionsBase> Localizer { get; set; } [Inject] public IStringLocalizer<ModuleActionsBase> Localizer { get; set; }
[Parameter] public PageState PageState { get; set; } [Parameter] public ModuleActionsPageState PageState { get; set; }
[Parameter] public Module ModuleState { get; set; } [Parameter] public Module ModuleState { get; set; }
public List<ActionViewModel> Actions; public List<ActionViewModel> Actions;

View File

@ -0,0 +1,12 @@
using Oqtane.Models;
namespace Oqtane.Themes.Controls
{
public class ModuleActionsPageState
{
public Alias Alias { get; set; }
public Page Page { get; set; }
public User User { get; set; }
public bool EditMode { get; set; }
}
}

View File

@ -32,11 +32,11 @@
{ {
@if (PageState.RenderMode == RenderModes.Interactive) @if (PageState.RenderMode == RenderModes.Interactive)
{ {
<ControlPanelInteractive PageState="@PageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" /> <ControlPanelInteractive PageState="@_controlPanelPageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" CanViewAdminDashboard="@_canViewAdminDashboard" />
} }
else else
{ {
<ControlPanelInteractive PageState="@PageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" /> <ControlPanelInteractive PageState="@_controlPanelPageState" SiteState="@SiteState" ButtonClass="@ButtonClass" ContainerClass="@ContainerClass" HeaderClass="@HeaderClass" BodyClass="@BodyClass" ShowLanguageSwitcher="@ShowLanguageSwitcher" LanguageDropdownAlignment="@LanguageDropdownAlignment" CanViewAdminDashboard="@_canViewAdminDashboard" @rendermode="@InteractiveRenderMode.GetInteractiveRenderMode(PageState.Site.Runtime, false)" />
} }
} }
@ -59,6 +59,7 @@
[Parameter] [Parameter]
public string LanguageDropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right public string LanguageDropdownAlignment { get; set; } = string.Empty; // Empty or Left or Right
private ControlPanelPageState _controlPanelPageState;
private bool _canViewAdminDashboard = false; private bool _canViewAdminDashboard = false;
private bool _showEditMode = false; private bool _showEditMode = false;
@ -82,6 +83,24 @@
} }
} }
} }
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
_controlPanelPageState = new ControlPanelPageState
{
Alias = PageState.Alias,
Site = new Site
{
DefaultContainerType = PageState.Site.DefaultContainerType,
Settings = PageState.Site.Settings,
Themes = PageState.Site.Themes
},
Page = PageState.Page,
User = PageState.User,
Uri = PageState.Uri,
Route = PageState.Route,
RenderMode = PageState.RenderMode,
Runtime = PageState.Runtime
};
} }
private bool CanViewAdminDashboard() private bool CanViewAdminDashboard()

View File

@ -28,7 +28,7 @@
</div> </div>
<div class="@BodyClass"> <div class="@BodyClass">
<div class="container-fluid"> <div class="container-fluid">
@if (_canViewAdminDashboard) @if (CanViewAdminDashboard)
{ {
<div class="row d-flex"> <div class="row d-flex">
<div class="col"> <div class="col">
@ -228,7 +228,7 @@
public SiteState SiteState { get; set; } public SiteState SiteState { get; set; }
[Parameter] [Parameter]
public PageState PageState { get; set; } public ControlPanelPageState PageState { get; set; }
[Parameter] [Parameter]
public string ButtonClass { get; set; } public string ButtonClass { get; set; }
@ -248,7 +248,9 @@
[Parameter] [Parameter]
public string LanguageDropdownAlignment { get; set; } public string LanguageDropdownAlignment { get; set; }
private bool _canViewAdminDashboard = false; [Parameter]
public bool CanViewAdminDashboard { get; set; }
private bool _deleteConfirmation = false; private bool _deleteConfirmation = false;
private List<string> _categories = new List<string>(); private List<string> _categories = new List<string>();
private List<ModuleDefinition> _allModuleDefinitions; private List<ModuleDefinition> _allModuleDefinitions;
@ -278,44 +280,18 @@
// repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary) // repopulate the SiteState service based on the values passed in the SiteState parameter (this is how state is marshalled across the render mode boundary)
ComponentSiteState.Hydrate(SiteState); ComponentSiteState.Hydrate(SiteState);
_canViewAdminDashboard = CanViewAdminDashboard();
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList)) if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, PageState.Page.PermissionList))
{ {
LoadSettingsAsync(); LoadSettingsAsync();
_pages = await PageService.GetPagesAsync(PageState.Page.SiteId);
_pages?.Clear();
foreach (Page p in PageState.Pages)
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList))
{
_pages.Add(p);
}
}
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType); _containers = ThemeService.GetContainerControls(PageState.Site.Themes, PageState.Page.ThemeType);
_containerType = PageState.Site.DefaultContainerType; _containerType = PageState.Site.DefaultContainerType;
_allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); _allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Page.SiteId);
_moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList(); _moduleDefinitions = _allModuleDefinitions.Where(item => item.Categories.Contains(_category)).ToList();
_categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',', StringSplitOptions.RemoveEmptyEntries)).Distinct().Where(item => item != "Headless").ToList(); _categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',', StringSplitOptions.RemoveEmptyEntries)).Distinct().Where(item => item != "Headless").ToList();
} }
} }
private bool CanViewAdminDashboard()
{
var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin");
if (admin != null)
{
foreach (var page in PageState.Pages.Where(item => item.ParentId == admin?.PageId))
{
if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList))
{
return true;
}
}
}
return false;
}
private void CategoryChanged(ChangeEventArgs e) private void CategoryChanged(ChangeEventArgs e)
{ {
_category = (string)e.Value; _category = (string)e.Value;
@ -371,7 +347,7 @@
if (_moduleType == "new") if (_moduleType == "new")
{ {
Module module = new Module(); Module module = new Module();
module.SiteId = PageState.Site.SiteId; module.SiteId = PageState.Page.SiteId;
module.PageId = PageState.Page.PageId; module.PageId = PageState.Page.PageId;
module.ModuleDefinitionName = _moduleDefinitionName; module.ModuleDefinitionName = _moduleDefinitionName;
module.AllPages = false; module.AllPages = false;
@ -384,7 +360,7 @@
{ {
var module = await ModuleService.GetModuleAsync(int.Parse(_moduleId)); var module = await ModuleService.GetModuleAsync(int.Parse(_moduleId));
module.ModuleId = 0; module.ModuleId = 0;
module.SiteId = PageState.Site.SiteId; module.SiteId = PageState.Page.SiteId;
module.PageId = PageState.Page.PageId; module.PageId = PageState.Page.PageId;
module.AllPages = false; module.AllPages = false;
module.PermissionList = GenerateDefaultPermissions(module.SiteId); module.PermissionList = GenerateDefaultPermissions(module.SiteId);
@ -509,11 +485,11 @@
case "publish": case "publish":
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone)) if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Everyone))
{ {
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true)); permissions.Add(new Permission(PageState.Page.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Everyone, null, true));
} }
if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered)) if (!permissions.Any(item => item.PermissionName == PermissionNames.View && item.RoleName == RoleNames.Registered))
{ {
permissions.Add(new Permission(PageState.Site.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true)); permissions.Add(new Permission(PageState.Page.SiteId, EntityNames.Page, PageState.Page.PageId, PermissionNames.View, RoleNames.Registered, null, true));
} }
break; break;
case "unpublish": case "unpublish":

View File

@ -0,0 +1,19 @@
using System.Collections.Generic;
using System;
using Oqtane.Models;
using Oqtane.UI;
namespace Oqtane.Themes.Controls
{
public class ControlPanelPageState
{
public Alias Alias { get; set; }
public Site Site { get; set; }
public Page Page { get; set; }
public User User { get; set; }
public Uri Uri { get; set; }
public Route Route { get; set; }
public string RenderMode { get; set; }
public Shared.Runtime Runtime { get; set; }
}
}

View File

@ -15,9 +15,6 @@
} }
@code { @code {
// this component is on the static side of the render mode boundary
// it passes state as serializable parameters across the boundary
[CascadingParameter] [CascadingParameter]
protected PageState PageState { get; set; } protected PageState PageState { get; set; }
@ -30,6 +27,7 @@
protected override void OnParametersSet() protected override void OnParametersSet()
{ {
_prerender = ModuleState.Prerender ?? PageState.Site.Prerender; _prerender = ModuleState.Prerender ?? PageState.Site.Prerender;
_comment = "<!-- rendermode: "; _comment = "<!-- rendermode: ";
if (PageState.RenderMode == RenderModes.Static && ModuleState.RenderMode == RenderModes.Static) if (PageState.RenderMode == RenderModes.Static && ModuleState.RenderMode == RenderModes.Static)
{ {
@ -40,6 +38,13 @@
_comment += $"{RenderModes.Interactive}:{PageState.Runtime} - prerender: {_prerender}"; _comment += $"{RenderModes.Interactive}:{PageState.Runtime} - prerender: {_prerender}";
} }
_comment += " -->"; _comment += " -->";
if (PageState.RenderMode != RenderModes.Static || ModuleState.RenderMode != RenderModes.Static)
{
// trim PageState to mitigate page bloat caused by Blazor serializing/encrypting state when crossing render mode boundaries
// please note that this performance optimization results in the PageState.Pages property not being available for use in Interactive components
PageState.Site.Pages = new List<Page>();
}
} }

View File

@ -20,7 +20,6 @@ namespace Oqtane.Services
private readonly IUserPermissions _userPermissions; private readonly IUserPermissions _userPermissions;
private readonly IHttpContextAccessor _accessor; private readonly IHttpContextAccessor _accessor;
public SearchService( public SearchService(
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
ISettingRepository settingRepository, ISettingRepository settingRepository,