Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix Display Names in action connectors #2519

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -687,9 +687,9 @@ private static ConnectorType GetOptionSetFromSuggestions(ConnectorType connector
array.AddRange(optionSet.EnumType.ValueTree.GetPairs().Select(kvp => new OpenApiString(kvp.Key)));

schema.Extensions.Add(new KeyValuePair<string, IOpenApiExtension>(Constants.XMsEnumDisplayName, array));

// For now, we keep the original formula type (number/string/bool...)
return new ConnectorType(schema, SwaggerParameter.New(openApiParameter), connectorType.FormulaType /* optionSet.FormulaType */);
return new ConnectorType(schema, SwaggerParameter.New(openApiParameter), connectorType.FormulaType /* optionSet.FormulaType */, ConnectorCompatibility.SwaggerCompatibility);
}

/// <summary>
Expand Down Expand Up @@ -1374,8 +1374,8 @@ private ConnectorParameterInternals Initialize()

// Ex: Api-Version
hiddenRequired = true;
}
else if (ConnectorSettings.Compatibility == ConnectorCompatibility.SwaggerCompatibility)
}
else if (ConnectorSettings.Compatibility != ConnectorCompatibility.PowerAppsCompatibility)
{
continue;
}
Expand Down Expand Up @@ -1445,7 +1445,7 @@ private ConnectorParameterInternals Initialize()

bodyPropertyHiddenRequired = ConnectorSettings.Compatibility != ConnectorCompatibility.PowerAppsCompatibility || !requestBody.Required;
}
else if (ConnectorSettings.Compatibility == ConnectorCompatibility.SwaggerCompatibility)
else if (ConnectorSettings.Compatibility != ConnectorCompatibility.PowerAppsCompatibility)
{
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ internal static RecordValue MergeRecords(RecordValue rv1, RecordValue rv2)

foreach (NamedValue nv in lst)
{
rt = rt.Add(nv.Name, nv.Value.Type, OpenApiExtensions.GetDisplayName(nv.Name));
rt = rt.Add(nv.Name, nv.Value.Type, OpenApiExtensions.CleanDisplayName(nv.Name));
}

return new InMemoryRecordValue(IRContext.NotInSource(rt), lst);
Expand Down Expand Up @@ -435,8 +435,8 @@ public async Task<FormulaValue> DecodeResponseAsync(HttpResponseMessage response

if (statusCode < 300)
{
// We only return UO for unknown fields (not declared in swagger file) if compatibility is SwaggerCompatibility
bool returnUnknownRecordFieldAsUO = _function.ConnectorSettings.Compatibility == ConnectorCompatibility.SwaggerCompatibility && _function.ConnectorSettings.ReturnUnknownRecordFieldsAsUntypedObjects;
// We only return UO for unknown fields (not declared in swagger file) if compatibility is SwaggerCompatibility(WithDisplayNames)
bool returnUnknownRecordFieldAsUO = _function.ConnectorSettings.Compatibility != ConnectorCompatibility.PowerAppsCompatibility && _function.ConnectorSettings.ReturnUnknownRecordFieldsAsUntypedObjects;

var typeToUse = _function.ReturnType;
if (returnTypeOverride != null)
Expand Down
69 changes: 37 additions & 32 deletions src/libraries/Microsoft.PowerFx.Connectors/OpenApiExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -418,32 +418,32 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar
switch (schema.Format)
{
case "uri":
return new ConnectorType(schema, openApiParameter, FormulaType.String);
return new ConnectorType(schema, openApiParameter, FormulaType.String, settings.Compatibility);

case "date": // full-date RFC3339
return new ConnectorType(schema, openApiParameter, FormulaType.Date);
return new ConnectorType(schema, openApiParameter, FormulaType.Date, settings.Compatibility);

case "date-time": // date-time RFC3339
case "date-no-tz":
return new ConnectorType(schema, openApiParameter, FormulaType.DateTime);
return new ConnectorType(schema, openApiParameter, FormulaType.DateTime, settings.Compatibility);

case "byte": // Base64 string
case "binary": // octet stream
return new ConnectorType(schema, openApiParameter, FormulaType.Blob);
return new ConnectorType(schema, openApiParameter, FormulaType.Blob, settings.Compatibility);

case "enum":
if (schema.Enum.All(e => e is OpenApiString))
{
OptionSet optionSet = new OptionSet("enum", schema.Enum.Select(e => new DName((e as OpenApiString).Value)).ToDictionary(k => k, e => e).ToImmutableDictionary());
return new ConnectorType(schema, openApiParameter, optionSet.FormulaType);
return new ConnectorType(schema, openApiParameter, optionSet.FormulaType, settings.Compatibility);
}
else
{
return new ConnectorType(error: $"Unsupported enum type {schema.Enum.GetType().Name}");
}

default:
return new ConnectorType(schema, openApiParameter, FormulaType.String);
return new ConnectorType(schema, openApiParameter, FormulaType.String, settings.Compatibility);
}

// OpenAPI spec: Format could be float, double, or not specified.
Expand All @@ -458,19 +458,19 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar
case "byte":
case "number":
case "int32":
return new ConnectorType(schema, openApiParameter, FormulaType.Decimal);
return new ConnectorType(schema, openApiParameter, FormulaType.Decimal, settings.Compatibility);

case null:
case "decimal":
case "currency":
return new ConnectorType(schema, openApiParameter, FormulaType.Decimal);
return new ConnectorType(schema, openApiParameter, FormulaType.Decimal, settings.Compatibility);

default:
return new ConnectorType(error: $"Unsupported type of number: {schema.Format}");
}

// Always a boolean (Format not used)
case "boolean": return new ConnectorType(schema, openApiParameter, FormulaType.Boolean);
case "boolean": return new ConnectorType(schema, openApiParameter, FormulaType.Boolean, settings.Compatibility);

// OpenAPI spec: Format could be <null>, int32, int64
case "integer":
Expand All @@ -479,11 +479,11 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar
case null:
case "integer":
case "int32":
return new ConnectorType(schema, openApiParameter, FormulaType.Decimal);
return new ConnectorType(schema, openApiParameter, FormulaType.Decimal, settings.Compatibility);

case "int64":
case "unixtime":
return new ConnectorType(schema, openApiParameter, FormulaType.Decimal);
return new ConnectorType(schema, openApiParameter, FormulaType.Decimal, settings.Compatibility);

default:
return new ConnectorType(error: $"Unsupported type of integer: {schema.Format}");
Expand All @@ -493,22 +493,22 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar
if (schema.Items == null)
{
// Type of items in unknown
return new ConnectorType(schema, openApiParameter, ConnectorType.DefaultType);
return new ConnectorType(schema, openApiParameter, ConnectorType.DefaultType, settings.Compatibility);
}

var itemIdentifier = GetUniqueIdentifier(schema.Items);

if (itemIdentifier.StartsWith("R:", StringComparison.Ordinal) && settings.Chain.Contains(itemIdentifier))
{
// Here, we have a circular reference and default to a table
return new ConnectorType(schema, openApiParameter, TableType.Empty());
return new ConnectorType(schema, openApiParameter, TableType.Empty(), settings.Compatibility);
}

// Inheritance/Polymorphism - Can't know the exact type
// https://github.com/OAI/OpenAPI-Specification/blob/main/versions/2.0.md
if (schema.Items.Discriminator != null)
{
return new ConnectorType(schema, openApiParameter, ConnectorType.DefaultType);
return new ConnectorType(schema, openApiParameter, ConnectorType.DefaultType, settings.Compatibility);
}

//ConnectorType arrayType = new OpenApiParameter() { Name = "Array", Required = true, Schema = schema.Items, Extensions = schema.Items.Extensions }.GetConnectorType(settings.Stack(itemIdentifier));
Expand All @@ -518,20 +518,20 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar

if (arrayType.FormulaType is RecordType connectorRecordType)
{
return new ConnectorType(schema, openApiParameter, connectorRecordType.ToTable(), arrayType);
return new ConnectorType(schema, openApiParameter, connectorRecordType.ToTable(), arrayType, settings.Compatibility);
}
else if (arrayType.FormulaType is TableType tableType)
{
// Array of array
TableType newTableType = new TableType(TableType.Empty().Add(TableValue.ValueName, tableType)._type);
return new ConnectorType(schema, openApiParameter, newTableType, arrayType);
return new ConnectorType(schema, openApiParameter, newTableType, arrayType, settings.Compatibility);
}
else if (arrayType.FormulaType is not AggregateType)
{
// Primitives get marshalled as a SingleColumn table.
// Make sure this is consistent with invoker.
var recordType3 = RecordType.Empty().Add(TableValue.ValueName, arrayType.FormulaType);
return new ConnectorType(schema, openApiParameter, recordType3.ToTable(), arrayType);
return new ConnectorType(schema, openApiParameter, recordType3.ToTable(), arrayType, settings.Compatibility);
}
else
{
Expand All @@ -545,7 +545,7 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar
// Key is always a string, Value is in AdditionalProperties
if ((schema.AdditionalProperties != null && schema.AdditionalProperties.Properties.Any()) || schema.Discriminator != null)
{
return new ConnectorType(schema, openApiParameter, ConnectorType.DefaultType);
return new ConnectorType(schema, openApiParameter, ConnectorType.DefaultType, settings.Compatibility);
}
else
{
Expand All @@ -570,33 +570,38 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar

hiddenRequired = true;
}
else if (settings.Compatibility == ConnectorCompatibility.SwaggerCompatibility)
else if (settings.Compatibility != ConnectorCompatibility.PowerAppsCompatibility)
{
continue;
}
}

string propLogicalName = kv.Key;
string propDisplayName = kv.Value.Title;
string propDisplayName = propLogicalName;

if (string.IsNullOrEmpty(propDisplayName))
if (settings.Compatibility == ConnectorCompatibility.SwaggerCompatibilityWithDisplayNames)
{
propDisplayName = kv.Value.GetSummary();
}
propDisplayName = kv.Value.Title;

if (string.IsNullOrEmpty(propDisplayName))
{
propDisplayName = kv.Key;
if (string.IsNullOrEmpty(propDisplayName))
{
propDisplayName = kv.Value.GetSummary();
}

if (string.IsNullOrEmpty(propDisplayName))
{
propDisplayName = kv.Key;
}
}

propDisplayName = GetDisplayName(propDisplayName);
propDisplayName = CleanDisplayName(propDisplayName);

string schemaIdentifier = GetUniqueIdentifier(kv.Value);

if (schemaIdentifier.StartsWith("R:", StringComparison.Ordinal) && settings.Chain.Contains(schemaIdentifier))
{
// Here, we have a circular reference and default to a string
return new ConnectorType(schema, openApiParameter, FormulaType.String, hiddenfields.ToRecordType());
return new ConnectorType(schema, openApiParameter, FormulaType.String, hiddenfields.ToRecordType(), settings.Compatibility);
}

//ConnectorType propertyType = new OpenApiParameter() { Name = propLogicalName, Required = schema.Required.Contains(propLogicalName), Schema = kv.Value, Extensions = kv.Value.Extensions }.GetConnectorType(settings.Stack(schemaIdentifier));
Expand Down Expand Up @@ -624,11 +629,11 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar
}
}

return new ConnectorType(schema, openApiParameter, fields.ToRecordType(), hiddenfields.ToRecordType(), connectorTypes.ToArray(), hiddenConnectorTypes.ToArray());
return new ConnectorType(schema, openApiParameter, fields.ToRecordType(), hiddenfields.ToRecordType(), connectorTypes.ToArray(), hiddenConnectorTypes.ToArray(), settings.Compatibility);
}

case "file":
return new ConnectorType(schema, openApiParameter, FormulaType.Blob);
return new ConnectorType(schema, openApiParameter, FormulaType.Blob, settings.Compatibility);

default:
return new ConnectorType(error: $"Unsupported schema type {schema.Type}");
Expand Down Expand Up @@ -676,7 +681,7 @@ internal static RecordType ToRecordType(this List<(string logicalName, string di
return rt;
}

internal static string GetDisplayName(string name)
internal static string CleanDisplayName(string name)
{
string displayName = name.Replace("{", string.Empty).Replace("}", string.Empty);
return displayName;
Expand All @@ -703,7 +708,7 @@ public static HttpMethod ToHttpMethod(this OperationType key)
}

public static FormulaType GetReturnType(this OpenApiOperation openApiOperation, ConnectorCompatibility compatibility)
{
{
ConnectorType connectorType = openApiOperation.GetConnectorReturnType(compatibility);
FormulaType ft = connectorType.HasErrors ? ConnectorType.DefaultType : connectorType?.FormulaType ?? new BlankType();
return ft;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,10 @@ public enum ConnectorCompatibility
// Swagger File Conformity
// - parameters appear in the order specified in the swagger file
// - internal visible parameters are completely hidden (required/optional, with or without default value)
SwaggerCompatibility = 2
SwaggerCompatibility = 2,

// Same as SwaggerCompatibility but with display names
// Mainly used for CDP
SwaggerCompatibilityWithDisplayNames = 3,
}
}
Loading