Merge pull request #2 from oqtane/master

Rebase
This commit is contained in:
Sean Long 2020-04-29 20:28:27 -04:00 committed by GitHub
commit dec6658047
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 453 additions and 352 deletions

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2019 .NET Foundation
Copyright (c) 2018-2020 .NET Foundation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -12,9 +12,9 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0-preview3.20168.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0-preview3.20168.3" PrivateAssets="all" />
<PackageReference Include="System.Net.Http.Json" Version="3.2.0-preview3.20175.8" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0-preview5.20216.8" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0-preview5.20216.8" PrivateAssets="all" />
<PackageReference Include="System.Net.Http.Json" Version="3.2.0-preview5.20210.3" />
</ItemGroup>
<ItemGroup>

View File

@ -23,7 +23,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.0-preview3.20168.3" />
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.0-preview5.20216.8" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.2" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="3.1.2" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.2" />

View File

@ -1,14 +1,27 @@
@namespace Oqtane.Themes.BlazorTheme
@inherits ThemeBase
<div class="breadcrumbs">
<Breadcrumbs />
</div>
<div class="sidebar">
<div align="center"><Logo /></div>
<Menu Orientation="Vertical" />
<nav class="navbar">
<Logo />
<button class="navbar-toggler" aria-expanded="false" aria-controls="navbarSupportedContent"
aria-label="Toggle navigation" type="button" data-toggle="collapse"
data-target="#navbarSupportedContent">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<Menu Orientation="Vertical" />
</div>
</nav>
</div>
<div class="main">
<div class="top-row px-4">
<Breadcrumbs /> <div class="ml-md-auto"><UserProfile /> <Login /> <ControlPanel /></div>
<div class="ml-md-auto"><UserProfile /> <Login /> <ControlPanel /></div>
</div>
<div class="container">
<div class="row px-4">

View File

@ -1,32 +1,34 @@
@namespace Oqtane.Themes.Controls
@inherits ThemeControlBase
@if (breadcrumbs != string.Empty)
@if (BreadCrumbPages.Any())
{
@((MarkupString)breadcrumbs)
<ol class="breadcrumb">
@foreach (var p in BreadCrumbPages)
{
<li class="breadcrumb-item @ActiveClass(p)">
<a href="@NavigateUrl(p.Path)">@p.Name</a>
</li>
}
</ol>
}
@code {
string breadcrumbs = string.Empty;
protected override void OnParametersSet()
protected IEnumerable<Page> BreadCrumbPages => GetBreadCrumbPages().Reverse().ToList();
protected string ActiveClass(Page page)
{
breadcrumbs = string.Empty;
int? pageid = PageState.Page.PageId;
for (int i = PageState.Pages.Count - 1; i >= 0; i--)
return (page.PageId == PageState.Page.PageId) ? " active" : string.Empty;
}
private IEnumerable<Page> GetBreadCrumbPages()
{
var page = PageState.Page;
do
{
var p = PageState.Pages[i];
if (p.PageId == pageid)
{
breadcrumbs = "<li class=\"breadcrumb-item" + ((p.PageId == PageState.Page.PageId) ? " active" : string.Empty) +
"\"><a href=\"" + NavigateUrl(p.Path) + "\">" + p.Name + "</a></li>" + breadcrumbs;
pageid = p.ParentId;
}
}
if (breadcrumbs != "")
{
breadcrumbs = "<ol class=\"breadcrumb\">" + breadcrumbs + "</ol>";
}
yield return page;
page = PageState.Pages.FirstOrDefault(p => page != null && p.PageId == page.ParentId);
} while (page != null);
}
}

View File

@ -1,9 +1,5 @@
@namespace Oqtane.Themes.Controls
@inherits ThemeControlBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IJSRuntime jsRuntime
@inject IServiceProvider ServiceProvider
@inherits LoginBase
<AuthorizeView>
<Authorizing>
@ -16,38 +12,3 @@
<button type="button" class="btn btn-primary" @onclick="LoginUser">Login</button>
</NotAuthorized>
</AuthorizeView>
@code {
private void LoginUser()
{
var returnurl = PageState.Alias.Path;
if (PageState.Page.Path != "/")
{
returnurl += "/" + PageState.Page.Path;
}
NavigationManager.NavigateTo(NavigateUrl("login", "returnurl=" + returnurl));
}
private async Task LogoutUser()
{
await UserService.LogoutUserAsync(PageState.User);
if (PageState.Runtime == Runtime.Server)
{
// server-side Blazor
var interop = new Interop(jsRuntime);
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
var fields = new { __RequestVerificationToken = antiforgerytoken, returnurl = (PageState.Alias.Path + "/" + PageState.Page.Path) };
await interop.SubmitForm("/pages/logout/", fields);
}
else
{
// client-side Blazor
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
authstateprovider.NotifyAuthenticationChanged();
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "reload"));
}
}
}

View File

@ -0,0 +1,49 @@
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Oqtane.Providers;
using Oqtane.Services;
using Oqtane.UI;
namespace Oqtane.Themes.Controls
{
public class LoginBase : ThemeControlBase
{
[Inject] public NavigationManager NavigationManager {get;set;}
[Inject]public IUserService UserService {get;set;}
[Inject]public IJSRuntime jsRuntime {get;set;}
[Inject]public IServiceProvider ServiceProvider {get;set;}
protected void LoginUser()
{
var returnurl = PageState.Alias.Path;
if (PageState.Page.Path != "/")
{
returnurl += "/" + PageState.Page.Path;
}
NavigationManager.NavigateTo(NavigateUrl("login", "returnurl=" + returnurl));
}
protected async Task LogoutUser()
{
await UserService.LogoutUserAsync(PageState.User);
if (PageState.Runtime == Runtime.Server)
{
// server-side Blazor
var interop = new Interop(jsRuntime);
string antiforgerytoken = await interop.GetElementByName("__RequestVerificationToken");
var fields = new { __RequestVerificationToken = antiforgerytoken, returnurl = (PageState.Alias.Path + "/" + PageState.Page.Path) };
await interop.SubmitForm("/pages/logout/", fields);
}
else
{
// client-side Blazor
var authstateprovider = (IdentityAuthenticationStateProvider)ServiceProvider.GetService(typeof(IdentityAuthenticationStateProvider));
authstateprovider.NotifyAuthenticationChanged();
NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, "reload"));
}
}
}
}

View File

@ -2,17 +2,20 @@
@inherits ThemeControlBase
@inject NavigationManager NavigationManager
@((MarkupString)logo)
@if (PageState.Site.LogoFileId != null)
{
<a href="@Href">
<img class="img-fluid" src="@ContentUrl(PageState.Site.LogoFileId.Value)" alt="@PageState.Site.Name"/>
</a>
}
@code {
string logo = "";
protected override void OnParametersSet()
string Href
{
if (PageState.Site.LogoFileId != null)
get
{
var uri = new Uri(NavigationManager.Uri);
logo = "<a href=\"" + uri.Scheme + "://" + uri.Authority + "\"><img src=\"" + ContentUrl(PageState.Site.LogoFileId.Value) + "\" alt=\"" + PageState.Site.Name + "\"/></a>";
return $"{uri.Scheme}://{uri.Authority}";
}
}
}
}

View File

@ -1,133 +1,20 @@
@namespace Oqtane.Themes.Controls
@inherits ThemeControlBase
@if (menu != string.Empty)
@switch (Orientation)
{
<div class="app-menu">
@((MarkupString)menu)
</div>
case "Horizontal":
<MenuHorizontal/>
break;
default: // Vertical
{
<MenuVertical/>
break;
}
}
@code {
private string menu = string.Empty;
@code{
[Parameter]
public string Orientation { get; set; }
protected override void OnParametersSet()
{
switch (Orientation)
{
case "Horizontal":
CreateHorizontalMenu();
break;
default: // Vertical
CreateVerticalMenu();
break;
}
}
private void CreateVerticalMenu()
{
var level = -1;
var securitylevel = int.MaxValue;
menu = "<ul class=\"nav flex-column\">\n";
foreach (Page p in PageState.Pages.Where(item => item.IsNavigation && !item.IsDeleted))
{
if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, p.Permissions) && p.Level <= securitylevel)
{
securitylevel = int.MaxValue;
menu += "<li class=\"nav-item px-3\">";
if (string.IsNullOrEmpty(p.Url))
{
menu += "<a href=\"" + NavigateUrl(p.Path) + "\" class=\"nav-link\" style=\"padding-left: " + ((p.Level + 1) * 15).ToString() + "px !important;\">";
}
else
{
string target = String.Empty;
if (p.Url.StartsWith("http"))
{
target = " target=\"_new\"";
}
menu += "<a href=\"" + p.Url + "\" class=\"nav-link\" style=\"padding-left: " + ((p.Level + 1) * 15).ToString() + "px !important;\"" + target + ">";
}
if (p.HasChildren)
{
menu += "<i class=\"oi oi-chevron-right\"></i>";
}
if (p.Icon != string.Empty)
{
menu += "<span class=\"oi oi-" + p.Icon + "\" aria-hidden=\"true\"></span>";
}
menu += p.Name;
menu += "</a>\n";
menu += "</li>\n";
level = p.Level;
}
else
{
if (securitylevel == int.MaxValue)
{
securitylevel = p.Level;
}
}
}
menu += "</ul>";
}
private void CreateHorizontalMenu()
{
var url = String.Empty;
var target = String.Empty;
menu = "<button class=\"navbar-toggler\" type=\"button\" data-toggle=\"collapse\" data-target=\"#Menu\" aria-controls=\"Menu\" aria-expanded=\"false\" aria-label=\"Toggle navigation\"><span class=\"navbar-toggler-icon\"></span></button>";
menu += "<div class=\"collapse navbar-collapse\" id=\"Menu\">";
menu += "<ul class=\"navbar-nav mr-auto\">";
foreach (Page p in PageState.Pages.Where(item => item.IsNavigation && !item.IsDeleted))
{
if (UserSecurity.IsAuthorized(PageState.User,PermissionNames.View, p.Permissions) && p.ParentId == PageState.Page.ParentId && p.Level == PageState.Page.Level)
{
if (string.IsNullOrEmpty(p.Url))
{
url = NavigateUrl(p.Path);
target = String.Empty;
}
else
{
url = p.Url;
if (p.Url.StartsWith("http"))
{
target = " target=\"_new\"";
}
}
if (p.PageId == PageState.Page.PageId)
{
menu += "<li class=\"nav-item active\">" +
"<a class=\"nav-link\" href=\"" + NavigateUrl(p.Path) + "\">" +
((p.Icon != string.Empty) ? "<span class=\"oi oi-" + p.Icon + "\" aria-hidden=\"true\"></span> " : string.Empty) +
p.Name + " <span class=\"sr-only\">(current)</span></a></li>";
}
else
{
menu += "<li class=\"nav-item\">" +
"<a class=\"nav-link\" href=\"" + NavigateUrl(p.Path) + "\">" +
((p.Icon != string.Empty) ? "<span class=\"oi oi-" + p.Icon + "\" aria-hidden=\"true\"></span> " : string.Empty) +
p.Name + "</a></li>";
}
}
}
menu += "</ul>";
menu += "</div>";
}
}

View File

@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.Linq;
using Oqtane.Models;
using Oqtane.Security;
using Oqtane.Shared;
namespace Oqtane.Themes.Controls
{
public class MenuBase : ThemeControlBase
{
protected IEnumerable<Page> MenuPages => GetMenuPages().ToList();
protected string GetTarget(Page page)
{
return page.Url != null && page.Url.StartsWith("http") ? "_new" : string.Empty;
}
protected string GetUrl(Page page)
{
return string.IsNullOrEmpty(page.Url) ? NavigateUrl(page.Path) : page.Url;
}
private IEnumerable<Page> GetMenuPages()
{
var securityLevel = int.MaxValue;
foreach (Page p in PageState.Pages.Where(item => item.IsNavigation && !item.IsDeleted))
{
if (p.Level <= securityLevel && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions))
{
securityLevel = int.MaxValue;
yield return p;
}
else
{
if (securityLevel == int.MaxValue)
{
securityLevel = p.Level;
}
}
}
}
}
}

View File

@ -0,0 +1,42 @@
@namespace Oqtane.Themes.Controls
@inherits MenuBase
@if (MenuPages.Any())
{
<div class="app-menu">
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#Menu" aria-controls="Menu" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="Menu">
<ul class="navbar-nav mr-auto">
@foreach (var p in MenuPages)
{
if (p.PageId == PageState.Page.PageId)
{
<li class="nav-item active">
<a class="nav-link" href="@NavigateUrl(p.Path)">
@if (p.Icon != string.Empty)
{
<span class="oi oi-@p.Icon" aria-hidden="true"></span>
}
@p.Name<span class="sr-only">(current)</span>
</a>
</li>
}
else
{
<li class="nav-item">
<a class="nav-link" href="@NavigateUrl(p.Path)">
@if (p.Icon != string.Empty)
{
<span class="oi oi-@p.Icon" aria-hidden="true"></span>
}
@p.Name
</a>
</li>
}
}
</ul>
</div>
</div>
}

View File

@ -0,0 +1,27 @@
@namespace Oqtane.Themes.Controls
@inherits MenuBase
@if (MenuPages.Any())
{
<div class="app-menu">
<ul class="nav flex-column">
@foreach (var p in MenuPages)
{
<li class="nav-item px-3">
<a href="@GetUrl(p)" class="nav-link" style="padding-left:@((p.Level + 1) * 15)px !important;" target="@GetTarget(p)">
@if (p.HasChildren)
{
<i class="oi oi-chevron-right"></i>
}
@if (p.Icon != string.Empty)
{
<span class="oi oi-@p.Icon" aria-hidden="true"></span>
}
@p.Name
</a>
</li>
}
</ul>
</div>
}

View File

@ -1,135 +1,20 @@
@namespace Oqtane.Themes.Controls
@inherits ContainerBase
@inject NavigationManager NavigationManager
@inject IUserService UserService
@inject IPageModuleService PageModuleService
@inherits ModuleActionsBase
@if (PageState.EditMode && !PageState.Page.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions))
{
<a class="nav-link dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"></a>
<div class="dropdown-menu" x-placement="bottom-start" style="position: absolute; will-change: transform; top: 0px; left: 0px; transform: translate3d(0px, 37px, 0px);">
@foreach (var action in actions)
@foreach (var action in Actions)
{
if (action.Action != "")
if (string.IsNullOrEmpty(action.Name))
{
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action.Action))">@action.Name</a>
<div class="dropdown-divider"></div>
}
else
{
<div class="dropdown-divider"></div>
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action))">@action.Name</a>
}
}
</div>
}
@code {
private List<ActionViewModel> actions;
protected override void OnParametersSet()
{
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions))
{
actions = new List<ActionViewModel>();
actions.Add(new ActionViewModel { Action = "settings", Name = "Manage Settings" });
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.ServerManagerType != "")
{
actions.Add(new ActionViewModel { Action = "import", Name = "Import Content" });
actions.Add(new ActionViewModel { Action = "export", Name = "Export Content" });
}
actions.Add(new ActionViewModel { Action = "delete", Name = "Delete Module" });
actions.Add(new ActionViewModel { Action = "", Name = "" });
if (ModuleState.PaneModuleIndex > 0)
{
actions.Add(new ActionViewModel { Action = "<<", Name = "Move To Top" });
}
if (ModuleState.PaneModuleIndex > 0)
{
actions.Add(new ActionViewModel { Action = "<", Name = "Move Up" });
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actions.Add(new ActionViewModel { Action = ">", Name = "Move Down" });
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actions.Add(new ActionViewModel { Action = ">>", Name = "Move To Bottom" });
}
foreach (string pane in PageState.Page.Panes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
{
if (pane != ModuleState.Pane)
{
actions.Add(new ActionViewModel { Action = pane, Name = "Move To " + pane + " Pane" });
}
}
}
}
protected async Task ModuleAction(string action)
{
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User,PermissionNames.Edit, ModuleState.Permissions))
{
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
string url = NavigateUrl();
switch (action)
{
case "<<":
pagemodule.Order = 0;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
case "<":
pagemodule.Order -= 3;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
case ">":
pagemodule.Order += 3;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
case ">>":
pagemodule.Order = int.MaxValue;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
case "settings":
url = EditUrl(pagemodule.ModuleId, "Settings");
break;
case "import":
url = EditUrl(pagemodule.ModuleId, "Import");
break;
case "export":
url = EditUrl(pagemodule.ModuleId, "Export");
break;
case "delete":
pagemodule.IsDeleted = true;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
break;
default: // move to pane
string pane = pagemodule.Pane;
pagemodule.Pane = action;
pagemodule.Order = int.MaxValue; // add to bottom of pane
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pane);
break;
}
NavigationManager.NavigateTo(url);
}
}
public class ActionViewModel
{
public string Action { set; get; }
public string Name { set; get; }
}
}

View File

@ -0,0 +1,164 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Oqtane.Models;
using Oqtane.Security;
using Oqtane.Services;
using Oqtane.Shared;
// ReSharper disable UnassignedGetOnlyAutoProperty
// ReSharper disable MemberCanBePrivate.Global
namespace Oqtane.Themes.Controls
{
public class ModuleActionsBase : ContainerBase
{
[Inject] public NavigationManager NavigationManager { get; set; }
[Inject] public IPageModuleService PageModuleService { get; set; }
protected List<ActionViewModel> Actions;
protected override void OnParametersSet()
{
Actions = GetActions();
}
protected virtual List<ActionViewModel> GetActions()
{
var actionList = new List<ActionViewModel>();
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions))
{
actionList.Add(new ActionViewModel {Name = "Manage Settings", Action = async (u, m) => await Settings(u, m)});
if (ModuleState.ModuleDefinition != null && ModuleState.ModuleDefinition.ServerManagerType != "")
{
actionList.Add(new ActionViewModel {Name = "Import Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Import")});
actionList.Add(new ActionViewModel {Name = "Export Content", Action = async (u, m) => await EditUrlAsync(u, m.ModuleId, "Export")});
}
actionList.Add(new ActionViewModel {Name = "Delete Module", Action = async (u, m) => await DeleteModule(u, m)});
actionList.Add(new ActionViewModel {Name = ""});
if (ModuleState.PaneModuleIndex > 0)
{
actionList.Add(new ActionViewModel {Name = "Move To Top", Action = async (s, m) => await MoveTop(s, m)});
}
if (ModuleState.PaneModuleIndex > 0)
{
actionList.Add(new ActionViewModel {Name = "Move Up", Action = async (s, m) => await MoveUp(s, m)});
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actionList.Add(new ActionViewModel {Name = "Move Down", Action = async (s, m) => await MoveDown(s, m)});
}
if (ModuleState.PaneModuleIndex < (ModuleState.PaneModuleCount - 1))
{
actionList.Add(new ActionViewModel {Name = "Move To Bottom", Action = async (s, m) => await MoveBottom(s, m)});
}
foreach (string pane in PageState.Page.Panes.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries))
{
if (pane != ModuleState.Pane)
{
actionList.Add(new ActionViewModel {Name = "Move To " + pane + " Pane", Action = async (s, m) => await MoveToPane(s, pane, m)});
}
}
}
return actionList;
}
private async Task<string> EditUrlAsync(string url, int moduleId, string import)
{
await Task.Yield();
EditUrl(moduleId, import);
return url;
}
protected async Task ModuleAction(ActionViewModel action)
{
if (PageState.EditMode && UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, ModuleState.Permissions))
{
PageModule pagemodule = await PageModuleService.GetPageModuleAsync(ModuleState.PageModuleId);
string url = NavigateUrl();
if (action.Action != null)
{
url = await action.Action(url, pagemodule);
}
NavigationManager.NavigateTo(url);
}
}
private async Task<string> MoveToPane(string url, string newPane, PageModule pagemodule)
{
string oldPane = pagemodule.Pane;
pagemodule.Pane = newPane;
pagemodule.Order = int.MaxValue; // add to bottom of pane
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, oldPane);
return url;
}
private async Task<string> DeleteModule(string url, PageModule pagemodule)
{
pagemodule.IsDeleted = true;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return url;
}
private async Task<string> Settings(string url, PageModule pagemodule)
{
await Task.Yield();
url = EditUrl(pagemodule.ModuleId, "Settings");
return url;
}
private async Task<string> MoveTop(string s, PageModule pagemodule)
{
pagemodule.Order = 0;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return s;
}
private async Task<string> MoveBottom(string s, PageModule pagemodule)
{
pagemodule.Order = int.MaxValue;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return s;
}
private async Task<string> MoveUp(string s, PageModule pagemodule)
{
pagemodule.Order -= 3;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return s;
}
private async Task<string> MoveDown(string s, PageModule pagemodule)
{
pagemodule.Order += 3;
await PageModuleService.UpdatePageModuleAsync(pagemodule);
await PageModuleService.UpdatePageModuleOrderAsync(pagemodule.PageId, pagemodule.Pane);
return s;
}
public class ActionViewModel
{
public string Name { set; get; }
public Func<string, PageModule, Task<string>> Action { set; get; }
}
}
}

View File

@ -179,31 +179,8 @@
};
var installation = await InstallationService.Install(config);
//TODO: Should be moved to Database manager
if (installation.Success)
{
Site site = new Site();
site.TenantId = -1; // will be populated on server
site.Name = "Default Site";
site.LogoFileId = null;
site.FaviconFileId = null;
site.DefaultThemeType = Constants.DefaultTheme;
site.DefaultLayoutType = Constants.DefaultLayout;
site.DefaultContainerType = Constants.DefaultContainer;
site.PwaIsEnabled = false;
site.PwaAppIconFileId = null;
site.PwaSplashIconFileId = null;
site.AllowRegistration = false;
site = await SiteService.AddSiteAsync(site, null);
User user = new User();
user.SiteId = site.SiteId;
user.Username = _hostUsername;
user.Password = _hostPassword;
user.Email = _hostEmail;
user.DisplayName = _hostUsername;
user = await UserService.AddUserAsync(user);
NavigationManager.NavigateTo("", true);
}
else

View File

@ -44,6 +44,7 @@ namespace Oqtane.Controllers
_config.Reload();
}
_databaseManager.BuildDefaultSite(config.Password, config.HostEmail);
installation.Success = true;
return installation;
}

View File

@ -130,10 +130,6 @@ namespace Oqtane.Controllers
System.IO.File.Delete(file);
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Assembly Removed {Filename}", file);
}
// clean up module schema versions
_sql.ExecuteNonQuery(tenant, "DELETE FROM [dbo].[SchemaVersions] WHERE ScriptName LIKE '" + assemblyname + "%'");
_logger.Log(LogLevel.Information, this, LogFunction.Delete, "Module Schema Versions Removed For {AssemblyName}", assemblyname);
}
// remove module definition

View File

@ -315,7 +315,7 @@ namespace Oqtane.Infrastructure
}
}
private void BuildDefaultSite(string password, string email)
public void BuildDefaultSite(string password, string email)
{
using (var scope = _serviceScopeFactory.CreateScope())
{

View File

@ -1,4 +1,8 @@

.breadcrumbs {
background-color: #e6e6e6;
border-bottom: 1px solid #d6d5d5;
}
.top-row {
height: 3.5rem;
display: flex;
@ -12,6 +16,7 @@
.main .top-row {
background-color: #e6e6e6;
border-bottom: 1px solid #d6d5d5;
z-index: 9999;
}
.sidebar {
@ -22,8 +27,8 @@
background-color: rgba(0,0,0,0.4);
}
.sidebar .navbar-brand {
font-size: 1.1rem;
.sidebar .navbar-toggler .navbar-toggler-icon {
background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e");
}
.sidebar .oi {
@ -33,6 +38,10 @@
top: -2px;
}
.breadcrumb {
margin-bottom: 0;
}
.app-menu .nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
@ -84,6 +93,13 @@
flex-direction: row;
}
.breadcrumbs {
position: fixed;
left: 275px;
top: 0;
z-index: 1;
}
.sidebar {
width: 250px;
height: 100vh;
@ -94,7 +110,6 @@
.main .top-row {
position: sticky;
top: 0;
z-index: 9999;
}
.main > div {
@ -110,6 +125,10 @@
/* Never collapse the sidebar for wide screens */
display: block;
}
.main > .container {
margin-top: 30px;
}
}
@-webkit-keyframes sk-stretchdelay {
@ -133,3 +152,35 @@
-webkit-transform: scaleY(1.0);
}
}
@media (max-width: 767px) {
.sidebar {
margin-top: 3.5rem;
position: fixed;
width: 100%;
}
.main > .top-row.px-4 {
display: flex;
position: fixed;
left: 0;
top: 0;
width: 100%;
}
.ml-md-auto {
margin-left: auto;
}
.breadcrumbs {
position: fixed;
top: 150px;
width: 100%;
left: 0;
}
.main > .container {
margin-top: 200px;
}
}

View File

@ -9,7 +9,7 @@ Please note that this project is governed by the **[.NET Foundation Contributor
**To get started with Oqtane:**
1.&nbsp;Install **[.NET Core 3.2 Preview4 SDK (v3.1.201)](https://dotnet.microsoft.com/download/dotnet-core/3.1)**.
1.&nbsp;Install **[.NET Core 3.2 Preview5 SDK (v3.1.201)](https://dotnet.microsoft.com/download/dotnet-core/3.1)**.
2.&nbsp;Install the Preview edition of [Visual Studio 2019](https://visualstudio.microsoft.com/vs/preview/) (version 16.6 or higher) with the **ASP.NET and web development** workload. If you do not have a SQL Server installation available already and you wish to use LocalDB for development, you must also install the **.NET desktop development workload**.