From 318948180945923052c5f627fb826acdcae58c5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=A0t=C4=9Bp=C3=A1nek?= Date: Tue, 21 Sep 2021 14:15:18 +0200 Subject: [PATCH 1/3] Add a configuration page stub --- .../DotvvmConfigurationPageConfiguration.cs | 78 +++++++++++++++++++ .../DotvvmDiagnosticsConfiguration.cs | 13 ++++ .../Diagnostics/ConfigurationPage.dothtml | 43 ++++++++++ .../Diagnostics/ConfigurationPageViewModel.cs | 14 ++++ .../Framework/DotVVM.Framework.csproj | 5 ++ 5 files changed, 153 insertions(+) create mode 100644 src/Framework/Framework/Configuration/DotvvmConfigurationPageConfiguration.cs create mode 100644 src/Framework/Framework/Diagnostics/ConfigurationPage.dothtml create mode 100644 src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs diff --git a/src/Framework/Framework/Configuration/DotvvmConfigurationPageConfiguration.cs b/src/Framework/Framework/Configuration/DotvvmConfigurationPageConfiguration.cs new file mode 100644 index 0000000000..69342ecf3c --- /dev/null +++ b/src/Framework/Framework/Configuration/DotvvmConfigurationPageConfiguration.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Text; +using Newtonsoft.Json; + +namespace DotVVM.Framework.Configuration +{ + public class DotvvmConfigurationPageConfiguration + { + public const string DefaultUrl = "_dotvvm/diagnostics/configuration"; + public const string DefaultRouteName = "_dotvvm_diagnostics_configuration"; + + /// + /// Gets or sets whether the configuration status page is enabled. + /// + /// + /// When null, the configuration page is automatically enabled if + /// is true. + /// + [JsonProperty("isEnabled", DefaultValueHandling = DefaultValueHandling.Ignore)] + [DefaultValue(null)] + public bool? IsEnabled + { + get { return _isEnabled; } + set { ThrowIfFrozen(); _isEnabled = value; } + } + private bool? _isEnabled = null; + + /// + /// Gets or sets the URL where the configuration page will be accessible from. + /// + [JsonProperty("url", DefaultValueHandling = DefaultValueHandling.Ignore)] + [DefaultValue(DefaultUrl)] + public string Url + { + get { return _url; } + set { ThrowIfFrozen(); _url = value; } + } + private string _url = DefaultUrl; + + /// + /// Gets or sets the name of the route that the configuration page will be registered as. + /// + [JsonProperty("routeName", DefaultValueHandling = DefaultValueHandling.Ignore)] + [DefaultValue(DefaultRouteName)] + public string RouteName + { + get { return _routeName; } + set { ThrowIfFrozen(); _routeName = value; } + } + private string _routeName = DefaultRouteName; + + private bool isFrozen = false; + + private void ThrowIfFrozen() + { + if (isFrozen) + throw FreezableUtils.Error(nameof(DotvvmConfigurationPageConfiguration)); + } + + public void Freeze() + { + isFrozen = true; + } + + public void Apply(DotvvmConfiguration config) + { + if (IsEnabled == true || (IsEnabled == null && config.Debug)) + { + config.RouteTable.Add( + routeName: RouteName, + url: Url, + virtualPath: "embedded://DotVVM.Framework/Diagnostics/ConfigurationPage.dothtml"); + } + } + } +} diff --git a/src/Framework/Framework/Configuration/DotvvmDiagnosticsConfiguration.cs b/src/Framework/Framework/Configuration/DotvvmDiagnosticsConfiguration.cs index a8ac223a28..dc7059afd1 100644 --- a/src/Framework/Framework/Configuration/DotvvmDiagnosticsConfiguration.cs +++ b/src/Framework/Framework/Configuration/DotvvmDiagnosticsConfiguration.cs @@ -21,6 +21,17 @@ public DotvvmCompilationPageConfiguration CompilationPage } private DotvvmCompilationPageConfiguration _compilationPage = new(); + /// + /// Gets or sets the options of the configuration status page. + /// + [JsonProperty("configurationPage")] + public DotvvmConfigurationPageConfiguration ConfigurationPage + { + get { return _configurationPage; } + set { ThrowIfFrozen(); _configurationPage = value; } + } + private DotvvmConfigurationPageConfiguration _configurationPage = new(); + private bool isFrozen = false; private void ThrowIfFrozen() @@ -33,11 +44,13 @@ public void Freeze() { isFrozen = true; CompilationPage.Freeze(); + ConfigurationPage.Freeze(); } public void Apply(DotvvmConfiguration config) { CompilationPage.Apply(config); + ConfigurationPage.Apply(config); } } } diff --git a/src/Framework/Framework/Diagnostics/ConfigurationPage.dothtml b/src/Framework/Framework/Diagnostics/ConfigurationPage.dothtml new file mode 100644 index 0000000000..16ab6ed4cf --- /dev/null +++ b/src/Framework/Framework/Diagnostics/ConfigurationPage.dothtml @@ -0,0 +1,43 @@ +@viewModel DotVVM.Framework.Diagnostics.ConfigurationPageViewModel + + + + + + DotVVM Configuration Status Page + + + +

Configuration Status Page

+
+ +
+
+
+

Tab 0

+
+ +
+

Tab 1

+
+ +
+

Tab 2

+
+
+
+ + diff --git a/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs b/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs new file mode 100644 index 0000000000..09518d6325 --- /dev/null +++ b/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using DotVVM.Framework.Compilation; +using DotVVM.Framework.ViewModel; + +namespace DotVVM.Framework.Diagnostics +{ + public class ConfigurationPageViewModel : DotvvmViewModelBase + { + public int ActiveTab { get; set; } = 0; + } +} diff --git a/src/Framework/Framework/DotVVM.Framework.csproj b/src/Framework/Framework/DotVVM.Framework.csproj index 0f02bde807..421bce0728 100644 --- a/src/Framework/Framework/DotVVM.Framework.csproj +++ b/src/Framework/Framework/DotVVM.Framework.csproj @@ -56,6 +56,7 @@ + @@ -121,6 +122,10 @@ + + + + From c1a1c58ea522fe5adb3fef1eb61432cfbd2ff4e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=A0t=C4=9Bp=C3=A1nek?= Date: Fri, 24 Sep 2021 13:49:25 +0200 Subject: [PATCH 2/3] Add stubs for configuration page sections --- .../Diagnostics/ConfigurationPageViewModel.cs | 52 +++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs b/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs index 09518d6325..e246293b25 100644 --- a/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs +++ b/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs @@ -1,8 +1,11 @@ using System; +using System.Collections.Generic; using System.Collections.Immutable; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using DotVVM.Framework.Compilation; +using DotVVM.Framework.Configuration; using DotVVM.Framework.ViewModel; namespace DotVVM.Framework.Diagnostics @@ -10,5 +13,54 @@ namespace DotVVM.Framework.Diagnostics public class ConfigurationPageViewModel : DotvvmViewModelBase { public int ActiveTab { get; set; } = 0; + + public Section RootSection { get; set; } = new(); + + public override Task Load() + { + RootSection = GetSection("Root", Context.Configuration); + return base.Load(); + } + + private static string GetSettingString(TSetting setting) + { + if (setting is null) + { + return "null"; + } + + if (setting is string + || typeof(TSetting).IsPrimitive + || typeof(TSetting).GetMethod( + nameof(ToString), + BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) is not null) + { + return setting.ToString(); + } + + throw new NotImplementedException(); + } + + private static Section GetSection(string name, TConfig config) + { + throw new NotImplementedException(); + } + + private static IEnumerable
GetSubsections(TConfig config) + { + return typeof(TConfig).GetProperties(BindingFlags.Public | BindingFlags.Instance) + .Where(p => p.PropertyType.Assembly == typeof(TConfig).Assembly + || p.PropertyType.GetInterfaces().Contains(typeof(IEnumerable<>))) + .Select(p => GetSection(p.Name, p.GetValue(config))); + } + + public class Section + { + public string? Name { get; set; } + + public List<(string key, string value)> Settings { get; set; } = new List<(string key, string value)>(); + + public List
Subsections { get; set; } = new List
(); + } } } From 0517a944c6ce5c164b153590cf922b03eea6898d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20=C5=A0t=C4=9Bp=C3=A1nek?= Date: Thu, 1 Dec 2022 17:52:51 +0100 Subject: [PATCH 3/3] Render at least something on the configuration page --- .../Diagnostics/ConfigurationPage.dothtml | 25 ++++-- .../Diagnostics/ConfigurationPageViewModel.cs | 84 ++++++++++++++----- 2 files changed, 81 insertions(+), 28 deletions(-) diff --git a/src/Framework/Framework/Diagnostics/ConfigurationPage.dothtml b/src/Framework/Framework/Diagnostics/ConfigurationPage.dothtml index 16ab6ed4cf..61f5f1d6fd 100644 --- a/src/Framework/Framework/Diagnostics/ConfigurationPage.dothtml +++ b/src/Framework/Framework/Diagnostics/ConfigurationPage.dothtml @@ -4,14 +4,14 @@ - DotVVM Configuration Status Page + DotVVM Configuration Page -

Configuration Status Page

+

Configuration Page



-
-

Tab 0

+
+ + +
+ {{value: Name}}: + {{value: Value}} +
+
+
-
+ <%--

Tab 1

Tab 2

-
+
--%>

diff --git a/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs b/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs index e246293b25..8320113c96 100644 --- a/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs +++ b/src/Framework/Framework/Diagnostics/ConfigurationPageViewModel.cs @@ -1,12 +1,14 @@ using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.Diagnostics; using System.Linq; using System.Reflection; using System.Threading.Tasks; using DotVVM.Framework.Compilation; using DotVVM.Framework.Configuration; using DotVVM.Framework.ViewModel; +using Newtonsoft.Json; namespace DotVVM.Framework.Diagnostics { @@ -14,53 +16,95 @@ public class ConfigurationPageViewModel : DotvvmViewModelBase { public int ActiveTab { get; set; } = 0; - public Section RootSection { get; set; } = new(); + public List
RootSections { get; set; } = new(); public override Task Load() { - RootSection = GetSection("Root", Context.Configuration); + RootSections = new List
{ GetSection(Context.Configuration) }; return base.Load(); } - private static string GetSettingString(TSetting setting) + private static string? GetSettingString(object? setting) { if (setting is null) { - return "null"; + return null; } - if (setting is string - || typeof(TSetting).IsPrimitive - || typeof(TSetting).GetMethod( - nameof(ToString), - BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly) is not null) + return setting.ToString(); + } + + private static Section GetSection(object config) + { + var configType = config.GetType(); + + var section = new Section { + Name = configType.Name + }; + + var props = configType.GetProperties(BindingFlags.Public | BindingFlags.Instance); + foreach (var prop in props) { - return setting.ToString(); + if (IsSetting(prop)) + { + section.Settings.Add(new Setting { + Name = prop.Name, + Value = GetSettingString(prop.GetValue(config)) + }); + } + else if (IsSubsection(prop)) + { + var subsection = prop.GetValue(config); + if (subsection is not null) + { + section.Subsections.Add(GetSection(subsection)); + } + } } - throw new NotImplementedException(); + if (configType.GetInterfaces() + .Any(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEnumerable<>))) + { + foreach (var subsection in (IEnumerable)config) + { + section.Subsections.Add(GetSection(subsection)); + } + } + return section; } - private static Section GetSection(string name, TConfig config) + private static bool IsSubsection(PropertyInfo prop) { - throw new NotImplementedException(); + return prop.GetCustomAttribute() is null + && prop.GetIndexParameters().Length == 0 + && prop.PropertyType.IsClass + && prop.PropertyType.Assembly == typeof(DotvvmConfiguration).Assembly; } - private static IEnumerable
GetSubsections(TConfig config) + private static bool IsSetting(PropertyInfo prop) { - return typeof(TConfig).GetProperties(BindingFlags.Public | BindingFlags.Instance) - .Where(p => p.PropertyType.Assembly == typeof(TConfig).Assembly - || p.PropertyType.GetInterfaces().Contains(typeof(IEnumerable<>))) - .Select(p => GetSection(p.Name, p.GetValue(config))); + return prop.GetCustomAttribute() is null + && prop.GetIndexParameters().Length == 0 + && (prop.PropertyType.IsPrimitive + || prop.PropertyType.IsEnum + || prop.PropertyType == typeof(string)); } + [DebuggerDisplay("Section {Name} [{Settings.Count}, {Subsections.Count}]")] public class Section { public string? Name { get; set; } - public List<(string key, string value)> Settings { get; set; } = new List<(string key, string value)>(); + public List Settings { get; set; } = new(); + + public List
Subsections { get; set; } = new(); + } - public List
Subsections { get; set; } = new List
(); + [DebuggerDisplay("Setting {Name}: {Value}")] + public class Setting + { + public string? Name { get; set; } + public string? Value { get; set; } } } }