From 0fcf1c27323ffb0b6217a1ca7adf6dbd67c6e305 Mon Sep 17 00:00:00 2001 From: Shaun Walker Date: Thu, 31 Mar 2022 21:05:58 -0400 Subject: [PATCH] filter deleted pages and modules in the router, provide support for cascading aspect of style sheets, replace ResourceDeclaration concept with ResourceLevel --- Oqtane.Client/Installer/Installer.razor | 4 +- .../Modules/Admin/Dashboard/Index.razor | 2 +- Oqtane.Client/Modules/Admin/Pages/Edit.razor | 2 +- Oqtane.Client/Modules/Admin/Pages/Index.razor | 1 + Oqtane.Client/Modules/ModuleBase.cs | 2 +- .../Themes/Controls/Theme/ControlPanel.razor | 5 +- .../Themes/Controls/Theme/MenuBase.cs | 2 +- Oqtane.Client/Themes/ThemeBase.cs | 2 +- Oqtane.Client/UI/Interop.cs | 8 +-- Oqtane.Client/UI/Pane.razor | 6 +- Oqtane.Client/UI/SiteRouter.razor | 27 +++++---- Oqtane.Client/UI/ThemeBuilder.razor | 16 +++--- Oqtane.Server/Pages/_Host.cshtml | 2 + Oqtane.Server/Pages/_Host.cshtml.cs | 56 +------------------ Oqtane.Server/wwwroot/js/interop.js | 30 ++++------ Oqtane.Shared/Enums/ResourceDeclaration.cs | 3 + Oqtane.Shared/Enums/ResourceLevel.cs | 8 +++ Oqtane.Shared/Models/Resource.cs | 11 +++- 18 files changed, 77 insertions(+), 110 deletions(-) create mode 100644 Oqtane.Shared/Enums/ResourceLevel.cs diff --git a/Oqtane.Client/Installer/Installer.razor b/Oqtane.Client/Installer/Installer.razor index 2dca6de9..1cf5360a 100644 --- a/Oqtane.Client/Installer/Installer.razor +++ b/Oqtane.Client/Installer/Installer.razor @@ -158,8 +158,8 @@ if (firstRender) { var interop = new Interop(JSRuntime); - await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css", "text/css", "sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==", "anonymous", ""); - await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js", "sha512-pax4MlgXjHEPfCwcJLQhigY7+N8rt6bVvWLFyUMuxShv170X53TRzGPmPkZmGBhk+jikR8WBM4yl7A9WMHHqvg==", "anonymous", "", "head", ""); + await interop.IncludeLink("", "stylesheet", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css", "text/css", "sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==", "anonymous"); + await interop.IncludeScript("", "https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.bundle.min.js", "sha512-pax4MlgXjHEPfCwcJLQhigY7+N8rt6bVvWLFyUMuxShv170X53TRzGPmPkZmGBhk+jikR8WBM4yl7A9WMHHqvg==", "anonymous", "", "head"); } } diff --git a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor index 3e3eb82c..6c665ba2 100644 --- a/Oqtane.Client/Modules/Admin/Dashboard/Index.razor +++ b/Oqtane.Client/Modules/Admin/Dashboard/Index.razor @@ -27,6 +27,6 @@ protected override void OnInitialized() { var admin = PageState.Pages.FirstOrDefault(item => item.Path == "admin"); - _pages = PageState.Pages.Where(item => item.ParentId == admin?.PageId && !item.IsDeleted).ToList(); + _pages = PageState.Pages.Where(item => item.ParentId == admin?.PageId).ToList(); } } diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor index 11533da8..3a1f4a67 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor @@ -252,7 +252,7 @@ _title = page.Title; _meta = page.Meta; _path = page.Path; - _pageModules = PageState.Modules.Where(m => m.PageId == page.PageId && m.IsDeleted == false).ToList(); + _pageModules = PageState.Modules.Where(m => m.PageId == page.PageId).ToList(); if (string.IsNullOrEmpty(_path)) { diff --git a/Oqtane.Client/Modules/Admin/Pages/Index.razor b/Oqtane.Client/Modules/Admin/Pages/Index.razor index 15c37493..198e3678 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Index.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Index.razor @@ -13,6 +13,7 @@
    +   @SharedLocalizer["Name"]
diff --git a/Oqtane.Client/Modules/ModuleBase.cs b/Oqtane.Client/Modules/ModuleBase.cs index 1f4f060c..b87c6a2c 100644 --- a/Oqtane.Client/Modules/ModuleBase.cs +++ b/Oqtane.Client/Modules/ModuleBase.cs @@ -53,7 +53,7 @@ namespace Oqtane.Modules if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script)) { var scripts = new List(); - foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script && item.Declaration != ResourceDeclaration.Global)) + foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script)) { scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module }); } diff --git a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor index 960b2dd4..89b90245 100644 --- a/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor +++ b/Oqtane.Client/Themes/Controls/Theme/ControlPanel.razor @@ -333,9 +333,8 @@ if (PageId != "-") { _modules = PageState.Modules - .Where(module => module.PageId == int.Parse(PageId) - && !module.IsDeleted - && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) + .Where(module => module.PageId == int.Parse(PageId) && + UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) .ToList(); } ModuleId = "-"; diff --git a/Oqtane.Client/Themes/Controls/Theme/MenuBase.cs b/Oqtane.Client/Themes/Controls/Theme/MenuBase.cs index 85a9b776..b98d11be 100644 --- a/Oqtane.Client/Themes/Controls/Theme/MenuBase.cs +++ b/Oqtane.Client/Themes/Controls/Theme/MenuBase.cs @@ -30,7 +30,7 @@ namespace Oqtane.Themes.Controls private IEnumerable GetMenuPages() { var securityLevel = int.MaxValue; - foreach (Page p in PageState.Pages.Where(item => item.IsNavigation && !item.IsDeleted)) + foreach (Page p in PageState.Pages.Where(item => item.IsNavigation)) { if (p.Level <= securityLevel && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.Permissions)) { diff --git a/Oqtane.Client/Themes/ThemeBase.cs b/Oqtane.Client/Themes/ThemeBase.cs index 883eb940..6f011b91 100644 --- a/Oqtane.Client/Themes/ThemeBase.cs +++ b/Oqtane.Client/Themes/ThemeBase.cs @@ -32,7 +32,7 @@ namespace Oqtane.Themes if (Resources != null && Resources.Exists(item => item.ResourceType == ResourceType.Script)) { var scripts = new List(); - foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script && item.Declaration != ResourceDeclaration.Global)) + foreach (Resource resource in Resources.Where(item => item.ResourceType == ResourceType.Script)) { scripts.Add(new { href = resource.Url, bundle = resource.Bundle ?? "", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", es6module = resource.ES6Module }); } diff --git a/Oqtane.Client/UI/Interop.cs b/Oqtane.Client/UI/Interop.cs index 43325047..f059cc51 100644 --- a/Oqtane.Client/UI/Interop.cs +++ b/Oqtane.Client/UI/Interop.cs @@ -72,13 +72,13 @@ namespace Oqtane.UI } } - public Task IncludeLink(string id, string rel, string href, string type, string integrity, string crossorigin, string key) + public Task IncludeLink(string id, string rel, string href, string type, string integrity, string crossorigin) { try { _jsRuntime.InvokeVoidAsync( "Oqtane.Interop.includeLink", - id, rel, href, type, integrity, crossorigin, key); + id, rel, href, type, integrity, crossorigin); return Task.CompletedTask; } catch @@ -102,13 +102,13 @@ namespace Oqtane.UI } } - public Task IncludeScript(string id, string src, string integrity, string crossorigin, string content, string location, string key) + public Task IncludeScript(string id, string src, string integrity, string crossorigin, string content, string location) { try { _jsRuntime.InvokeVoidAsync( "Oqtane.Interop.includeScript", - id, src, integrity, crossorigin, content, location, key); + id, src, integrity, crossorigin, content, location); return Task.CompletedTask; } catch diff --git a/Oqtane.Client/UI/Pane.razor b/Oqtane.Client/UI/Pane.razor index fd99bd9c..357d9b26 100644 --- a/Oqtane.Client/UI/Pane.razor +++ b/Oqtane.Client/UI/Pane.razor @@ -48,7 +48,7 @@ else if (Name.ToLower() == PaneNames.Admin.ToLower()) { Module module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId); - if (module != null && !module.IsDeleted) + if (module != null) { var moduleType = Type.GetType(module.ModuleType); if (moduleType != null) @@ -97,7 +97,7 @@ else if (PageState.ModuleId != -1) { Module module = PageState.Modules.FirstOrDefault(item => item.ModuleId == PageState.ModuleId); - if (module != null && module.Pane.ToLower() == Name.ToLower() && !module.IsDeleted) + if (module != null && module.Pane.ToLower() == Name.ToLower()) { // check if user is authorized to view module if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) @@ -108,7 +108,7 @@ else } else { - foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId && item.Pane.ToLower() == Name.ToLower() && !item.IsDeleted).OrderBy(x => x.Order).ToArray()) + foreach (Module module in PageState.Modules.Where(item => item.PageId == PageState.Page.PageId && item.Pane.ToLower() == Name.ToLower()).OrderBy(x => x.Order).ToArray()) { // check if user is authorized to view module if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, module.Permissions)) diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index ad520fb5..3946fbcb 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -164,6 +164,7 @@ if (PageState == null || refresh == UI.Refresh.Site) { pages = await PageService.GetPagesAsync(site.SiteId); + pages = pages.Where(item => !item.IsDeleted).ToList(); } else { @@ -206,6 +207,7 @@ if (PageState == null || refresh == UI.Refresh.Site) { modules = await ModuleService.GetModulesAsync(site.SiteId); + modules = modules.Where(item => !item.IsDeleted).ToList(); } else { @@ -268,7 +270,7 @@ } else { - // site does not exist + // site does not exist } } @@ -322,7 +324,7 @@ { if (page.IsPersonalizable && user != null) { - // load the personalized page + // load the personalized page page = await PageService.GetPageAsync(page.PageId, user.UserId); } @@ -338,7 +340,7 @@ Type themetype = Type.GetType(page.ThemeType); if (themetype == null) { - // fallback + // fallback page.ThemeType = Constants.DefaultTheme; themetype = Type.GetType(Constants.DefaultTheme); } @@ -351,14 +353,14 @@ { panes = themeobject.Panes; } - page.Resources = ManagePageResources(page.Resources, themeobject.Resources); + page.Resources = ManagePageResources(page.Resources, themeobject.Resources, ResourceLevel.Page); } } page.Panes = panes.Replace(";", ",").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList(); } catch { - // error loading theme or layout + // error loading theme or layout } return page; @@ -369,7 +371,7 @@ var paneindex = new Dictionary(); foreach (Module module in modules) { - // initialize module control properties + // initialize module control properties module.SecurityAccessLevel = SecurityAccessLevel.Host; module.ControlTitle = ""; module.Actions = ""; @@ -422,17 +424,17 @@ // get additional metadata from IModuleControl interface if (moduletype != null && module.ModuleType != "") { - // retrieve module component resources + // retrieve module component resources var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl; - page.Resources = ManagePageResources(page.Resources, moduleobject.Resources); + page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module); if (action.ToLower() == "settings" && module.ModuleDefinition != null) { - // settings components are embedded within a framework settings module + // settings components are embedded within a framework settings module moduletype = Type.GetType(module.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, action), false, true); if (moduletype != null) { moduleobject = Activator.CreateInstance(moduletype) as IModuleControl; - page.Resources = ManagePageResources(page.Resources, moduleobject.Resources); + page.Resources = ManagePageResources(page.Resources, moduleobject.Resources, ResourceLevel.Module); } } @@ -483,15 +485,16 @@ return (page, modules); } - private List ManagePageResources(List pageresources, List resources) + private List ManagePageResources(List pageresources, List resources, ResourceLevel level) { if (resources != null) { foreach (var resource in resources) { - // ensure resource does not exist already + // ensure resource does not exist already if (pageresources.Find(item => item.Url == resource.Url) == null) { + resource.Level = level; pageresources.Add(resource); } } diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index 77f95a6c..449cc4ca 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -28,20 +28,22 @@ protected override async Task OnAfterRenderAsync(bool firstRender) { - var interop = new Interop(JsRuntime); + var interop = new Interop(JsRuntime); // manage stylesheets for this page - string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"); - var links = new List(); - foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet && item.Declaration != ResourceDeclaration.Global)) - { - links.Add(new { id = "app-stylesheet-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", key = "" }); + string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"); + var links = new List(); + foreach (Resource resource in PageState.Page.Resources.Where(item => item.ResourceType == ResourceType.Stylesheet)) + { + var prefix = "app-stylesheet-" + resource.Level.ToString().ToLower(); + links.Add(new { id = prefix + "-" + batch + "-" + (links.Count + 1).ToString("00"), rel = "stylesheet", href = resource.Url, type = "text/css", integrity = resource.Integrity ?? "", crossorigin = resource.CrossOrigin ?? "", insertbefore = prefix }); } if (links.Any()) { await interop.IncludeLinks(links.ToArray()); } - await interop.RemoveElementsById("app-stylesheet", "", "app-stylesheet-" + batch + "-00"); + await interop.RemoveElementsById("app-stylesheet-page-", "", "app-stylesheet-page-" + batch + "-00"); + await interop.RemoveElementsById("app-stylesheet-module-", "", "app-stylesheet-module-" + batch + "-00"); // set page title if (!string.IsNullOrEmpty(PageState.Page.Title)) diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml index 3c8288ff..18fcaad2 100644 --- a/Oqtane.Server/Pages/_Host.cshtml +++ b/Oqtane.Server/Pages/_Host.cshtml @@ -19,6 +19,8 @@ @Html.Raw(Model.HeadResources) + + @if (string.IsNullOrEmpty(Model.Message)) diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs index eef2c690..4f899ca4 100644 --- a/Oqtane.Server/Pages/_Host.cshtml.cs +++ b/Oqtane.Server/Pages/_Host.cshtml.cs @@ -1,9 +1,7 @@ using Microsoft.AspNetCore.Mvc.RazorPages; using Oqtane.Infrastructure; using Oqtane.Shared; -using Oqtane.Modules; using Oqtane.Models; -using Oqtane.Themes; using System; using System.Linq; using System.Reflection; @@ -190,8 +188,6 @@ namespace Oqtane.Pages foreach (Assembly assembly in assemblies) { ProcessHostResources(assembly); - ProcessModuleControls(assembly); - ProcessThemeControls(assembly); } // set culture if not specified @@ -411,65 +407,19 @@ namespace Oqtane.Pages var obj = Activator.CreateInstance(type) as IHostResources; foreach (var resource in obj.Resources) { - resource.Declaration = ResourceDeclaration.Global; - ProcessResource(resource, 0); + ProcessResource(resource); } } } - private void ProcessModuleControls(Assembly assembly) - { - var types = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModuleControl))); - foreach (var type in types) - { - // Check if type should be ignored - if (type.IsOqtaneIgnore()) continue; - - var obj = Activator.CreateInstance(type) as IModuleControl; - if (obj.Resources != null) - { - foreach (var resource in obj.Resources) - { - if (resource.Declaration == ResourceDeclaration.Global) - { - ProcessResource(resource, 0); - } - } - } - } - } - - private void ProcessThemeControls(Assembly assembly) - { - var types = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IThemeControl))); - foreach (var type in types) - { - // Check if type should be ignored - if (type.IsOqtaneIgnore()) continue; - - var obj = Activator.CreateInstance(type) as IThemeControl; - if (obj.Resources != null) - { - int count = 0; // required for local stylesheets for current theme - foreach (var resource in obj.Resources) - { - if (resource.Declaration == ResourceDeclaration.Global || (Utilities.GetFullTypeName(type.AssemblyQualifiedName) == ThemeType && resource.ResourceType == ResourceType.Stylesheet)) - { - ProcessResource(resource, count++); - } - } - } - } - } - private void ProcessResource(Resource resource, int count) + private void ProcessResource(Resource resource) { switch (resource.ResourceType) { case ResourceType.Stylesheet: if (!HeadResources.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) { - var id = (resource.Declaration == ResourceDeclaration.Global) ? "" : "id=\"app-stylesheet-" + DateTime.UtcNow.ToString("yyyyMMddHHmmssfff") + "-" + count.ToString("00") + "\" "; - HeadResources += "" + Environment.NewLine; + HeadResources += "" + Environment.NewLine; } break; case ResourceType.Script: diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js index e2122912..d7c9e814 100644 --- a/Oqtane.Server/wwwroot/js/interop.js +++ b/Oqtane.Server/wwwroot/js/interop.js @@ -53,14 +53,8 @@ Oqtane.Interop = { } } }, - includeLink: function (id, rel, href, type, integrity, crossorigin, key) { - var link; - if (id !== "" && key === "id") { - link = document.getElementById(id); - } - else { - link = document.querySelector("link[href=\"" + CSS.escape(href) + "\"]"); - } + includeLink: function (id, rel, href, type, integrity, crossorigin, insertbefore) { + var link = document.querySelector("link[href=\"" + CSS.escape(href) + "\"]"); if (link === null) { link = document.createElement("link"); if (id !== "") { @@ -77,7 +71,13 @@ Oqtane.Interop = { if (crossorigin !== "") { link.crossOrigin = crossorigin; } - document.head.appendChild(link); + if (insertbefore === "") { + document.head.appendChild(link); + } + else { + var sibling = document.getElementById(insertbefore); + sibling.parentNode.insertBefore(link, sibling); + } } else { if (link.id !== id) { @@ -116,17 +116,11 @@ Oqtane.Interop = { }, includeLinks: function (links) { for (let i = 0; i < links.length; i++) { - this.includeLink(links[i].id, links[i].rel, links[i].href, links[i].type, links[i].integrity, links[i].crossorigin, links[i].key); + this.includeLink(links[i].id, links[i].rel, links[i].href, links[i].type, links[i].integrity, links[i].crossorigin, links[i].insertbefore); } }, - includeScript: function (id, src, integrity, crossorigin, content, location, key) { - var script; - if (id !== "" && key === "id") { - script = document.getElementById(id); - } - else { - script = document.querySelector("script[src=\"" + CSS.escape(src) + "\"]"); - } + includeScript: function (id, src, integrity, crossorigin, content, location) { + var script = document.querySelector("script[src=\"" + CSS.escape(src) + "\"]"); if (script === null) { script = document.createElement("script"); if (id !== "") { diff --git a/Oqtane.Shared/Enums/ResourceDeclaration.cs b/Oqtane.Shared/Enums/ResourceDeclaration.cs index 2d86adcb..45ddb3e7 100644 --- a/Oqtane.Shared/Enums/ResourceDeclaration.cs +++ b/Oqtane.Shared/Enums/ResourceDeclaration.cs @@ -1,5 +1,8 @@ +using System; + namespace Oqtane.Shared { + [Obsolete("ResourceDeclaration is deprecated", false)] public enum ResourceDeclaration { Local, diff --git a/Oqtane.Shared/Enums/ResourceLevel.cs b/Oqtane.Shared/Enums/ResourceLevel.cs new file mode 100644 index 00000000..cc5aafe9 --- /dev/null +++ b/Oqtane.Shared/Enums/ResourceLevel.cs @@ -0,0 +1,8 @@ +namespace Oqtane.Shared +{ + public enum ResourceLevel + { + Page, + Module + } +} diff --git a/Oqtane.Shared/Models/Resource.cs b/Oqtane.Shared/Models/Resource.cs index 2a80ac56..ce7087e8 100644 --- a/Oqtane.Shared/Models/Resource.cs +++ b/Oqtane.Shared/Models/Resource.cs @@ -1,3 +1,4 @@ +using System; using Oqtane.Shared; namespace Oqtane.Models @@ -33,12 +34,12 @@ namespace Oqtane.Models public string Bundle { get; set; } /// - /// Determines if the Resource is global or local, meaning that the entire solution uses it or just some modules. + /// For Stylesheets this defines the relative position for cascading purposes /// - public ResourceDeclaration Declaration { get; set; } + public ResourceLevel Level { get; set; } /// - /// If the Resource should be included in the `head` of the HTML document or the `body` + /// For Scripts this defines if the resource should be included in the Head or Body /// public ResourceLocation Location { get; set; } @@ -46,5 +47,9 @@ namespace Oqtane.Models /// For Scripts this allows type="module" registrations - not applicable to Stylesheets /// public bool ES6Module { get; set; } + + + [Obsolete("ResourceDeclaration is deprecated", false)] + public ResourceDeclaration Declaration { get; set; } } }