diff --git a/Oqtane.Client/Modules/Admin/Themes/Index.razor b/Oqtane.Client/Modules/Admin/Themes/Index.razor index 61076ca2..9f5a76e2 100644 --- a/Oqtane.Client/Modules/Admin/Themes/Index.razor +++ b/Oqtane.Client/Modules/Admin/Themes/Index.razor @@ -1,4 +1,5 @@ @namespace Oqtane.Modules.Admin.Themes +@using System.Net @inherits ModuleBase @inject NavigationManager NavigationManager @inject IThemeService ThemeService @@ -14,25 +15,27 @@ else
+     Name Version  
+ @if (context.AssemblyName != "Oqtane.Client") - { + { - } + } @context.Name @context.Version @if (UpgradeAvailable(context.ThemeName, context.Version)) - { + { - } + }
diff --git a/Oqtane.Client/Modules/Admin/Themes/View.razor b/Oqtane.Client/Modules/Admin/Themes/View.razor new file mode 100644 index 00000000..eb655799 --- /dev/null +++ b/Oqtane.Client/Modules/Admin/Themes/View.razor @@ -0,0 +1,101 @@ +@namespace Oqtane.Modules.Admin.Themes +@using System.Net +@inherits ModuleBase +@inject IThemeService ThemeService +@inject NavigationManager NavigationManager + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+ + + +
+Cancel + +@code { + private string _themeName = ""; + private string _name; + private string _version; + private string _owner = ""; + private string _url = ""; + private string _contact = ""; + private string _license = ""; + + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; + + protected override async Task OnInitializedAsync() + { + try + { + _themeName = WebUtility.UrlDecode(PageState.QueryString["name"]); + var themes = await ThemeService.GetThemesAsync(); + var theme = themes.FirstOrDefault(item => item.ThemeName == _themeName); + if (theme != null) + { + _name = theme.Name; + _version = theme.Version; + _owner = theme.Owner; + _url = theme.Url; + _contact = theme.Contact; + _license = theme.License; + } + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Theme {ThemeName} {Error}", _themeName, ex.Message); + AddModuleMessage("Error Loading Theme", MessageType.Error); + } + } +} diff --git a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs index 4a600a62..7521b9f3 100644 --- a/Oqtane.Server/Repository/ModuleDefinitionRepository.cs +++ b/Oqtane.Server/Repository/ModuleDefinitionRepository.cs @@ -188,6 +188,7 @@ namespace Oqtane.Repository private List LoadModuleDefinitionsFromAssembly(List moduledefinitions, Assembly assembly) { ModuleDefinition moduledefinition; + Type[] modulecontroltypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IModuleControl))).ToArray(); foreach (Type modulecontroltype in modulecontroltypes) { @@ -198,8 +199,8 @@ namespace Oqtane.Repository || modulecontroltype.IsOqtaneIgnore() ) continue; - string moduleNamespace = modulecontroltype.Namespace; - string qualifiedModuleType = moduleNamespace + ", " + modulecontroltype.Assembly.GetName().Name; + // create namespace root typename + string qualifiedModuleType = modulecontroltype.Namespace + ", " + modulecontroltype.Assembly.GetName().Name; int index = moduledefinitions.FindIndex(item => item.ModuleDefinitionName == qualifiedModuleType); if (index == -1) @@ -208,7 +209,7 @@ namespace Oqtane.Repository Type moduletype = assembly .GetTypes() .Where(item => item.Namespace != null) - .Where(item => item.Namespace.StartsWith(moduleNamespace)) + .Where(item => item.Namespace == modulecontroltype.Namespace || item.Namespace.StartsWith(modulecontroltype.Namespace + ".")) .FirstOrDefault(item => item.GetInterfaces().Contains(typeof(IModule))); if (moduletype != null) { @@ -221,8 +222,8 @@ namespace Oqtane.Repository // set default property values moduledefinition = new ModuleDefinition { - Name = moduleNamespace.Substring(moduleNamespace.LastIndexOf(".") + 1), - Description = "Manage " + moduleNamespace.Substring(moduleNamespace.LastIndexOf(".") + 1), + Name = Utilities.GetTypeNameLastSegment(modulecontroltype.Namespace, 0), + Description = "Manage " + Utilities.GetTypeNameLastSegment(modulecontroltype.Namespace, 0), Categories = ((qualifiedModuleType.StartsWith("Oqtane.Modules.Admin.")) ? "Admin" : "") }; } @@ -230,7 +231,7 @@ namespace Oqtane.Repository // set internal properties moduledefinition.ModuleDefinitionName = qualifiedModuleType; moduledefinition.Version = ""; // will be populated from database - moduledefinition.ControlTypeTemplate = moduleNamespace + "." + Constants.ActionToken + ", " + modulecontroltype.Assembly.GetName().Name; + moduledefinition.ControlTypeTemplate = modulecontroltype.Namespace + "." + Constants.ActionToken + ", " + modulecontroltype.Assembly.GetName().Name; moduledefinition.AssemblyName = assembly.GetName().Name; if (string.IsNullOrEmpty(moduledefinition.Categories)) diff --git a/Oqtane.Server/Repository/ThemeRepository.cs b/Oqtane.Server/Repository/ThemeRepository.cs index 13fe85dc..bc14de74 100644 --- a/Oqtane.Server/Repository/ThemeRepository.cs +++ b/Oqtane.Server/Repository/ThemeRepository.cs @@ -44,36 +44,33 @@ namespace Oqtane.Repository private List LoadThemesFromAssembly(List themes, Assembly assembly) { Theme theme; + List themeTypes = new List(); + Type[] themeControlTypes = assembly.GetTypes().Where(item => item.GetInterfaces().Contains(typeof(IThemeControl))).ToArray(); foreach (Type themeControlType in themeControlTypes) { // Check if type should be ignored if (themeControlType.Name == "ThemeBase" || themeControlType.IsGenericType + || themeControlType.IsAbstract || themeControlType.IsOqtaneIgnore() ) continue; - string themeNamespace = themeControlType.Namespace; - // 2dm disabled - not used anywhere in code - //string qualifiedModuleType = themeNamespace + ", " + themeControlType.Assembly.GetName().Name; - - int index = themes.FindIndex(item => item.ThemeName == themeNamespace); - - // Find all types in the assembly which have the same namespace-root as the theme file - // Check with "." in the end to - List typesInTheme = assembly.GetTypes() - .Where(item=>!item.IsOqtaneIgnore()) - .Where(item => item.Namespace != null) - // Namespace must be the same or start with "xxx." to ensure that - // similar namespaces like "MyTheme" and "MyTheme2" don't match in StartsWith(...) - .Where(item => item.Namespace == themeNamespace - || item.Namespace.StartsWith(themeNamespace + ".")) - .ToList(); + // create namespace root typename + string qualifiedThemeType = themeControlType.Namespace + ", " + themeControlType.Assembly.GetName().Name; + int index = themes.FindIndex(item => item.ThemeName == qualifiedThemeType); if (index == -1) { + // Find all types in the assembly with the same namespace root + themeTypes = assembly.GetTypes() + .Where(item => !item.IsOqtaneIgnore()) + .Where(item => item.Namespace != null) + .Where(item => item.Namespace == themeControlType.Namespace || item.Namespace.StartsWith(themeControlType.Namespace + ".")) + .ToList(); + // determine if this theme implements ITheme - Type themetype = typesInTheme + Type themetype = themeTypes .FirstOrDefault(item => item.GetInterfaces().Contains(typeof(ITheme))); if (themetype != null) { @@ -89,19 +86,19 @@ namespace Oqtane.Repository }; } // set internal properties - theme.ThemeName = themeNamespace; + theme.ThemeName = qualifiedThemeType; theme.ThemeControls = ""; theme.PaneLayouts = ""; theme.ContainerControls = ""; theme.AssemblyName = assembly.FullName.Split(",")[0]; themes.Add(theme); - index = themes.FindIndex(item => item.ThemeName == themeNamespace); + index = themes.FindIndex(item => item.ThemeName == qualifiedThemeType); } theme = themes[index]; theme.ThemeControls += (themeControlType.FullName + ", " + themeControlType.Assembly.GetName().Name + ";"); // layouts - Type[] layouttypes = typesInTheme + Type[] layouttypes = themeTypes .Where(item => item.GetInterfaces().Contains(typeof(ILayoutControl))).ToArray(); foreach (Type layouttype in layouttypes) { @@ -113,7 +110,7 @@ namespace Oqtane.Repository } // containers - Type[] containertypes = typesInTheme + Type[] containertypes = themeTypes .Where(item => item.GetInterfaces().Contains(typeof(IContainerControl))).ToArray(); foreach (Type containertype in containertypes) {