Skip to content

Commit

Permalink
added support for Component Library on Component Instances (#642)
Browse files Browse the repository at this point in the history
  • Loading branch information
mizrael authored Apr 17, 2024
1 parent 6269d33 commit 42e7d5e
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 33 deletions.
8 changes: 6 additions & 2 deletions src/Persistence.Tests/Yaml/RoundTripTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,11 @@ public void RoundTrip_ValidYaml(string path, bool isControlIdentifiers, Type roo
}

[TestMethod]
[DataRow(@"_TestData/ValidYaml{0}/Screen/with-component-instance.pa.yaml", true)]
public void Screen_With_Component_Instance(string path, bool isControlIdentifiers)
[DataRow(@"_TestData/ValidYaml{0}/Screen/with-component-instance.pa.yaml", true, "MyComponentLibrary")]
[DataRow(@"_TestData/ValidYaml{0}/Screen/with-component-instance.pa.yaml", false, "MyComponentLibrary")]
[DataRow(@"_TestData/ValidYaml{0}/Screen/with-component-instance-no-library.pa.yaml", true, "")]
[DataRow(@"_TestData/ValidYaml{0}/Screen/with-component-instance-no-library.pa.yaml", false, "")]
public void Screen_With_Component_Instance(string path, bool isControlIdentifiers, string componentLibraryName)
{
// Arrange
var deserializer = CreateDeserializer(isControlIdentifiers);
Expand All @@ -92,6 +95,7 @@ public void Screen_With_Component_Instance(string path, bool isControlIdentifier
customControl.Should().NotBeNull();
customControl.Name.Should().Be("This is custom component");
customControl.ComponentName.Should().Be("ComponentDefinition_1");
customControl.ComponentLibraryUniqueName.Should().Be(componentLibraryName);

// Act II: Serialize the object back into yaml.
var serializer = CreateSerializer(isControlIdentifiers);
Expand Down
31 changes: 31 additions & 0 deletions src/Persistence.Tests/Yaml/ValidSerializerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,4 +314,35 @@ public void Serialize_ShouldCreateValidYamlForComponentDefinitions(ComponentType

serializedComponent.Should().Be(expectedYaml);
}

[TestMethod]
[DataRow(@"_TestData/ValidYaml{0}/Screen/with-component-instance.pa.yaml", true)]
[DataRow(@"_TestData/ValidYaml{0}/Screen/with-component-instance.pa.yaml", false)]
public void Serialize_ShouldCreateValidYamlForComponentInstance(string expectedPath, bool isControlIdentifiers)
{
var graph = ControlFactory.CreateScreen("Hello",
properties: new(),
children: new Control[]
{
new ComponentInstance()
{
Name = "This is custom component",
ComponentName = "ComponentDefinition_1",
ComponentLibraryUniqueName = "MyComponentLibrary",
Variant = string.Empty,
Template = new Microsoft.PowerPlatform.PowerApps.Persistence.Templates.ControlTemplate("http://localhost/Component"),
Properties = new()
{
new ControlProperty("X", "15"),
new ControlProperty("Y", "55"),
}
}
});
var sut = CreateSerializer(isControlIdentifiers: isControlIdentifiers);

var serializedGraph = sut.SerializeControl(graph).NormalizeNewlines();

var expectedYaml = File.ReadAllText(GetTestFilePath(expectedPath, isControlIdentifiers)).NormalizeNewlines();
serializedGraph.Should().Be(expectedYaml);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Hello:
Control: Screen
Children:
- This is custom component:
Control: Component
ComponentName: ComponentDefinition_1
Properties:
X: =15
Y: =55
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Hello:
- This is custom component:
Control: Component
ComponentName: ComponentDefinition_1
ComponentLibraryUniqueName: MyComponentLibrary
Properties:
X: =15
Y: =55
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Control: Screen
Name: Hello
Children:
- Control: Component
Name: This is custom component
ComponentName: ComponentDefinition_1
Properties:
X: =15
Y: =55
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Control: Screen
Name: Hello
Children:
- Control: Component
Name: This is custom component
ComponentName: ComponentDefinition_1
ComponentLibraryUniqueName: MyComponentLibrary
Properties:
X: =15
Y: =55
3 changes: 3 additions & 0 deletions src/Persistence/Models/ComponentInstance.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,7 @@ public ComponentInstance(string name, string variant, ControlTemplate controlTem

[YamlMember(Order = 1)]
public string ComponentName { get; set; } = string.Empty;

[YamlMember(Order = 2)]
public string? ComponentLibraryUniqueName { get; set; } = string.Empty;
}
34 changes: 26 additions & 8 deletions src/Persistence/Templates/ControlFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ public ControlFactory(IControlTemplateStore controlTemplateStore)
_controlTemplateStore = controlTemplateStore ?? throw new ArgumentNullException(nameof(controlTemplateStore));
}

public Control Create(string name, string template, string? componentDefinitionName = null, string? variant = null,
public Control Create(string name, string template,
string? componentDefinitionName = null,
string? componentLibraryUniqueName = null,
string? variant = null,
ControlPropertiesCollection? properties = null, IList<Control>? children = null)
{
if (TryCreateComponent(name, template, componentDefinitionName, variant, properties, children, controlDefinition: null, out var control))
if (TryCreateComponent(name, template, componentDefinitionName, componentLibraryUniqueName, variant, properties, children, controlDefinition: null, out var control))
return control;

if (_controlTemplateStore.TryGetByIdOrName(template, out var controlTemplate))
Expand All @@ -42,7 +45,10 @@ public Control Create(string name, string template, string? componentDefinitionN
};
}

public Control Create(string name, string template, string componentDefinitionName, Dictionary<string, object?>? controlDefinition)
public Control Create(string name, string template,
string componentDefinitionName,
string componentLibraryUniqueName,
Dictionary<string, object?>? controlDefinition)
{
string? variant = null;
ControlPropertiesCollection? properties = null;
Expand All @@ -55,7 +61,7 @@ public Control Create(string name, string template, string componentDefinitionNa
controlDefinition.TryGetValue(nameof(Control.Children), out children);
}

if (TryCreateComponent(name, template, componentDefinitionName, variant, properties, children, controlDefinition, out var control))
if (TryCreateComponent(name, template, componentDefinitionName, componentLibraryUniqueName, variant, properties, children, controlDefinition, out var control))
return control;

if (_controlTemplateStore.TryGetByIdOrName(template, out var controlTemplate))
Expand All @@ -79,9 +85,13 @@ public Control Create(string name, string template, string componentDefinitionNa
};
}

public Control Create(string name, ControlTemplate template, string? componentDefinitionName = null, string? variant = null, ControlPropertiesCollection? properties = null, IList<Control>? children = null)
public Control Create(string name, ControlTemplate template,
string? componentDefinitionName = null,
string? componentLibraryUniqueName = null,
string? variant = null,
ControlPropertiesCollection? properties = null, IList<Control>? children = null)
{
if (TryCreateComponent(name, template, componentDefinitionName, variant, properties, children, controlDefinition: null, out var control))
if (TryCreateComponent(name, template, componentDefinitionName, componentLibraryUniqueName, variant, properties, children, controlDefinition: null, out var control))
return control;

if (TryCreateFirstClassControl(name, template.Name, variant ?? string.Empty, properties, children, controlDefinition: null, out control))
Expand Down Expand Up @@ -112,7 +122,10 @@ public Screen CreateScreen(string name, ControlPropertiesCollection? properties
};
}

private bool TryCreateComponent(string name, string template, string? componentDefinitionName, string? variant,
private bool TryCreateComponent(string name, string template,
string? componentDefinitionName,
string? componentLibraryUniqueName,
string? variant,
ControlPropertiesCollection? properties, IList<Control>? children, Dictionary<string, object?>? controlDefinition,
[MaybeNullWhen(false)] out Control control)
{
Expand All @@ -123,6 +136,7 @@ private bool TryCreateComponent(string name, string template, string? componentD
new ControlTemplate(ComponentInstance.ComponentInstanceTemplateId) { Name = componentDefinitionName })
{
ComponentName = componentDefinitionName,
ComponentLibraryUniqueName = componentLibraryUniqueName,
Properties = properties ?? new(),
Children = children
};
Expand All @@ -142,7 +156,10 @@ private bool TryCreateComponent(string name, string template, string? componentD
return control != null;
}

private static bool TryCreateComponent(string name, ControlTemplate template, string? componentDefinitionName, string? variant,
private static bool TryCreateComponent(string name, ControlTemplate template,
string? componentDefinitionName,
string? componentLibraryUniqueName,
string? variant,
ControlPropertiesCollection? properties, IList<Control>? children, Dictionary<string, object?>? controlDefinition,
[MaybeNullWhen(false)] out Control control)
{
Expand All @@ -151,6 +168,7 @@ private static bool TryCreateComponent(string name, ControlTemplate template, st
control = new ComponentInstance(name, variant ?? string.Empty, template)
{
ComponentName = componentDefinitionName,
ComponentLibraryUniqueName = componentLibraryUniqueName,
Properties = properties ?? new(),
Children = children
};
Expand Down
5 changes: 0 additions & 5 deletions src/Persistence/Templates/ControlTemplate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,5 @@ public class CustomComponentInfo
/// The friendly identifier of the component.
/// </summary>
public required string Name { get; init; }

/// <summary>
/// The unique name of the component library if this component originates from a component library.
/// </summary>
public string? ComponentLibraryUniqueName { get; init; }
}
}
6 changes: 3 additions & 3 deletions src/Persistence/Templates/IControlFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ namespace Microsoft.PowerPlatform.PowerApps.Persistence.Templates;

public interface IControlFactory
{
Control Create(string name, string template, string? componentDefinitionName = null, string? variant = null, ControlPropertiesCollection? properties = null, IList<Control>? children = null);
Control Create(string name, string template, string? componentDefinitionName = null, string? componentLibraryUniqueName = null, string? variant = null, ControlPropertiesCollection? properties = null, IList<Control>? children = null);

Control Create(string name, ControlTemplate template, string? componentDefinitionName = null, string? variant = null, ControlPropertiesCollection? properties = null, IList<Control>? children = null);
Control Create(string name, ControlTemplate template, string? componentDefinitionName = null, string? componentLibraryUniqueName = null, string? variant = null, ControlPropertiesCollection? properties = null, IList<Control>? children = null);

Control Create(string name, string template, string componentDefinitionName, Dictionary<string, object?>? controlDefinition);
Control Create(string name, string template, string componentDefinitionName, string componentLibraryUniqueName, Dictionary<string, object?>? controlDefinition);

App CreateApp(string name, ControlPropertiesCollection? properties = null);

Expand Down
1 change: 1 addition & 0 deletions src/Persistence/Yaml/ComponentConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ public override void OnWriteAfterName(IEmitter emitter, Control control)
if (control is ComponentInstance componentInstance)
{
emitter.Emit(nameof(ComponentInstance.ComponentName), componentInstance.ComponentName);
emitter.Emit(nameof(ComponentInstance.ComponentLibraryUniqueName), componentInstance.ComponentLibraryUniqueName);
base.OnWriteAfterName(emitter, control);
return;
}
Expand Down
30 changes: 15 additions & 15 deletions src/Persistence/Yaml/ControlConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,9 @@ public virtual bool Accepts(Type type)
ReadControlDefinitonHeader(parser, out var controlName, out var templateName);

var controlDefinition = new Dictionary<string, object?>();
var componentInstance = string.Empty;
var componentInstanceName = string.Empty;
var componentLibraryUniqueName = string.Empty;

while (!parser.Accept<MappingEnd>(out _))
{
var key = parser.Consume<Scalar>();
Expand Down Expand Up @@ -75,18 +77,15 @@ public virtual bool Accepts(Type type)
if (parser.Current is Scalar)
{
value = parser.Consume<Scalar>().Value;
if (Options.IsControlIdentifiers)
{
if (key.Value == nameof(Control))
templateName = (string)value;
else if (key.Value == nameof(ComponentInstance.ComponentName))
componentInstance = (string)value;
}
else
{
if (key.Value == nameof(Control.Name))
controlName = (string)value;
}

if (key.Value == nameof(Control))
templateName = (string)value;
else if (key.Value == nameof(ComponentInstance.ComponentName))
componentInstanceName = (string)value;
else if (key.Value == nameof(ComponentInstance.ComponentLibraryUniqueName))
componentLibraryUniqueName = (string)value;
else if (key.Value == nameof(Control.Name))
controlName = (string)value;
}
else
value = ReadKey(parser, key.Value);
Expand All @@ -97,7 +96,7 @@ public virtual bool Accepts(Type type)

if (Options.IsControlIdentifiers)
{
if (string.IsNullOrWhiteSpace(templateName) && string.IsNullOrWhiteSpace(componentInstance))
if (string.IsNullOrWhiteSpace(templateName) && string.IsNullOrWhiteSpace(componentInstanceName))
throw new YamlException(parser.Current!.Start, parser.Current.End, $"Control '{controlName}' doesn't have template name");
}

Expand All @@ -108,7 +107,8 @@ public virtual bool Accepts(Type type)
// Create control instance
var control = _controlFactory.Create(
string.IsNullOrWhiteSpace(controlName) ? templateName : controlName,
templateName, componentInstance, controlDefinition);
templateName, componentInstanceName, componentLibraryUniqueName, controlDefinition);

return control.AfterDeserialize(_controlFactory);
}

Expand Down

0 comments on commit 42e7d5e

Please sign in to comment.