User experience improvements

This commit is contained in:
Shaun Walker 2021-04-17 19:18:24 -04:00
parent 1d3a79437c
commit cbe843bafc
84 changed files with 1020 additions and 710 deletions

View File

@ -100,7 +100,7 @@ else
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
protected override async Task OnParametersSetAsync()
{
try
{
@ -160,8 +160,7 @@ else
Module module = await ModuleService.GetModuleAsync(ModuleState.ModuleId);
module.ModuleDefinitionName = _moduledefinitionname;
await ModuleService.UpdateModuleAsync(module);
ClearModuleMessage();
NavigationManager.NavigateTo(NavigateUrl());
NavigationManager.NavigateTo(NavigateUrl(), true);
}
}
catch (Exception ex)

View File

@ -0,0 +1,158 @@
@namespace Oqtane.Modules.Admin.ModuleDefinitions
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IModuleDefinitionService ModuleDefinitionService
@inject IModuleService ModuleService
@inject ISystemService SystemService
@inject ISettingService SettingService
@inject IStringLocalizer<Index> Localizer
@using System.Text.RegularExpressions
@using System.IO;
@if (_systeminfo != null && _templates != null)
{
<table class="table table-borderless">
<tr>
<td>
<Label For="owner" HelpText="Enter the name of the organization who is developing this module. It should not contain spaces or punctuation." ResourceKey="OwnerName">Owner Name: </Label>
</td>
<td>
<input id="owner" class="form-control" @bind="@_owner" />
</td>
</tr>
<tr>
<td>
<Label For="module" HelpText="Enter a name for this module. It should not contain spaces or punctuation." ResourceKey="ModuleName">Module Name: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_module" />
</td>
</tr>
<tr>
<td>
<Label For="description" HelpText="Enter a short description for the module" ResourceKey="Description">Description: </Label>
</td>
<td>
<textarea id="description" class="form-control" @bind="@_description" rows="3"></textarea>
</td>
</tr>
<tr>
<td>
<Label For="template" HelpText="Select a module template. Templates are located in the wwwroot/Modules/Templates folder on the server." ResourceKey="Template">Template: </Label>
</td>
<td>
<select id="template" class="form-control" @onchange="(e => TemplateChanged(e))">
<option value="-">&lt;@Localizer["Select Template"]&gt;</option>
@foreach (string template in _templates)
{
<option value="@template">@template</option>
}
</select>
</td>
</tr>
<tr>
<td>
<Label For="reference" HelpText="Select a framework reference version" ResourceKey="FrameworkReference">Framework Reference: </Label>
</td>
<td>
<select id="reference" class="form-control" @bind="@_reference">
@foreach (string version in Constants.ReleaseVersions.Split(','))
{
if (Version.Parse(version).CompareTo(Version.Parse("2.0.0")) >= 0)
{
<option value="@(version)">@(version)</option>
}
}
<option value="local">@Localizer["Local Version"]</option>
</select>
</td>
</tr>
@if (!string.IsNullOrEmpty(_location))
{
<tr>
<td>
<Label For="location" HelpText="Location where the module will be created" ResourceKey="Location">Location: </Label>
</td>
<td>
<input id="module" class="form-control" @bind="@_location" readonly />
</td>
</tr>
}
</table>
<button type="button" class="btn btn-success" @onclick="CreateModule">@Localizer["Create Module"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
}
@code {
private string _owner = string.Empty;
private string _module = string.Empty;
private string _description = string.Empty;
private string _template = "-";
private string _reference = Constants.Version;
private string _location = string.Empty;
private Dictionary<string, string> _systeminfo;
private List<string> _templates;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnParametersSetAsync()
{
try
{
_systeminfo = await SystemService.GetSystemInfoAsync();
_templates = await ModuleDefinitionService.GetModuleDefinitionTemplatesAsync();
AddModuleMessage(Localizer["Please Note That The Module Creator Is Only Intended To Be Used In A Development Environment"], MessageType.Info);
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Module Creator");
}
}
private async Task CreateModule()
{
try
{
if (IsValid(_owner) && IsValid(_module) && _owner != _module && _template != "-")
{
var moduleDefinition = new ModuleDefinition { Owner = _owner, Name = _module, Description = _description, Template = _template, Version = _reference };
moduleDefinition = await ModuleDefinitionService.CreateModuleDefinitionAsync(moduleDefinition);
GetLocation();
AddModuleMessage(Localizer["The Source Code For Your Module Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href=\"{0}\">Restart</a> Your Application To Activate The Module.", NavigateUrl("admin/system")], MessageType.Success);
}
else
{
AddModuleMessage(Localizer["You Must Provide A Valid Owner Name And Module Name ( ie. No Punctuation Or Spaces And The Values Cannot Be The Same ) And Choose A Template"], MessageType.Warning);
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Creating Module");
}
}
private bool IsValid(string name)
{
// must contain letters, underscores and digits and first character must be letter or underscore
return !string.IsNullOrEmpty(name) && Regex.IsMatch(name, "^[A-Za-z_][A-Za-z0-9_]*$");
}
private void TemplateChanged(ChangeEventArgs e)
{
_template = (string)e.Value;
GetLocation();
}
private void GetLocation()
{
_location = string.Empty;
if (_template != "-" && _systeminfo != null && _systeminfo.ContainsKey("serverpath"))
{
string[] path = _systeminfo["serverpath"].Split(Path.DirectorySeparatorChar);
_location = string.Join(Path.DirectorySeparatorChar, path, 0, path.Length - 2) +
Path.DirectorySeparatorChar + _owner + "." + _module;
}
StateHasChanged();
}
}

View File

@ -12,6 +12,8 @@
else
{
<ActionLink Action="Add" Text="Install Module" ResourceKey="InstallModule" />
@((MarkupString)"&nbsp;")
<ActionLink Action="Create" Text="Create Module" ResourceKey="CreateModule" />
<Pager Items="@_moduleDefinitions">
<Header>
@ -25,17 +27,17 @@ else
<td><ActionLink Action="Edit" Parameters="@($"id=" + context.ModuleDefinitionId.ToString())" ResourceKey="EditModule" /></td>
<td>
@if (context.AssemblyName != "Oqtane.Client")
{
{
<ActionDialog Header="Delete Module" Message="@Localizer["Are You Sure You Wish To Delete The {0} Module?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteModule(context))" ResourceKey="DeleteModule" />
}
}
</td>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
@if (UpgradeAvailable(context.ModuleDefinitionName, context.Version))
{
{
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadModule(context.ModuleDefinitionName, context.Version))>@Localizer["Upgrade"]</button>
}
}
</td>
</Row>
</Pager>

View File

@ -8,7 +8,7 @@
@inject IStringLocalizer<Settings> Localizer
<TabStrip>
<TabPanel Name="Settings" Heading="Module Settings" ResourceKey="ModuleSettings">
<TabPanel Name="Settings" Heading="Settings" ResourceKey="Settings">
@if (_containers != null)
{
<table class="table table-borderless">
@ -26,7 +26,6 @@
</td>
<td>
<select id="container" class="form-control" @bind="@_containerType">
<option value="-">&lt;@Localizer["Inherit From Page Or Site"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
@ -47,7 +46,7 @@
</tr>
<tr>
<td>
<Label For="page" HelpText="The page that the module is on" ResourceKey="Page">Page: </Label>
<Label For="page" HelpText="The page that the module is located on" ResourceKey="Page">Page: </Label>
</td>
<td>
<select id="page" class="form-control" @bind="@_pageId">
@ -76,10 +75,16 @@
</table>
}
</TabPanel>
@if (_settingsModuleType != null)
@if (_moduleSettingsType != null)
{
<TabPanel Name="ModuleSettings" Heading="@_settingstitle" ResourceKey="Module Settings">
@DynamicComponent
<TabPanel Name="ModuleSettings" Heading="@_moduleSettingsTitle" ResourceKey="ModuleSettings">
@ModuleSettingsComponent
</TabPanel>
}
@if (_containerSettingsType != null)
{
<TabPanel Name="ContainerSettings" Heading="Container Settings" ResourceKey="ContainerSettings">
@ContainerSettingsComponent
</TabPanel>
}
</TabStrip>
@ -87,6 +92,10 @@
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
public override string Title => "Module Settings";
private List<Theme> _themes;
private List<ThemeControl> _containers = new List<ThemeControl>();
private string _title;
private string _containerType;
@ -95,50 +104,65 @@
private string _permissions = null;
private string _pageId;
private PermissionGrid _permissionGrid;
private Type _settingsModuleType;
private string _settingstitle = "Other Settings";
private object _settings;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
public override string Title => "Module Settings";
private RenderFragment DynamicComponent { get; set; }
private Type _moduleSettingsType;
private object _moduleSettings;
private string _moduleSettingsTitle = "Module Settings";
private RenderFragment ModuleSettingsComponent { get; set; }
private Type _containerSettingsType;
private object _containerSettings;
private RenderFragment ContainerSettingsComponent { get; set; }
protected override async Task OnInitializedAsync()
{
_title = ModuleState.Title;
_containers = ThemeService.GetContainerControls(await ThemeService.GetThemesAsync(), PageState.Page.ThemeType);
_themes = await ThemeService.GetThemesAsync();
_containers = ThemeService.GetContainerControls(_themes, PageState.Page.ThemeType);
_containerType = ModuleState.ContainerType;
if (!string.IsNullOrEmpty(PageState.Page.DefaultContainerType) && _containerType == PageState.Page.DefaultContainerType)
{
_containerType = "-";
}
if (_containerType == PageState.Site.DefaultContainerType)
{
_containerType = "-";
}
_allPages = ModuleState.AllPages.ToString();
_permissions = ModuleState.Permissions;
_permissionNames = ModuleState.ModuleDefinition.PermissionNames;
_pageId = ModuleState.PageId.ToString();
_settingsModuleType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
if (_settingsModuleType != null)
if (!string.IsNullOrEmpty(ModuleState.ModuleDefinition.SettingsType))
{
var moduleobject = Activator.CreateInstance(_settingsModuleType) as IModuleControl;
_settingstitle = moduleobject.Title;
if (string.IsNullOrEmpty(_settingstitle))
// module settings type explicitly declared in IModule interface
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.SettingsType);
}
else
{
// legacy support - module settings type determined by convention ( ie. existence of a "Settings.razor" component in module )
_moduleSettingsType = Type.GetType(ModuleState.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, PageState.Action), false, true);
}
if (_moduleSettingsType != null)
{
var moduleobject = Activator.CreateInstance(_moduleSettingsType) as IModuleControl;
if (!string.IsNullOrEmpty(moduleobject.Title))
{
_settingstitle = "Other Settings";
_moduleSettingsTitle = moduleobject.Title;
}
DynamicComponent = builder =>
ModuleSettingsComponent = builder =>
{
builder.OpenComponent(0, _settingsModuleType);
builder.AddComponentReferenceCapture(1, inst => { _settings = Convert.ChangeType(inst, _settingsModuleType); });
builder.OpenComponent(0, _moduleSettingsType);
builder.AddComponentReferenceCapture(1, inst => { _moduleSettings = Convert.ChangeType(inst, _moduleSettingsType); });
builder.CloseComponent();
};
}
}
var theme = _themes.FirstOrDefault(item => item.Containers.Any(themecontrol => themecontrol.TypeName.Equals(_containerType)));
if (theme != null && !string.IsNullOrEmpty(theme.ContainerSettingsType))
{
_containerSettingsType = Type.GetType(theme.ContainerSettingsType);
if (_containerSettingsType != null)
{
ContainerSettingsComponent = builder =>
{
builder.OpenComponent(0, _containerSettingsType);
builder.AddComponentReferenceCapture(1, inst => { _containerSettings = Convert.ChangeType(inst, _containerSettingsType); });
builder.CloseComponent();
};
}
}
}
private async Task SaveModule()
@ -163,16 +187,25 @@
module.Permissions = _permissionGrid.GetPermissions();
await ModuleService.UpdateModuleAsync(module);
if (_settings is ISettingsControl control)
if (_moduleSettingsType != null)
{
await control.UpdateSettings();
if (_moduleSettings is ISettingsControl moduleSettingsControl)
{
// module settings updated using explicit interface
await moduleSettingsControl.UpdateSettings();
}
else
{
// legacy support - module settings updated by convention ( ie. by calling a public method named "UpdateSettings" in settings component )
_moduleSettings?.GetType().GetMethod("UpdateSettings")?.Invoke(_moduleSettings, null);
}
}
else
if (_containerSettingsType != null && _containerSettings is ISettingsControl containerSettingsControl)
{
// Compatibility 2.0 fallback
_settings?.GetType().GetMethod("UpdateSettings")?.Invoke(_settings, null); // method must be public in settings component
await containerSettingsControl.UpdateSettings();
}
NavigationManager.NavigateTo(NavigateUrl());
}

View File

@ -102,7 +102,6 @@
</td>
<td>
<select id="Theme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;@Localizer["Inherit From Site"]&gt;</option>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
@ -110,37 +109,13 @@
</select>
</td>
</tr>
@if (_layouts.Count > 0)
{
<tr>
<td>
<Label For="Layout" HelpText="Select a layout for the page (if the selected theme supports it)" ResourceKey="Layout">Layout: </Label>
</td>
<td>
<select id="Layout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;@Localizer["Inherit From Site"]&gt;</option>
@foreach (var layout in _layouts)
{
if (layout.TypeName == _layouttype)
{
<option value="@(layout.TypeName)" selected>@(layout.Name)</option>
}
else
{
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the page" ResourceKey="DefaultContainer">Default Container: </Label>
</td>
<td>
<select id="defaultContainer" class="form-control" @bind="@_containertype">
<option value="-">&lt;@Localizer["Inherit From Site"]&gt;</option>
<option value="-">&lt;@Localizer["Select Container"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
@ -180,14 +155,21 @@
</tr>
</table>
</TabPanel>
@if (_themeSettingsType != null)
{
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
@ThemeSettingsComponent
</TabPanel>
}
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SavePage">@Localizer["Save"]</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">@Localizer["Cancel"]</button>
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<Page> _pageList;
private string _name;
@ -200,25 +182,28 @@
private string _isnavigation = "True";
private string _url;
private string _ispersonalizable = "False";
private string _themetype = "-";
private string _layouttype = "-";
private string _containertype = "-";
private string _themetype = string.Empty;
private string _containertype = string.Empty;
private string _icon = string.Empty;
private string _permissions = string.Empty;
private PermissionGrid _permissionGrid;
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
private Type _themeSettingsType;
private object _themeSettings;
private RenderFragment ThemeSettingsComponent { get; set; }
protected override async Task OnInitializedAsync()
{
try
{
_themeList = await ThemeService.GetThemesAsync();
_themes = ThemeService.GetThemeControls(_themeList);
_themetype = PageState.Site.DefaultThemeType;
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = PageState.Site.DefaultContainerType;
_pageList = PageState.Pages;
_children = PageState.Pages.Where(item => item.ParentId == null).ToList();
_themes = ThemeService.GetThemeControls(_themeList);
_permissions = string.Empty;
ThemeSettings();
}
catch (Exception ex)
{
@ -267,18 +252,9 @@
try
{
_themetype = (string)e.Value;
if (_themetype != "-")
{
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = "-";
ThemeSettings();
StateHasChanged();
}
catch (Exception ex)
@ -288,12 +264,31 @@
}
}
private void ThemeSettings()
{
_themeSettingsType = null;
var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
{
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
if (_themeSettingsType != null)
{
ThemeSettingsComponent = builder =>
{
builder.OpenComponent(0, _themeSettingsType);
builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
builder.CloseComponent();
};
}
}
}
private async Task SavePage()
{
Page page = null;
try
{
if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && (_layouts.Count == 0 || _layouttype != "-"))
if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && _containertype != "-")
{
page = new Page();
page.SiteId = PageState.Page.SiteId;
@ -360,11 +355,6 @@
{
page.ThemeType = string.Empty;
}
page.LayoutType = (_layouttype != "-") ? _layouttype : string.Empty;
if (!string.IsNullOrEmpty(page.LayoutType) && page.LayoutType == PageState.Site.DefaultLayoutType)
{
page.LayoutType = string.Empty;
}
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
{
@ -390,7 +380,7 @@
}
else
{
AddModuleMessage(Localizer["You Must Provide Page Name And Theme/Layout"], MessageType.Warning);
AddModuleMessage(Localizer["You Must Provide Page Name, Theme, and Container"], MessageType.Warning);
}
}

View File

@ -1,4 +1,5 @@
@namespace Oqtane.Modules.Admin.Pages
@using Oqtane.Interfaces
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IPageService PageService
@ -109,7 +110,6 @@
</td>
<td>
<select id="Theme" class="form-control" value="@_themetype" @onchange="(e => ThemeChanged(e))">
<option value="-">&lt;@Localizer["Inherit From Site"]&gt;</option>
@foreach (var theme in _themes)
{
<option value="@theme.TypeName">@theme.Name</option>
@ -117,37 +117,13 @@
</select>
</td>
</tr>
@if (_layouts.Count > 0)
{
<tr>
<td>
<Label For="Layout" HelpText="Select a layout for the page (if the selected theme supports it)" ResourceKey="Layout">Layout: </Label>
</td>
<td>
<select id="Layout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;@Localizer["Inherit From Site"]&gt;</option>
@foreach (var layout in _layouts)
{
if (layout.TypeName == _layouttype)
{
<option value="@(layout.TypeName)" selected>@(layout.Name)</option>
}
else
{
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the page" ResourceKey="DefaultContainer">Default Container: </Label>
</td>
<td>
<select id="defaultContainer" class="form-control" @bind="@_containertype">
<option value="-">&lt;@Localizer["Inherit From Site"]&gt;</option>
<option value="-">&lt;@Localizer["Select Container"]&gt;</option>
@foreach (var container in _containers)
{
<option value="@container.TypeName">@container.Name</option>
@ -192,14 +168,21 @@
</table>
}
</TabPanel>
@if (_themeSettingsType != null)
{
<TabPanel Name="ThemeSettings" Heading="Theme Settings" ResourceKey="ThemeSettings">
@ThemeSettingsComponent
</TabPanel>
}
</TabStrip>
<button type="button" class="btn btn-success" @onclick="SavePage">@Localizer["Save"]</button>
<button type="button" class="btn btn-secondary" @onclick="Cancel">@Localizer["Cancel"]</button>
@code {
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<Page> _pageList;
private int _pageId;
@ -214,8 +197,7 @@
private string _isnavigation;
private string _url;
private string _ispersonalizable;
private string _themetype = "-";
private string _layouttype = "-";
private string _themetype;
private string _containertype = "-";
private string _icon;
private string _permissions = null;
@ -225,12 +207,10 @@
private DateTime _modifiedon;
private string _deletedby;
private DateTime? _deletedon;
#pragma warning disable 649
private PermissionGrid _permissionGrid;
#pragma warning restore 649
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin;
private Type _themeSettingsType;
private object _themeSettings;
private RenderFragment ThemeSettingsComponent { get; set; }
protected override async Task OnInitializedAsync()
{
@ -269,21 +249,15 @@
_url = page.Url;
_ispersonalizable = page.IsPersonalizable.ToString();
_themetype = page.ThemeType;
if (_themetype == PageState.Site.DefaultThemeType)
if (string.IsNullOrEmpty(_themetype))
{
_themetype = "-";
_themetype = PageState.Site.DefaultThemeType;
}
_layouts = ThemeService.GetLayoutControls(_themeList, page.ThemeType);
_layouttype = page.LayoutType;
if (_layouttype == PageState.Site.DefaultLayoutType)
{
_layouttype = "-";
}
_containers = ThemeService.GetContainerControls(_themeList, page.ThemeType);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = page.DefaultContainerType;
if (string.IsNullOrEmpty(_containertype))
{
_containertype = "-";
_containertype = PageState.Site.DefaultContainerType;
}
_icon = page.Icon;
_permissions = page.Permissions;
@ -293,6 +267,8 @@
_modifiedon = page.ModifiedOn;
_deletedby = page.DeletedBy;
_deletedon = page.DeletedOn;
ThemeSettings();
}
}
catch (Exception ex)
@ -350,18 +326,9 @@
try
{
_themetype = (string)e.Value;
if (_themetype != "-")
{
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = "-";
ThemeSettings();
StateHasChanged();
}
catch (Exception ex)
@ -371,12 +338,31 @@
}
}
private void ThemeSettings()
{
_themeSettingsType = null;
var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
{
_themeSettingsType = Type.GetType(theme.ThemeSettingsType);
if (_themeSettingsType != null)
{
ThemeSettingsComponent = builder =>
{
builder.OpenComponent(0, _themeSettingsType);
builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
builder.CloseComponent();
};
}
}
}
private async Task SavePage()
{
Page page = null;
try
{
if (_name != string.Empty)
if (_name != string.Empty && !string.IsNullOrEmpty(_themetype) && _containertype != "-")
{
page = PageState.Pages.FirstOrDefault(item => item.PageId == _pageId);
string currentPath = page.Path;
@ -445,11 +431,6 @@
{
page.ThemeType = string.Empty;
}
page.LayoutType = (_layouttype != "-") ? _layouttype : string.Empty;
if (!string.IsNullOrEmpty(page.LayoutType) && page.LayoutType == PageState.Site.DefaultLayoutType)
{
page.LayoutType = string.Empty;
}
page.DefaultContainerType = (_containertype != "-") ? _containertype : string.Empty;
if (!string.IsNullOrEmpty(page.DefaultContainerType) && page.DefaultContainerType == PageState.Site.DefaultContainerType)
{
@ -481,6 +462,11 @@
}
}
if (_themeSettingsType != null && _themeSettings is ISettingsControl themeSettingsControl)
{
await themeSettingsControl.UpdateSettings();
}
await logger.LogInformation("Page Saved {Page}", page);
if (PageState.QueryString.ContainsKey("cp"))
{
@ -493,7 +479,7 @@
}
else
{
AddModuleMessage(Localizer["You Must Provide Page Name"], MessageType.Warning);
AddModuleMessage(Localizer["You Must Provide Page Name, Theme, and Container"], MessageType.Warning);
}
}
catch (Exception ex)

View File

@ -91,23 +91,6 @@
</select>
</td>
</tr>
@if (_layouts.Count > 0)
{
<tr>
<td>
<Label For="defaultLayout" HelpText="Select the sites default layout" ResourceKey="DefaultLayout">Default Layout: </Label>
</td>
<td>
<select id="defaultLayout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;@Localizer["Select Layout"]&gt;</option>
@foreach (var layout in _layouts)
{
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
@ -244,7 +227,6 @@
private bool _initialized = false;
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private string _name = string.Empty;
private List<Tenant> _tenantList;
@ -256,7 +238,6 @@
private int _faviconfileid = -1;
private FileManager _faviconfilemanager;
private string _themetype = "-";
private string _layouttype = "-";
private string _containertype = "-";
private string _admincontainertype = "-";
private string _allowregistration;
@ -309,8 +290,6 @@
_themes = ThemeService.GetThemeControls(_themeList);
_themetype = site.DefaultThemeType;
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_layouttype = site.DefaultLayoutType;
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = site.DefaultContainerType;
_admincontainertype = site.AdminContainerType;
@ -371,15 +350,12 @@
_themetype = (string)e.Value;
if (_themetype != "-")
{
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containertype = "-";
_admincontainertype = "";
StateHasChanged();
@ -395,7 +371,7 @@
{
try
{
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && (_layouts.Count == 0 || _layouttype != "-") && _containertype != "-")
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-")
{
var unique = true;
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
@ -427,7 +403,6 @@
}
site.DefaultThemeType = _themetype;
site.DefaultLayoutType = (_layouttype == "-" ? string.Empty : _layouttype);
site.DefaultContainerType = _containertype;
site.AdminContainerType = _admincontainertype;
site.AllowRegistration = (_allowregistration == null ? true : Boolean.Parse(_allowregistration));
@ -491,7 +466,7 @@
}
else
{
AddModuleMessage(Localizer["You Must Provide A Site Name, Alias, And Default Theme/Layout/Container"], MessageType.Warning);
AddModuleMessage(Localizer["You Must Provide A Site Name, Alias, And Default Theme/Container"], MessageType.Warning);
}
}
catch (Exception ex)

View File

@ -47,23 +47,6 @@ else
</select>
</td>
</tr>
@if (_layouts.Count > 0)
{
<tr>
<td>
<Label For="defaultLayout" HelpText="Select the default layout for the site" ResourceKey="DefaultLayout">Default Layout: </Label>
</td>
<td>
<select id="defaultLayout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;@Localizer["Select Layout"]&gt;</option>
@foreach (var layout in _layouts)
{
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
@ -219,7 +202,6 @@ else
@code {
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private List<SiteTemplate> _siteTemplates;
private List<Tenant> _tenants;
@ -238,7 +220,6 @@ else
private string _name = string.Empty;
private string _urls = string.Empty;
private string _themetype = "-";
private string _layouttype = "-";
private string _containertype = "-";
private string _admincontainertype = "";
private string _sitetemplatetype = "-";
@ -284,29 +265,26 @@ else
_themetype = (string)e.Value;
if (_themetype != "-")
{
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containertype = "-";
_admincontainertype = "";
StateHasChanged();
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Loading Pane Layouts For Theme {ThemeType} {Error}", _themetype, ex.Message);
AddModuleMessage(Localizer["Error Loading Pane Layouts For Theme"], MessageType.Error);
await logger.LogError(ex, "Error Loading Containers For Theme {ThemeType} {Error}", _themetype, ex.Message);
AddModuleMessage(Localizer["Error Loading Containers For Theme"], MessageType.Error);
}
}
private async Task SaveSite()
{
if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && (_layouts.Count == 0 || _layouttype != "-") && _containertype != "-" && _sitetemplatetype != "-")
if (_tenantid != "-" && _name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-" && _sitetemplatetype != "-")
{
var duplicates = new List<string>();
var aliases = await AliasService.GetAliasesAsync();
@ -393,7 +371,6 @@ else
config.SiteName = _name;
config.Aliases = _urls.Replace("\n", ",");
config.DefaultTheme = _themetype;
config.DefaultLayout = _layouttype;
config.DefaultContainer = _containertype;
config.DefaultAdminContainer = _admincontainertype;
config.SiteTemplate = _sitetemplatetype;
@ -421,7 +398,7 @@ else
}
else
{
AddModuleMessage(Localizer["You Must Provide A Tenant, Site Name, Alias, Default Theme/Layout/Container, And Site Template"], MessageType.Warning);
AddModuleMessage(Localizer["You Must Provide A Tenant, Site Name, Alias, Default Theme/Container, And Site Template"], MessageType.Warning);
}
}
}

View File

@ -40,23 +40,6 @@
</select>
</td>
</tr>
@if (_layouts.Count > 0)
{
<tr>
<td>
<Label For="defaultLayout" HelpText="Select the default layout for the site" ResourceKey="DefaultLayout">Default Layout: </Label>
</td>
<td>
<select id="defaultLayout" class="form-control" @bind="@_layouttype">
<option value="-">&lt;@Localizer["Select Layout"]&gt;</option>
@foreach (var layout in _layouts)
{
<option value="@(layout.TypeName)">@(layout.Name)</option>
}
</select>
</td>
</tr>
}
<tr>
<td>
<Label For="defaultContainer" HelpText="Select the default container for the site" ResourceKey="DefaultContainer">Default Container: </Label>
@ -127,14 +110,12 @@
private bool _initialized = false;
private List<Theme> _themeList;
private List<ThemeControl> _themes = new List<ThemeControl>();
private List<ThemeControl> _layouts = new List<ThemeControl>();
private List<ThemeControl> _containers = new List<ThemeControl>();
private Alias _alias;
private string _name = string.Empty;
private List<Alias> _aliasList;
private string _urls = string.Empty;
private string _themetype;
private string _layouttype;
private string _containertype = "-";
private string _admincontainertype = "-";
private string _createdby;
@ -170,8 +151,6 @@
_themes = ThemeService.GetThemeControls(_themeList);
_themetype = site.DefaultThemeType;
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_layouttype = site.DefaultLayoutType;
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
_containertype = site.DefaultContainerType;
_admincontainertype = site.AdminContainerType;
@ -208,15 +187,12 @@
_themetype = (string)e.Value;
if (_themetype != "-")
{
_layouts = ThemeService.GetLayoutControls(_themeList, _themetype);
_containers = ThemeService.GetContainerControls(_themeList, _themetype);
}
else
{
_layouts = new List<ThemeControl>();
_containers = new List<ThemeControl>();
}
_layouttype = "-";
_containertype = "-";
_admincontainertype = "";
StateHasChanged();
@ -232,7 +208,7 @@
{
try
{
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && (_layouts.Count == 0 || _layouttype != "-") && _containertype != "-")
if (_name != string.Empty && _urls != string.Empty && _themetype != "-" && _containertype != "-")
{
var unique = true;
foreach (string name in _urls.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries))
@ -252,7 +228,6 @@
site.Name = _name;
site.LogoFileId = null;
site.DefaultThemeType = _themetype;
site.DefaultLayoutType = _layouttype ?? string.Empty;
site.DefaultContainerType = _containertype;
site.AdminContainerType = _admincontainertype;
site.IsDeleted = (_isdeleted == null || Boolean.Parse(_isdeleted));

View File

@ -1,15 +0,0 @@
using Oqtane.Models;
namespace Oqtane.Modules.Admin.ThemeCreator
{
public class ModuleInfo : IModule
{
public ModuleDefinition ModuleDefinition => new ModuleDefinition
{
Name = "Theme Creator",
Description = "Enables software developers to quickly create themes by automating many of the initial theme creation tasks",
Version = "1.0.0",
Categories = "Developer"
};
}
}

View File

@ -1,8 +1,8 @@
@namespace Oqtane.Modules.Admin.ThemeCreator
@namespace Oqtane.Modules.Admin.Themes
@inherits ModuleBase
@inject NavigationManager NavigationManager
@inject IThemeService ThemeService
@inject IModuleService ModuleService
@inject IModuleService ModuleService
@inject IPageModuleService PageModuleService
@inject ISystemService SystemService
@inject ISettingService SettingService
@ -10,7 +10,7 @@
@using System.Text.RegularExpressions
@using System.IO;
@if (string.IsNullOrEmpty(_themename) && _systeminfo != null && _templates != null)
@if (_systeminfo != null && _templates != null)
{
<table class="table table-borderless">
<tr>
@ -73,14 +73,10 @@
}
</table>
<button type="button" class="btn btn-success" @onclick="CreateTheme">@Localizer["Create Theme"]</button>
}
else
{
<button type="button" class="btn btn-success" @onclick="ActivateTheme">@Localizer["Activate Theme"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
}
@code {
private string _themename = string.Empty;
private string _owner = string.Empty;
private string _theme = string.Empty;
private string _template = "-";
@ -92,22 +88,13 @@ else
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host;
protected override async Task OnInitializedAsync()
protected override async Task OnParametersSetAsync()
{
try
{
_themename = SettingService.GetSetting(ModuleState.Settings, "ThemeName", "");
_systeminfo = await SystemService.GetSystemInfoAsync();
_templates = await ThemeService.GetThemeTemplatesAsync();
if (string.IsNullOrEmpty(_themename))
{
AddModuleMessage(Localizer["Please Note That The Theme Creator Is Only Intended To Be Used In A Development Environment"], MessageType.Info);
}
else
{
AddModuleMessage(Localizer["Once You Have Compiled The Theme And Restarted The Application You Can Activate The Theme Below"], MessageType.Info);
}
AddModuleMessage(Localizer["Please Note That The Theme Creator Is Only Intended To Be Used In A Development Environment"], MessageType.Info);
}
catch (Exception ex)
{
@ -123,14 +110,9 @@ else
{
var theme = new Theme { Owner = _owner, Name = _theme, Template = _template, Version = _reference };
theme = await ThemeService.CreateThemeAsync(theme);
var settings = ModuleState.Settings;
SettingService.SetSetting(settings, "ThemeName", theme.ThemeName);
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
GetLocation();
AddModuleMessage(Localizer["The Source Code For Your Theme Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href=\"{0}\">Restart</a> Your Application To Apply These Changes.", NavigateUrl("admin/system")], MessageType.Success);
AddModuleMessage(Localizer["The Source Code For Your Theme Has Been Created At The Location Specified Below And Must Be Compiled In Order To Make It Functional. Once It Has Been Compiled You Must <a href=\"{0}\">Restart</a> Your Application To Activate The Module.", NavigateUrl("admin/system")], MessageType.Success);
}
else
{
@ -143,23 +125,6 @@ else
}
}
private async Task ActivateTheme()
{
try
{
if (!string.IsNullOrEmpty(_themename))
{
await PageModuleService.DeletePageModuleAsync(ModuleState.PageModuleId);
await ModuleService.DeleteModuleAsync(ModuleState.ModuleId);
NavigationManager.NavigateTo(NavigateUrl());
}
}
catch (Exception ex)
{
await logger.LogError(ex, "Error Activating Theme");
}
}
private bool IsValid(string name)
{
// must contain letters, underscores and digits and first character must be letter or underscore

View File

@ -13,6 +13,8 @@
else
{
<ActionLink Action="Add" Text="Install Theme" />
@((MarkupString)"&nbsp;")
<ActionLink Action="Create" Text="Create Theme" ResourceKey="CreateTheme" />
<Pager Items="@_themes">
<Header>
@ -26,17 +28,17 @@ else
<td><ActionLink Action="View" Parameters="@($"name=" + WebUtility.UrlEncode(context.ThemeName))" ResourceKey="ViewTheme" /></td>
<td>
@if (context.AssemblyName != "Oqtane.Client")
{
{
<ActionDialog Header="Delete Theme" Message="@Localizer["Are You Sure You Wish To Delete The {0} Theme?", context.Name]" Action="Delete" Security="SecurityAccessLevel.Host" Class="btn btn-danger" OnClick="@(async () => await DeleteTheme(context))" ResourceKey="DeleteTheme" />
}
}
</td>
<td>@context.Name</td>
<td>@context.Version</td>
<td>
@if (UpgradeAvailable(context.ThemeName, context.Version))
{
{
<button type="button" class="btn btn-success" @onclick=@(async () => await DownloadTheme(context.ThemeName, context.Version))>@Localizer["Upgrade"]</button>
}
}
</td>
<td></td>
</Row>

View File

@ -6,21 +6,24 @@
<div class="col">
<TabStrip>
<TabPanel Name="Rich" Heading="Rich Text Editor">
@if (_filemanagervisible)
@if (AllowFileManagement)
{
<FileManager @ref="_fileManager" Filter="@Constants.ImageFiles" />
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
<br />
}
<div class="row justify-content-center" style="margin-bottom: 20px;">
<button type="button" class="btn btn-secondary" @onclick="RefreshRichText">@Localizer["Synchronize Content"]</button>&nbsp;&nbsp;
<button type="button" class="btn btn-primary" @onclick="InsertImage">@Localizer["Insert Image"]</button>
@if (_filemanagervisible)
{
@((MarkupString)"&nbsp;&nbsp;")
<button type="button" class="btn btn-secondary" @onclick="CloseFileManager">@Localizer["Close"]</button>
<FileManager @ref="_fileManager" Filter="@Constants.ImageFiles" />
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
<br />
}
</div>
<div class="row justify-content-center" style="margin-bottom: 20px;">
<button type="button" class="btn btn-secondary" @onclick="RefreshRichText">@Localizer["Synchronize Content"]</button>&nbsp;&nbsp;
<button type="button" class="btn btn-primary" @onclick="InsertImage">@Localizer["Insert Image"]</button>
@if (_filemanagervisible)
{
@((MarkupString)"&nbsp;&nbsp;")
<button type="button" class="btn btn-secondary" @onclick="CloseFileManager">@Localizer["Close"]</button>
}
</div>
}
<div class="row">
<div class="col">
<div @ref="@_toolBar">
@ -107,6 +110,9 @@
[Parameter]
public string DebugLevel { get; set; } = "info";
[Parameter]
public bool AllowFileManagement { get; set; } = true;
public override List<Resource> Resources => new List<Resource>()
{
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill1.3.6.min.js" },

View File

@ -30,16 +30,12 @@ else
[Parameter]
public SecurityAccessLevel? Security { get; set; } // optional - can be used to specify SecurityAccessLevel
protected override void OnInitialized()
{
base.OnInitialized();
Parent.AddTabPanel((TabPanel)this);
}
protected override void OnParametersSet()
{
base.OnParametersSet();
Parent.AddTabPanel((TabPanel)this);
if (string.IsNullOrEmpty(Heading))
{
Name = Localize(nameof(Name), Name);

View File

@ -9,7 +9,7 @@
{
@if (IsAuthorized(tabPanel))
{
<li class="nav-item">
<li class="nav-item" @key="tabPanel.Name">
@if (tabPanel.Name == ActiveTab)
{
<a class="nav-link active" data-toggle="tab" href="#@tabPanel.Name" role="tab" @onclick:preventDefault="true">
@ -35,7 +35,7 @@
</CascadingValue>
@code {
private List<TabPanel> _tabPanels = new List<TabPanel>();
private List<TabPanel> _tabPanels;
[Parameter]
public RenderFragment ChildContent { get; set; } // contains the TabPanels
@ -51,14 +51,22 @@
}
}
protected override void OnParametersSet()
{
_tabPanels = new List<TabPanel>();
}
internal void AddTabPanel(TabPanel tabPanel)
{
_tabPanels.Add(tabPanel);
if (string.IsNullOrEmpty(ActiveTab))
if (!_tabPanels.Exists(item => item.Name == tabPanel.Name))
{
ActiveTab = tabPanel.Name;
_tabPanels.Add(tabPanel);
if (string.IsNullOrEmpty(ActiveTab))
{
ActiveTab = tabPanel.Name;
}
StateHasChanged();
}
StateHasChanged();
}
private bool IsAuthorized(TabPanel tabPanel)

View File

@ -4,12 +4,13 @@
@namespace Oqtane.Modules.HtmlText
@inherits ModuleBase
@inject IHtmlTextService HtmlTextService
@inject ISettingService SettingService
@inject NavigationManager NavigationManager
@inject IStringLocalizer<Edit> Localizer
@if (_content != null)
{
<RichTextEditor Content="@_content" @ref="@RichTextEditorHtml"></RichTextEditor>
<RichTextEditor Content="@_content" AllowFileManagement="@_allowfilemanagement" @ref="@RichTextEditorHtml"></RichTextEditor>
<button type="button" class="btn btn-success" @onclick="SaveContent">@Localizer["Save"]</button>
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@Localizer["Cancel"]</NavLink>
@if (!string.IsNullOrEmpty(_content))
@ -26,13 +27,14 @@
public override string Title => "Edit Html/Text";
public override List<Resource> Resources => new List<Resource>()
{
{
new Resource { ResourceType = ResourceType.Stylesheet, Url = ModulePath() + "Module.css" },
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.bubble.css" },
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill1.3.6.snow.css" }
};
private RichTextEditor RichTextEditorHtml;
private bool _allowfilemanagement;
private string _content = null;
private string _createdby;
private DateTime _createdon;
@ -43,6 +45,8 @@
{
try
{
_allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
if (htmltext != null)
{

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
namespace Oqtane.Modules.HtmlText
{
@ -10,7 +10,8 @@ namespace Oqtane.Modules.HtmlText
Description = "Renders HTML or Text Content",
Version = "1.0.0",
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
ReleaseVersions = "1.0.0"
ReleaseVersions = "1.0.0",
SettingsType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"
};
}
}

View File

@ -0,0 +1,49 @@
@namespace Oqtane.Modules.HtmlText
@inherits ModuleBase
@inject ISettingService SettingService
@implements Oqtane.Interfaces.ISettingsControl
@inject IStringLocalizer<Settings> Localizer
<table class="table table-borderless">
<tr>
<td>
<Label For="files" ResourceKey="Allow File Management" HelpText="Specify If Editors Can Upload and Select Files">Allow File Management: </Label>
</td>
<td>
<select id="files" class="form-control" @bind="@_allowfilemanagement">
<option value="true">@Localizer["Yes"]</option>
<option value="false">@Localizer["No"]</option>
</select>
</td>
</tr>
</table>
@code {
private string _allowfilemanagement;
protected override void OnInitialized()
{
try
{
_allowfilemanagement = SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true");
}
catch (Exception ex)
{
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
}
}
public async Task UpdateSettings()
{
try
{
var settings = ModuleState.Settings;
settings = SettingService.SetSetting(settings, "AllowFileManagement", _allowfilemanagement);
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
}
catch (Exception ex)
{
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

View File

@ -129,19 +129,19 @@ namespace Oqtane.Client
foreach (ZipArchiveEntry entry in archive.Entries)
{
if (!assemblies.Contains(Path.GetFileNameWithoutExtension(entry.Name)))
if (!assemblies.Contains(Path.GetFileNameWithoutExtension(entry.FullName)))
{
using (var memoryStream = new MemoryStream())
{
entry.Open().CopyTo(memoryStream);
byte[] file = memoryStream.ToArray();
switch (Path.GetExtension(entry.Name))
switch (Path.GetExtension(entry.FullName))
{
case ".dll":
dlls.Add(entry.Name, file);
dlls.Add(entry.FullName, file);
break;
case ".pdb":
pdbs.Add(entry.Name, file);
pdbs.Add(entry.FullName, file);
break;
}
}

View File

@ -29,10 +29,10 @@ namespace Oqtane.Services
return themes.SelectMany(item => item.Themes).ToList();
}
//[Obsolete("This method is deprecated.", false)]
public List<ThemeControl> GetLayoutControls(List<Theme> themes, string themeName)
{
return themes.Where(item => Utilities.GetTypeName(themeName).StartsWith(Utilities.GetTypeName(item.ThemeName)))
.SelectMany(item => item.Layouts).ToList();
return null;
}
public List<ThemeControl> GetContainerControls(List<Theme> themes, string themeName)

View File

@ -17,13 +17,13 @@
</div>
<div class="container">
<div class="row px-4">
<Pane Name="Content" />
<Pane Name="@PaneNames.Admin" />
</div>
</div>
</div>
@code {
public override string Panes => "Content";
public override string Panes => PaneNames.Admin;
public override List<Resource> Resources => new List<Resource>()
{

View File

@ -22,21 +22,24 @@
</li>
}
}
<li class="dropdown-submenu">
<a class="dropdown-item" onclick="return subMenu(this)">
<span class="@Icons.AccountLogin" aria-hidden="true"></span>&nbsp;Move To &gt;
</a>
<ul class="dropdown-menu">
@foreach (var action in Actions.Where(item => item.Name.Contains("Pane")))
{
<li>
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action))">
<span class="@action.Icon" aria-hidden="true"></span>&nbsp;@action.Name
</a>
</li>
}
</ul>
</li>
@if (Actions.Where(item => item.Name.Contains("Pane")).Any())
{
<li class="dropdown-submenu">
<a class="dropdown-item" onclick="return subMenu(this)">
<span class="@Icons.AccountLogin" aria-hidden="true"></span>&nbsp;Move To &gt;
</a>
<ul class="dropdown-menu">
@foreach (var action in Actions.Where(item => item.Name.Contains("Pane")))
{
<li>
<a class="dropdown-item" @onclick="(async () => await ModuleAction(action))">
<span class="@action.Icon" aria-hidden="true"></span>&nbsp;@action.Name
</a>
</li>
}
</ul>
</li>
}
</ul>
</div>
}

View File

@ -1,12 +0,0 @@
@namespace Oqtane.Themes.Controls
@inherits ThemeControlBase
@if (!string.IsNullOrWhiteSpace(Value))
{
<span class="@Value" aria-hidden="true"></span>
}
@code {
[Parameter()]
public string Value { get; set; }
}

View File

@ -599,7 +599,7 @@
Dictionary<string, string> settings = await SettingService.GetUserSettingsAsync(PageState.User.UserId);
_category = SettingService.GetSetting(settings, settingCategory, "Common");
var pane = SettingService.GetSetting(settings, settingPane, "");
_pane = PageState.Page.Panes.Contains(pane) ? pane : PageState.Page.Panes.FirstOrDefault();
_pane = PageState.Page.Panes.Contains(pane) ? pane : PaneNames.Admin;
}
private async Task UpdateSettingsAsync()

View File

@ -1,4 +1,4 @@
namespace Oqtane.Themes
namespace Oqtane.Themes
{
public interface ILayoutControl
{

View File

@ -1,5 +1,8 @@
namespace Oqtane.Themes
using System;
namespace Oqtane.Themes
{
[Obsolete("This class is deprecated", false)]
public abstract class LayoutBase : ThemeBase, ILayoutControl
{

View File

@ -0,0 +1,47 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ContainerBase
@inject ISettingService SettingService
<div class="@_classes">
@if (_title)
{
<div class="row px-4">
<div class="d-flex flex-nowrap">
<ModuleActions /><h2><ModuleTitle /></h2>
</div>
<hr class="app-rule" />
</div>
}
else
{
<ModuleActions />
}
<div class="row px-4">
<div class="container">
<ModuleInstance />
</div>
</div>
</div>
@code {
public override string Name => "Customizable Container";
private bool _title = true;
private string _classes = "container";
protected override void OnParametersSet()
{
try
{
_title = bool.Parse(SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Title", "true"));
_classes += " " + SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Background", "");
_classes += " " + SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Text", "");
_classes += " " + SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Border", "");
_classes = _classes.Trim();
}
catch
{
// error loading container settings
}
}
}

View File

@ -0,0 +1,113 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ModuleBase
@implements Oqtane.Interfaces.ISettingsControl
@inject ISettingService SettingService
@attribute [OqtaneIgnore]
<table class="table table-borderless">
<tr>
<td>
<Label For="title" ResourceKey="Title" HelpText="Specify If The Module Title Should Be Displayed">Display Title?</Label>
</td>
<td>
<select id="title" class="form-control" @bind="@_title">
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="background\" ResourceKey="Background" HelpText="Optionally Specify A Background Color For The Container">Background Color:</Label>
</td>
<td>
<select id="background" class="form-control" @bind="@_background">
<option value="">None</option>
<option value="bg-primary">Primary</option>
<option value="bg-secondary">Secondary</option>
<option value="bg-success">Success</option>
<option value="bg-danger">Danger</option>
<option value="bg-warning">Warning</option>
<option value="bg-info">Info</option>
<option value="bg-light">Light</option>
<option value="bg-dark">Dark</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="text" ResourceKey="Text" HelpText="Optionally Specify A Text Color For The Container">Text Color:</Label>
</td>
<td>
<select id="text" class="form-control" @bind="@_text">
<option value="">None</option>
<option value="text-primary">Primary</option>
<option value="text-secondary">Secondary</option>
<option value="text-success">Success</option>
<option value="text-danger">Danger</option>
<option value="text-warning">Warning</option>
<option value="text-info">Info</option>
<option value="text-light">Light</option>
<option value="text-dark">Dark</option>
</select>
</td>
</tr>
<tr>
<td>
<Label For="border" ResourceKey="Border" HelpText="Optionally Specify A Border For The Container">Border Color:</Label>
</td>
<td>
<select id="border" class="form-control" @bind="@_border">
<option value="">None</option>
<option value="border">Default</option>
<option value="border border-primary">Primary</option>
<option value="border border-secondary">Secondary</option>
<option value="border border-success">Success</option>
<option value="border border-danger">Danger</option>
<option value="border border-warning">Warning</option>
<option value="border border-info">Info</option>
<option value="border border-light">Light</option>
<option value="border border-dark">Dark</option>
</select>
</td>
</tr>
</table>
@code {
private string _title = "true";
private string _background = "";
private string _text = "";
private string _border = "";
protected override void OnInitialized()
{
try
{
_title = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Title", "true");
_background = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Background", "");
_text = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Text", "");
_border = SettingService.GetSetting(ModuleState.Settings, GetType().Namespace + ":Border", "");
}
catch (Exception ex)
{
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
}
}
public async Task UpdateSettings()
{
try
{
var settings = ModuleState.Settings;
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Title", _title);
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Background", _background);
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Text", _text);
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Border", _border);
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
}
catch (Exception ex)
{
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

View File

@ -1,10 +0,0 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ContainerBase
<div class="container">
<ModuleActions /><ModuleInstance />
</div>
@code {
public override string Name => "No Background Color - No Title";
}

View File

@ -1,20 +0,0 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ContainerBase
<div class="container">
<div class="row px-4">
<div class="d-flex flex-nowrap">
<ModuleActions /><h2><ModuleTitle /></h2>
</div>
<hr class="app-rule" />
</div>
<div class="row px-4">
<div class="container">
<ModuleInstance />
</div>
</div>
</div>
@code {
public override string Name => "No Background Color - With Title";
}

View File

@ -1,10 +0,0 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ContainerBase
<div class="container bg-primary">
<ModuleActions /><ModuleInstance />
</div>
@code {
public override string Name => "Primary Background Color - No Title";
}

View File

@ -1,20 +0,0 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ContainerBase
<div class="container bg-primary">
<div class="row px-4">
<div class="d-flex flex-nowrap">
<ModuleActions /><h2><ModuleTitle /></h2>
</div>
<hr class="app-rule" />
</div>
<div class="row px-4">
<div class="container">
<ModuleInstance />
</div>
</div>
</div>
@code {
public override string Name => "Primary Background Color - With Title";
}

View File

@ -1,10 +0,0 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ContainerBase
<div class="container bg-secondary">
<ModuleActions /><ModuleInstance />
</div>
@code {
public override string Name => "Secondary Background Color - No Title";
}

View File

@ -1,20 +0,0 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ContainerBase
<div class="container bg-secondary">
<div class="row px-4">
<div class="d-flex flex-nowrap">
<ModuleActions /><h2><ModuleTitle /></h2>
</div>
<hr class="app-rule" />
</div>
<div class="row px-4">
<div class="container">
<ModuleInstance />
</div>
</div>
</div>
@code {
public override string Name => "Secondary Background Color - With Title";
}

View File

@ -1,90 +0,0 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits LayoutBase
<div class="container">
<div class="row">
<div class="col-md-12">
<Pane Name="Content" />
</div>
</div>
</div>
<Pane Name="Top Full Width" />
<div class="container">
<div class="row">
<div class="col-md-12">
<Pane Name="Top 100%" />
</div>
</div>
<div class="row">
<div class="col-md-6">
<Pane Name="Left 50%" />
</div>
<div class="col-md-6">
<Pane Name="Right 50%" />
</div>
</div>
<div class="row">
<div class="col-md-4">
<Pane Name="Left 33%" />
</div>
<div class="col-md-4">
<Pane Name="Center 33%" />
</div>
<div class="col-md-4">
<Pane Name="Right 33%" />
</div>
</div>
<div class="row">
<div class="col-md-3">
<Pane Name="Left Outer 25%" />
</div>
<div class="col-md-3">
<Pane Name="Left Inner 25%" />
</div>
<div class="col-md-3">
<Pane Name="Right Inner 25%" />
</div>
<div class="col-md-3">
<Pane Name="Right Outer 25%" />
</div>
</div>
<div class="row">
<div class="col-md-3">
<Pane Name="Left 25%" />
</div>
<div class="col-md-6">
<Pane Name="Center 50%" />
</div>
<div class="col-md-3">
<Pane Name="Right 25%" />
</div>
</div>
<div class="row">
<div class="col-md-8">
<Pane Name="Left Sidebar 66%" />
</div>
<div class="col-md-4">
<Pane Name="Right Sidebar 33%" />
</div>
</div>
<div class="row">
<div class="col-md-4">
<Pane Name="Left Sidebar 33%" />
</div>
<div class="col-md-8">
<Pane Name="Right Sidebar 66%" />
</div>
</div>
<div class="row">
<div class="col-md-12">
<Pane Name="Bottom 100%" />
</div>
</div>
</div>
<Pane Name="Bottom Full Width" />
@code {
public override string Name => "Multiple Panes";
public override string Panes => "Content, Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width";
}

View File

@ -1,16 +0,0 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits LayoutBase
<div class="container">
<div class="row">
<div class="col-md-12">
<Pane Name="Content" />
</div>
</div>
</div>
@code {
public override string Name => "Single Pane";
public override string Panes => "Content";
}

View File

@ -1,4 +1,4 @@
using Oqtane.Models;
using Oqtane.Models;
namespace Oqtane.Themes.OqtaneTheme
{
@ -7,7 +7,9 @@ namespace Oqtane.Themes.OqtaneTheme
public Theme Theme => new Theme
{
Name = "Oqtane Theme",
Version = "1.0.0"
Version = "1.0.0",
ThemeSettingsType = "Oqtane.Themes.OqtaneTheme.ThemeSettings, Oqtane.Client",
ContainerSettingsType = "Oqtane.Themes.OqtaneTheme.ContainerSettings, Oqtane.Client"
};
}
}

View File

@ -1,5 +1,6 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ThemeBase
@inject ISettingService SettingService
<main role="main">
<nav class="navbar navbar-expand-md navbar-dark bg-primary fixed-top">
@ -8,20 +9,123 @@
<div class="controls-group"><UserProfile /> <Login /> <ControlPanel /></div>
</div>
</nav>
<PaneLayout />
<div class="content">
<div class="container">
<div class="row">
<div class="col-md-12">
<Pane Name="@PaneNames.Admin" />
</div>
</div>
</div>
<Pane Name="Top Full Width" />
<div class="container">
<div class="row">
<div class="col-md-12">
<Pane Name="Top 100%" />
</div>
</div>
<div class="row">
<div class="col-md-6">
<Pane Name="Left 50%" />
</div>
<div class="col-md-6">
<Pane Name="Right 50%" />
</div>
</div>
<div class="row">
<div class="col-md-4">
<Pane Name="Left 33%" />
</div>
<div class="col-md-4">
<Pane Name="Center 33%" />
</div>
<div class="col-md-4">
<Pane Name="Right 33%" />
</div>
</div>
<div class="row">
<div class="col-md-3">
<Pane Name="Left Outer 25%" />
</div>
<div class="col-md-3">
<Pane Name="Left Inner 25%" />
</div>
<div class="col-md-3">
<Pane Name="Right Inner 25%" />
</div>
<div class="col-md-3">
<Pane Name="Right Outer 25%" />
</div>
</div>
<div class="row">
<div class="col-md-3">
<Pane Name="Left 25%" />
</div>
<div class="col-md-6">
<Pane Name="Center 50%" />
</div>
<div class="col-md-3">
<Pane Name="Right 25%" />
</div>
</div>
<div class="row">
<div class="col-md-8">
<Pane Name="Left Sidebar 66%" />
</div>
<div class="col-md-4">
<Pane Name="Right Sidebar 33%" />
</div>
</div>
<div class="row">
<div class="col-md-4">
<Pane Name="Left Sidebar 33%" />
</div>
<div class="col-md-8">
<Pane Name="Right Sidebar 66%" />
</div>
</div>
<div class="row">
<div class="col-md-12">
<Pane Name="Bottom 100%" />
</div>
</div>
</div>
<Pane Name="Bottom Full Width" />
@if (_footer)
{
<div class="bg-primary footer">
<Pane Name="Footer" />
</div>
}
</div>
</main>
@code {
public override string Name => "Default Theme";
public override string Panes => string.Empty;
public override string Panes => PaneNames.Admin + ",Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width,Footer";
public override List<Resource> Resources => new List<Resource>()
{
{
new Resource { ResourceType = ResourceType.Stylesheet, Url = "https://stackpath.bootstrapcdn.com/bootswatch/4.5.0/cyborg/bootstrap.min.css", Integrity = "sha384-GKugkVcT8wqoh3M8z1lqHbU+g6j498/ZT/zuXbepz7Dc09/otQZxTimkEMTkRWHP", CrossOrigin = "anonymous" },
new Resource { ResourceType = ResourceType.Stylesheet, Url = ThemePath() + "Theme.css" },
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://code.jquery.com/jquery-3.5.1.slim.min.js", Integrity = "sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj", CrossOrigin = "anonymous" },
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js", Integrity = "sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo", CrossOrigin = "anonymous" },
new Resource { ResourceType = ResourceType.Script, Bundle = "Bootstrap", Url = "https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js", Integrity = "sha384-OgVRvuATP1z7JjHLkuOU7Xw704+h835Lr+6QL9UvYjZE3Ipu6Tp75j7Bh/kR0JKI", CrossOrigin = "anonymous" }
};
private bool _footer = false;
protected override void OnParametersSet()
{
try
{
_footer = bool.Parse(SettingService.GetSetting(PageState.Page.Settings, GetType().Namespace + ":Footer", "false"));
}
catch
{
// error loading theme settings
}
}
}

View File

@ -0,0 +1,49 @@
@namespace Oqtane.Themes.OqtaneTheme
@inherits ModuleBase
@implements Oqtane.Interfaces.ISettingsControl
@inject ISettingService SettingService
@attribute [OqtaneIgnore]
<table class="table table-borderless">
<tr>
<td>
<Label For="title" ResourceKey="Title" HelpText="Specify If The Page Footer Should Be Displayed">Display Footer?</Label>
</td>
<td>
<select id="title" class="form-control" @bind="@_footer">
<option value="true">Yes</option>
<option value="false">No</option>
</select>
</td>
</tr>
</table>
@code {
private string _footer = "false";
protected override void OnInitialized()
{
try
{
_footer = SettingService.GetSetting(PageState.Page.Settings, GetType().Namespace + ":Footer", "false");
}
catch (Exception ex)
{
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
}
}
public async Task UpdateSettings()
{
try
{
var settings = PageState.Page.Settings;
settings = SettingService.SetSetting(settings, GetType().Namespace + ":Footer", _footer);
await SettingService.UpdatePageSettingsAsync(settings, PageState.Page.PageId);
}
catch (Exception ex)
{
ModuleInstance.AddModuleMessage(ex.Message, MessageType.Error);
}
}
}

View File

@ -1,6 +1,6 @@
@namespace Oqtane.UI
<CascadingValue Value="@_moduleState" IsFixed="true">
<CascadingValue Value="@ModuleState" IsFixed="true">
@if (_useadminborder)
{
<div class="app-pane-admin-border">
@ -14,22 +14,20 @@
</CascadingValue>
@code {
private Module _moduleState;
private bool _useadminborder = false;
[CascadingParameter]
protected PageState PageState { get; set; }
[Parameter]
public Module Module { get; set; }
public Module ModuleState { get; set; }
RenderFragment DynamicComponent { get; set; }
protected override void OnParametersSet()
{
_moduleState = Module; // passed in from Pane component
string container = _moduleState.ContainerType;
if (PageState.ModuleId != -1 && _moduleState.UseAdminContainer)
string container = ModuleState.ContainerType;
if (PageState.ModuleId != -1 && ModuleState.UseAdminContainer)
{
container = (!string.IsNullOrEmpty(PageState.Site.AdminContainerType)) ? PageState.Site.AdminContainerType : Constants.DefaultAdminContainer;
}

View File

@ -124,7 +124,7 @@ else
private void CreateComponent(RenderTreeBuilder builder, Module module)
{
builder.OpenComponent(0, Type.GetType(Constants.ContainerComponent));
builder.AddAttribute(1, "Module", module);
builder.AddAttribute(1, "ModuleState", module);
builder.SetKey(module.PageModuleId);
builder.CloseComponent();
}

View File

@ -1,25 +1,5 @@
@namespace Oqtane.UI
@DynamicComponent
@namespace Oqtane.UI
@code {
[CascadingParameter]
protected PageState PageState { get; set; }
RenderFragment DynamicComponent { get; set; }
protected override void OnParametersSet()
{
DynamicComponent = builder =>
{
var layoutType = Type.GetType(PageState.Page.LayoutType);
if (layoutType == null)
{
// fallback
layoutType = Type.GetType(Constants.DefaultLayout);
}
builder.OpenComponent(0, layoutType);
builder.CloseComponent();
};
}
// panelayouts are deprecated - this component is included for backward compatibility
}

View File

@ -384,21 +384,15 @@
page.ThemeType = site.DefaultThemeType;
}
if (string.IsNullOrEmpty(page.LayoutType))
{
page.LayoutType = site.DefaultLayoutType;
}
page.Panes = new List<string>();
page.Resources = new List<Resource>();
string panes = "";
string panes = PaneNames.Admin;
Type themetype = Type.GetType(page.ThemeType);
if (themetype == null)
{
// fallback
page.ThemeType = Constants.DefaultTheme;
page.LayoutType = Constants.DefaultLayout;
themetype = Type.GetType(Constants.DefaultTheme);
}
if (themetype != null)
@ -406,24 +400,13 @@
var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
if (themeobject != null)
{
panes = themeobject.Panes;
if (!string.IsNullOrEmpty(themeobject.Panes))
{
panes = themeobject.Panes;
}
page.Resources = ManagePageResources(page.Resources, themeobject.Resources);
}
}
if (!string.IsNullOrEmpty(page.LayoutType))
{
Type layouttype = Type.GetType(page.LayoutType);
if (layouttype != null)
{
var layoutobject = Activator.CreateInstance(layouttype) as IThemeControl;
if (layoutobject != null)
{
panes = layoutobject.Panes;
}
}
}
page.Panes = panes.Replace(";", ",").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
}
catch

View File

@ -0,0 +1,83 @@
/* Oqtane Styles */
body {
padding-top: 7rem;
}
.controls {
z-index: 2000;
padding-top: 15px;
padding-bottom: 15px;
margin-right: 10px;
}
.app-menu .nav-item {
font-size: 0.9rem;
padding-bottom: 0.5rem;
}
.app-menu .nav-item a {
border-radius: 4px;
height: 3rem;
display: flex;
align-items: center;
line-height: 3rem;
}
.app-menu .nav-item a.active {
background-color: rgba(255,255,255,0.25);
color: white;
}
.app-menu .nav-item a:hover {
background-color: rgba(255,255,255,0.1);
color: white;
}
.app-menu .nav-link .oi {
width: 1.5rem;
font-size: 1.1rem;
vertical-align: text-top;
top: -2px;
}
.navbar-toggler {
background-color: rgba(255, 255, 255, 0.1);
margin-left: auto;
}
div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu {
color:#000000;
}
@media (max-width: 767px) {
.app-menu {
width: 100%
}
.navbar {
position: fixed;
top: 60px;
width: 100%;
}
.controls {
height: 60px;
top: 15px;
position: fixed;
top: 0px;
width: 100%;
background-color: rgb(0, 0, 0);
}
.controls-group {
float: right;
margin-right: 25px;
}
.content {
position: relative;
top: 60px;
}
}

View File

@ -12,6 +12,7 @@ using Oqtane.Modules;
using Oqtane.Shared;
using Oqtane.Themes;
using Microsoft.Extensions.Caching.Memory;
using System.Collections.Generic;
namespace Oqtane.Controllers
{
@ -180,6 +181,7 @@ namespace Oqtane.Controllers
}
}
}
return memoryStream.ToArray();
}
});

View File

@ -1,4 +1,4 @@
using System.Collections.Generic;
using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Oqtane.Models;
@ -19,16 +19,18 @@ namespace Oqtane.Controllers
private readonly IPageRepository _pages;
private readonly IModuleRepository _modules;
private readonly IPageModuleRepository _pageModules;
private readonly ISettingRepository _settings;
private readonly IUserPermissions _userPermissions;
private readonly ITenantResolver _tenants;
private readonly ISyncManager _syncManager;
private readonly ILogManager _logger;
public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger)
public PageController(IPageRepository pages, IModuleRepository modules, IPageModuleRepository pageModules, ISettingRepository settings, IUserPermissions userPermissions, ITenantResolver tenants, ISyncManager syncManager, ILogManager logger)
{
_pages = pages;
_modules = modules;
_pageModules = pageModules;
_settings = settings;
_userPermissions = userPermissions;
_tenants = tenants;
_syncManager = syncManager;
@ -39,11 +41,15 @@ namespace Oqtane.Controllers
[HttpGet]
public IEnumerable<Page> Get(string siteid)
{
List<Setting> settings = _settings.GetSettings(EntityNames.Page).ToList();
List<Page> pages = new List<Page>();
foreach (Page page in _pages.GetPages(int.Parse(siteid)))
{
if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions))
{
page.Settings = settings.Where(item => item.EntityId == page.PageId)
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
pages.Add(page);
}
}
@ -65,6 +71,8 @@ namespace Oqtane.Controllers
}
if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions))
{
page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId)
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
return page;
}
else
@ -84,6 +92,8 @@ namespace Oqtane.Controllers
{
if (_userPermissions.IsAuthorized(User,PermissionNames.View, page.Permissions))
{
page.Settings = _settings.GetSettings(EntityNames.Page, page.PageId)
.ToDictionary(setting => setting.SettingName, setting => setting.SettingValue);
return page;
}
else
@ -164,7 +174,6 @@ namespace Oqtane.Controllers
page.IsNavigation = false;
page.Url = "";
page.ThemeType = parent.ThemeType;
page.LayoutType = parent.LayoutType;
page.DefaultContainerType = parent.DefaultContainerType;
page.Icon = parent.Icon;
page.Permissions = new List<Permission> {

View File

@ -90,7 +90,6 @@ namespace Oqtane.Infrastructure
install.HostName = UserNames.Host;
install.SiteTemplate = GetInstallationConfig(SettingKeys.SiteTemplateKey, Constants.DefaultSiteTemplate);
install.DefaultTheme = GetInstallationConfig(SettingKeys.DefaultThemeKey, Constants.DefaultTheme);
install.DefaultLayout = GetInstallationConfig(SettingKeys.DefaultLayoutKey, Constants.DefaultLayout);
install.DefaultContainer = GetInstallationConfig(SettingKeys.DefaultContainerKey, Constants.DefaultContainer);
install.SiteName = Constants.DefaultSite;
install.IsNewTenant = true;
@ -122,10 +121,6 @@ namespace Oqtane.Infrastructure
if (string.IsNullOrEmpty(install.DefaultTheme))
{
install.DefaultTheme = GetInstallationConfig(SettingKeys.DefaultThemeKey, Constants.DefaultTheme);
if (string.IsNullOrEmpty(install.DefaultLayout))
{
install.DefaultLayout = GetInstallationConfig(SettingKeys.DefaultLayoutKey, Constants.DefaultLayout);
}
}
if (string.IsNullOrEmpty(install.DefaultContainer))
{
@ -438,7 +433,6 @@ namespace Oqtane.Infrastructure
Name = install.SiteName,
LogoFileId = null,
DefaultThemeType = install.DefaultTheme,
DefaultLayoutType = install.DefaultLayout,
DefaultContainerType = install.DefaultContainer,
SiteTemplateType = install.SiteTemplate
};

View File

@ -1,4 +1,4 @@
namespace Oqtane.Infrastructure
namespace Oqtane.Infrastructure
{
public interface ILocalizationManager
{

View File

@ -1,9 +1,7 @@
namespace Oqtane.Infrastructure
namespace Oqtane.Infrastructure
{
public class LocalizationOptions
{
public string DefaultCulture { get; set; }
public string[] SupportedCultures { get; set; }
}
}

View File

@ -1,4 +1,6 @@
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Microsoft.Extensions.Options;
using Oqtane.Shared;
@ -22,8 +24,23 @@ namespace Oqtane.Infrastructure
: _localizationOptions.DefaultCulture;
public string[] GetSupportedCultures()
=> _localizationOptions.SupportedCultures.IsNullOrEmpty()
? SupportedCultures
: _localizationOptions.SupportedCultures;
{
List<string> cultures = new List<string>();
foreach(var file in Directory.EnumerateFiles(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "*.resources.dll", SearchOption.AllDirectories))
{
if (!cultures.Contains(Path.GetFileName(Path.GetDirectoryName(file))))
{
cultures.Add(Path.GetFileName(Path.GetDirectoryName(file)));
}
}
if (cultures.Count == 0)
{
return SupportedCultures;
}
else
{
return cultures.ToArray();
}
}
}
}

View File

@ -91,7 +91,14 @@ namespace Oqtane.Infrastructure
var internalTemplatePath = Utilities.PathCombine(_environment.WebRootPath, "Modules", "Templates", "Internal", Path.DirectorySeparatorChar.ToString());
if (Directory.Exists(internalTemplatePath))
{
Directory.Delete(internalTemplatePath, true);
try
{
Directory.Delete(internalTemplatePath, true);
}
catch
{
// error deleting directory
}
}
}

View File

@ -41,6 +41,7 @@
<EmbeddedResource Include="Scripts\Tenant.02.00.01.03.sql" />
<EmbeddedResource Include="Scripts\Tenant.02.00.02.01.sql" />
<EmbeddedResource Include="Scripts\Tenant.02.00.02.02.sql" />
<EmbeddedResource Include="Scripts\Tenant.02.00.02.03.sql" />
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.1.0.0.sql" />
<EmbeddedResource Include="Modules\HtmlText\Scripts\HtmlText.Uninstall.sql" />
</ItemGroup>

View File

@ -745,7 +745,6 @@ namespace Oqtane.Repository
Url = "",
IsNavigation = pagetemplate.IsNavigation,
ThemeType = "",
LayoutType = "",
DefaultContainerType = "",
Icon = pagetemplate.Icon,
Permissions = pagetemplate.PagePermissions,

View File

@ -63,7 +63,7 @@ namespace Oqtane.Repository
{
// Check if type should be ignored
if (themeControlType.IsOqtaneIgnore() ||
themeControlType.GetInterfaces().Contains(typeof(ILayoutControl)) ||
themeControlType.GetInterfaces().Contains(typeof(ILayoutControl)) || // deprecated
themeControlType.GetInterfaces().Contains(typeof(IContainerControl))) continue;
// create namespace root typename
@ -98,7 +98,6 @@ namespace Oqtane.Repository
// set internal properties
theme.ThemeName = qualifiedThemeType;
theme.Themes = new List<ThemeControl>();
theme.Layouts = new List<ThemeControl>();
theme.Containers = new List<ThemeControl>();
theme.AssemblyName = assembly.FullName.Split(",")[0];
themes.Add(theme);
@ -113,27 +112,10 @@ namespace Oqtane.Repository
TypeName = themeControlType.FullName + ", " + themeControlType.Assembly.GetName().Name,
Name = theme.Name + " - " + ((string.IsNullOrEmpty(themecontrolobject.Name)) ? Utilities.GetTypeNameLastSegment(themeControlType.FullName, 0) : themecontrolobject.Name),
Thumbnail = themecontrolobject.Thumbnail,
Panes = themecontrolobject.Panes
Panes = (!string.IsNullOrEmpty(themecontrolobject.Panes)) ? themecontrolobject.Panes : PaneNames.Admin
}
);
// layouts
Type[] layouttypes = themeTypes
.Where(item => item.GetInterfaces().Contains(typeof(ILayoutControl))).ToArray();
foreach (Type layouttype in layouttypes)
{
var layoutobject = Activator.CreateInstance(layouttype) as IThemeControl;
theme.Layouts.Add(
new ThemeControl
{
TypeName = layouttype.FullName + ", " + themeControlType.Assembly.GetName().Name,
Name = (string.IsNullOrEmpty(layoutobject.Name)) ? Utilities.GetTypeNameLastSegment(layouttype.FullName, 0) : layoutobject.Name,
Thumbnail = layoutobject.Thumbnail,
Panes = layoutobject.Panes
}
);
}
// containers
Type[] containertypes = themeTypes
.Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray();

View File

@ -0,0 +1,31 @@
/*
Version 2.0.2 Tenant migration script
*/
ALTER TABLE [dbo].[Setting] ALTER COLUMN [SettingName] [nvarchar](200) NOT NULL
GO
ALTER TABLE [dbo].[Site]
DROP COLUMN DefaultLayoutType
GO
ALTER TABLE [dbo].[Page]
DROP COLUMN LayoutType
GO
UPDATE [dbo].[Site] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client';
GO
UPDATE [dbo].[Site] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client';
GO
UPDATE [dbo].[Page] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client';
GO
UPDATE [dbo].[Page] SET DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client' WHERE DefaultContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client';
GO
UPDATE [dbo].[PageModule] SET ContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client' WHERE ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client';
GO
UPDATE [dbo].[PageModule] SET ContainerType = 'Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client' WHERE ContainerType = 'Oqtane.Themes.OqtaneTheme.DefaultNoTitle, Oqtane.Client';
GO

View File

@ -41,7 +41,6 @@ namespace Oqtane
Configuration = builder.Build();
_supportedCultures = localizationManager.GetSupportedCultures();
_runtime = (Configuration.GetSection("Runtime").Value == "WebAssembly") ? Runtime.WebAssembly : Runtime.Server;
//add possibility to switch off swagger on production.

View File

@ -74,7 +74,7 @@
{
try
{
if (string.IsNullOrEmpty(_name))
if (!string.IsNullOrEmpty(_name))
{
if (PageState.Action == "Add")
{

View File

@ -36,40 +36,6 @@ else
}
}
<!-- The content below is for informational purposes only and can be safely removed -->
<hr />
[Module] Module Created Successfully. Use Edit Mode To Add A [Module]. You Can Access The Files At The Following Locations:<br /><br />
[RootPath]Client\<br />
- [Owner].[Module].Client.csproj - client project<br />
- _Imports.razor - global imports for module components<br />
- Edit.razor - component for adding or editing content<br />
- Index.razor - main component for your module **the content you are reading is in this file**<br />
- ModuleInfo.cs - implements IModule interface to provide configuration settings for your module<br />
- Settings.razor - component for managing module settings<br />
- Services\I[Module]Service.cs - interface for defining service API methods<br />
- Services\[Module]Service.cs - implements service API interface methods<br /><br />
[RootPath]Package\<br />
- [Owner].[Module].nuspec - nuget manifest for packaging module<br />
- [Owner].[Module].Package.csproj - packaging project<br />
- debug.cmd - copies assemblies to Oqtane bin folder when in Debug mode<br />
- release.cmd - creates nuget package and deploys to Oqtane wwwroot/modules folder when in Release mode<br /><br />
[RootPath]Server\<br />
- [Owner].[Module].Server.csproj - server project<br />
- Controllers\[Module]Controller.cs - API methods implemented using a REST pattern<br />
- Manager\[Module]Manager.cs - implements optional module interfaces for features such as import/export of content<br />
- Repository\I[Module]Repository.cs - interface for defining repository methods<br />
- Repository\[Module]Respository.cs - implements repository interface methods for data access using EF Core<br />
- Repository\[Module]Context.cs - provides a DB Context for data access<br />
- Scripts\[Owner].[Module].1.0.0.sql - database schema definition script<br />
- Scripts\[Owner].[Module].Uninstall.sql - database uninstall script<br />
- wwwroot\Module.css - module style sheet<br /><br />
[RootPath]Shared\<br />
- [Owner].[Module].csproj - shared project<br />
- Models\[Module].cs - model definition<br /><br />
<!-- The content above is for informational purposes only and can be safely removed -->
@code {
public override List<Resource> Resources => new List<Resource>()
{

View File

@ -1,4 +1,4 @@
/* Oqtane Styles */
/* Oqtane Styles */
body {
padding-top: 7rem;
@ -50,6 +50,13 @@ div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu
color:#ffffff;
}
.footer {
padding-top: 15px;
min-height: 40px;
text-align: center;
color: #ffffff;
}
@media (max-width: 767px) {
.app-menu {

View File

@ -8,10 +8,11 @@
<div class="controls-group"><UserProfile /> <Login /> <ControlPanel /></div>
</div>
</nav>
<div class="content">
<div class="container">
<div class="row">
<div class="col-md-12">
<Pane Name="Content" />
<Pane Name="@PaneNames.Admin" />
</div>
</div>
</div>
@ -89,12 +90,13 @@
</div>
</div>
<Pane Name="Bottom Full Width" />
</div>
</main>
@code {
public override string Name => "Theme1";
public override string Panes => "Content,Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width";
public override string Panes => PaneNames.Admin + ",Top Full Width,Top 100%,Left 50%,Right 50%,Left 33%,Center 33%,Right 33%,Left Outer 25%,Left Inner 25%,Right Inner 25%,Right Outer 25%,Left 25%,Center 50%,Right 25%,Left Sidebar 66%,Right Sidebar 33%,Left Sidebar 33%,Right Sidebar 66%,Bottom 100%,Bottom Full Width";
public override List<Resource> Resources => new List<Resource>()
{

View File

@ -47,7 +47,7 @@ body {
}
div.app-moduleactions a.dropdown-toggle, div.app-moduleactions div.dropdown-menu {
color:#ffffff;
color:#000000;
}
@media (max-width: 767px) {

View File

@ -0,0 +1,11 @@
The _content folder should only contain static resources from shared razor component libraries (RCLs). Static resources can be extracted from shared RCL Nuget packages by executing a Publish task on the module's Server project to a local folder and copying the files from the _content folder which is created. Each shared RCL would have its own appropriately named subfolder within the module's _content folder.
ie.
/_content
/Radzen.Blazor
/css
/fonts
/syncfusion.blazor
/scripts
/styles

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.ComponentModel.DataAnnotations.Schema;
namespace Oqtane.Models
@ -21,6 +21,7 @@ namespace Oqtane.Models
ControlTypeRoutes = "";
ReleaseVersions = "";
DefaultAction = "";
SettingsType = "";
Runtimes = "";
Template = "";
}
@ -60,6 +61,8 @@ namespace Oqtane.Models
public string ReleaseVersions { get; set; }
[NotMapped]
public string DefaultAction { get; set; }
[NotMapped]
public string SettingsType { get; set; } // added in 2.0.2
// internal properties
[NotMapped]

View File

@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations.Schema;
@ -15,7 +15,6 @@ namespace Oqtane.Models
public int Order { get; set; }
public string Url { get; set; }
public string ThemeType { get; set; }
public string LayoutType { get; set; }
public string DefaultContainerType { get; set; }
public string Icon { get; set; }
public bool IsNavigation { get; set; }
@ -37,12 +36,19 @@ namespace Oqtane.Models
[NotMapped]
public string Permissions { get; set; }
[NotMapped]
public Dictionary<string, string> Settings { get; set; }
[NotMapped]
public int Level { get; set; }
[NotMapped]
public bool HasChildren { get; set; }
[Obsolete("This property is obsolete", false)]
[Obsolete("This property is deprecated", false)]
[NotMapped]
public bool EditMode { get; set; }
[Obsolete("This property is deprecated", false)]
[NotMapped]
public string LayoutType { get; set; }
}
}

View File

@ -11,7 +11,6 @@ namespace Oqtane.Models
public int? LogoFileId { get; set; }
public int? FaviconFileId { get; set; }
public string DefaultThemeType { get; set; }
public string DefaultLayoutType { get; set; }
public string DefaultContainerType { get; set; }
public string AdminContainerType { get; set; }
public bool PwaIsEnabled { get; set; }
@ -30,5 +29,9 @@ namespace Oqtane.Models
[NotMapped]
public string SiteTemplateType { get; set; }
[NotMapped]
[Obsolete("This property is deprecated.", false)]
public string DefaultLayoutType { get; set; }
}
}

View File

@ -25,17 +25,22 @@ namespace Oqtane.Models
public string Contact { get; set; }
public string License { get; set; }
public string Dependencies { get; set; }
public string ThemeSettingsType { get; set; }
public string ContainerSettingsType { get; set; }
// internal properties
public string AssemblyName { get; set; }
public List<ThemeControl> Themes { get; set; }
public List<ThemeControl> Layouts { get; set; }
public List<ThemeControl> Containers { get; set; }
public string Template { get; set; }
//[Obsolete("This property is obsolete. Use Themes instead.", false)]
[Obsolete("This property is obsolete. Use Themes instead.", false)]
public string ThemeControls { get; set; }
//[Obsolete("This property is obsolete. Use Layouts instead.", false)]
[Obsolete("This property is obsolete. Use Layouts instead.", false)]
public string PaneLayouts { get; set; }
//[Obsolete("This property is obsolete. Use Containers instead.", false)]
[Obsolete("This property is obsolete. Use Containers instead.", false)]
public string ContainerControls { get; set; }
[Obsolete("This property is obsolete.", false)]
public List<ThemeControl> Layouts { get; set; }
}
}

View File

@ -12,8 +12,9 @@ namespace Oqtane.Shared {
public const string ContainerComponent = "Oqtane.UI.ContainerBuilder, Oqtane.Client";
public const string DefaultTheme = "Oqtane.Themes.OqtaneTheme.Default, Oqtane.Client";
public const string DefaultLayout = "Oqtane.Themes.OqtaneTheme.SinglePane, Oqtane.Client";
public const string DefaultContainer = "Oqtane.Themes.OqtaneTheme.DefaultTitle, Oqtane.Client";
[Obsolete("DefaultLayout is deprecated")]
public const string DefaultLayout = "";
public const string DefaultContainer = "Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client";
public const string DefaultAdminContainer = "Oqtane.Themes.AdminContainer, Oqtane.Client";
public const string ActionToken = "{Action}";

View File

@ -12,7 +12,6 @@ namespace Oqtane.Shared
public string HostName { get; set; }
public string SiteTemplate { get; set; }
public string DefaultTheme { get; set; }
public string DefaultLayout { get; set; }
public string DefaultContainer { get; set; }
public string DefaultAdminContainer { get; set; }
}

View File

@ -1,5 +1,5 @@
namespace Oqtane.Shared {
public class PaneNames {
public const string Admin = "Content";
public const string Admin = "Admin";
}
}