Skip to content

Commit

Permalink
Merged from master
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkMpn committed Jul 29, 2023
2 parents b68d47c + 252f2c9 commit 10673a6
Show file tree
Hide file tree
Showing 113 changed files with 7,001 additions and 2,326 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,4 @@ ModelManifest.xml
/tmp
/.vs/config/applicationhost.config
/.vs
/QEx samples
2 changes: 1 addition & 1 deletion FXBEditorUtils/Prompt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static string ShowDialog(string text, string caption, string startvalue =
Label textLabel = new Label() { Left = 50, Top = 20, Width = 430, Text = text };
TextBox textBox = new TextBox() { Left = 50, Top = 45, Width = 400, Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right, Text = startvalue };
Button cancellation = new Button() { Text = "Cancel", Left = 220, Width = 100, Top = 80, DialogResult = DialogResult.Cancel };
Button confirmation = new Button() { Text = "Ok", Left = 350, Width = 100, Top = 80, DialogResult = DialogResult.OK };
Button confirmation = new Button() { Text = "OK", Left = 350, Width = 100, Top = 80, DialogResult = DialogResult.OK };
//confirmation.Click += (sender, e) => { prompt.Close(); };
prompt.Controls.Add(textBox);
prompt.Controls.Add(cancellation);
Expand Down
7 changes: 4 additions & 3 deletions FXBTests/QueryExpressionTests.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.Xrm.Sdk.Query;
using Rappen.XTB.FetchXmlBuilder.Converters;
using Rappen.XTB.FetchXmlBuilder.Settings;

namespace FXBTests
{
Expand All @@ -14,7 +15,7 @@ public void StandardCondition()
qe.ColumnSet = new ColumnSet("fullname", "lastname");
qe.Criteria.AddCondition("modifiedon", ConditionOperator.GreaterThan, "2020-01-01");

var converted = QueryExpressionCodeGenerator.GetCSharpQueryExpression(qe);
var converted = CSharpCodeGenerator.GetCSharpQueryExpression(qe, null, new FXBSettings());

var expected = @"// Define Condition Values
var query_modifiedon = ""2020-01-01"";
Expand All @@ -39,7 +40,7 @@ public void ColumnComparisonCondition()
qe.ColumnSet = new ColumnSet("fullname", "lastname");
qe.Criteria.AddCondition(new ConditionExpression("modifiedon", ConditionOperator.GreaterThan, true, "createdon"));

var converted = QueryExpressionCodeGenerator.GetCSharpQueryExpression(qe);
var converted = CSharpCodeGenerator.GetCSharpQueryExpression(qe, null, new FXBSettings());

var expected = @"// Define Condition Values
var query_modifiedon = ""createdon"";
Expand All @@ -65,7 +66,7 @@ public void MultipleComparisonsOnSameField()
qe.Criteria.AddCondition("modifiedon", ConditionOperator.GreaterThan, "2020-01-01");
qe.Criteria.AddCondition(new ConditionExpression("modifiedon", ConditionOperator.GreaterThan, true, "createdon"));

var converted = QueryExpressionCodeGenerator.GetCSharpQueryExpression(qe);
var converted = CSharpCodeGenerator.GetCSharpQueryExpression(qe, null, new FXBSettings());

var expected = @"// Define Condition Values
var query_modifiedon = ""2020-01-01"";
Expand Down
12 changes: 7 additions & 5 deletions FetchXMLBuilder.nuspec
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
<authors>Jonas Rapp</authors>
<owners>rappen</owners>
<projectUrl>https://fetchxmlbuilder.com</projectUrl>
<iconUrl>https://fetchxmlbuilder.com/fxb150/</iconUrl>
<iconUrl>https://jonasr.app/wp-content/uploads/2019/09/FXB-2019-2-150-tsp.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<summary>Build queries for Microsoft Dataverse and the Power Platform. Investigate data. Get code. Empower yourself to achieve more.</summary>
<summary>Build queries for Microsoft Dataverse and the Power Platform. Investigate data. Fix the layouts. Get code. Empower yourself to achieve more.</summary>
<description>
Build queries for Microsoft Dataverse and the Power Platform. Investigate data. Get code. Empower yourself to achieve more.
Build queries for Microsoft Dataverse and the Power Platform. Investigate data. Fix the layouts. Get code. Empower yourself to achieve more.

Read more: https://fetchxmlbuilder.com/

FetchXML Builder is used to create and execute queries against Microsoft Dataverse / Power Apps / Dynamics 365.
The Power Platform includes technologies we know as:
Expand Down Expand Up @@ -55,10 +57,10 @@ https://fetchxmlbuilder.com/releases/#$versionnumber$
Released for manual download:
https://github.com/rappen/FetchXMLBuilder/releases/tag/$buildnumber$
</releaseNotes>
<copyright>Copyright Jonas Rapp 2014-2022</copyright>
<copyright>Copyright Jonas Rapp 2014-2023</copyright>
<tags>XrmToolBox Plugins FetchXML Builder</tags>
<dependencies>
<dependency id="XrmToolBox" version="1.2022.4.55" />
<dependency id="XrmToolBox" version="1.2023.1.63" />
</dependencies>
</metadata>
<files>
Expand Down
1 change: 1 addition & 0 deletions FetchXmlBuilder/AppCode/QueryInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Rappen.XTB.FetchXmlBuilder.AppCode
internal class QueryInfo
{
public QueryBase Query;
public string QuerySignature;
public string AttributesSignature;
public EntityCollection Results;
}
Expand Down
1 change: 1 addition & 0 deletions FetchXmlBuilder/AppCode/Utils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public static string ProcessURL(string url)
if (urib.Host.ToLowerInvariant().Contains("microsoft.com"))
{
microsoftparams.AllKeys.ToList().ForEach(k => qry[k] = microsoftparams[k]);
urib.Path = urib.Path.Replace("/en-us/", "/");
}
commonparams.AllKeys.ToList().ForEach(k => qry[k] = commonparams[k]);

Expand Down
11 changes: 8 additions & 3 deletions FetchXmlBuilder/AppCode/WebAPIMetadataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,19 @@ public EntityMetadata GetEntity(string logicalName)

public EntityMetadata GetEntity(int otc)
{
var metadata = fetchXmlBuilder.entities.SingleOrDefault(e => e.ObjectTypeCode == otc);
if (fetchXmlBuilder.entities == null)
{
throw new Exception("Metadata not loaded");
}

if (metadata == null)
var entity = fetchXmlBuilder.entities.SingleOrDefault(e => e.ObjectTypeCode == otc);

if (entity == null)
{
throw new Exception($"No metadata for entity: {otc}");
}

return metadata;
return GetEntity(entity.LogicalName);
}
}
}
43 changes: 43 additions & 0 deletions FetchXmlBuilder/Builder/TreeNodeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,22 @@ internal static string Value(this TreeNode node, string key)
return string.Empty;
}

internal static void SetValue(this TreeNode node, string key, object value)
{
if (node == null)
{
return;
}
if (node.Tag == null)
{
node.Tag = new Dictionary<string, string>();
}
if (node.Tag is Dictionary<string, string> tag)
{
tag[key] = value.ToString();
}
}

internal static bool IsFetchAggregate(this TreeNode node)
{
var aggregate = false;
Expand Down Expand Up @@ -71,6 +87,33 @@ internal static bool IsFetchDistinct(this TreeNode node)
return distinct;
}

internal static bool IsAttributeValidForView(this TreeNode node)
{
var entity = node.Parent;
return node.Name == "attribute" && (entity?.Name == "entity" || (entity?.Name == "link-entity" && !string.IsNullOrWhiteSpace(entity.Value("alias"))));
}

internal static string GetAttributeLayoutName(this TreeNode node)
{
var entity = node.LocalEntityNode();
var entityalias = entity.Name == "link-entity" ? entity.Value("alias") : string.Empty;
var attribute = node.Value("name");
var alias = node.Value("alias");
if (!string.IsNullOrWhiteSpace(alias))
{
attribute = alias;
}
else if (!string.IsNullOrWhiteSpace(entityalias))
{
attribute = entityalias + "." + attribute;
}
if (!string.IsNullOrWhiteSpace(attribute))
{
return attribute;
}
return null;
}

internal static string GetTooltip(this TreeNode node)
{
if (node == null)
Expand Down
2 changes: 1 addition & 1 deletion FetchXmlBuilder/Builder/TreeNodeHelper.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Rappen.XTB.FetchXmlBuilder.Controls;
using Rappen.XRM.Helpers.FetchXML;
using Rappen.XTB.FetchXmlBuilder.DockControls;
using Rappen.XTB.FetchXmlBuilder.Settings;
using System.Collections.Generic;
Expand Down
50 changes: 49 additions & 1 deletion FetchXmlBuilder/Builder/Validations.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
using Microsoft.Xrm.Sdk.Metadata;
using Rappen.XTB.FetchXmlBuilder.Controls;
using Rappen.XRM.Helpers.FetchXML;
using System;
using System.Linq;
using System.Windows.Forms;

namespace Rappen.XTB.FetchXmlBuilder.Builder
{
internal static class Validations
{
internal const string allowedaliaschars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_";

internal static ControlValidationResult GetWarning(TreeNode node, FetchXmlBuilder fxb)
{
if (!fxb.settings.ShowValidation || node == null)
Expand All @@ -27,6 +30,9 @@ internal static ControlValidationResult GetWarning(TreeNode node, FetchXmlBuilde
case "attribute":
return ValidateAttribute(node, fxb);

case "all-attributes":
return ValidateAllAttribute(node, fxb);

case "filter":
return ValidateFilter(node, fxb);

Expand All @@ -42,6 +48,24 @@ internal static ControlValidationResult GetWarning(TreeNode node, FetchXmlBuilde
return null;
}

internal static ControlValidationResult ValidateAlias(string alias)
{
if (string.IsNullOrEmpty(alias))
{
return null;
}
var aliasinvalid = alias.Where(c => !allowedaliaschars.Contains(c) && !char.IsDigit(c));
if (aliasinvalid.Any())
{
return new ControlValidationResult(ControlValidationLevel.Error, $"Incorrect characters in Alias: {string.Join(", ", aliasinvalid)}");
}
if (!allowedaliaschars.Contains(alias[0]))
{
return new ControlValidationResult(ControlValidationLevel.Error, $"Incorrect first characters in Alias: {alias[0]}");
}
return null;
}

private static ControlValidationResult ValidateFetch(TreeNode node, FetchXmlBuilder fxb)
{
if (!node.Nodes.OfType<TreeNode>().Any(n => n.Name == "entity"))
Expand Down Expand Up @@ -77,12 +101,23 @@ private static ControlValidationResult ValidateLinkEntity(TreeNode node, FetchXm
}

var name = node.Value("name");
var alias = node.Value("alias");
if (ValidateAlias(alias) is ControlValidationResult aliasresult)
{
return aliasresult;
}
if (string.IsNullOrWhiteSpace(name) ||
string.IsNullOrWhiteSpace(node.Value("to")) ||
string.IsNullOrWhiteSpace(node.Value("from")))
{
return new ControlValidationResult(ControlValidationLevel.Warning, "Link-Entity must include Name, To, From.");
}
if (fxb.settings.Results.WorkWithLayout &&
string.IsNullOrWhiteSpace(alias) &&
node.Nodes.OfType<TreeNode>().Any(n => n.Name == "attribute"))
{
return new ControlValidationResult(ControlValidationLevel.Warning, "Using Layout: Alias is needed to show these attributes");
}

if (node.Value("intersect") != "true" &&
fxb.GetAttribute(name, node.Value("from")) is AttributeMetadata fromAttr && fromAttr.IsPrimaryId == false)
Expand Down Expand Up @@ -115,6 +150,10 @@ private static ControlValidationResult ValidateAttribute(TreeNode node, FetchXml
}
}
var alias = node.Value("alias");
if (ValidateAlias(alias) is ControlValidationResult aliasresult)
{
return aliasresult;
}
if (node.IsFetchAggregate())
{
if (string.IsNullOrWhiteSpace(alias))
Expand Down Expand Up @@ -150,6 +189,15 @@ private static ControlValidationResult ValidateAttribute(TreeNode node, FetchXml
return null;
}

private static ControlValidationResult ValidateAllAttribute(TreeNode node, FetchXmlBuilder fxb)
{
if (fxb.settings.Results.WorkWithLayout)
{
return new ControlValidationResult(ControlValidationLevel.Warning, "Using Layout: All-Attributes is not possible to show");
}
return null;
}

private static ControlValidationResult ValidateFilter(TreeNode node, FetchXmlBuilder fxb)
{
if (node.Nodes.Count == 0)
Expand Down
62 changes: 2 additions & 60 deletions FetchXmlBuilder/Controls/FetchXmlElementControlBase.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Microsoft.Xrm.Sdk.Metadata;
using Rappen.XRM.Helpers.FetchXML;
using Rappen.XTB.FetchXmlBuilder.DockControls;
using Rappen.XTB.XmlEditorUtils;
using System;
Expand Down Expand Up @@ -89,7 +90,7 @@ public void InitializeFXB(Dictionary<string, string> collection, FetchXmlBuilder

protected FetchXmlBuilder fxb { get; set; }

protected TreeNode Node { get; set; }
internal TreeNode Node { get; set; }

protected TreeBuilderControl Tree { get; set; }

Expand Down Expand Up @@ -283,63 +284,4 @@ public virtual MetadataBase Metadata()
return;
}
}

public enum ControlValidationLevel
{
Success,
Info,
Warning,
Error
}

public class ControlValidationResult
{
private const string IsRequired = "{0} is required";
private const string InValid = "{0} is not valid";
private const string NotInMetadata = "{0} is not in the database.";
private const string NotShowingNow = "{0} is not currently shown.";

public ControlValidationResult(ControlValidationLevel level, string message, string url = null)
{
Level = level;
Message = message;
Url = url;
}

public ControlValidationResult(ControlValidationLevel level, string control, ControlValidationMessage message, string url = null)
{
Level = level;
switch (message)
{
case ControlValidationMessage.IsRequired:
Message = string.Format(IsRequired, control);
break;

case ControlValidationMessage.InValid:
Message = string.Format(InValid, control);
break;

case ControlValidationMessage.NotInMetadata:
Message = string.Format(NotInMetadata, control);
break;

case ControlValidationMessage.NotShowingNow:
Message = string.Format(NotShowingNow, control);
break;
}
Url = url;
}

public ControlValidationLevel Level { get; }
public string Message { get; }
public string Url { get; }
}

public enum ControlValidationMessage
{
IsRequired,
InValid,
NotInMetadata,
NotShowingNow
}
}
Loading

0 comments on commit 10673a6

Please sign in to comment.