From c815b1de4f5af36a2e2e5c9af37f2bc820aa7211 Mon Sep 17 00:00:00 2001 From: Michael Becker Date: Thu, 7 Nov 2024 07:31:33 -0500 Subject: [PATCH] begin migration to logic fully on OMS so we can deprecate sloooow PHP logic --- mocha-common | 2 +- .../src/app/Mocha.Oms.Server/Program.cs | 657 ++++++++++++------ .../MochaWebApplication.cs | 10 +- .../src/assets/ui-html/css/common/uwt.less | 8 + .../src/lib/Mocha.Core/KnownAttributeGuids.cs | 6 +- .../src/lib/Mocha.Core/KnownInstanceGuids.cs | 14 + .../lib/Mocha.Core/KnownRelationshipGuids.cs | 12 + mocha-dotnet/src/lib/Mocha.Core/Oms.cs | 26 +- .../OmsImplementations/MemoryOms.cs | 27 +- .../src/lib/Mocha.Core/UI/Renderer.cs | 70 ++ mocha-dotnet/src/lib/Mocha.Core/UI/Widget.cs | 85 +++ .../src/lib/Mocha.Core/UI/Widgets/Element.cs | 67 ++ .../src/lib/Mocha.Core/UI/Widgets/File.cs | 95 +++ .../lib/Mocha.Core/UI/Widgets/MonikerList.cs | 30 + .../src/lib/Mocha.Core/UI/Widgets/Text.cs | 52 ++ .../MethodTests/GetRelationshipTests.cs | 8 +- web-framework-dotnet | 2 +- 17 files changed, 950 insertions(+), 221 deletions(-) create mode 100644 mocha-dotnet/src/lib/Mocha.Core/UI/Renderer.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Core/UI/Widget.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/Element.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/File.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/MonikerList.cs create mode 100644 mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/Text.cs diff --git a/mocha-common b/mocha-common index 3fb99e1..a542b97 160000 --- a/mocha-common +++ b/mocha-common @@ -1 +1 @@ -Subproject commit 3fb99e1159a9ffcd0e031f04ca3ed0b5df18743d +Subproject commit a542b975e5fcd1014f0c8caab0e020c47617ebb3 diff --git a/mocha-dotnet/src/app/Mocha.Oms.Server/Program.cs b/mocha-dotnet/src/app/Mocha.Oms.Server/Program.cs index c685ca2..7c9e528 100644 --- a/mocha-dotnet/src/app/Mocha.Oms.Server/Program.cs +++ b/mocha-dotnet/src/app/Mocha.Oms.Server/Program.cs @@ -10,10 +10,11 @@ using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.Json.Nodes; +using Mocha.Core.UI; public class Program : WebApplication { - protected override int DefaultPort => 14678; + protected override int DefaultPort => 4436; public Program() { @@ -25,6 +26,14 @@ public class Program : WebApplication private Oms oms; + protected override WebServer CreateWebServer() + { + WebServer server = base.CreateWebServer(); + // server.SSLCertificateFile = "/etc/ssl/certs/localhost.crt"; + // server.SSLCertificateKeyFile = "/etc/ssl/certs/localhost.key"; + return server; + } + protected override void OnStartup(EventArgs e) { // this all has to be done before the Web server is started... @@ -32,10 +41,20 @@ public class Program : WebApplication TenantHandle th = oms.CreateTenant("super"); oms.SelectTenant(th); - LibraryHandle lh = oms.LoadLibrary("/home/beckermj/Documents/Projects/mochapowered/mocha-dotnet/mocha-common/mocha-common/output/net.alcetech.Mocha.System.mcl"); + string path = "/home/beckermj/Documents/Projects/mochapowered/mocha-dotnet/mocha-common/mocha-common/output"; + if (!System.IO.Directory.Exists(path)) + { + path = "/usr/share/mocha/system"; + if (!System.IO.Directory.Exists(path)) + { + Console.Error.WriteLine("path not found: " + path); + } + } + + LibraryHandle lh = oms.LoadLibrary(path + "/net.alcetech.Mocha.System.mcl"); oms.AddLibraryReference(lh); - LibraryHandle lh2 = oms.LoadLibrary("/home/beckermj/Documents/Projects/mochapowered/mocha-dotnet/mocha-common/mocha-common/output/net.alcetech.Mocha.Web.mcl"); + LibraryHandle lh2 = oms.LoadLibrary(path + "/net.alcetech.Mocha.Web.mcl"); oms.AddLibraryReference(lh2); // now we can start the Web server @@ -46,6 +65,9 @@ public class Program : WebApplication { base.OnProcessRequest(e); + e.Context.Response.ResponseCode = 404; + e.Context.Response.ResponseText = "Not Found"; + StreamWriter sw = new StreamWriter(e.Context.Response.Stream); if (e.Context.Request.Path == "/robots.txt") { @@ -53,201 +75,316 @@ public class Program : WebApplication } else if (e.Context.Request.PathParts.Length > 1) { - if (e.Context.Request.PathParts[1] == "instances") + if (e.Context.Request.PathParts.Length == 2 && e.Context.Request.PathParts[1] == "ping") { - if (e.Context.Request.PathParts.Length > 2) + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "application/json"; + + JsonObject obj = new JsonObject(); + obj.Add("result", JsonValue.Create("success")); + sw.Write(obj.ToJsonString()); + + sw.Flush(); + sw.Close(); + return; + } + + if (e.Context.Request.PathParts[1] == "tenants") + { + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "application/json"; + + JsonArray ary = new JsonArray(); + + IEnumerable tenants = oms.GetTenants(); + foreach (string tenant in tenants) { - if (e.Context.Request.PathParts[2] == "create") + ary.Add(JsonValue.Create(tenant)); + } + + if (e.Context.Request.PathParts.Length == 2) + { + JsonObject obj = new JsonObject(); + obj.Add("result", JsonValue.Create("success")); + obj.Add("tenants", ary); + sw.Write(obj.ToJsonString()); + } + else if (e.Context.Request.PathParts.Length > 3) + { + // /tenants/{tenantName}/instances + string tenantName = e.Context.Request.PathParts[2]; + + TenantHandle th = oms.GetTenantByName(tenantName); + if (th == TenantHandle.Empty) { - // usage: - // POST /instances/create - // - // parentClassIid=1$1&title=My+New+Class - if (e.Context.Request.Form.ContainsKey("parentClassIid")) - { - string pclass = e.Context.Request.Form["parentClassIid"]; - InstanceKey key = InstanceKey.Parse(pclass); - - if (oms.TryGetInstance(key, out InstanceHandle ihParentClass)) - { - InstanceHandle ihRet = oms.CreateInstanceOf(ihParentClass); - - if (e.Context.Request.Form.ContainsKey("title")) - { - oms.SetAttributeValue(ihRet, oms.GetInstance(KnownAttributeGuids.Text.Name), e.Context.Request.Form["title"]); - } - - e.Context.Response.ResponseCode = 200; - e.Context.Response.ResponseText = "OK"; - e.Context.Response.ContentType = "application/json"; - - JsonObject obj = new JsonObject(); - obj.Add("result", JsonValue.Create("success")); - obj.Add("iid", JsonValue.Create(oms.GetInstanceKey(ihRet).ToString())); - sw.Write(obj.ToJsonString()); - } - else - { - e.Context.Response.ResponseCode = 422; - e.Context.Response.ResponseText = "Unprocessable Content"; - e.Context.Response.ContentType = "application/json"; - - JsonObject obj = new JsonObject(); - obj.Add("result", JsonValue.Create("failure")); - obj.Add("message", JsonValue.Create("parent class instance does not exist")); - sw.Write(obj.ToJsonString()); - } - } - } - else if (e.Context.Request.PathParts[2] == "search") - { - string query = ""; - if (e.Context.Request.Query.ContainsKey("q") && e.Context.Request.Query["q"].Count > 0) - { - query = e.Context.Request.Query["q"][0]; - } - - string parentClassIid = null; - InstanceHandle ihParentClass = InstanceHandle.Empty; - if (e.Context.Request.Query.ContainsKey("parentClassIid") && e.Context.Request.Query["parentClassIid"].Count > 0) - { - parentClassIid = e.Context.Request.Query["parentClassIid"][0]; - if (InstanceKey.TryParse(parentClassIid, out InstanceKey ikParentClass)) - { - ihParentClass = oms.GetInstance(ikParentClass); - } - } - - IEnumerable ihs = null; - if (ihParentClass != InstanceHandle.Empty) - { - ihs = oms.GetInstancesOf(ihParentClass); - } - else - { - ihs = oms.GetInstances(); - } - - if (!String.IsNullOrEmpty(query)) - { - List list = new List(); - foreach (InstanceHandle ih in ihs) - { - string text = oms.GetInstanceText(ih); - if (text.ToLower().Contains(query.ToLower())) - { - list.Add(ih); - } - } - ihs = list; - } - - e.Context.Response.ResponseCode = 200; - e.Context.Response.ResponseText = "OK"; + e.Context.Response.ResponseCode = 404; + e.Context.Response.ResponseText = "Not Found"; e.Context.Response.ContentType = "application/json"; JsonObject obj = new JsonObject(); - - JsonArray objInstances = InstancesToJson(ihs); - obj.Add("instances", objInstances); - + obj.Add("result", JsonValue.Create("failure")); + obj.Add("message", JsonValue.Create("tenant does not exist")); sw.Write(obj.ToJsonString()); + sw.Flush(); + return; } - else if (e.Context.Request.PathParts.Length > 2) + else { - InstanceKey k = InstanceKey.Parse(e.Context.Request.PathParts[2]); - InstanceHandle h = InstanceHandle.Empty; - if (!oms.TryGetInstance(k, out h)) - { - e.Context.Response.ResponseCode = 404; - e.Context.Response.ResponseText = "Not Found"; + oms.SelectTenant(th); + } - sw.Flush(); - sw.Close(); - return; - } - if (e.Context.Request.PathParts.Length > 3) + if (e.Context.Request.PathParts[3] == "instances") + { + if (e.Context.Request.PathParts.Length > 4) { - if (e.Context.Request.PathParts[3] == "attributes") + if (e.Context.Request.PathParts[4] == "create") { - - if (e.Context.Request.PathParts.Length > 5) + // usage: + // POST /tenants/{tenantName}/instances/create + // + // parentClassIid=1$1&title=My+New+Class + if (e.Context.Request.Form.ContainsKey("parentClassIid")) { - string iid = e.Context.Request.PathParts[4]; - InstanceHandle att = oms.GetInstance(InstanceKey.Parse(iid)); - - DateTime dt = DateTime.Now; - if (e.Context.Request.PathParts[5].Equals("current")) + string pclass = e.Context.Request.Form["parentClassIid"]; + if (TryParseInstanceRef(pclass, out InstanceHandle ihParentClass)) { + InstanceHandle ihRet = oms.CreateInstanceOf(ihParentClass); + + if (e.Context.Request.Form.ContainsKey("title")) + { + oms.SetAttributeValue(ihRet, oms.GetInstance(KnownAttributeGuids.Text.Name), e.Context.Request.Form["title"]); + } + + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "application/json"; + + JsonObject obj = new JsonObject(); + obj.Add("result", JsonValue.Create("success")); + obj.Add("value", InstanceToJson(ihRet)); + sw.Write(obj.ToJsonString()); } + else + { + e.Context.Response.ResponseCode = 422; + e.Context.Response.ResponseText = "Unprocessable Content"; + e.Context.Response.ContentType = "application/json"; - string value = oms.GetAttributeValue(h, att, String.Empty, dt); - e.Context.Response.ResponseCode = 200; - e.Context.Response.ResponseText = "OK"; - e.Context.Response.ContentType = "text/plain"; - - sw.Write(value); - sw.Flush(); - sw.Close(); - return; + JsonObject obj = new JsonObject(); + obj.Add("result", JsonValue.Create("failure")); + obj.Add("message", JsonValue.Create("parent class instance does not exist")); + sw.Write(obj.ToJsonString()); + } } - - JsonObject obj = new JsonObject(); - - InstanceHandle hAtt = InstanceHandle.Empty; - if (e.Context.Request.PathParts.Length > 4) - { - hAtt = oms.GetInstance(InstanceKey.Parse(e.Context.Request.PathParts[4])); - } - - JsonArray objAttributes = GetAttributesAsJson(h, hAtt); - obj.Add("attributes", objAttributes); - - - e.Context.Response.ResponseCode = 200; - e.Context.Response.ResponseText = "OK"; - e.Context.Response.ContentType = "application/json"; - - sw.Write(obj.ToJsonString()); } - else if (e.Context.Request.PathParts[3] == "relationships") + else if (e.Context.Request.PathParts.Length >= 5) { - - if (e.Context.Request.PathParts.Length > 5) + // /tenants/{tenantName}/instances/{instanceKey}/... + TryParseInstanceRef(e.Context.Request.PathParts[4], out InstanceHandle h); + + if (h == InstanceHandle.Empty) { - string iid = e.Context.Request.PathParts[4]; - InstanceHandle rel = oms.GetInstance(InstanceKey.Parse(iid)); - - DateTime dt = DateTime.Now; - if (e.Context.Request.PathParts[5].Equals("current")) - { - } - - IEnumerable rel_insts = oms.GetRelatedInstances(h, rel, dt); - JsonObject obj = new JsonObject(); - - JsonArray a = new JsonArray(); - foreach (InstanceHandle ih in rel_insts) - { - a.Add(oms.GetInstanceKey(ih)); - } - - obj.Add("relationships", a); - - e.Context.Response.ResponseCode = 200; - e.Context.Response.ResponseText = "OK"; + e.Context.Response.ResponseCode = 404; + e.Context.Response.ResponseText = "Not Found"; e.Context.Response.ContentType = "application/json"; + JsonObject obj = new JsonObject(); + obj.Add("result", "failure"); + obj.Add("message", String.Format("invalid inst id {0} (inst not found)", e.Context.Request.PathParts[4])); sw.Write(obj.ToJsonString()); + sw.Flush(); sw.Close(); return; } + + if (e.Context.Request.PathParts.Length >= 6) + { + string command = e.Context.Request.PathParts[5]; + if (command == "attributes") + { + if (e.Context.Request.PathParts.Length > 7) + { + // /tenants/{tenantName}/instances/{iid}/attrbutes/{attkey}/current + TryParseInstanceRef(e.Context.Request.PathParts[6], out InstanceHandle att); + + string value; + if (e.Context.Request.Method == "POST" && e.Context.Request.PathParts[7].Equals("update")) + { + value = e.Context.Request.Form["value"]; + oms.SetAttributeValue(h, att, value); + + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "text/plain"; + + sw.Write(value); + sw.Flush(); + sw.Close(); + return; + } + + DateTime dt = DateTime.Now; + if (e.Context.Request.PathParts[7].Equals("current")) + { + } + + value = oms.GetAttributeValue(h, att, String.Empty, dt); + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "text/plain"; + + sw.Write(value); + sw.Flush(); + sw.Close(); + return; + } + + JsonObject obj = new JsonObject(); + + InstanceHandle hAtt = InstanceHandle.Empty; + if (e.Context.Request.PathParts.Length == 7) + { + TryParseInstanceRef(e.Context.Request.PathParts[6], out hAtt); + } + + JsonArray objAttributes = GetAttributesAsJson(h, hAtt); + obj.Add("attributes", objAttributes); + + + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "application/json"; + + sw.Write(obj.ToJsonString()); + } + else if (command == "relationships") + { + if (e.Context.Request.PathParts.Length >= 7) + { + TryParseInstanceRef(e.Context.Request.PathParts[6], out InstanceHandle rel); + + DateTime dt = DateTime.Now; + if (e.Context.Request.PathParts.Length > 7) + { + if (e.Context.Request.Method == "POST" && e.Context.Request.PathParts[7].Equals("update")) + { + if (Int32.TryParse(e.Context.Request.Form["count"], out int count)) + { + JsonObject obj1 = new JsonObject(); + obj1.Add("result", "success"); + + JsonArray ary1 = new JsonArray(); + + List list = new List(); + for (int i = 0; i < count; i++) + { + string key = String.Format("item{0}", i); + if (e.Context.Request.Form.ContainsKey(key)) + { + Console.Error.WriteLine("debug: trying to add inst " + e.Context.Request.Form[key]); + if (TryParseInstanceRef(e.Context.Request.Form[key], out InstanceHandle inst)) + { + ary1.Add(InstanceToJson(inst)); + list.Add(inst); + } + } + } + + Console.Error.WriteLine("ok assigning relationship"); + oms.AssignRelationship(h, rel, list.ToArray()); + + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "application/json"; + + obj1.Add("targetInstances", ary1); + + sw.Write(obj1.ToJsonString()); + sw.Flush(); + sw.Close(); + } + + return; + } + + if (e.Context.Request.PathParts[7].Equals("current")) + { + } + } + + IEnumerable rel_insts = oms.GetRelatedInstances(h, rel, dt); + JsonObject obj = new JsonObject(); + + JsonArray a = new JsonArray(); + foreach (InstanceHandle ih in rel_insts) + { + a.Add(InstanceToJson(ih)); + } + + obj.Add("result", JsonValue.Create("success")); + obj.Add("sourceInstance", InstanceToJson(h)); + obj.Add("relationshipInstance", InstanceToJson(rel)); + obj.Add("value", a); + + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "application/json"; + + sw.Write(obj.ToJsonString()); + sw.Flush(); + sw.Close(); + return; + } + else + { + JsonObject obj = new JsonObject(); + obj.Add("relationships", GetRelationshipsAsJson(h)); + + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "application/json"; + + sw.Write(obj.ToJsonString()); + } + } + else if (command == "element") + { + Renderer renderer = new Renderer(oms); + if (oms.IsInstanceOf(h, oms.GetInstance(KnownInstanceGuids.Classes.Element))) + { + Widget widget = renderer.Parse(h); + JsonObject obj3 = widget.ToJSONObject(); + + JsonObject obj2 = new JsonObject(); + obj2.Add("widget", JsonValue.Create("root")); + obj2.Add("body", widget.ToJSONObject()); + + JsonObject obj = new JsonObject(); + obj.Add("result", "success"); + obj.Add("value", obj2); + RespondWithJson(sw, e.Context, 200, "OK", obj); + } + } + else + { + JsonObject obj = new JsonObject(); + obj.Add("result", "failure"); + obj.Add("message", String.Format("unknown cmd '{0}'", command)); + RespondWithJson(sw, e.Context, 404, "Not Found", obj); + } + } else { JsonObject obj = new JsonObject(); - obj.Add("relationships", GetRelationshipsAsJson(h)); + obj.Add("instanceKey", JsonValue.Create(oms.GetInstanceKey(h).ToString())); + obj.Add("globalIdentifier", JsonValue.Create(oms.GetGlobalIdentifier(h).ToString("b"))); + obj.Add("text", JsonValue.Create(oms.GetInstanceText(h))); + obj.Add("attributes", GetAttributesAsJson(h)); + obj.Add("relationshps", GetRelationshipsAsJson(h)); e.Context.Response.ResponseCode = 200; e.Context.Response.ResponseText = "OK"; @@ -259,42 +396,67 @@ public class Program : WebApplication } else { + e.Context.Response.ResponseCode = 200; + e.Context.Response.ResponseText = "OK"; + e.Context.Response.ContentType = "application/json"; + JsonObject obj = new JsonObject(); - obj.Add("instanceKey", JsonValue.Create(oms.GetInstanceKey(h).ToString())); - obj.Add("globalIdentifier", JsonValue.Create(oms.GetGlobalIdentifier(h).ToString("b"))); - obj.Add("attributes", GetAttributesAsJson(h)); - obj.Add("relationshps", GetRelationshipsAsJson(h)); + + Stopwatch watch = new Stopwatch(); + watch.Start(); + + string query = ""; + if (e.Context.Request.Query.ContainsKey("q") && e.Context.Request.Query["q"].Count > 0) + { + query = e.Context.Request.Query["q"][0]; + } + + string parentClassIid = null; + InstanceHandle ihParentClass = InstanceHandle.Empty; + if (e.Context.Request.Query.ContainsKey("parentClassIid") && e.Context.Request.Query["parentClassIid"].Count > 0) + { + parentClassIid = e.Context.Request.Query["parentClassIid"][0]; + TryParseInstanceRef(parentClassIid, out ihParentClass); + } + + IEnumerable ihs = null; + if (ihParentClass != InstanceHandle.Empty) + { + ihs = oms.GetInstancesOf(ihParentClass); + } + else + { + ihs = oms.GetInstances(); + } + + if (!String.IsNullOrEmpty(query)) + { + List list = new List(); + foreach (InstanceHandle ih in ihs) + { + string text = oms.GetInstanceText(ih); + if (text.ToLower().Contains(query.ToLower())) + { + list.Add(ih); + } + } + ihs = list; + } e.Context.Response.ResponseCode = 200; e.Context.Response.ResponseText = "OK"; e.Context.Response.ContentType = "application/json"; - sw.Write(obj.ToJsonString()); + JsonArray objInstances = InstancesToJson(ihs); + obj.Add("instances", objInstances); + watch.Stop(); + obj.Add("time", JsonValue.Create(watch.ElapsedMilliseconds.ToString())); + + sw.Write(obj.ToJsonString()); } } } - else - { - e.Context.Response.ResponseCode = 200; - e.Context.Response.ResponseText = "OK"; - e.Context.Response.ContentType = "application/json"; - - JsonObject obj = new JsonObject(); - - Stopwatch watch = new Stopwatch(); - watch.Start(); - - IEnumerable ihs = oms.GetInstances(); - - watch.Stop(); - obj.Add("time", JsonValue.Create(watch.ElapsedMilliseconds.ToString())); - - JsonArray objInstances = InstancesToJson(ihs); - obj.Add("instances", objInstances); - - sw.Write(obj.ToJsonString()); - } } } else @@ -310,6 +472,102 @@ public class Program : WebApplication sw.Close(); } +/* + private JsonObject? ElementContentToJSON(InstanceHandle content) + { + JsonObject? objC = null; + InstanceHandle contentWidget = oms.GetRelatedInstance(content, oms.GetInstance(KnownRelationshipGuids.Element_Content__has__Instance)); + + // Mocha.Core.UI.Widget widget = renderer.BuildFromInstance() + if (oms.IsInstanceOf(contentWidget, oms.GetInstance(KnownInstanceGuids.Classes.Element))) + { + objC = ElementToJSON(contentWidget, content); + } + else if (oms.IsInstanceOf(contentWidget, oms.GetInstance(KnownInstanceGuids.Classes.TextAttribute))) + { + objC = TextAttributeToJSON(contentWidget, content); + } + else if (oms.IsInstanceOf(contentWidget, oms.GetInstance(KnownInstanceGuids.Classes.File))) + { + objC = FileToJSON(contentWidget, content); + } + return objC; + } + + private JsonObject? FileToJSON(InstanceHandle contentWidget, InstanceHandle parentElementContent) + { + JsonObject obj3 = new JsonObject(); + InsertCommonProperties(obj3, contentWidget, parentElementContent); + + string value = oms.GetAttributeValue(contentWidget, oms.GetInstance(KnownAttributeGuids.Text.Value)); + if (value != null) + { + obj3.Add("value", JsonValue.Create(value)); + } + return obj3; + } + private JsonObject? TextAttributeToJSON(InstanceHandle contentWidget, InstanceHandle parentElementContent) + { + JsonObject obj3 = new JsonObject(); + InsertCommonProperties(obj3, contentWidget, parentElementContent); + + string value = oms.GetAttributeValue(contentWidget, oms.GetInstance(KnownAttributeGuids.Text.Value)); + if (value != null) + { + obj3.Add("value", JsonValue.Create(value)); + } + return obj3; + } + + */ + + private void RespondWithJson(StreamWriter sw, WebContext context, int responseCode, string responseText, JsonObject obj) + { + context.Response.ResponseCode = responseCode; + context.Response.ResponseText = responseText; + context.Response.ContentType = "application/json"; + + sw.Write(obj.ToJsonString()); + } + + private bool TryParseInstanceRef(string instanceKeyOrGuid, out InstanceHandle h) + { + h = InstanceHandle.Empty; + if (InstanceKey.TryParse(instanceKeyOrGuid, out InstanceKey k)) + { + oms.TryGetInstance(k, out h); + return true; + } + else if (Guid.TryParse(instanceKeyOrGuid, out Guid g)) + { + oms.TryGetInstance(g, out h); + return true; + } + else + { + Console.Error.WriteLine("could not parse: {0}", instanceKeyOrGuid); + } + return false; + } + + private JsonNode? InstanceToJson(InstanceHandle ih) + { + InstanceHandle parentClass = oms.GetParentClass(ih); + + JsonObject objInstance = new JsonObject(); + objInstance.Add("iid", JsonValue.Create(oms.GetInstanceKey(ih).ToString())); + objInstance.Add("globalIdentifier", JsonValue.Create(oms.GetGlobalIdentifier(ih).ToString())); + objInstance.Add("text", JsonValue.Create(oms.GetInstanceText(ih))); + + JsonObject objParentClass = new JsonObject(); + objParentClass.Add("iid", JsonValue.Create(oms.GetInstanceKey(parentClass).ToString())); + objParentClass.Add("globalIdentifier", JsonValue.Create(oms.GetGlobalIdentifier(parentClass).ToString())); + objParentClass.Add("text", JsonValue.Create(oms.GetInstanceText(parentClass))); + objInstance.Add("parentClass", objParentClass); + + return objInstance; + } + private JsonArray GetRelationshipsAsJson(InstanceHandle h, InstanceHandle hRel = default(InstanceHandle)) { JsonArray a = new JsonArray(); @@ -386,18 +644,7 @@ public class Program : WebApplication JsonArray array = new JsonArray(); foreach (InstanceHandle ih in ihs) { - InstanceHandle parentClass = oms.GetParentClass(ih); - - JsonObject objInstance = new JsonObject(); - objInstance.Add("iid", JsonValue.Create(oms.GetInstanceKey(ih).ToString())); - objInstance.Add("text", JsonValue.Create(oms.GetInstanceText(ih))); - - JsonObject objParentClass = new JsonObject(); - objParentClass.Add("iid", JsonValue.Create(oms.GetInstanceKey(parentClass).ToString())); - objParentClass.Add("text", JsonValue.Create(oms.GetInstanceText(parentClass))); - objInstance.Add("parentClass", objParentClass); - - array.Add(objInstance); + array.Add(InstanceToJson(ih)); } return array; } diff --git a/mocha-dotnet/src/app/Mocha.ServerApplication/MochaWebApplication.cs b/mocha-dotnet/src/app/Mocha.ServerApplication/MochaWebApplication.cs index 74eaecf..58b45cd 100644 --- a/mocha-dotnet/src/app/Mocha.ServerApplication/MochaWebApplication.cs +++ b/mocha-dotnet/src/app/Mocha.ServerApplication/MochaWebApplication.cs @@ -69,7 +69,15 @@ public abstract class MochaWebApplication : WebApplication return oms; } - protected override void OnProcessRequest(WebServerProcessRequestEventArgs e) + protected override WebServer CreateWebServer() + { + WebServer server = base.CreateWebServer(); + server.SSLCertificateFile = "/etc/ssl/certs/localhost.crt"; + server.SSLCertificateKeyFile = "/etc/ssl/certs/localhost.key"; + return server; + } + + protected override void OnProcessRequest(WebServerProcessRequestEventArgs e) { base.OnProcessRequest(e); diff --git a/mocha-dotnet/src/assets/ui-html/css/common/uwt.less b/mocha-dotnet/src/assets/ui-html/css/common/uwt.less index 9a65cfb..68c5450 100644 --- a/mocha-dotnet/src/assets/ui-html/css/common/uwt.less +++ b/mocha-dotnet/src/assets/ui-html/css/common/uwt.less @@ -199,3 +199,11 @@ body > div.uwt-page-content { padding: 16px; } + +a.uwt-external-link::after +{ + content: "\f08e"; + font-family: "Font Awesome 6 Pro"; + padding-left: 8px; + font-weight: 300; +} \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/KnownAttributeGuids.cs b/mocha-dotnet/src/lib/Mocha.Core/KnownAttributeGuids.cs index 051812d..b82073c 100755 --- a/mocha-dotnet/src/lib/Mocha.Core/KnownAttributeGuids.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/KnownAttributeGuids.cs @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License // along with Mocha.NET. If not, see . -using System; +using System; namespace Mocha.Core { public static class KnownAttributeGuids @@ -43,7 +43,9 @@ namespace Mocha.Core public static Guid Token { get; } = new Guid("{da7686b6-3803-4f15-97f6-7f8f3ae16668}"); public static Guid DebugDefinitionFileName { get; } = new Guid("{03bf47c7-dc97-43c8-a8c9-c6147bee4e1f}"); - } + public static Guid Label { get; } = new Guid("{69cdf8af-fcf2-4477-b75d-71593e7dbb22}"); + public static Guid LabelOverride { get; } = new Guid("{89b361e0-9f13-4fea-9b1e-6eca573bd6ba}"); + } public static class Boolean { public static Guid MethodIsOfTypeSpecified { get; } = new Guid("{6e9df667-0f95-4320-a4be-5cdb00f1d4ee}"); diff --git a/mocha-dotnet/src/lib/Mocha.Core/KnownInstanceGuids.cs b/mocha-dotnet/src/lib/Mocha.Core/KnownInstanceGuids.cs index 069614c..86b8560 100755 --- a/mocha-dotnet/src/lib/Mocha.Core/KnownInstanceGuids.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/KnownInstanceGuids.cs @@ -126,6 +126,9 @@ namespace Mocha.Core public static Guid User { get; } = new Guid("{9C6871C1-9A7F-4A3A-900E-69D1D9E24486}"); public static Guid UserLogin { get; } = new Guid("{64F4BCDB-38D0-4373-BA30-8AE99AF1A5F7}"); + public static Guid GroupLayout { get; } = new Guid("{108605af-c20d-42eb-af4f-35b2ff701921}"); + public static Guid ImageLayout { get; } = new Guid("{4b1bb7c6-168e-4ce0-b4f8-76dd5069a80b}"); + public static Guid Menu { get; } = new Guid("{c952ef83-af18-4512-9dd9-0f00a19d399c}"); public static Guid MenuItem { get; } = new Guid("{f606f612-2d12-4600-bee1-a071d1019ffe}"); public static Guid MenuItemCommand { get; } = new Guid("{9D3EDE23-6DB9-4664-9145-ABCBD3A0A2C2}"); @@ -444,5 +447,16 @@ namespace Mocha.Core public static Guid Japanese { get; } = new Guid ("{1e16de9d-0e49-4a79-b690-4905c46a94cc}"); public static Guid Korean { get; } = new Guid ("{d03a795e-906b-49ee-87ea-c1bef4b8ee9a}"); } + public static class GroupLayoutOptions + { + public static Guid Tabbed { get; } = new Guid("{f600c4f6-964b-4a27-b5b0-24fd4c8d0878}"); + public static Guid FieldSet { get; } = new Guid("{7dd84757-e1c1-4bbb-9ef6-5b88fb9a76fc}"); + } + public static class Alignments + { + public static Guid Near { get; } = new Guid("{35ea407a-45e1-462f-a923-a526d12fbc47}"); + public static Guid Far { get; } = new Guid("{f19d16c7-99ff-48a3-b86a-7db8f400d869}"); + public static Guid Center { get; } = new Guid("{63179b92-9a6a-495b-a823-f45e353be9d8}"); + } } } diff --git a/mocha-dotnet/src/lib/Mocha.Core/KnownRelationshipGuids.cs b/mocha-dotnet/src/lib/Mocha.Core/KnownRelationshipGuids.cs index e0d9a90..2e477e2 100755 --- a/mocha-dotnet/src/lib/Mocha.Core/KnownRelationshipGuids.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/KnownRelationshipGuids.cs @@ -231,6 +231,12 @@ namespace Mocha.Core public static Guid Style__has__Style_Rule { get; } = new Guid("{4CC8A654-B2DF-4B17-A956-24939530790E}"); public static Guid Style_Rule__has__Style_Property { get; } = new Guid("{B69C2708-E78D-413A-B491-ABB6F1D2A6E0}"); + public static Guid Style__has_width__Measurement { get; } = new Guid("{4930ca87-641a-426d-9d67-cda6d5f22303}"); + public static Guid Style__has_height__Measurement { get; } = new Guid("{978e6de0-af73-45a0-bb56-aaf451615b06}"); + + public static Guid Style__has_horizontal__Alignment { get; } = new Guid("{cc8d60e3-1b42-4ab1-a918-3d109891bb4e}"); + public static Guid Style__has_vertical__Alignment { get; } = new Guid("{24c175dd-c34c-4ffc-aef0-440aa032ceeb}"); + public static Guid Page__has_master__Page { get; } = new Guid("{9bdbfd64-0915-419f-83fd-e8cf8bcc74ae}"); public static Guid Page__master_for__Page { get; } = new Guid("{7fe8f2a2-c94d-4010-83aa-9300cc99d71d}"); @@ -311,6 +317,12 @@ namespace Mocha.Core public static Guid Element_Content__has__Instance { get; } = new Guid("{315b71ba-953d-45fc-87e5-4f0a268242a9}"); public static Guid Instance__for__Element_Content { get; } = new Guid("{c3959f84-248d-4ede-a3f2-f262917c7b56}"); + public static Guid Element_Content__has__Layout { get; } = new Guid("{1ab74120-05ea-4aca-b6d3-c7e0133e0c4f}"); + + public static Guid Layout__has__Style { get; } = new Guid("{e684bb26-7e78-4a21-b8b4-5a550f3053d5}"); + + public static Guid Group_Layout__uses__Group_Layout_Option { get; } = new Guid("{5bea01b6-c33e-4f37-a940-579712ab47c7}"); + public static Guid Element_Content__has__Element_Content_Display_Option { get; } = new Guid("{f070dfa7-6260-4488-a779-fae291903f2d}"); public static Guid Element_Content_Display_Option__for__Element_Content { get; } = new Guid("{12fe7923-b3d2-4152-96c7-a901410b3466}"); diff --git a/mocha-dotnet/src/lib/Mocha.Core/Oms.cs b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs index ffecdb0..1283dfc 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/Oms.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs @@ -17,7 +17,6 @@ namespace Mocha.Core; -using System.Collections.Frozen; using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Data.SqlTypes; @@ -452,6 +451,16 @@ public abstract class Oms return true; } } + else if (val is string && typeof(T) == typeof(decimal)) + { + // HACK HACK HACK - fix the underlying assignment so it assigns boolean true instead of string "True" + // !!! !!! !!! it's probably in the yaml2mcl compiler somewhere + if (Decimal.TryParse((string)val, out decimal actual)) + { + value = (T)((object)actual); + return true; + } + } } value = default(T); @@ -601,11 +610,15 @@ public abstract class Oms public string GetAttachmentUrl(InstanceHandle fileInstance) { - string entropy = ""; - string accessKey = BuildAccessKeyForOmsAttachment(fileInstance, entropy); - return BasePath + TenantName + "/attachment/" + GetInstanceKey(fileInstance).ToString() + "/" + accessKey; + string accessKey = BuildAccessKeyForOmsAttachment(fileInstance); + return String.Format("{0}{1}/attachment/{2}/{3}", BasePath, TenantName, GetInstanceKey(fileInstance), accessKey); } + public string BuildAccessKeyForOmsAttachment(InstanceHandle fileInstance) + { + string entropy = ""; + return BuildAccessKeyForOmsAttachment(fileInstance, entropy); + } private string BuildAccessKeyForOmsAttachment(InstanceHandle fileInstance, string entropy) { /* @@ -1403,4 +1416,9 @@ public abstract class Oms { return GetRelationshipsInternal(h); } + + public IEnumerable GetTenants() + { + return _tenantsByName.Keys; + } } diff --git a/mocha-dotnet/src/lib/Mocha.Core/OmsImplementations/MemoryOms.cs b/mocha-dotnet/src/lib/Mocha.Core/OmsImplementations/MemoryOms.cs index e1c1fc4..04b4519 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/OmsImplementations/MemoryOms.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/OmsImplementations/MemoryOms.cs @@ -177,7 +177,13 @@ public class MemoryOms : Oms if (oms._libraries.ContainsKey(lh)) { IReadOnlyCollection insts2 = oms._libraries[lh].GetRelatedInstances(source, relationship, effectiveDate); - list2.AddRange(insts2); + foreach (InstanceHandle i in insts2) + { + if (!list2.Contains(i)) + { + list2.Add(i); + } + } } } @@ -190,7 +196,13 @@ public class MemoryOms : Oms { if (val.EffectiveDate <= effectiveDate) { - list2.AddRange(val.TargetInstances); + foreach (InstanceHandle i in val.TargetInstances) + { + if (!list2.Contains(i)) + { + list2.Add(i); + } + } } } } @@ -278,8 +290,15 @@ public class MemoryOms : Oms { if (!_libraryReferences.Contains(library)) { - // please don't reference the same library multiple times - _libraryReferences.Add(library); + if (oms._libraries.ContainsKey(library)) + { + // please don't reference the same library multiple times + _libraryReferences.Add(library); + } + else + { + Console.Error.WriteLine("oms: error: trying to add reference to library which hasn't been loaded yet"); + } } } public void RemoveLibraryReference(LibraryHandle library) diff --git a/mocha-dotnet/src/lib/Mocha.Core/UI/Renderer.cs b/mocha-dotnet/src/lib/Mocha.Core/UI/Renderer.cs new file mode 100644 index 0000000..ad398ae --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/UI/Renderer.cs @@ -0,0 +1,70 @@ +// Copyright (C) 2024 Michael Becker +// +// This file is part of Mocha.NET. +// +// Mocha.NET is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Mocha.NET is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Mocha.NET. If not, see . + +using System.Text.Json.Nodes; + +namespace Mocha.Core.UI; + +public class Renderer +{ + public Oms OMS { get; private set; } + public Renderer(Oms oms) + { + OMS = oms; + } + + + public Widget Parse(InstanceHandle h) + { + return Parse(h, InstanceHandle.Empty); + } + public Widget Parse(InstanceHandle h, InstanceHandle parentElementContent) + { + Widget[] availableWidgets = MBS.Core.Reflection.TypeLoader.GetAvailableTypes(); + + InstanceHandle parentClassInstance = OMS.GetParentClass(h); + Guid gid = OMS.GetGlobalIdentifier(parentClassInstance); + + Widget? useWidget = null; + foreach (Widget w in availableWidgets) + { + if (w.SupportedClassGuids.Contains(gid)) + { + useWidget = w; + break; + } + } + + if (useWidget == null) + { + Console.Error.WriteLine("not found widget for GID " + gid.ToString()); + return null; + } + + useWidget.OMS = OMS; + useWidget.ParentInstance = h; + useWidget.ParentElementContent = parentElementContent; + useWidget.Renderer = this; + return useWidget; + } + + public Widget ParseElementContent(InstanceHandle content) + { + InstanceHandle h = OMS.GetRelatedInstance(content, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Instance)); + return Parse(h, content); + } +} \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/UI/Widget.cs b/mocha-dotnet/src/lib/Mocha.Core/UI/Widget.cs new file mode 100644 index 0000000..5211ed7 --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/UI/Widget.cs @@ -0,0 +1,85 @@ +// Copyright (C) 2024 Michael Becker +// +// This file is part of Mocha.NET. +// +// Mocha.NET is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Mocha.NET is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Mocha.NET. If not, see . + +using System.Text.Json.Nodes; + +namespace Mocha.Core.UI; + +public abstract class Widget +{ + protected abstract void RenderJSONInternal(JsonObject obj); + protected abstract string GetWidgetName(); + + public InstanceHandle ParentInstance { get; internal set; } = InstanceHandle.Empty; + public InstanceHandle ParentElementContent { get; internal set; } = InstanceHandle.Empty; + + public JsonObject ToJSONObject() + { + JsonObject obj = new JsonObject(); + InsertCommonProperties(obj); + RenderJSONInternal(obj); + return obj; + } + + public virtual Guid[] SupportedClassGuids { get; } = new Guid[0]; + public Oms OMS { get; internal set; } + public Renderer Renderer { get; internal set; } + + public IEnumerable GetDisplayOptions() + { + IEnumerable displayOptions = OMS.GetRelatedInstances(ParentElementContent, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Element_Content_Display_Option)); + return displayOptions; + } + + private void InsertCommonProperties(JsonObject obj) + { + obj.Add("widget", GetWidgetName()); + obj.Add("iid", JsonValue.Create(OMS.GetInstanceKey(ParentInstance).ToString())); + if (ParentElementContent != InstanceHandle.Empty) + { + IEnumerable displayOptions = GetDisplayOptions(); + obj.Add("ecid", JsonValue.Create(OMS.GetInstanceKey(ParentElementContent).ToString())); + + if (!displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.DoNotShowLabel))) + { + string label = OMS.GetAttributeValue(ParentElementContent, OMS.GetInstance(KnownAttributeGuids.Text.LabelOverride)); + if (label == null) + { + label = OMS.GetAttributeValue(ParentElementContent, OMS.GetInstance(KnownAttributeGuids.Text.Label)); + if (label == null) + { + label = OMS.GetInstanceText(ParentInstance); + } + } + obj.Add("label", label); + } + if (displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.NotEnterable))) + { + obj.Add("enabled", false); + } + if (displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.DoNotShow))) + { + obj.Add("visible", false); + } + if (displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.Required))) + { + obj.Add("required", true); + } + } + } + +} \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/Element.cs b/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/Element.cs new file mode 100644 index 0000000..faebf5e --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/Element.cs @@ -0,0 +1,67 @@ +// Copyright (C) 2024 Michael Becker +// +// This file is part of Mocha.NET. +// +// Mocha.NET is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Mocha.NET is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Mocha.NET. If not, see . + + +using System.Text.Json.Nodes; + +namespace Mocha.Core.UI; + +public class Element : Widget +{ + protected override string GetWidgetName() + { + InstanceHandle layout = OMS.GetRelatedInstance(ParentElementContent, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Layout)); + if (OMS.IsInstanceOf(layout, OMS.GetInstance(KnownInstanceGuids.Classes.GroupLayout))) + { + InstanceHandle ihGLOFieldSet = OMS.GetInstance(KnownInstanceGuids.GroupLayoutOptions.FieldSet); + IEnumerable groupLayoutOptions = OMS.GetRelatedInstances(layout, OMS.GetInstance(KnownRelationshipGuids.Group_Layout__uses__Group_Layout_Option)); + if (groupLayoutOptions.Contains(ihGLOFieldSet)) + { + return "fieldSet"; + } + } + return "vbox"; + } + + public override Guid[] SupportedClassGuids => new Guid[] { KnownInstanceGuids.Classes.Element }; + + protected override void RenderJSONInternal(JsonObject obj) + { + JsonArray objA = new JsonArray(); + + IEnumerable contents = OMS.GetRelatedInstances(ParentInstance, OMS.GetInstance(KnownRelationshipGuids.Element__has__Element_Content)); + foreach (InstanceHandle content in contents) + { + Widget widget = Renderer.ParseElementContent(content); + if (widget == null) + { + JsonObject objC = new JsonObject(); + objC.Add("widget", JsonValue.Create("error")); + objC.Add("text", JsonValue.Create("could not create EC")); + objC.Add("ecid", JsonValue.Create(OMS.GetInstanceKey(content).ToString())); + objC.Add("iid", JsonValue.Create(OMS.GetInstanceKey(OMS.GetRelatedInstance(content, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Instance))).ToString())); + objA.Add(objC); + } + else + { + objA.Add(widget.ToJSONObject()); + } + } + + obj.Add("children", objA); + } +} diff --git a/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/File.cs b/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/File.cs new file mode 100644 index 0000000..78de9d1 --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/File.cs @@ -0,0 +1,95 @@ +// Copyright (C) 2024 Michael Becker +// +// This file is part of Mocha.NET. +// +// Mocha.NET is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Mocha.NET is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Mocha.NET. If not, see . + + +using System.Text.Json.Nodes; + +namespace Mocha.Core.UI; + +public class File : Widget +{ + protected override string GetWidgetName() => "image"; + public override Guid[] SupportedClassGuids => new Guid[] { KnownInstanceGuids.Classes.File }; + + protected override void RenderJSONInternal(JsonObject obj) + { + obj.Add("target", OMS.BuildAccessKeyForOmsAttachment(ParentInstance)); + if (ParentElementContent != null) + { + InstanceHandle layoutInstance = OMS.GetRelatedInstance(ParentElementContent, OMS.GetInstance(KnownRelationshipGuids.Element_Content__has__Layout)); + if (layoutInstance != InstanceHandle.Empty) + { + InstanceHandle styleInstance = OMS.GetRelatedInstance(layoutInstance, OMS.GetInstance(KnownRelationshipGuids.Layout__has__Style)); + if (styleInstance != InstanceHandle.Empty) + { + InstanceHandle attValue = OMS.GetInstance(KnownAttributeGuids.Text.Value); + + // ! FIXME: output the proper Measurement string representations for HTML/CSS + InstanceHandle widthMeasurement = OMS.GetRelatedInstance(styleInstance, OMS.GetInstance(KnownRelationshipGuids.Style__has_width__Measurement)); + if (widthMeasurement != InstanceHandle.Empty) + { + obj.Add("width", OMS.GetAttributeValue(widthMeasurement, attValue) + "px"); + } + + InstanceHandle heightMeasurement = OMS.GetRelatedInstance(styleInstance, OMS.GetInstance(KnownRelationshipGuids.Style__has_height__Measurement)); + if (heightMeasurement != InstanceHandle.Empty) + { + obj.Add("height", OMS.GetAttributeValue(heightMeasurement, attValue) + "px"); + } + + InstanceHandle horizontalAlignment = OMS.GetRelatedInstance(styleInstance, OMS.GetInstance(KnownRelationshipGuids.Style__has_horizontal__Alignment)); + if (horizontalAlignment != InstanceHandle.Empty) + { + if (horizontalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Center) + { + obj.Add("horizontalAlignment", "center"); + } + if (horizontalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Far) + { + obj.Add("horizontalAlignment", "far"); + } + if (horizontalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Near) + { + obj.Add("horizontalAlignment", "near"); + } + } + + InstanceHandle verticalAlignment = OMS.GetRelatedInstance(styleInstance, OMS.GetInstance(KnownRelationshipGuids.Style__has_vertical__Alignment)); + if (verticalAlignment != InstanceHandle.Empty) + { + if (verticalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Center) + { + obj.Add("verticalAlignment", "center"); + } + if (verticalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Far) + { + obj.Add("verticalAlignment", "far"); + } + if (verticalAlignment.GlobalIdentifier == KnownInstanceGuids.Alignments.Near) + { + obj.Add("verticalAlignment", "near"); + } + } + } + + if (OMS.IsInstanceOf(layoutInstance, OMS.GetInstance(KnownInstanceGuids.Classes.ImageLayout))) + { + } + } + } + } +} diff --git a/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/MonikerList.cs b/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/MonikerList.cs new file mode 100644 index 0000000..2a67e8c --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/MonikerList.cs @@ -0,0 +1,30 @@ +// Copyright (C) 2024 Michael Becker +// +// This file is part of Mocha.NET. +// +// Mocha.NET is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Mocha.NET is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Mocha.NET. If not, see . + +using System.Text.Json.Nodes; + +namespace Mocha.Core.UI; + +public class MonikerList : Widget +{ + protected override string GetWidgetName() => "monikerList"; + public override Guid[] SupportedClassGuids => new Guid[] { KnownInstanceGuids.Classes.WorkSet }; + + protected override void RenderJSONInternal(JsonObject obj) + { + } +} diff --git a/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/Text.cs b/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/Text.cs new file mode 100644 index 0000000..389cbfe --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/UI/Widgets/Text.cs @@ -0,0 +1,52 @@ +// Copyright (C) 2024 Michael Becker +// +// This file is part of Mocha.NET. +// +// Mocha.NET is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Mocha.NET is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Mocha.NET. If not, see . + + +using System.Text.Json.Nodes; + +namespace Mocha.Core.UI; + +public class Text : Widget +{ + protected override string GetWidgetName() + { + if (ParentElementContent != InstanceHandle.Empty) + { + IEnumerable displayOptions = GetDisplayOptions(); + if (displayOptions.Contains(OMS.GetInstance(KnownInstanceGuids.ElementContentDisplayOptions.ObscuredText))) + { + return "obscuredText"; + } + } + return "text"; + } + public override Guid[] SupportedClassGuids => new Guid[] { KnownInstanceGuids.Classes.TextAttribute }; + + protected override void RenderJSONInternal(JsonObject obj) + { + string value = OMS.GetAttributeValue(ParentInstance, OMS.GetInstance(KnownAttributeGuids.Text.Value)); + if (value != null) + { + obj.Add("value", value); + } + + if (OMS.TryGetAttributeValue(ParentInstance, OMS.GetInstance(KnownAttributeGuids.Numeric.MaximumLength), out decimal maximumLength)) + { + obj.Add("maximumLength", maximumLength); + } + } +} diff --git a/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/GetRelationshipTests.cs b/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/GetRelationshipTests.cs index 9f39c05..3dbcd6f 100644 --- a/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/GetRelationshipTests.cs +++ b/mocha-dotnet/tests/Mocha.Core.Tests/MethodTests/GetRelationshipTests.cs @@ -103,10 +103,12 @@ public class GetRelationshipTests : MethodTestsBase InstanceHandle valueIH = Oms.Execute(context, rsmb); object? value_o = context.GetWorkData(valueIH); - IEnumerable values = (IEnumerable)value_o; - for (int i = 0; i < TEST_VALUES.Length; i++) + if (value_o is IEnumerable values) { - Assert.That(values.ElementAt(i), Is.EqualTo(TEST_VALUES[i])); + for (int i = 0; i < TEST_VALUES.Length; i++) + { + Assert.That(values.ElementAt(i), Is.EqualTo(TEST_VALUES[i])); + } } } diff --git a/web-framework-dotnet b/web-framework-dotnet index 05c3fd5..0054320 160000 --- a/web-framework-dotnet +++ b/web-framework-dotnet @@ -1 +1 @@ -Subproject commit 05c3fd5274e76511bd2ccf8b33d347c2de1930e3 +Subproject commit 0054320a0ea9592fe691205f21441a8c9e01319a