Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Route parsing abstraction and optimization, site router performance improvements, migrate site-based concepts (favicon, PWA support) to server for performance and prerendering benefits, move ThemeBuilder interop logic to OnAfterRenderAsync, upgrade SqlClient to release version, update installer to Bootstrap 5.1.3 #1840

Merged
merged 1 commit into from
Dec 1, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Oqtane.Client/Installer/Installer.razor
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@
if (firstRender)
{
var interop = new Interop(JSRuntime);
await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/css/bootstrap.min.css", "text/css", "sha512-usVBAd66/NpVNfBge19gws2j6JZinnca12rAe2l+d+QkLU9fiG02O1X8Q6hepIpr/EYKZvKx/I9WsnujJuOmBA==", "anonymous", "");
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.0.2/js/bootstrap.min.js", "sha512-a6ctI6w1kg3J4dSjknHj3aWLEbjitAXAjLDRUxo2wyYmDFRcz2RJuQr5M3Kt8O/TtUSp8n2rAyaXYy1sjoKmrQ==", "anonymous", "", "head", "");
await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css", "text/css", "sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==", "anonymous", "");
await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js", "sha512-pax4MlgXjHEPfCwcJLQhigY7+N8rt6bVvWLFyUMuxShv170X53TRzGPmPkZmGBhk+jikR8WBM4yl7A9WMHHqvg==", "anonymous", "", "head", "");
}
}

Expand Down
2 changes: 1 addition & 1 deletion Oqtane.Client/Modules/Admin/Pages/Edit.razor
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@
<td><ActionLink Action="Settings" Text="Edit" ModuleId="@context.ModuleId" Security="SecurityAccessLevel.Edit" Permissions="@context.Permissions" ResourceKey="ModuleSettings" /></td>
<td><ActionDialog Header="Delete Module" Message="Are You Sure You Wish To Delete This Module?" Action="Delete" Security="SecurityAccessLevel.Edit" Permissions="@context.Permissions" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" /></td>
<td>@context.Title</td>
<td>@context.ModuleDefinition.Name</td>
<td>@context.ModuleDefinition?.Name</td>
</Row>
</Pager>
}
Expand Down
216 changes: 73 additions & 143 deletions Oqtane.Client/UI/SiteRouter.razor
Original file line number Diff line number Diff line change
Expand Up @@ -15,78 +15,72 @@
@DynamicComponent

@code {
private string _absoluteUri;
private bool _navigationInterceptionEnabled;
private PageState _pagestate;

[Parameter]
public string Runtime { get; set; }

[Parameter]
public string RenderMode { get; set; }

[CascadingParameter]
PageState PageState { get; set; }

[Parameter]
public Action<PageState> OnStateChange { get; set; }

private RenderFragment DynamicComponent { get; set; }

protected override void OnInitialized()
{
_absoluteUri = NavigationManager.Uri;
NavigationManager.LocationChanged += LocationChanged;

DynamicComponent = builder =>
{
if (PageState != null)
{
builder.OpenComponent(0, Type.GetType(Constants.PageComponent));
builder.CloseComponent();
}
};
}

public void Dispose()
{
NavigationManager.LocationChanged -= LocationChanged;
}

protected override async Task OnParametersSetAsync()
{
if (PageState == null)
{
await Refresh();
}
}

[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
private async Task Refresh()
{
Site site;
List<Page> pages;
Page page;
User user = null;
List<Module> modules;
var moduleid = -1;
var action = Constants.DefaultAction;
var urlparameters = string.Empty;
var editmode = false;
var refresh = UI.Refresh.None;
var lastsyncdate = DateTime.UtcNow.AddHours(-1);
var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime);

Uri uri = new Uri(_absoluteUri);

// get path
var path = uri.LocalPath.Substring(1);

// parse querystring
var querystring = ParseQueryString(uri.Query);
private string _absoluteUri;
private bool _navigationInterceptionEnabled;
private PageState _pagestate;

[Parameter]
public string Runtime { get; set; }

[Parameter]
public string RenderMode { get; set; }

[CascadingParameter]
PageState PageState { get; set; }

[Parameter]
public Action<PageState> OnStateChange { get; set; }

private RenderFragment DynamicComponent { get; set; }

protected override void OnInitialized()
{
_absoluteUri = NavigationManager.Uri;
NavigationManager.LocationChanged += LocationChanged;

DynamicComponent = builder =>
{
if (PageState != null)
{
builder.OpenComponent(0, Type.GetType(Constants.PageComponent));
builder.CloseComponent();
}
};
}

public void Dispose()
{
NavigationManager.LocationChanged -= LocationChanged;
}

protected override async Task OnParametersSetAsync()
{
if (PageState == null)
{
await Refresh();
}
}

[SuppressMessage("ReSharper", "StringIndexOfIsCultureSpecific.1")]
private async Task Refresh()
{
Site site;
List<Page> pages;
Page page;
User user = null;
List<Module> modules;
var editmode = false;
var refresh = UI.Refresh.None;
var lastsyncdate = DateTime.UtcNow.AddHours(-1);
var runtime = (Shared.Runtime)Enum.Parse(typeof(Shared.Runtime), Runtime);

Route route = new Route(_absoluteUri, SiteState.Alias.Path);
var moduleid = (int.TryParse(route.ModuleId, out int mid)) ? mid : -1;
var action = (!string.IsNullOrEmpty(route.Action)) ? route.Action : Constants.DefaultAction;
var querystring = ParseQueryString(route.Query);

// reload the client application if there is a forced reload or the user navigated to a site with a different alias
if (querystring.ContainsKey("reload") || (!path.ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
if (querystring.ContainsKey("reload") || (!route.AbsolutePath.Substring(1).ToLower().StartsWith(SiteState.Alias.Path.ToLower()) && !string.IsNullOrEmpty(SiteState.Alias.Path)))
{
NavigationManager.NavigateTo(_absoluteUri.Replace("?reload", ""), true);
return;
Expand Down Expand Up @@ -168,87 +162,23 @@
pages = PageState.Pages;
}

// format path and remove alias
path = path.Replace("//", "/"); // in case of doubleslash at end
path += (!path.EndsWith("/")) ? "/" : "";
if (SiteState.Alias.Path != "" && path.StartsWith(SiteState.Alias.Path))
{
path = path.Substring(SiteState.Alias.Path.Length + 1);
}

// extract admin route elements from path
var segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
int result;

int modIdPos = 0;
int actionPos = 0;
int urlParametersPos = 0;

for (int i = 0; i < segments.Length; i++)
{

if (segments[i] == Constants.UrlParametersDelimiter)
{
urlParametersPos = i + 1;
}

if (i >= urlParametersPos && urlParametersPos != 0)
{
urlparameters += "/" + segments[i];
}

if (segments[i] == Constants.ModuleDelimiter)
{
modIdPos = i + 1;
actionPos = modIdPos + 1;
if (actionPos <= segments.Length - 1)
{
action = segments[actionPos];
}
}
}

// check if path has moduleid and action specification ie. pagename/*/moduleid/action/
if (modIdPos > 0)
{
int.TryParse(segments[modIdPos], out result);
moduleid = result;
if (actionPos > segments.Length - 1)
{
path = path.Replace(segments[modIdPos - 1] + "/" + segments[modIdPos] + "/", "");
}
else
{
path = path.Replace(segments[modIdPos - 1] + "/" + segments[modIdPos] + "/" + segments[actionPos] + "/", "");
}
}

if (urlParametersPos > 0)
{
path = path.Replace(segments[urlParametersPos - 1] + urlparameters + "/", "");
}

// remove trailing slash so it can be used as a key for Pages
if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1);

if (PageState == null || refresh == UI.Refresh.Site)
{
page = pages.FirstOrDefault(item => item.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
}
else
{
page = PageState.Page;
}

// get the page if the path has changed
if (page == null || page.Path != path)
if (page == null || page.Path != route.PagePath)
{
page = pages.FirstOrDefault(item => item.Path.Equals(path, StringComparison.OrdinalIgnoreCase));
// if the home page path does not exist then use the first page in the collection (a future enhancement would allow the admin to specify a home page)
if (page == null && path == "")
page = pages.FirstOrDefault(item => item.Path.Equals(route.PagePath, StringComparison.OrdinalIgnoreCase));
// if the home page path does not exist then use the first page in the collection (a future enhancement would allow the admin to specify the home page)
if (page == null && route.PagePath == "")
{
page = pages.FirstOrDefault();
path = page.Path;
}
editmode = false;
}
Expand Down Expand Up @@ -286,7 +216,7 @@
Modules = modules,
Uri = new Uri(_absoluteUri, UriKind.Absolute),
QueryString = querystring,
UrlParameters = urlparameters,
UrlParameters = route.UrlParameters,
ModuleId = moduleid,
Action = action,
EditMode = editmode,
Expand All @@ -302,12 +232,12 @@
if (user == null)
{
// redirect to login page
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + path));
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "login", "?returnurl=" + route.AbsolutePath));
}
else
{
await LogService.Log(null, null, user.UserId, GetType().AssemblyQualifiedName, Utilities.GetTypeNameLastSegment(GetType().AssemblyQualifiedName, 1), LogFunction.Security, LogLevel.Error, null, "Page Does Not Exist Or User Is Not Authorized To View Page {Path}", path);
if (path != "")
await LogService.Log(null, null, user.UserId, GetType().AssemblyQualifiedName, Utilities.GetTypeNameLastSegment(GetType().AssemblyQualifiedName, 1), LogFunction.Security, LogLevel.Error, null, "Page Does Not Exist Or User Is Not Authorized To View Page {Path}", route.PagePath);
if (route.PagePath != "")
{
// redirect to home page
NavigationManager.NavigateTo(Utilities.NavigateUrl(SiteState.Alias.Path, "", ""));
Expand Down
Loading