|
|
@@ -17,6 +17,9 @@ using InABox.Clients;
|
|
|
using InABox.Scripting;
|
|
|
using Microsoft.Win32;
|
|
|
using Microsoft.CodeAnalysis;
|
|
|
+using InABox.Configuration;
|
|
|
+using Document = InABox.Core.Document;
|
|
|
+using System.Configuration;
|
|
|
|
|
|
namespace PRSDesktop.Forms.Issues;
|
|
|
|
|
|
@@ -127,40 +130,173 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
|
|
|
scriptButton.Margin = new Thickness(20, scriptButton.Margin.Top, scriptButton.Margin.Right, scriptButton.Margin.Bottom);
|
|
|
}
|
|
|
|
|
|
- private List<Tuple<CustomModule, string>> CheckCustomModules(bool showHidden, bool showWarnings)
|
|
|
+ private interface IScriptReference
|
|
|
{
|
|
|
- var results = new List<Tuple<CustomModule, string>>();
|
|
|
- Progress.ShowModal("Loading Data", progress =>
|
|
|
+ string Name { get; }
|
|
|
+
|
|
|
+ string Script { get; }
|
|
|
+
|
|
|
+ void Update(string script);
|
|
|
+ }
|
|
|
+
|
|
|
+ private class EntityScriptReference(Entity entity, IProperty property) : IScriptReference
|
|
|
+ {
|
|
|
+ public string Name => entity.ToString() ?? entity.GetType().Name;
|
|
|
+
|
|
|
+ public string Script => (property.Getter()(entity) as string) ?? "";
|
|
|
+
|
|
|
+ public void Update(string script)
|
|
|
{
|
|
|
- var filter = showHidden
|
|
|
- ? Filter.All<CustomModule>()
|
|
|
- : Filter<CustomModule>.Where(x => x.Visible).IsEqualTo(true);
|
|
|
+ property.Setter()(entity, script);
|
|
|
+ Client.Create(entity.GetType()).Save(entity, "Updated by User");
|
|
|
+ }
|
|
|
|
|
|
- var modules = Client.Query(
|
|
|
- filter,
|
|
|
- Columns.None<CustomModule>()
|
|
|
- .Add(x => x.ID)
|
|
|
- .Add(x => x.Section)
|
|
|
- .Add(x => x.Name)
|
|
|
- .Add(x => x.Script))
|
|
|
- .ToArray<CustomModule>();
|
|
|
- foreach(var module in modules)
|
|
|
+ public override string ToString()
|
|
|
+ {
|
|
|
+ return Name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private class GlobalSettingsScriptReference(IGlobalConfiguration configuration, IGlobalConfigurationSettings settings, IProperty property) : IScriptReference
|
|
|
+ {
|
|
|
+ public string Name => configuration.Section.IsNullOrWhiteSpace() ? settings.GetType().Name : $"{settings.GetType().Name}/{configuration.Section}";
|
|
|
+
|
|
|
+ public string Script => (property.Getter()(settings) as string) ?? "";
|
|
|
+
|
|
|
+ public void Update(string script)
|
|
|
+ {
|
|
|
+ property.Setter()(settings, script);
|
|
|
+ configuration.Save(settings);
|
|
|
+ }
|
|
|
+
|
|
|
+ public override string ToString()
|
|
|
+ {
|
|
|
+ return Name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private class CustomModuleReference(CustomModule module) : IScriptReference
|
|
|
+ {
|
|
|
+ public string Name => $"{module.Section}/{module.Name}";
|
|
|
+
|
|
|
+ public string Script => module.Script;
|
|
|
+
|
|
|
+ public void Update(string script)
|
|
|
+ {
|
|
|
+ module.Script = script;
|
|
|
+ Client.Save(module, "Updated by User");
|
|
|
+ }
|
|
|
+
|
|
|
+ public override string ToString()
|
|
|
+ {
|
|
|
+ return Name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private Tuple<Type, IProperty>[]? _desktopScriptedTypes;
|
|
|
+
|
|
|
+ private Tuple<Type, IProperty>[] DesktopScriptedTypes
|
|
|
+ {
|
|
|
+ get
|
|
|
+ {
|
|
|
+ _desktopScriptedTypes ??= CoreUtils.Entities.Where(x => x.HasInterface(typeof(IHasDesktopScript)))
|
|
|
+ .Select(x =>
|
|
|
+ {
|
|
|
+ var property = DatabaseSchema.LocalProperties(x)
|
|
|
+ .FirstOrDefault(x => x.Editor is ScriptEditor);
|
|
|
+ if(property is null)
|
|
|
+ {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return new Tuple<Type, IProperty>(x, property);
|
|
|
+ }
|
|
|
+ })
|
|
|
+ .NotNull()
|
|
|
+ .ToArray();
|
|
|
+ return _desktopScriptedTypes;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private IEnumerable<IScriptReference> GetScripts(bool showHidden)
|
|
|
+ {
|
|
|
+ var filter = showHidden
|
|
|
+ ? Filter.All<CustomModule>()
|
|
|
+ : Filter<CustomModule>.Where(x => x.Visible).IsEqualTo(true);
|
|
|
+
|
|
|
+ var queries = new List<Tuple<IKeyedQueryDef, Func<CoreTable, IEnumerable<IScriptReference>>>>();
|
|
|
+ var extraTasks = new List<Task<IEnumerable<IScriptReference>>>();
|
|
|
+ foreach(var (type, property) in DesktopScriptedTypes)
|
|
|
+ {
|
|
|
+ if (type.IsSubclassOf(typeof(Entity)))
|
|
|
+ {
|
|
|
+ if(type == typeof(CustomModule))
|
|
|
+ {
|
|
|
+ queries.Add(new(
|
|
|
+ new KeyedQueryDef<CustomModule>(
|
|
|
+ filter,
|
|
|
+ Columns.None<CustomModule>()
|
|
|
+ .Add(x => x.ID)
|
|
|
+ .Add(x => x.Section)
|
|
|
+ .Add(x => x.Name)
|
|
|
+ .Add(x => x.Script)),
|
|
|
+ x => x.ToArray<CustomModule>().ToArray(x => new CustomModuleReference(x))));
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ queries.Add(new(
|
|
|
+ new KeyedQueryDef(type.Name, type,
|
|
|
+ Filter.Create(type, property.Name, Operator.IsNotEqualTo, ""),
|
|
|
+ Columns.None(type)
|
|
|
+ .Add<Entity>(x => x.ID)
|
|
|
+ .Add(property.Name)),
|
|
|
+ x => x.ToObjects(type).Cast<Entity>().Select(x => new EntityScriptReference(x, property))));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else if (type.HasInterface(typeof(IGlobalConfigurationSettings)))
|
|
|
+ {
|
|
|
+ extraTasks.Add(Task.Run(() =>
|
|
|
+ {
|
|
|
+ var config = (Activator.CreateInstance(typeof(GlobalConfiguration<>).MakeGenericType(type), "") as IGlobalConfiguration)!;
|
|
|
+ var result = config.LoadAll();
|
|
|
+ return result.Select<KeyValuePair<string, IGlobalConfigurationSettings>, IScriptReference>(x =>
|
|
|
+ {
|
|
|
+ var thisConfig = (Activator.CreateInstance(typeof(GlobalConfiguration<>).MakeGenericType(type), x.Key) as IGlobalConfiguration)!;
|
|
|
+ return new GlobalSettingsScriptReference(thisConfig, x.Value, property);
|
|
|
+ });
|
|
|
+ }));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var results = Client.QueryMultiple(queries.Select(x => x.Item1));
|
|
|
+ return queries.SelectMany(x => x.Item2(results.Get(x.Item1.Key)))
|
|
|
+ .Concat(extraTasks.SelectMany(x => x.Result));
|
|
|
+ }
|
|
|
+
|
|
|
+ private List<Tuple<IScriptReference, string>> CheckCustomModules(bool showHidden, bool showWarnings)
|
|
|
+ {
|
|
|
+ var results = new List<Tuple<IScriptReference, string>>();
|
|
|
+ Progress.ShowModal("Loading Data", progress =>
|
|
|
+ {
|
|
|
+ var scripts = GetScripts(showHidden);
|
|
|
+ foreach(var script in scripts)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
- progress.Report($"{module.Section} -> {module.Name}");
|
|
|
+ progress.Report(script.Name);
|
|
|
|
|
|
- var scriptDocument = new ScriptDocument(module.Script);
|
|
|
+ var scriptDocument = new ScriptDocument("#nullable enable\n" + script.Script);
|
|
|
var ok = scriptDocument.Compile();
|
|
|
if (!ok || (showWarnings && scriptDocument.Diagnostics.Any(x => x.Severity == DiagnosticSeverity.Error || x.Severity == DiagnosticSeverity.Warning)))
|
|
|
{
|
|
|
var errors = scriptDocument.Diagnostics.Select(x => x.Contents);
|
|
|
- results.Add(new(module, string.Join('\n', errors.Select(x => $"- {x}"))));
|
|
|
+ results.Add(new(script, string.Join('\n', errors.Select(x => $"- {x}"))));
|
|
|
}
|
|
|
}
|
|
|
catch(Exception e)
|
|
|
{
|
|
|
- results.Add(new(module, e.Message));
|
|
|
+ results.Add(new(script, e.Message));
|
|
|
}
|
|
|
}
|
|
|
});
|
|
|
@@ -195,7 +331,7 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
|
|
|
void RebuildList()
|
|
|
{
|
|
|
list.Items.Clear();
|
|
|
- foreach(var (module, errors) in results)
|
|
|
+ foreach(var (script, errors) in results)
|
|
|
{
|
|
|
var itemGrid = new Grid
|
|
|
{
|
|
|
@@ -213,14 +349,14 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
|
|
|
Height = 30,
|
|
|
Padding = new(5),
|
|
|
Margin = new(0, 0, 5, 0),
|
|
|
- Tag = module
|
|
|
+ Tag = script
|
|
|
};
|
|
|
itemBtn.VerticalAlignment = VerticalAlignment.Top;
|
|
|
itemBtn.Click += ModuleOpen_Click;
|
|
|
itemGrid.AddChild(itemBtn, 0, 0);
|
|
|
itemGrid.AddChild(new Label
|
|
|
{
|
|
|
- Content = $"{module.Section}/{module.Name}:\n{errors}"
|
|
|
+ Content = $"{script.Name}:\n{errors}"
|
|
|
}, 0, 1);
|
|
|
list.Items.Add(itemGrid);
|
|
|
}
|
|
|
@@ -242,7 +378,7 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
|
|
|
};
|
|
|
exportButton.Click += (o, e) =>
|
|
|
{
|
|
|
- var result = string.Join("\n\n", results.Select(x => $"{x.Item1.Section}/{x.Item1.Name}:\n{x.Item2}"));
|
|
|
+ var result = string.Join("\n\n", results.Select(x => $"{x.Item1.Name}:\n{x.Item2}"));
|
|
|
var dlg = new SaveFileDialog()
|
|
|
{
|
|
|
Filter = "Text Files (*.txt)|*.txt"
|
|
|
@@ -291,13 +427,12 @@ public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
|
|
|
private void ModuleOpen_Click(object sender, RoutedEventArgs e)
|
|
|
{
|
|
|
if (sender is not FrameworkElement element
|
|
|
- || element.Tag is not CustomModule module) return;
|
|
|
+ || element.Tag is not IScriptReference script) return;
|
|
|
|
|
|
- var editor = new ScriptEditorWindow(module.Script, scriptTitle: $"{module.Section}/{module.Name}");
|
|
|
+ var editor = new ScriptEditorWindow(script.Script, scriptTitle: script.Name);
|
|
|
if (editor.ShowDialog() == true)
|
|
|
{
|
|
|
- module.Script = editor.Script;
|
|
|
- Client.Save(module, "Updated by User");
|
|
|
+ script.Update(editor.Script);
|
|
|
}
|
|
|
}
|
|
|
|