diff --git a/Oqtane.Client/Modules/Admin/Sites/Index.razor b/Oqtane.Client/Modules/Admin/Sites/Index.razor index 7133f8b5..9b758fdd 100644 --- a/Oqtane.Client/Modules/Admin/Sites/Index.razor +++ b/Oqtane.Client/Modules/Admin/Sites/Index.razor @@ -20,7 +20,7 @@ else - + @context.Name diff --git a/Oqtane.Client/Modules/Controls/ActionDialog.razor b/Oqtane.Client/Modules/Controls/ActionDialog.razor index 3a8a94ce..aaffa1f7 100644 --- a/Oqtane.Client/Modules/Controls/ActionDialog.razor +++ b/Oqtane.Client/Modules/Controls/ActionDialog.razor @@ -28,7 +28,14 @@ } @if (authorized) { - + if (Disabled) + { + + } + else + { + + } } @code { @@ -36,13 +43,13 @@ public string Header { get; set; } // required [Parameter] - public string Message { get; set; } // required + public string Message { get; set; } // required [Parameter] public string Text { get; set; } // optional - defaults to Action if not specified [Parameter] - public string Action { get; set; } // optional + public string Action { get; set; } // optional [Parameter] public SecurityAccessLevel? Security { get; set; } // optional - can be used to explicitly specify SecurityAccessLevel @@ -50,6 +57,9 @@ [Parameter] public string Class { get; set; } // optional + [Parameter] + public bool Disabled { get; set; } // optional + [Parameter] public string EditMode { get; set; } // optional - specifies if a user must be in edit mode to see the action - default is true diff --git a/Oqtane.Client/Modules/Controls/ActionLink.razor b/Oqtane.Client/Modules/Controls/ActionLink.razor index d3c3a08b..2ed9c3e7 100644 --- a/Oqtane.Client/Modules/Controls/ActionLink.razor +++ b/Oqtane.Client/Modules/Controls/ActionLink.razor @@ -4,7 +4,14 @@ @if (authorized) { - @text + if (Disabled) + { + @text + } + else + { + @text + } } @code { @@ -26,6 +33,9 @@ [Parameter] public string Style { get; set; } // optional + [Parameter] + public bool Disabled { get; set; } // optional + [Parameter] public string EditMode { get; set; } // optional - specifies if a user must be in edit mode to see the action - default is true diff --git a/Oqtane.Client/Shared/SiteRouter.razor b/Oqtane.Client/Shared/SiteRouter.razor index 2438ed57..9cbed5f8 100644 --- a/Oqtane.Client/Shared/SiteRouter.razor +++ b/Oqtane.Client/Shared/SiteRouter.razor @@ -190,7 +190,10 @@ { page = pages.Where(item => item.Path == path).FirstOrDefault(); reload = Reload.Page; - editmode = page.EditMode; + if (page!=null) + { + editmode = page.EditMode; + } } user = null; diff --git a/Oqtane.Client/Themes/Controls/ControlPanel.razor b/Oqtane.Client/Themes/Controls/ControlPanel.razor index 68a80cfe..e433f30e 100644 --- a/Oqtane.Client/Themes/Controls/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/ControlPanel.razor @@ -301,7 +301,7 @@ private async Task AddModule() { - if (UserSecurity.IsAuthorized(PageState.User, "Edit", PageState.Page.Permissions)) + if (UserSecurity.IsAuthorized(PageState.User, "Edit", PageState.Page.Permissions) && !string.IsNullOrWhiteSpace(moduledefinitionname) && moduledefinitionname != "-") { if (moduletype == "new") { diff --git a/Oqtane.Server/Controllers/SiteController.cs b/Oqtane.Server/Controllers/SiteController.cs index 23b5c4d7..dc8361ec 100644 --- a/Oqtane.Server/Controllers/SiteController.cs +++ b/Oqtane.Server/Controllers/SiteController.cs @@ -87,8 +87,15 @@ namespace Oqtane.Controllers [Authorize(Roles = Constants.HostRole)] public void Delete(int id) { - Sites.DeleteSite(id); - logger.Log(LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", id); + if (Sites.GetSites().Count() > 1) + { + Sites.DeleteSite(id); + logger.Log(LogLevel.Information, this, LogFunction.Delete, "Site Deleted {SiteId}", id); + } + else + { + logger.Log(LogLevel.Warning, this, LogFunction.Delete, "Unable to delete the root site."); + } } } } diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index 495930ba..b51aace3 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -142,10 +142,13 @@ namespace Oqtane.Repository } public void DeleteSite(int siteId) - { - Site site = db.Site.Find(siteId); - db.Site.Remove(site); - db.SaveChanges(); + { + if (db.Site.Count() > 1) + { + var site = db.Site.Find(siteId); + db.Site.Remove(site); + db.SaveChanges(); + } } private void CreateSite(Site site) diff --git a/Oqtane.Server/appsettings.json b/Oqtane.Server/appsettings.json index dbfefb7f..7f07c90a 100644 --- a/Oqtane.Server/appsettings.json +++ b/Oqtane.Server/appsettings.json @@ -2,4 +2,4 @@ "ConnectionStrings": { "DefaultConnection": "" } -} \ No newline at end of file +} diff --git a/README.md b/README.md index e719bd89..f3fa1aa3 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,9 @@ Oqtane uses Blazor, a new web framework for .NET Core that lets you build intera **To get started with Oqtane:** - 1. Oqtane is currently compatible with **[.NET Core 3.1](https://dotnet.microsoft.com/download/dotnet-core/3.1)**. + 1. Install **[.NET Core 3.1 SDK](https://dotnet.microsoft.com/download/dotnet-core/3.1)**. - 2. Install the latest edition of [Visual Studio 2019](https://visualstudio.com/vs/) (version 16.4 or higher) with the **ASP.NET and web development** workload. Installing the latest edition will also install the latest version of .NET Core 3.1. + 2. Install the latest edition of [Visual Studio 2019](https://visualstudio.com/vs/) (version 16.4 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**. 3. Download or Clone the Oqtane source code to your local system. Open the **Oqtane.sln** solution file. If you want to develop using **server-side** Blazor (which includes a full debugging experience in Visual Studio) you should choose to Build the solution using the default Debug configuration. If you want to develop using **client-side** Blazor (WebAssembly) you should first choose the "Wasm" configuration option in the Visual Studio toolbar and then Build. @@ -18,6 +18,29 @@ Oqtane uses Blazor, a new web framework for .NET Core that lets you build intera # Roadmap This project is a work in progress and the schedule for implementing enhancements is dependent upon the availability of community members who are willing/able to assist. +V1 (MVP) +- Multi-Tenant ( Shared Database & Isolated Database ) **done** +- Modular Architecture / Headless API **done** +- Dynamic Page Compositing Model / Site & Page Management **done** +- Authentication / User Management / Profile Management **done** +- Authorization / Roles Management / Granular Permissions **done** +- Dynamic Routing **done** +- Extensibility via Custom Modules **done** +- Extensibility via Custom Themes **done** +- Event Logging **done** +- Folder / File Management **done** +- Recycle Bin **done** +- Scheduled Jobs ( Background Processing ) **done** +- Notifications / Email Delivery **done** +- Auto-Upgrade Framework **done** + +V.Next +- Optional Encryption of Settings Values ( ie. via an IsSecure flag ) +- Localization +- Migrate to Code-Behind Pattern ( *.razor.cs ) +- Generic Repository Pattern +- JwT token authentication + # Background Oqtane was created by [Shaun Walker](https://www.linkedin.com/in/shaunbrucewalker/) and is inspired by the DotNetNuke web application framework. Initially created as a proof of concept, Oqtane is a native Blazor application written from the ground up using modern .NET Core technology. It is a modular application framework offering a fully dynamic page compositing model, multi-site support, designer friendly templates (skins), and extensibility via third party modules. @@ -55,3 +78,6 @@ Control panel for adding, editing, and deleting pages as well as adding new modu ![Manage Page](https://github.com/oqtane/framework/blob/master/screenshot5.png?raw=true "Manage Page") +Admin dashboard for accessing the variuous administrative features of the framework: + +![Admin Dashboard](https://github.com/oqtane/framework/blob/master/screenshot6.png?raw=true "Admin Dashboard")