@PageState.Page.Name - Theme #2
@PageState.Page.Name
-
Admin Dashboard diff --git a/Oqtane.Client/Themes/Controls/Logo.razor b/Oqtane.Client/Themes/Controls/Logo.razor index 192a0f66..00ab7f89 100644 --- a/Oqtane.Client/Themes/Controls/Logo.razor +++ b/Oqtane.Client/Themes/Controls/Logo.razor @@ -1,5 +1,6 @@ @namespace Oqtane.Themes.Controls @inherits ThemeControlBase +@inject NavigationManager NavigationManager @((MarkupString)logo) @@ -10,7 +11,8 @@ { if (PageState.Site.Logo != "") { - logo = ""; + Uri uri = new Uri(NavigationManager.Uri); + logo = "
"; } } } \ No newline at end of file diff --git a/Oqtane.Client/Themes/Controls/ModuleActions.razor b/Oqtane.Client/Themes/Controls/ModuleActions.razor index a86e7548..c39cb8c4 100644 --- a/Oqtane.Client/Themes/Controls/ModuleActions.razor +++ b/Oqtane.Client/Themes/Controls/ModuleActions.razor @@ -7,7 +7,7 @@ @if (PageState.DesignMode && UserSecurity.IsAuthorized(PageState.User, "Edit", ModuleState.Permissions)) {
- +@foreach (var action in actions) { diff --git a/Oqtane.Client/Themes/ILayoutControl.cs b/Oqtane.Client/Themes/ILayoutControl.cs new file mode 100644 index 00000000..4aaa961a --- /dev/null +++ b/Oqtane.Client/Themes/ILayoutControl.cs @@ -0,0 +1,7 @@ +namespace Oqtane.Themes +{ + public interface ILayoutControl + { + + } +} diff --git a/Oqtane.Client/Themes/IThemeControl.cs b/Oqtane.Client/Themes/IThemeControl.cs index fe8906d1..e9e19e7c 100644 --- a/Oqtane.Client/Themes/IThemeControl.cs +++ b/Oqtane.Client/Themes/IThemeControl.cs @@ -2,7 +2,6 @@ { public interface IThemeControl { - string Name { get; } - string Panes { get; } // if a theme has different panes, delimit them with ";" + string Panes { get; } // identifies all panes in a theme ( delimited by ";" ) - assumed to be a layout if no panes specified } } diff --git a/Oqtane.Client/Themes/LayoutBase.cs b/Oqtane.Client/Themes/LayoutBase.cs new file mode 100644 index 00000000..546937ab --- /dev/null +++ b/Oqtane.Client/Themes/LayoutBase.cs @@ -0,0 +1,18 @@ +using Microsoft.AspNetCore.Components; +using Oqtane.Shared; + +namespace Oqtane.Themes +{ + public class LayoutBase : ComponentBase, ILayoutControl + { + [CascadingParameter] + protected PageState PageState { get; set; } + public virtual string Panes { get; set; } + + public string LayoutPath() + { + return "Themes/" + this.GetType().Namespace + "/"; + } + + } +} diff --git a/Oqtane.Client/Themes/Theme2/Container2.razor b/Oqtane.Client/Themes/OqtaneTheme/Container.razor similarity index 89% rename from Oqtane.Client/Themes/Theme2/Container2.razor rename to Oqtane.Client/Themes/OqtaneTheme/Container.razor index 45163ad6..b3d0bfb2 100644 --- a/Oqtane.Client/Themes/Theme2/Container2.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Container.razor @@ -1,4 +1,4 @@ -@namespace Oqtane.Themes.Theme2 +@namespace Oqtane.Themes.OqtaneTheme @inherits ContainerBasediff --git a/Oqtane.Client/Themes/Theme1/Theme1.razor b/Oqtane.Client/Themes/OqtaneTheme/Default.razor similarity index 50% rename from Oqtane.Client/Themes/Theme1/Theme1.razor rename to Oqtane.Client/Themes/OqtaneTheme/Default.razor index 9021eef8..054ceb5b 100644 --- a/Oqtane.Client/Themes/Theme1/Theme1.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Default.razor @@ -1,4 +1,4 @@ -@namespace Oqtane.Themes.Theme1 +@namespace Oqtane.Themes.OqtaneTheme @inherits ThemeBase@@ -8,16 +8,14 @@-@PageState.Page.Name - Theme #1
+@PageState.Page.Name
-+--- -+- + +@@ -26,6 +24,10 @@ @@ -11,6 +11,5 @@@code { - public override string Name { get { return "Horizontal Layout"; } } public override string Panes { get { return "Left;Right"; } } } \ No newline at end of file diff --git a/Oqtane.Client/Themes/Theme3/Theme3.razor b/Oqtane.Client/Themes/OqtaneTheme/Layouts.razor similarity index 54% rename from Oqtane.Client/Themes/Theme3/Theme3.razor rename to Oqtane.Client/Themes/OqtaneTheme/Layouts.razor index e9d5a4bf..0f34ec48 100644 --- a/Oqtane.Client/Themes/Theme3/Theme3.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Layouts.razor @@ -1,4 +1,4 @@ -@namespace Oqtane.Themes.Theme3 +@namespace Oqtane.Themes.OqtaneTheme @inherits ThemeBase@@ -8,7 +8,7 @@-@PageState.Page.Name - Theme #3
+@PageState.Page.Name
@@ -19,6 +19,8 @@ properties = new Dictionary { - { "Name", "Theme1" }, + { "Name", "Oqtane Theme" }, { "Version", "1.0.0" } }; return properties; diff --git a/Oqtane.Client/Themes/Theme3/VerticalLayout.razor b/Oqtane.Client/Themes/OqtaneTheme/Vertical.razor similarity index 60% rename from Oqtane.Client/Themes/Theme3/VerticalLayout.razor rename to Oqtane.Client/Themes/OqtaneTheme/Vertical.razor index 46a81562..39da1cde 100644 --- a/Oqtane.Client/Themes/Theme3/VerticalLayout.razor +++ b/Oqtane.Client/Themes/OqtaneTheme/Vertical.razor @@ -1,5 +1,5 @@ -@namespace Oqtane.Themes.Theme3 -@inherits ThemeBase +@namespace Oqtane.Themes.OqtaneTheme +@inherits LayoutBase @@ -9,6 +9,5 @@ -diff --git a/Oqtane.Client/Themes/Theme3/Theme.cs b/Oqtane.Client/Themes/Theme3/Theme.cs deleted file mode 100644 index 53def728..00000000 --- a/Oqtane.Client/Themes/Theme3/Theme.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; - -namespace Oqtane.Themes.Theme3 -{ - public class Theme : ITheme - { - public Dictionary--
-
------ Properties - { - get - { - Dictionary properties = new Dictionary - { - { "Name", "Theme3" }, - { "Version", "1.0.0" } - }; - return properties; - } - } - } -} diff --git a/Oqtane.Client/Themes/ThemeBase.cs b/Oqtane.Client/Themes/ThemeBase.cs index 1f6b1247..631ef9ea 100644 --- a/Oqtane.Client/Themes/ThemeBase.cs +++ b/Oqtane.Client/Themes/ThemeBase.cs @@ -12,7 +12,6 @@ namespace Oqtane.Themes [CascadingParameter] protected PageState PageState { get; set; } - public virtual string Name { get; set; } public virtual string Panes { get; set; } public string ThemePath() @@ -20,14 +19,14 @@ namespace Oqtane.Themes return "Themes/" + this.GetType().Namespace + "/"; } - public async Task AddCSS(string Url) + public async Task IncludeCSS(string Url) { if (!Url.StartsWith("http")) { Url = ThemePath() + Url; } var interop = new Interop(JSRuntime); - await interop.AddCSS("Theme:" + Utilities.CreateIdFromUrl(Url), Url); + await interop.IncludeCSS("Theme", Url); } public string NavigateUrl() diff --git a/Oqtane.Server/wwwroot/css/site.css b/Oqtane.Client/wwwroot/css/app.css similarity index 51% rename from Oqtane.Server/wwwroot/css/site.css rename to Oqtane.Client/wwwroot/css/app.css index 5a0e330e..0aa84c9f 100644 --- a/Oqtane.Server/wwwroot/css/site.css +++ b/Oqtane.Client/wwwroot/css/app.css @@ -10,144 +10,8 @@ app { flex-direction: column; } -.top-row { - height: 3.5rem; - display: flex; - align-items: center; -} - -.main { - flex: 1; -} - - .main .top-row { - background-color: #e6e6e6; - border-bottom: 1px solid #d6d5d5; - } - -.sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); -} - - .sidebar .top-row { - background-color: rgba(0,0,0,0.4); - } - - .sidebar .navbar-brand { - font-size: 1.1rem; - } - - .sidebar .oi { - width: 2rem; - font-size: 1.1rem; - vertical-align: text-top; - top: -2px; - } - -.nav-item { - font-size: 0.9rem; - padding-bottom: 0.5rem; -} - - .nav-item:first-of-type { - padding-top: 1rem; - } - - .nav-item:last-of-type { - padding-bottom: 1rem; - } - - .nav-item a { - color: #d7d7d7; - border-radius: 4px; - height: 3rem; - display: flex; - align-items: center; - line-height: 3rem; - } - - .nav-item a.active { - background-color: rgba(255,255,255,0.25); - color: white; - } - - .nav-item a:hover { - background-color: rgba(255,255,255,0.1); - color: white; - } - -.content { - padding-top: 1.1rem; -} - -.navbar-toggler { - background-color: rgba(255, 255, 255, 0.1); -} - -@media (max-width: 767.98px) { - .main .top-row { - display: none; - } -} - -@media (min-width: 768px) { - app { - flex-direction: row; - } - - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } - - .main .top-row { - position: sticky; - top: 0; - z-index: 9999; - } - - .main > div { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } - - .navbar-toggler { - display: none; - } - - .sidebar .collapse { - /* Never collapse the sidebar for wide screens */ - display: block; - } -} - -@-webkit-keyframes sk-stretchdelay { - 0%, 40%, 100% { - -webkit-transform: scaleY(0.4) - } - - 20% { - -webkit-transform: scaleY(1.0) - } -} - -@keyframes sk-stretchdelay { - 0%, 40%, 100% { - transform: scaleY(0.4); - -webkit-transform: scaleY(0.4); - } - - 20% { - transform: scaleY(1.0); - -webkit-transform: scaleY(1.0); - } -} - /* Control Panel */ -.overlay { - /* Height & width depends on how you want to reveal the overlay (see JS below) */ +.app-controlpanel { height: 100%; width: 0; position: fixed; /* Stay in place */ @@ -161,7 +25,7 @@ app { } /* Position the content inside the overlay */ -.overlay-content { +.app-controlpanel-content { position: relative; top: 5%; /* 5% from the top */ width: 100%; /* 100% width */ @@ -170,7 +34,7 @@ app { } /* Position the close button (top right corner) */ -.overlay .closebtn { +.app-controlpanel .closebtn { position: absolute; top: 20px; right: 45px; @@ -179,11 +43,11 @@ app { /* When the height of the screen is less than 450 pixels, change the font-size of the links and position the close button again, so they don't overlap */ @media screen and (max-height: 450px) { - .overlay a { + .app-controlpanel a { font-size: 20px } - .overlay .closebtn { + .app-controlpanel-close { font-size: 40px; top: 15px; right: 35px; @@ -191,7 +55,7 @@ app { } /* Admin Modal */ -.modal { +.app-admin-modal { display: none; /* Hidden by default */ position: fixed; /* Stay in place */ z-index: 9999; /* Sit on top */ @@ -204,7 +68,7 @@ app { background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ } -.modal-content { +.app-admin-modal-content { background-color: #fefefe; margin: 5% auto; /* 5% from the top and centered */ padding: 20px; @@ -212,22 +76,22 @@ app { width: 80%; /* Could be more or less, depending on screen size */ } -.close { +.app-admin-modal-close { position: absolute; top: 20px; right: 45px; font-size: 40px; } -.close:hover, -.close:focus { + .app-admin-modal-close:hover, + .app-admin-modal-close:focus { color: black; text-decoration: none; cursor: pointer; -} + } /* Action Menu */ -.dropdown-toggle { +.app-actions-toggle { background-color: transparent; border-color: #fff; border-style: hidden; @@ -236,20 +100,20 @@ app { border-left: none; } -.pane-admin-border { +.app-pane-admin-border { width: 100%; border-width: 1px; border-style: dashed; border-color: gray; } -.pane-admin-title { +.app-pane-admin-title { width: 100%; text-align: center; color: gray; } -.loading { +.app-progress-indicator { background: rgba(0,0,0,0.2) url('../loading.gif') no-repeat 50% 50%; width: 100%; height: 100%; diff --git a/Oqtane.Client/wwwroot/css/site.css b/Oqtane.Client/wwwroot/css/site.css deleted file mode 100644 index 443fddd0..00000000 --- a/Oqtane.Client/wwwroot/css/site.css +++ /dev/null @@ -1,259 +0,0 @@ -@import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); - -html, body { - font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; -} - -app { - position: relative; - display: flex; - flex-direction: column; -} - -.top-row { - height: 3.5rem; - display: flex; - align-items: center; -} - -.main { - flex: 1; -} - - .main .top-row { - background-color: #e6e6e6; - border-bottom: 1px solid #d6d5d5; - } - -.sidebar { - background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); -} - - .sidebar .top-row { - background-color: rgba(0,0,0,0.4); - } - - .sidebar .navbar-brand { - font-size: 1.1rem; - } - - .sidebar .oi { - width: 2rem; - font-size: 1.1rem; - vertical-align: text-top; - top: -2px; - } - -.nav-item { - font-size: 0.9rem; - padding-bottom: 0.5rem; -} - - .nav-item:first-of-type { - padding-top: 1rem; - } - - .nav-item:last-of-type { - padding-bottom: 1rem; - } - - .nav-item a { - color: #d7d7d7; - border-radius: 4px; - height: 3rem; - display: flex; - align-items: center; - line-height: 3rem; - } - - .nav-item a.active { - background-color: rgba(255,255,255,0.25); - color: white; - } - - .nav-item a:hover { - background-color: rgba(255,255,255,0.1); - color: white; - } - -.content { - padding-top: 1.1rem; -} - -.navbar-toggler { - background-color: rgba(255, 255, 255, 0.1); -} - -@media (max-width: 767.98px) { - .main .top-row { - display: none; - } -} - -@media (min-width: 768px) { - app { - flex-direction: row; - } - - .sidebar { - width: 250px; - height: 100vh; - position: sticky; - top: 0; - } - - .main .top-row { - position: sticky; - top: 0; - z-index: 9999; - } - - .main > div { - padding-left: 2rem !important; - padding-right: 1.5rem !important; - } - - .navbar-toggler { - display: none; - } - - .sidebar .collapse { - /* Never collapse the sidebar for wide screens */ - display: block; - } -} - -@-webkit-keyframes sk-stretchdelay { - 0%, 40%, 100% { - -webkit-transform: scaleY(0.4) - } - - 20% { - -webkit-transform: scaleY(1.0) - } -} - -@keyframes sk-stretchdelay { - 0%, 40%, 100% { - transform: scaleY(0.4); - -webkit-transform: scaleY(0.4); - } - - 20% { - transform: scaleY(1.0); - -webkit-transform: scaleY(1.0); - } -} - -/* Control Panel */ -.overlay { - height: 100%; - width: 0; - position: fixed; /* Stay in place */ - z-index: 9999; /* Sit on top */ - right: 0; /* Position at right side of screen */ - top: 0; /* Position at top of screen */ - background-color: rgb(0,0,0); /* Black fallback color */ - background-color: rgba(0,0,0, 0.9); /* Black w/opacity */ - overflow-x: hidden; /* Disable horizontal scroll */ - transition: 0.5s; /* 0.5 second transition effect to slide in or slide down the overlay (height or width, depending on reveal) */ -} - -/* Position the content inside the overlay */ -.overlay-content { - position: relative; - top: 5%; /* 5% from the top */ - width: 100%; /* 100% width */ - text-align: center; /* Centered text/links */ - margin-top: 30px; /* 30px top margin to avoid conflict with the close button on smaller screens */ -} - -/* Position the close button (top right corner) */ -.overlay .closebtn { - position: absolute; - top: 20px; - right: 45px; - font-size: 40px; -} - -/* When the height of the screen is less than 450 pixels, change the font-size of the links and position the close button again, so they don't overlap */ -@media screen and (max-height: 450px) { - .overlay a { - font-size: 20px - } - - .overlay .closebtn { - font-size: 40px; - top: 15px; - right: 35px; - } -} - -/* Admin Modal */ -.modal { - display: none; /* Hidden by default */ - position: fixed; /* Stay in place */ - z-index: 9999; /* Sit on top */ - left: 0; - top: 0; - width: 100%; /* Full width */ - height: 100%; /* Full height */ - overflow: auto; /* Enable scroll if needed */ - background-color: rgb(0,0,0); /* Fallback color */ - background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ -} - -.modal-content { - background-color: #fefefe; - margin: 5% auto; /* 5% from the top and centered */ - padding: 20px; - border: 1px solid #888; - width: 80%; /* Could be more or less, depending on screen size */ -} - -.close { - position: absolute; - top: 20px; - right: 45px; - font-size: 40px; -} - -.close:hover, -.close:focus { - color: black; - text-decoration: none; - cursor: pointer; -} - -/* Action Menu */ -.dropdown-toggle { - background-color: transparent; - border-color: #fff; - border-style: hidden; - border-top: none; - border-right: none; - border-left: none; -} - -.pane-admin-border { - width: 100%; - border-width: 1px; - border-style: dashed; - border-color: gray; -} - -.pane-admin-title { - width: 100%; - text-align: center; - color: gray; -} - -.loading { - background: rgba(0,0,0,0.2) url('../loading.gif') no-repeat 50% 50%; - width: 100%; - height: 100%; - position: fixed; - top: 0; - left: 0; - z-index: 9999; /* Sit on top */ -} \ No newline at end of file diff --git a/Oqtane.Client/wwwroot/index.html b/Oqtane.Client/wwwroot/index.html index 5c5f51c0..1335536d 100644 --- a/Oqtane.Client/wwwroot/index.html +++ b/Oqtane.Client/wwwroot/index.html @@ -6,7 +6,7 @@ Oqtane - + diff --git a/Oqtane.Client/wwwroot/js/interop.js b/Oqtane.Client/wwwroot/js/interop.js index 3c4279d0..3c087010 100644 --- a/Oqtane.Client/wwwroot/js/interop.js +++ b/Oqtane.Client/wwwroot/js/interop.js @@ -28,21 +28,19 @@ window.interop = { return ""; } }, - addCSS: function (id, url) { - if (document.getElementById(id) === null) { - var link = document.createElement("link"); + includeCSS: function (id, url) { + var link = document.getElementById('yourid'); + if (link === null) { + link = document.createElement("link"); link.id = id; link.type = "text/css"; link.rel = "stylesheet"; link.href = url; document.head.appendChild(link); } - }, - removeCSS: function (pattern) { - var links = document.getElementsByTagName("link"); - for (var i = 0; i < links.length; i++) { - if (links[i].id.includes(pattern)) { - document.head.removeChild(links[i]); + else { + if (link.href !== url) { + link.setAttribute('href', url); } } }, diff --git a/Oqtane.Server/Controllers/InstallationController.cs b/Oqtane.Server/Controllers/InstallationController.cs index 7e444a23..d76ad8df 100644 --- a/Oqtane.Server/Controllers/InstallationController.cs +++ b/Oqtane.Server/Controllers/InstallationController.cs @@ -210,6 +210,19 @@ namespace Oqtane.Controllers } else { + using (var db = new InstallationContext(connectionString)) + { + ApplicationVersion version = db.ApplicationVersion.ToList().LastOrDefault(); + if (version == null || version.Version != Constants.Version) + { + version = new ApplicationVersion(); + version.Version = Constants.Version; + version.CreatedOn = DateTime.Now; + db.ApplicationVersion.Add(version); + db.SaveChanges(); + } + } + Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(item => item.FullName.Contains(".Module.")).ToArray(); @@ -283,6 +296,7 @@ namespace Oqtane.Controllers protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) => optionsBuilder.UseSqlServer(_connectionString); + public virtual DbSet ApplicationVersion { get; set; } public virtual DbSet Tenant { get; set; } } } diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index b8e8ccf7..e176283d 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -11,7 +11,7 @@ Oqtane - + @(Html.AntiForgeryToken()) diff --git a/Oqtane.Server/Repository/Context/TenantDBContext.cs b/Oqtane.Server/Repository/Context/TenantDBContext.cs index f21256bb..1465de45 100644 --- a/Oqtane.Server/Repository/Context/TenantDBContext.cs +++ b/Oqtane.Server/Repository/Context/TenantDBContext.cs @@ -19,7 +19,7 @@ namespace Oqtane.Repository public TenantDBContext(ITenantResolver TenantResolver, IHttpContextAccessor accessor) : base(TenantResolver, accessor) { - // ContextBase handles multi-tenant database connections + // DBContextBase handles multi-tenant database connections } } diff --git a/Oqtane.Server/Repository/SiteRepository.cs b/Oqtane.Server/Repository/SiteRepository.cs index d649b666..07a8eb12 100644 --- a/Oqtane.Server/Repository/SiteRepository.cs +++ b/Oqtane.Server/Repository/SiteRepository.cs @@ -36,13 +36,13 @@ namespace Oqtane.Repository // define the default site template SiteTemplate = new List (); SiteTemplate.Add(new PageTemplate { Name = "Home", Parent = "", Path = "", Order = 1, Icon = "home", IsNavigation = true, EditMode = false, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Welcome To Oqtane...", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Welcome To Oqtane...", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = " Oqtane is an open source modular application framework built from the ground up using modern .NET Core technology. It leverages the revolutionary new Blazor component model to create a fully dynamic web development experience which can be executed on a client or server. Whether you are looking for a platform to accelerate your web development efforts, or simply interested in exploring the anatomy of a large-scale Blazor application, Oqtane provides a solid foundation based on proven enterprise architectural principles.
" + "
" + "
Join Our Community Clone Our RepoBlazor is a single-page app framework that lets you build interactive web applications using C# instead of JavaScript. Client-side Blazor relies on WebAssembly, an open web standard that does not require plugins or code transpilation in order to run natively in a web browser. Server-side Blazor uses SignalR to host your application on a web server and provide a responsive and robust debugging experience. Blazor applications works in all modern web browsers, including mobile browsers.
" + "Blazor is a feature of ASP.NET Core 3.0, the popular cross platform web development framework from Microsoft that extends the .NET developer platform with tools and libraries for building web apps.
" }, - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "MIT License", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.HtmlText, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "MIT License", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "Copyright (c) 2019 .NET Foundation
" + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
" + "The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
" + @@ -51,43 +51,43 @@ namespace Oqtane.Repository } }); SiteTemplate.Add(new PageTemplate { Name = "Admin", Parent = "", Path = "admin", Order = 1, Icon = "", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List{ - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Dashboard, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Administration", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Dashboard, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Administration", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Site Management", Parent = "Admin", Path = "admin/sites", Order = 1, Icon = "globe", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Sites, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Site Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Sites, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Site Management", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Page Management", Parent = "Admin", Path = "admin/pages", Order = 1, Icon = "layers", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Pages, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Page Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Pages, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Page Management", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "File Management", Parent = "Admin", Path = "admin/files", Order = 1, Icon = "file", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Files, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "File Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Files, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "File Management", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "User Management", Parent = "Admin", Path = "admin/users", Order = 1, Icon = "person", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Users, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "User Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Users, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "User Management", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Role Management", Parent = "Admin", Path = "admin/roles", Order = 1, Icon = "lock-locked", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Roles, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Role Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Roles, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Role Management", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Tenant Management", Parent = "Admin", Path = "admin/tenants", Order = 1, Icon = "list", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Tenants, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Tenant Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Tenants, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Tenant Management", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Module Management", Parent = "Admin", Path = "admin/modules", Order = 1, Icon = "browser", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.ModuleDefinitions, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Module Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.ModuleDefinitions, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Module Management", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Theme Management", Parent = "Admin", Path = "admin/themes", Order = 1, Icon = "brush", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Themes, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Theme Management", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Themes, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Theme Management", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Upgrade Service", Parent = "Admin", Path = "admin/upgrade", Order = 1, Icon = "aperture", IsNavigation = false, EditMode = true, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Upgrade, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Upgrade Service", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Upgrade, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "Upgrade Service", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Login", Parent = "", Path = "login", Order = 1, Icon = "lock-locked", IsNavigation = false, EditMode = false, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Login, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "User Login", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Login, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "User Login", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Register", Parent = "", Path = "register", Order = 1, Icon = "person", IsNavigation = false, EditMode = false, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Register, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "User Registration", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Register, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "User Registration", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); SiteTemplate.Add(new PageTemplate { Name = "Profile", Parent = "", Path = "profile", Order = 1, Icon = "person", IsNavigation = false, EditMode = false, PagePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", PageTemplateModules = new List { - new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Profile, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "User Profile", Pane = "Top", ContainerType = "Oqtane.Themes.Theme2.Container2, Oqtane.Client", Content = "" } + new PageTemplateModule { ModuleDefinitionName = "Oqtane.Modules.Admin.Profile, Oqtane.Client", ModulePermissions = "[{\"PermissionName\":\"View\",\"Permissions\":\"All Users;Administrators\"},{\"PermissionName\":\"Edit\",\"Permissions\":\"Administrators\"}]", Title = "User Profile", Pane = "Top", ContainerType = Constants.DefaultContainer, Content = "" } }}); } diff --git a/Oqtane.Server/Repository/TenantResolver.cs b/Oqtane.Server/Repository/TenantResolver.cs index 579c99b9..59969dc3 100644 --- a/Oqtane.Server/Repository/TenantResolver.cs +++ b/Oqtane.Server/Repository/TenantResolver.cs @@ -23,9 +23,9 @@ namespace Oqtane.Repository aliasname = accessor.HttpContext.Request.Host.Value; string path = accessor.HttpContext.Request.Path.Value; string[] segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); - if (segments.Length > 0 && segments[0] == "api" && segments[1] != "~") + if (segments.Length > 1 && segments[1] == "api" && segments[0] != "~") { - aliasname += "/" + segments[1]; + aliasname += "/" + segments[0]; } if (aliasname.EndsWith("/")) { diff --git a/Oqtane.Server/Repository/ThemeRepository.cs b/Oqtane.Server/Repository/ThemeRepository.cs index 578ac3e3..0de27194 100644 --- a/Oqtane.Server/Repository/ThemeRepository.cs +++ b/Oqtane.Server/Repository/ThemeRepository.cs @@ -88,15 +88,22 @@ namespace Oqtane.Repository index = themes.FindIndex(item => item.ThemeName == Namespace); } theme = themes[index]; - // layouts and themes - if (themeControlType.FullName.EndsWith("Layout")) + theme.ThemeControls += (themeControlType.FullName + ", " + typename[1] + ";"); + + // layouts + Type[] layouttypes = assembly.GetTypes() + .Where(item => item.Namespace != null) + .Where(item => item.Namespace.StartsWith(Namespace)) + .Where(item => item.GetInterfaces().Contains(typeof(ILayoutControl))).ToArray(); + foreach (Type layouttype in layouttypes) { - theme.PaneLayouts += (themeControlType.FullName + ", " + typename[1] + ";"); - } - else - { - theme.ThemeControls += (themeControlType.FullName + ", " + typename[1] + ";"); + string panelayout = layouttype.FullName + ", " + typename[1] + ";"; + if (!theme.PaneLayouts.Contains(panelayout)) + { + theme.PaneLayouts += panelayout; + } } + // containers Type[] containertypes = assembly.GetTypes() .Where(item => item.Namespace != null) @@ -104,8 +111,13 @@ namespace Oqtane.Repository .Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray(); foreach (Type containertype in containertypes) { - theme.ContainerControls += (containertype.FullName + ", " + typename[1] + ";"); + string container = containertype.FullName + ", " + typename[1] + ";"; + if (!theme.ContainerControls.Contains(container)) + { + theme.ContainerControls += container; + } } + themes[index] = theme; } } diff --git a/Oqtane.Server/Scripts/Master.sql b/Oqtane.Server/Scripts/Master.sql index 0f9101f0..fc25a415 100644 --- a/Oqtane.Server/Scripts/Master.sql +++ b/Oqtane.Server/Scripts/Master.sql @@ -24,6 +24,7 @@ CREATE TABLE [dbo].[Tenant]( [Name] [nvarchar](100) NOT NULL, [DBConnectionString] [nvarchar](1024) NOT NULL, [DBSchema] [nvarchar](50) NOT NULL, + [IsInitialized] [bit] NOT NULL, [CreatedBy] [nvarchar](256) NOT NULL, [CreatedOn] [datetime] NOT NULL, [ModifiedBy] [nvarchar](256) NOT NULL, @@ -49,6 +50,17 @@ CREATE TABLE [dbo].[ModuleDefinition]( ) GO +CREATE TABLE [dbo].[ApplicationVersion]( + [ApplicationVersionId] [int] IDENTITY(1,1) NOT NULL, + [Version] [nvarchar](50) NOT NULL, + [CreatedOn] [datetime] NOT NULL + CONSTRAINT [PK_ApplicationVersion] PRIMARY KEY CLUSTERED + ( + [ApplicationVersionId] ASC + ) +) +GO + /* Create foreign key relationships @@ -66,8 +78,8 @@ Create seed data */ SET IDENTITY_INSERT [dbo].[Tenant] ON GO -INSERT [dbo].[Tenant] ([TenantId], [Name], [DBConnectionString], [DBSchema], [CreatedBy], [CreatedOn], [ModifiedBy], [ModifiedOn]) -VALUES (1, N'Tenant1', N'{ConnectionString}', N'', '', getdate(), '', getdate()) +INSERT [dbo].[Tenant] ([TenantId], [Name], [DBConnectionString], [DBSchema], [IsInitialized], [CreatedBy], [CreatedOn], [ModifiedBy], [ModifiedOn]) +VALUES (1, N'Master', N'{ConnectionString}', N'', 1, '', getdate(), '', getdate()) GO SET IDENTITY_INSERT [dbo].[Tenant] OFF GO diff --git a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css new file mode 100644 index 00000000..be382962 --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.BlazorTheme/Theme.css @@ -0,0 +1,135 @@ + +.top-row { + height: 3.5rem; + display: flex; + align-items: center; +} + +.main { + flex: 1; +} + + .main .top-row { + background-color: #e6e6e6; + border-bottom: 1px solid #d6d5d5; + } + +.sidebar { + background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%); +} + + .sidebar .top-row { + background-color: rgba(0,0,0,0.4); + } + + .sidebar .navbar-brand { + font-size: 1.1rem; + } + + .sidebar .oi { + width: 2rem; + font-size: 1.1rem; + vertical-align: text-top; + top: -2px; + } + +.nav-item { + font-size: 0.9rem; + padding-bottom: 0.5rem; +} + + .nav-item:first-of-type { + padding-top: 1rem; + } + + .nav-item:last-of-type { + padding-bottom: 1rem; + } + + .nav-item a { + color: #d7d7d7; + border-radius: 4px; + height: 3rem; + display: flex; + align-items: center; + line-height: 3rem; + } + + .nav-item a.active { + background-color: rgba(255,255,255,0.25); + color: white; + } + + .nav-item a:hover { + background-color: rgba(255,255,255,0.1); + color: white; + } + +.content { + padding-top: 1.1rem; +} + +.navbar-toggler { + background-color: rgba(255, 255, 255, 0.1); +} + +@media (max-width: 767.98px) { + .main .top-row { + display: none; + } +} + +@media (min-width: 768px) { + app { + flex-direction: row; + } + + .sidebar { + width: 250px; + height: 100vh; + position: sticky; + top: 0; + } + + .main .top-row { + position: sticky; + top: 0; + z-index: 9999; + } + + .main > div { + padding-left: 2rem !important; + padding-right: 1.5rem !important; + } + + .navbar-toggler { + display: none; + } + + .sidebar .collapse { + /* Never collapse the sidebar for wide screens */ + display: block; + } +} + +@-webkit-keyframes sk-stretchdelay { + 0%, 40%, 100% { + -webkit-transform: scaleY(0.4) + } + + 20% { + -webkit-transform: scaleY(1.0) + } +} + +@keyframes sk-stretchdelay { + 0%, 40%, 100% { + transform: scaleY(0.4); + -webkit-transform: scaleY(0.4); + } + + 20% { + transform: scaleY(1.0); + -webkit-transform: scaleY(1.0); + } +} diff --git a/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css new file mode 100644 index 00000000..b7f85f3e --- /dev/null +++ b/Oqtane.Server/wwwroot/Themes/Oqtane.Themes.OqtaneTheme/Theme.css @@ -0,0 +1,135 @@ + +.top-row { + height: 3.5rem; + display: flex; + align-items: center; +} + +.main { + flex: 1; +} + + .main .top-row { + background-color: #e6e6e6; + border-bottom: 1px solid #d6d5d5; + } + +.sidebar { + background-image: linear-gradient(180deg, black 0%, black 70%); +} + + .sidebar .top-row { + background-color: rgba(0,0,0,0.4); + } + + .sidebar .navbar-brand { + font-size: 1.1rem; + } + + .sidebar .oi { + width: 2rem; + font-size: 1.1rem; + vertical-align: text-top; + top: -2px; + } + +.nav-item { + font-size: 0.9rem; + padding-bottom: 0.5rem; +} + + .nav-item:first-of-type { + padding-top: 1rem; + } + + .nav-item:last-of-type { + padding-bottom: 1rem; + } + + .nav-item a { + color: #FFFFFF; + border-radius: 4px; + height: 3rem; + display: flex; + align-items: center; + line-height: 3rem; + } + + .nav-item a.active { + background-color: rgba(255,255,255,0.25); + color: white; + } + + .nav-item a:hover { + background-color: rgba(255,255,255,0.1); + color: white; + } + +.content { + padding-top: 1.1rem; +} + +.navbar-toggler { + background-color: rgba(255, 255, 255, 0.1); +} + +@media (max-width: 767.98px) { + .main .top-row { + display: none; + } +} + +@media (min-width: 768px) { + app { + flex-direction: row; + } + + .sidebar { + width: 250px; + height: 100vh; + position: sticky; + top: 0; + } + + .main .top-row { + position: sticky; + top: 0; + z-index: 9999; + } + + .main > div { + padding-left: 2rem !important; + padding-right: 1.5rem !important; + } + + .navbar-toggler { + display: none; + } + + .sidebar .collapse { + /* Never collapse the sidebar for wide screens */ + display: block; + } +} + +@-webkit-keyframes sk-stretchdelay { + 0%, 40%, 100% { + -webkit-transform: scaleY(0.4) + } + + 20% { + -webkit-transform: scaleY(1.0) + } +} + +@keyframes sk-stretchdelay { + 0%, 40%, 100% { + transform: scaleY(0.4); + -webkit-transform: scaleY(0.4); + } + + 20% { + transform: scaleY(1.0); + -webkit-transform: scaleY(1.0); + } +} diff --git a/Oqtane.Server/wwwroot/css/app.css b/Oqtane.Server/wwwroot/css/app.css new file mode 100644 index 00000000..232d5f6f --- /dev/null +++ b/Oqtane.Server/wwwroot/css/app.css @@ -0,0 +1,124 @@ +@import url('open-iconic/font/css/open-iconic-bootstrap.min.css'); + +html, body { + font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; +} + +app { + position: relative; + display: flex; + flex-direction: column; +} + +/* Control Panel */ +.app-controlpanel { + height: 100%; + width: 0; + position: fixed; /* Stay in place */ + z-index: 9999; /* Sit on top */ + right: 0; + top: 0; + background-color: rgb(0,0,0); /* Black fallback color */ + background-color: rgba(0,0,0, 0.9); /* Black w/opacity */ + overflow-x: hidden; /* Disable horizontal scroll */ + transition: 0.5s; /* 0.5 second transition effect to slide in or slide down the overlay (height or width, depending on reveal) */ +} + +/* Position the content inside the overlay */ +.app-controlpanel-content { + position: relative; + top: 5%; /* 5% from the top */ + width: 100%; /* 100% width */ + text-align: center; /* Centered text/links */ + margin-top: 30px; /* 30px top margin to avoid conflict with the close button on smaller screens */ +} + +/* Position the close button (top right corner) */ +.app-controlpanel-close { + position: absolute; + top: 20px; + right: 45px; + font-size: 40px; +} + +/* When the height of the screen is less than 450 pixels, change the font-size of the links and position the close button again, so they don't overlap */ +@media screen and (max-height: 450px) { + .app-controlpanel a { + font-size: 20px + } + + .app-controlpanel-close { + font-size: 40px; + top: 15px; + right: 35px; + } +} + +/* Admin Modal */ +.app-admin-modal { + display: none; /* Hidden by default */ + position: fixed; /* Stay in place */ + z-index: 9999; /* Sit on top */ + left: 0; + top: 0; + width: 100%; /* Full width */ + height: 100%; /* Full height */ + overflow: auto; /* Enable scroll if needed */ + background-color: rgb(0,0,0); /* Fallback color */ + background-color: rgba(0,0,0,0.4); /* Black w/ opacity */ +} + +.app-admin-modal-content { + background-color: #fefefe; + margin: 5% auto; /* 5% from the top and centered */ + padding: 20px; + border: 1px solid #888; + width: 80%; /* Could be more or less, depending on screen size */ +} + +.app-admin-modal-close { + position: absolute; + top: 20px; + right: 45px; + font-size: 40px; +} + +.app-admin-modal-close:hover, +.app-admin-modal-close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} + +/* Action Menu */ +.app-actions-toggle { + background-color: transparent; + border-color: #fff; + border-style: hidden; + border-top: none; + border-right: none; + border-left: none; +} + +.app-pane-admin-border { + width: 100%; + border-width: 1px; + border-style: dashed; + border-color: gray; +} + +.app-pane-admin-title { + width: 100%; + text-align: center; + color: gray; +} + +.app-progress-indicator { + background: rgba(0,0,0,0.2) url('../loading.gif') no-repeat 50% 50%; + width: 100%; + height: 100%; + position: fixed; + top: 0; + left: 0; + z-index: 9999; /* Sit on top */ +} \ No newline at end of file diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index e6e5395c..983af5e9 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -28,21 +28,19 @@ window.interop = { return ""; } }, - addCSS: function (id, url) { - if (document.getElementById(id) === null) { - var link = document.createElement("link"); + includeCSS: function (id, url) { + var link = document.getElementById('yourid'); + if (link === null) { + link = document.createElement("link"); link.id = id; link.type = "text/css"; link.rel = "stylesheet"; link.href = url; document.head.appendChild(link); } - }, - removeCSS: function (pattern) { - var links = document.getElementsByTagName("link"); - for (var i = 0; i < links.length; i++) { - if (links[i].id.includes(pattern)) { - document.head.removeChild(links[i]); + else { + if (link.href !== url) { + link.setAttribute('href', url); } } }, diff --git a/Oqtane.Server/wwwroot/js/site.js b/Oqtane.Server/wwwroot/js/site.js index 523c8227..3a3e3ed9 100644 --- a/Oqtane.Server/wwwroot/js/site.js +++ b/Oqtane.Server/wwwroot/js/site.js @@ -1,20 +1,3 @@ -/* called by index.html to check if mode is set */ -function getCookie(name) { - name = name + "="; - var decodedCookie = decodeURIComponent(document.cookie); - var ca = decodedCookie.split(';'); - for (var i = 0; i < ca.length; i++) { - var c = ca[i]; - while (c.charAt(0) === ' ') { - c = c.substring(1); - } - if (c.indexOf(name) === 0) { - return c.substring(name.length, c.length); - } - } - return ""; -} - /* Open when someone clicks on the span element */ function openActions() { document.getElementById("actions").style.width = "25%"; diff --git a/Oqtane.Shared/Models/Alias.cs b/Oqtane.Shared/Models/Alias.cs index 072b7e12..2d49f21a 100644 --- a/Oqtane.Shared/Models/Alias.cs +++ b/Oqtane.Shared/Models/Alias.cs @@ -15,33 +15,6 @@ namespace Oqtane.Models public string ModifiedBy { get; set; } public DateTime ModifiedOn { get; set; } - - [NotMapped] - public string Scheme { get; set; } - - [NotMapped] - public string Url - { - get - { - return Scheme + "://" + Name; - } - } - - [NotMapped] - public string BaseUrl - { - get - { - string name = Name; - if (name.Contains("/")) - { - name = name.Substring(0, name.IndexOf("/")); - } - return Scheme + "://" + name; - } - } - [NotMapped] public string Path { diff --git a/Oqtane.Shared/Models/ApplicationVersion.cs b/Oqtane.Shared/Models/ApplicationVersion.cs new file mode 100644 index 00000000..9babb7cd --- /dev/null +++ b/Oqtane.Shared/Models/ApplicationVersion.cs @@ -0,0 +1,11 @@ +using System; + +namespace Oqtane.Models +{ + public class ApplicationVersion + { + public int ApplicationVersionId { get; set; } + public string Version { get; set; } + public DateTime CreatedOn { get; set; } + } +} diff --git a/Oqtane.Shared/Models/Tenant.cs b/Oqtane.Shared/Models/Tenant.cs index f7eb85a4..bf6c4627 100644 --- a/Oqtane.Shared/Models/Tenant.cs +++ b/Oqtane.Shared/Models/Tenant.cs @@ -8,6 +8,7 @@ namespace Oqtane.Models public string Name { get; set; } public string DBConnectionString { get; set; } public string DBSchema { get; set; } + public bool IsInitialized { get; set; } public string CreatedBy { get; set; } public DateTime CreatedOn { get; set; } diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 20867723..cead036a 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -5,25 +5,24 @@ public const string PackageId = "Oqtane.Framework"; public const string Version = "0.0.1"; - public const string DefaultPage = "Oqtane.Shared.ThemeBuilder, Oqtane.Client"; - public const string DefaultContainer = "Oqtane.Shared.ContainerBuilder, Oqtane.Client"; + public const string PageComponent = "Oqtane.Shared.ThemeBuilder, Oqtane.Client"; + public const string ContainerComponent = "Oqtane.Shared.ContainerBuilder, Oqtane.Client"; + + public const string DefaultTheme = "Oqtane.Themes.OqtaneTheme.Default, Oqtane.Client"; + public const string DefaultContainer = "Oqtane.Themes.OqtaneTheme.Container, Oqtane.Client"; public const string DefaultAdminContainer = "Oqtane.Themes.AdminContainer, Oqtane.Client"; + public static readonly string[] DefaultModuleActions = new[] { "Settings", "Import", "Export" }; public const string DefaultModuleActionsTemplate = "Oqtane.Modules.Admin.Modules.{Control}, Oqtane.Client"; public const string PageManagementModule = "Oqtane.Modules.Admin.Pages, Oqtane.Client"; public const string ModuleMessageControl = "Oqtane.Modules.Controls.ModuleMessage, Oqtane.Client"; - public const string DefaultControl = "Index"; + public const string DefaultControl = "Index"; public const string AdminPane = "Admin"; public const string AllUsersRole = "All Users"; public const string HostRole = "Host Users"; public const string AdminRole = "Administrators"; public const string RegisteredRole = "Registered Users"; - - public const int ReloadApplication = 3; - public const int ReloadSite = 2; - public const int ReloadPage = 1; - public const int ReloadReset = 0; } }