diff --git a/src/libraries/Microsoft.PowerFx.Connectors/ConnectorFunction.cs b/src/libraries/Microsoft.PowerFx.Connectors/ConnectorFunction.cs index ddeedd5ab5..ee49cf5002 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/ConnectorFunction.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/ConnectorFunction.cs @@ -156,7 +156,7 @@ public IReadOnlyCollection Warnings /// /// Return type of the function. /// - public FormulaType ReturnType => Operation.GetReturnType(ConnectorSettings.Compatibility); + public FormulaType ReturnType => Operation.GetReturnType(ConnectorSettings); /// /// Minimum number of arguments. @@ -988,7 +988,7 @@ private async Task GetConnectorSuggestionsFromDynamicSchemaAsync( return null; } - ConnectorType connectorType = GetConnectorType(cds.ValuePath, sv, ConnectorSettings.Compatibility); + ConnectorType connectorType = GetConnectorType(cds.ValuePath, sv, ConnectorSettings); if (connectorType.HasErrors) { @@ -1002,15 +1002,15 @@ private async Task GetConnectorSuggestionsFromDynamicSchemaAsync( return connectorType; } - internal static ConnectorType GetConnectorType(string valuePath, StringValue sv, ConnectorCompatibility compatibility) + internal static ConnectorType GetConnectorType(string valuePath, StringValue sv, ConnectorSettings settings) { JsonElement je = ExtractFromJson(sv, valuePath); - return GetConnectorTypeInternal(compatibility, je); + return GetConnectorTypeInternal(settings, je); } // Only called by ConnectorTable.GetSchema // Returns a FormulaType with AssociatedDataSources set (done in AddTabularDataSource) - internal static ConnectorType GetCdpTableType(ICdpTableResolver tableResolver, string connectorName, string tableName, string valuePath, StringValue stringValue, ConnectorCompatibility compatibility, string datasetName, + internal static ConnectorType GetCdpTableType(ICdpTableResolver tableResolver, string connectorName, string tableName, string valuePath, StringValue stringValue, ConnectorSettings settings, string datasetName, out string name, out string displayName, out TableDelegationInfo delegationInfo, out IEnumerable optionSets) { // There are some errors when parsing this Json payload but that's not a problem here as we only need x-ms-capabilities parsing to work @@ -1025,7 +1025,7 @@ internal static ConnectorType GetCdpTableType(ICdpTableResolver tableResolver, s IList referencedEntities = GetReferenceEntities(connectorName, stringValue); SymbolTable symbolTable = new SymbolTable(); - ConnectorType connectorType = new ConnectorType(jsonElement, tableName, symbolTable, compatibility, referencedEntities, datasetName, name, connectorName, tableResolver, serviceCapabilities, isTableReadOnly); + ConnectorType connectorType = new ConnectorType(jsonElement, tableName, symbolTable, settings, referencedEntities, datasetName, name, connectorName, tableResolver, serviceCapabilities, isTableReadOnly); delegationInfo = ((DataSourceInfo)connectorType.FormulaType._type.AssociatedDataSources.First()).DelegationInfo; optionSets = symbolTable.OptionSets.Select(kvp => kvp.Value); @@ -1081,12 +1081,12 @@ internal class SalesForceReferencedEntity public bool RestrictedDelete { get; set; } } - private static ConnectorType GetConnectorTypeInternal(ConnectorCompatibility compatibility, JsonElement je) + private static ConnectorType GetConnectorTypeInternal(ConnectorSettings settings, JsonElement je) { OpenApiReaderSettings oars = new OpenApiReaderSettings() { RuleSet = DefaultValidationRuleSet }; OpenApiSchema schema = new OpenApiStringReader(oars).ReadFragment(je.ToString(), OpenApi.OpenApiSpecVersion.OpenApi2_0, out OpenApiDiagnostic diag); - return new ConnectorType(SwaggerSchema.New(schema), compatibility); + return new ConnectorType(SwaggerSchema.New(schema), settings); } private async Task GetConnectorSuggestionsFromDynamicPropertyAsync(NamedValue[] knownParameters, BaseRuntimeConnectorContext runtimeContext, ConnectorDynamicProperty cdp, CancellationToken cancellationToken) @@ -1107,7 +1107,7 @@ private async Task GetConnectorSuggestionsFromDynamicPropertyAsyn return null; } - ConnectorType connectorType = GetConnectorType(cdp.ItemValuePath, sv, ConnectorSettings.Compatibility); + ConnectorType connectorType = GetConnectorType(cdp.ItemValuePath, sv, ConnectorSettings); if (connectorType.HasErrors) { @@ -1414,7 +1414,7 @@ private ConnectorParameterInternals Initialize() return null; } - ConnectorParameter connectorParameter = errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(parameter, ConnectorSettings.Compatibility)); + ConnectorParameter connectorParameter = errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(parameter, ConnectorSettings)); if (connectorParameter.HiddenRecordType != null) { @@ -1460,7 +1460,12 @@ private ConnectorParameterInternals Initialize() OpenApiSchema bodyPropertySchema = bodyProperty.Value; string bodyPropertyName = bodyProperty.Key; bool bodyPropertyRequired = bodySchema.Required.Contains(bodyPropertyName); - bool bodyPropertyHiddenRequired = false; + bool bodyPropertyHiddenRequired = false; + + if (ConnectorSettings.UseDefaultBodyNameForSinglePropertyObject && bodySchema.Properties.Count == 1) + { + bodyPropertyName = bodyName; + } if (bodyPropertySchema.IsInternal()) { @@ -1483,12 +1488,12 @@ private ConnectorParameterInternals Initialize() } OpenApiParameter bodyParameter = new OpenApiParameter() { Name = bodyPropertyName, Schema = bodyPropertySchema, Description = requestBody.Description, Required = bodyPropertyRequired, Extensions = bodyPropertySchema.Extensions }; - ConnectorParameter bodyConnectorParameter2 = errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(bodyParameter, requestBody, ConnectorSettings.Compatibility)); + ConnectorParameter bodyConnectorParameter2 = errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(bodyParameter, requestBody, ConnectorSettings)); openApiBodyParameters.Add(bodyConnectorParameter2, OpenApiExtensions.TryGetOpenApiValue(bodyConnectorParameter2.Schema.Default, null, out FormulaValue defaultValue, errorsAndWarnings) ? defaultValue : null); if (bodyConnectorParameter2.HiddenRecordType != null) { - hiddenRequiredParameters.Add(errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(bodyParameter, true, ConnectorSettings.Compatibility))); + hiddenRequiredParameters.Add(errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(bodyParameter, true, ConnectorSettings))); } List parameterList = !bodyPropertyRequired ? optionalParameters : bodyPropertyHiddenRequired ? hiddenRequiredParameters : requiredParameters; @@ -1507,7 +1512,7 @@ private ConnectorParameterInternals Initialize() } OpenApiParameter bodyParameter2 = new OpenApiParameter() { Name = bodyName, Schema = bodySchema, Description = requestBody.Description, Required = requestBody.Required, Extensions = bodySchema.Extensions }; - ConnectorParameter bodyConnectorParameter3 = errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(bodyParameter2, requestBody, ConnectorSettings.Compatibility)); + ConnectorParameter bodyConnectorParameter3 = errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(bodyParameter2, requestBody, ConnectorSettings)); openApiBodyParameters.Add(bodyConnectorParameter3, OpenApiExtensions.TryGetOpenApiValue(bodyConnectorParameter3.Schema.Default, null, out FormulaValue defaultValue, errorsAndWarnings) ? defaultValue : null); if (bodyConnectorParameter3.HiddenRecordType != null) @@ -1527,7 +1532,7 @@ private ConnectorParameterInternals Initialize() OpenApiSchema bodyParameterSchema = new OpenApiSchema() { Type = "string" }; OpenApiParameter bodyParameter3 = new OpenApiParameter() { Name = bodyName, Schema = bodyParameterSchema, Description = "Body", Required = requestBody.Required }; - ConnectorParameter bodyParameter = errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(bodyParameter3, requestBody, ConnectorSettings.Compatibility)); + ConnectorParameter bodyParameter = errorsAndWarnings.AggregateErrorsAndWarnings(new ConnectorParameter(bodyParameter3, requestBody, ConnectorSettings)); openApiBodyParameters.Add(bodyParameter, OpenApiExtensions.TryGetOpenApiValue(bodyParameter.Schema.Default, null, out FormulaValue defaultValue, errorsAndWarnings) ? defaultValue : null); List parameterList = requestBody.Required ? requiredParameters : optionalParameters; @@ -1570,7 +1575,7 @@ private ConnectorParameterInternals Initialize() _arityMax = _arityMin + (_optionalParameters.Length == 0 ? 0 : 1); _warnings = new List(); - _returnType = errorsAndWarnings.AggregateErrorsAndWarnings(Operation.GetConnectorReturnType(ConnectorSettings.Compatibility)); + _returnType = errorsAndWarnings.AggregateErrorsAndWarnings(Operation.GetConnectorReturnType(ConnectorSettings)); if (IsDeprecated) { diff --git a/src/libraries/Microsoft.PowerFx.Connectors/OpenApiExtensions.cs b/src/libraries/Microsoft.PowerFx.Connectors/OpenApiExtensions.cs index 4947f4d677..3a8656c951 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/OpenApiExtensions.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/OpenApiExtensions.cs @@ -1,5 +1,5 @@ -// Copyright (c) Microsoft Corporation. -// Licensed under the MIT license. +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. using System; using System.Collections.Generic; @@ -66,7 +66,7 @@ private static string GetUriElement(this OpenApiDocument openApiDocument, Func>, bool isNumber) GetEnumValues(this ISwaggerParameter openApiParameter) { // x-ms-enum-values is: array of { value: string, displayName: string}. if (openApiParameter.Extensions.TryGetValue(XMsEnumValues, out var enumValues)) { if (enumValues is IList array) - { - SingleSourceDisplayNameProvider displayNameProvider = new SingleSourceDisplayNameProvider(); + { + List> list = new List>(); + bool isNumber = false; foreach (var item in array) { @@ -110,6 +111,7 @@ internal static DisplayNameProvider GetEnumValues(this ISwaggerParameter openApi else if (openApiLogical is OpenApiInteger logicalInt) { logical = logicalInt.Value.ToString(CultureInfo.InvariantCulture); + isNumber = true; } } @@ -122,21 +124,22 @@ internal static DisplayNameProvider GetEnumValues(this ISwaggerParameter openApi else if (openApiDisplay is OpenApiInteger displayInt) { display = displayInt.Value.ToString(CultureInfo.InvariantCulture); + isNumber = true; } } if (!string.IsNullOrEmpty(logical) && !string.IsNullOrEmpty(display)) { - displayNameProvider = displayNameProvider.AddField(new DName(logical), new DName(display)); + list.Add(new KeyValuePair(new DName(logical), new DName(display))); } } } - return displayNameProvider.LogicalToDisplayPairs.Any() ? displayNameProvider : null; + return (list, isNumber); } } - - return null; + + return (null, false); } public static bool IsTrigger(this OpenApiOperation op) @@ -350,7 +353,7 @@ internal static bool TryGetOpenApiValue(IOpenApiAny openApiAny, FormulaType form internal static string GetVisibility(this IOpenApiExtensible oae) => SwaggerExtensions.New(oae)?.GetVisibility(); - internal static string GetEnumName(this IOpenApiExtensible oae) => SwaggerExtensions.New(oae)?.GetEnumName(); + internal static (string name, bool modelAsString) GetEnumName(this IOpenApiExtensible oae) => SwaggerExtensions.New(oae)?.GetEnumName() ?? (null, false); // Internal parameters are not showen to the user. // They can have a default value or be special cased by the infrastructure (like "connectionId"). @@ -358,12 +361,17 @@ internal static bool TryGetOpenApiValue(IOpenApiAny openApiAny, FormulaType form internal static string GetVisibility(this ISwaggerExtensions schema) => schema.Extensions.TryGetValue(XMsVisibility, out IOpenApiExtension openApiExt) && openApiExt is OpenApiString openApiStr ? openApiStr.Value : null; - internal static string GetEnumName(this ISwaggerExtensions schema) => schema.Extensions.TryGetValue(XMsEnum, out IOpenApiExtension openApiExt) && - openApiExt is SwaggerJsonObject jsonObject && - jsonObject.TryGetValue("name", out IOpenApiAny enumName) && - enumName is OpenApiString enumNameStr - ? enumNameStr.Value - : null; + internal static (string name, bool modelAsString) GetEnumName(this ISwaggerExtensions schema) => schema.Extensions.TryGetValue(XMsEnum, out IOpenApiExtension openApiExt) && + openApiExt is IDictionary jsonObject && + jsonObject.TryGetValue("name", out IOpenApiAny enumName) && + enumName is OpenApiString enumNameStr + ? (enumNameStr.Value, jsonObject.GetModelAsString()) + : (null, false); + + private static bool GetModelAsString(this IDictionary jsonObject) => jsonObject.TryGetValue("modelAsString", out IOpenApiAny modelAsString) && + modelAsString is OpenApiBoolean modelAsStringBool + ? modelAsStringBool.Value + : false; internal static string GetMediaKind(this ISwaggerExtensions schema) => schema.Extensions.TryGetValue(XMsMediaKind, out IOpenApiExtension openApiExt) && openApiExt is OpenApiString openApiStr ? openApiStr.Value : null; @@ -392,17 +400,17 @@ internal static void WhenPresent(this IDictionary apiObj, s internal class ConnectorTypeGetterSettings { - internal readonly ConnectorCompatibility Compatibility; + internal readonly ConnectorSettings Settings; internal Stack Chain = new Stack(); internal int Level = 0; internal readonly SymbolTable OptionSets; private readonly string _tableName; - internal ConnectorTypeGetterSettings(ConnectorCompatibility connectorCompatibility, string tableName, SymbolTable optionSets) + internal ConnectorTypeGetterSettings(ConnectorSettings settings, string tableName, SymbolTable optionSets) { - Compatibility = connectorCompatibility; - OptionSets = optionSets; + Settings = settings; + OptionSets = optionSets; _tableName = tableName; } @@ -435,15 +443,15 @@ internal string GetOptionSetName(string optionSetNameBase) } } - internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiParameter, ConnectorCompatibility compatibility) + internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiParameter, ConnectorSettings settings) { - return openApiParameter.GetConnectorType(tableName: null, optionSets: null, compatibility); + return openApiParameter.GetConnectorType(tableName: null, optionSets: null, settings); } - internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiParameter, string tableName, SymbolTable optionSets, ConnectorCompatibility compatibility) + internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiParameter, string tableName, SymbolTable optionSets, ConnectorSettings settings) { - ConnectorTypeGetterSettings settings = new ConnectorTypeGetterSettings(compatibility, tableName, optionSets); - ConnectorType connectorType = openApiParameter.GetConnectorType(settings); + ConnectorTypeGetterSettings getterSettings = new ConnectorTypeGetterSettings(settings, tableName, optionSets); + ConnectorType connectorType = openApiParameter.GetConnectorType(getterSettings); return connectorType; } @@ -489,34 +497,7 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar return new ConnectorType(schema, openApiParameter, FormulaType.Blob); } - // Try getting enum from 'x-ms-enum-values' - DisplayNameProvider optionSetDisplayNameProvider = openApiParameter.GetEnumValues(); - - if (optionSetDisplayNameProvider != null && (settings.Compatibility.IsCDP() || schema.Format == "enum")) - { - string optionSetName = settings.GetOptionSetName(schema.GetEnumName() ?? openApiParameter.Name); - OptionSet optionSet = new OptionSet(optionSetName, optionSetDisplayNameProvider); - optionSet = settings.OptionSets.TryAddOptionSet(optionSet); - return new ConnectorType(schema, openApiParameter, optionSet.FormulaType); - } - - // Try getting enum from 'enum' - if (schema.Enum != null && (settings.Compatibility.IsCDP() || schema.Format == "enum")) - { - if (schema.Enum.All(e => e is OpenApiString)) - { - string optionSetName = settings.GetOptionSetName(schema.GetEnumName() ?? openApiParameter.Name); - OptionSet optionSet = new OptionSet(optionSetName, schema.Enum.Select(e => new DName((e as OpenApiString).Value)).ToDictionary(k => k, e => e).ToImmutableDictionary()); - optionSet = settings.OptionSets.TryAddOptionSet(optionSet); - return new ConnectorType(schema, openApiParameter, optionSet.FormulaType); - } - else - { - return new ConnectorType(error: $"Unsupported enum type {schema.Enum.GetType().Name}"); - } - } - - return new ConnectorType(schema, openApiParameter, FormulaType.String); + return TryGetOptionSet(openApiParameter, settings) ?? new ConnectorType(schema, openApiParameter, FormulaType.String); // OpenAPI spec: Format could be float, double, or not specified. // we assume not specified implies decimal @@ -557,12 +538,10 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar case "byte": case "integer": case "int32": - return new ConnectorType(schema, openApiParameter, FormulaType.Decimal); - case "int64": case "uint64": case "unixtime": - return new ConnectorType(schema, openApiParameter, FormulaType.Decimal); + return TryGetOptionSet(openApiParameter, settings) ?? new ConnectorType(schema, openApiParameter, FormulaType.Decimal); default: return new ConnectorType(error: $"Unsupported type of integer: {schema.Format}"); @@ -649,7 +628,7 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar hiddenRequired = true; } - else if (settings.Compatibility.ExcludeInternals()) + else if (settings.Settings.Compatibility.ExcludeInternals()) { continue; } @@ -714,6 +693,72 @@ internal static ConnectorType GetConnectorType(this ISwaggerParameter openApiPar } } + private static ConnectorType TryGetOptionSet(ISwaggerParameter openApiParameter, ConnectorTypeGetterSettings settings) + { + ISwaggerSchema schema = openApiParameter.Schema; + + if (settings.Settings.Compatibility.IsCDP() || schema.Format == "enum" || settings.Settings.SupportXMsEnumValues) + { + // Try getting enum from 'x-ms-enum-values' + (IEnumerable> list, bool isNumber) = openApiParameter.GetEnumValues(); + + if (list != null && list.Any()) + { + (string enumName, bool modelAsString) = schema.GetEnumName(); + enumName ??= openApiParameter.Name; + + string optionSetName = settings.GetOptionSetName(enumName); + OptionSet optionSet = new OptionSet(optionSetName, new SingleSourceDisplayNameProvider(list)); + optionSet = settings.OptionSets.TryAddOptionSet(optionSet); + + if (modelAsString) + { + return new ConnectorType(schema, openApiParameter, FormulaType.String, list: list, isNumber: isNumber); + } + + if (settings.Settings.ReturnEnumsAsPrimitive) + { + return new ConnectorType(schema, openApiParameter, isNumber ? FormulaType.Decimal : FormulaType.String, list: list, isNumber: isNumber); + } + + return new ConnectorType(schema, openApiParameter, optionSet.FormulaType); + } + + // Try getting enum from 'enum' + if (schema.Enum != null && schema.Enum.Any()) + { + if (schema.Enum.All(e => e is OpenApiString)) + { + (string enumName, bool modelAsString) = schema.GetEnumName(); + enumName ??= openApiParameter.Name; + + Dictionary dic = schema.Enum.Select(e => new DName((e as OpenApiString).Value)).ToDictionary(k => k, e => e); + string optionSetName = settings.GetOptionSetName(enumName); + OptionSet optionSet = new OptionSet(optionSetName, dic.ToImmutableDictionary()); + optionSet = settings.OptionSets.TryAddOptionSet(optionSet); + + if (modelAsString) + { + return new ConnectorType(schema, openApiParameter, FormulaType.String, list: dic); + } + + if (settings.Settings.ReturnEnumsAsPrimitive) + { + return new ConnectorType(schema, openApiParameter, isNumber ? FormulaType.Decimal : FormulaType.String, list: list, isNumber: isNumber); + } + + return new ConnectorType(schema, openApiParameter, optionSet.FormulaType); + } + else + { + return new ConnectorType(error: $"Unsupported enum type {schema.Enum.GetType().Name}"); + } + } + } + + return null; + } + // If an OptionSet doesn't exist, we add it (and return it) // If an identical OptionSet exists (same name & list of options), we return it // Otherwise we throw in case of conflict @@ -813,10 +858,16 @@ public static HttpMethod ToHttpMethod(this OperationType key) _ => new HttpMethod(key.ToString()) }; } + + [Obsolete("Use a ConnectorSettings parameter instead")] + public static FormulaType GetReturnType(this OpenApiOperation openApiOperation, ConnectorCompatibility compatibility) + { + return openApiOperation.GetReturnType(new ConnectorSettings(null) { Compatibility = compatibility }); + } - public static FormulaType GetReturnType(this OpenApiOperation openApiOperation, ConnectorCompatibility compatibility) - { - ConnectorType connectorType = openApiOperation.GetConnectorReturnType(compatibility); + public static FormulaType GetReturnType(this OpenApiOperation openApiOperation, ConnectorSettings settings) + { + ConnectorType connectorType = openApiOperation.GetConnectorReturnType(settings); FormulaType ft = connectorType.HasErrors ? ConnectorType.DefaultType : connectorType?.FormulaType ?? new BlankType(); return ft; } @@ -826,7 +877,7 @@ public static bool GetRequiresUserConfirmation(this OpenApiOperation op) return op.Extensions.TryGetValue(XMsRequireUserConfirmation, out IOpenApiExtension openExt) && openExt is OpenApiBoolean b && b.Value; } - internal static ConnectorType GetConnectorReturnType(this OpenApiOperation openApiOperation, ConnectorCompatibility compatibility) + internal static ConnectorType GetConnectorReturnType(this OpenApiOperation openApiOperation, ConnectorSettings settings) { OpenApiResponses responses = openApiOperation.Responses; OpenApiResponse response = responses.Where(kvp => kvp.Key?.Length == 3 && kvp.Key.StartsWith("2", StringComparison.Ordinal)).OrderBy(kvp => kvp.Key).FirstOrDefault().Value; @@ -850,7 +901,7 @@ internal static ConnectorType GetConnectorReturnType(this OpenApiOperation openA if (response.Content.Count == 0) { OpenApiSchema schema = new OpenApiSchema() { Type = "string", Format = "no_format" }; - return new SwaggerParameter("response", true, new SwaggerSchema("string", "no_format"), response.Extensions).GetConnectorType(compatibility); + return new SwaggerParameter("response", true, new SwaggerSchema("string", "no_format"), response.Extensions).GetConnectorType(settings); } // Responses is a list by content-type. Find "application/json" @@ -869,10 +920,10 @@ internal static ConnectorType GetConnectorReturnType(this OpenApiOperation openA if (openApiMediaType.Schema == null) { // Treat as void. - return new SwaggerParameter("response", true, new SwaggerSchema("string", "no_format"), response.Extensions).GetConnectorType(compatibility); + return new SwaggerParameter("response", true, new SwaggerSchema("string", "no_format"), response.Extensions).GetConnectorType(settings); } - return new SwaggerParameter("response", true, SwaggerSchema.New(openApiMediaType.Schema), openApiMediaType.Schema.Extensions).GetConnectorType(compatibility); + return new SwaggerParameter("response", true, SwaggerSchema.New(openApiMediaType.Schema), openApiMediaType.Schema.Extensions).GetConnectorType(settings); } } diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorParameter.cs b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorParameter.cs index 4fde16dcd3..6058fd5983 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorParameter.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorParameter.cs @@ -22,24 +22,24 @@ public class ConnectorParameter : ConnectorSchema internal bool IsBodyParameter = false; - internal ConnectorParameter(OpenApiParameter openApiParameter, ConnectorCompatibility compatibility) - : this(openApiParameter, null, false, compatibility) + internal ConnectorParameter(OpenApiParameter openApiParameter, ConnectorSettings settings) + : this(openApiParameter, null, false, settings) { - } + } - internal ConnectorParameter(OpenApiParameter openApiParameter, bool useHiddenTypes, ConnectorCompatibility compatibility) - : this(openApiParameter, null, useHiddenTypes, compatibility) + internal ConnectorParameter(OpenApiParameter openApiParameter, bool useHiddenTypes, ConnectorSettings settings) + : this(openApiParameter, null, useHiddenTypes, settings) { } - internal ConnectorParameter(OpenApiParameter openApiParameter, IOpenApiExtensible bodyExtensions, ConnectorCompatibility compatibility) - : this(openApiParameter, bodyExtensions, false, compatibility) + internal ConnectorParameter(OpenApiParameter openApiParameter, IOpenApiExtensible bodyExtensions, ConnectorSettings settings) + : this(openApiParameter, bodyExtensions, false, settings) { IsBodyParameter = true; } - internal ConnectorParameter(OpenApiParameter openApiParameter, IOpenApiExtensible bodyExtensions, bool useHiddenTypes, ConnectorCompatibility compatibility) - : base(SwaggerParameter.New(openApiParameter), SwaggerExtensions.New(bodyExtensions), useHiddenTypes, compatibility) + internal ConnectorParameter(OpenApiParameter openApiParameter, IOpenApiExtensible bodyExtensions, bool useHiddenTypes, ConnectorSettings settings) + : base(SwaggerParameter.New(openApiParameter), SwaggerExtensions.New(bodyExtensions), useHiddenTypes, settings) { Name = openApiParameter.Name; Description = openApiParameter.Description; diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorSchema.cs b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorSchema.cs index 7e8417c5a4..b6bd3a636f 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorSchema.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorSchema.cs @@ -33,11 +33,11 @@ public class ConnectorSchema : SupportsConnectorErrors public AiSensitivity AiSensitivity => ConnectorType.AiSensitivity; - internal ConnectorSchema(ISwaggerParameter openApiParameter, ISwaggerExtensions bodyExtensions, bool useHiddenTypes, ConnectorCompatibility compatibility) + internal ConnectorSchema(ISwaggerParameter openApiParameter, ISwaggerExtensions bodyExtensions, bool useHiddenTypes, ConnectorSettings settings) { Schema = openApiParameter.Schema; UseHiddenTypes = useHiddenTypes; - ConnectorType = AggregateErrorsAndWarnings(openApiParameter.GetConnectorType(compatibility)); + ConnectorType = AggregateErrorsAndWarnings(openApiParameter.GetConnectorType(settings)); DefaultValue = openApiParameter.Schema.TryGetDefaultValue(FormulaType, out FormulaValue defaultValue, this) && defaultValue is not BlankValue ? defaultValue : null; ConnectorExtensions = new ConnectorExtensions(openApiParameter, bodyExtensions); } diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorSettings.cs b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorSettings.cs index d77b8860c4..82431b299a 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorSettings.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorSettings.cs @@ -7,9 +7,17 @@ namespace Microsoft.PowerFx.Connectors { /// /// Settings for a connector. - /// + /// + [ThreadSafeImmutable] public class ConnectorSettings - { + { + internal static readonly ConnectorSettings DefaultCdp = new ConnectorSettings(null) + { + Compatibility = ConnectorCompatibility.CdpCompatibility, + SupportXMsEnumValues = true, + ReturnEnumsAsPrimitive = false + }; + public ConnectorSettings(string @namespace) { Namespace = @namespace; @@ -70,9 +78,29 @@ public bool ExposeInternalParamsWithoutDefaultValue /// /// In Power Apps, all record fields which are not declared in the swagger file will not be part of the Power Fx response. /// ReturnUnknownRecordFieldsAsUntypedObjects modifies this behavior to return all unknown fields as UntypedObjects. - /// This flag is only working when Compatibility is set to ConnectorCompatibility.SwaggerCompatibility or ConnectorCompatibility.CdpCompatibility. + /// This flag is only working when Compatibility is set to ConnectorCompatibility.SwaggerCompatibility or ConnectorCompatibility.CdpCompatibility. /// - public bool ReturnUnknownRecordFieldsAsUntypedObjects { get; init; } = false; + public bool ReturnUnknownRecordFieldsAsUntypedObjects { get; init; } = false; + + /// + /// By default action connectors won't parse x-ms-enum-values. + /// Only CDP connectors will have this enabled by default. + /// + public bool SupportXMsEnumValues { get; init; } = false; + + /// + /// This flag will force all enums to be returns as FormulaType.String or FormulaType.Decimal regardless of x-ms-enum-*. + /// This flag is only in effect when SupportXMsEnumValues is true. + /// + public bool ReturnEnumsAsPrimitive { get; init; } = false; + + /// + /// In Power Apps, when a body parameter is used it's flattened and we create one parameter for each + /// body object property. With that logic each parameter name will be the object property name. + /// When set, this setting will use the real body name specified in the swagger instead of the property name + /// of the object, provided there is only one property. + /// + public bool UseDefaultBodyNameForSinglePropertyObject { get; init; } = false; public ConnectorCompatibility Compatibility { get; init; } = ConnectorCompatibility.Default; } diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorType.cs b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorType.cs index e658b59a3b..83e8204eb3 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorType.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Public/ConnectorType.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.Linq; using System.Text.Json; using Microsoft.OpenApi.Any; @@ -121,7 +122,7 @@ public class ConnectorType : SupportsConnectorErrors internal string ForeignKey { get; set; } - internal ConnectorType(ISwaggerSchema schema, ISwaggerParameter openApiParameter, FormulaType formulaType, ErrorResourceKey warning = default) + internal ConnectorType(ISwaggerSchema schema, ISwaggerParameter openApiParameter, FormulaType formulaType, ErrorResourceKey warning = default, IEnumerable> list = null, bool isNumber = false) { Name = openApiParameter?.Name; IsRequired = openApiParameter?.Required == true; @@ -132,35 +133,39 @@ internal ConnectorType(ISwaggerSchema schema, ISwaggerParameter openApiParameter MediaKind = openApiParameter?.GetMediaKind().ToMediaKind() ?? (Binary ? MediaKind.File : MediaKind.NotBinary); NotificationUrl = openApiParameter?.GetNotificationUrl(); AiSensitivity = openApiParameter?.GetAiSensitivity().ToAiSensitivity() ?? AiSensitivity.Unknown; + Description = schema.Description; + + string summary = schema.GetSummary(); + string title = schema.Title; + + DisplayName = string.IsNullOrEmpty(title) ? summary : title; + ExplicitInput = schema.GetExplicitInput(); + Capabilities = schema.GetColumnCapabilities(); + Relationships = schema.GetRelationships(); // x-ms-relationships + KeyType = schema.GetKeyType(); + KeyOrder = schema.GetKeyOrder(); + Permission = schema.GetPermission(); + + // We only support one reference for now + // SalesForce only + if (schema.ReferenceTo != null && schema.ReferenceTo.Count == 1) + { + ExternalTables = new List(schema.ReferenceTo); + RelationshipName = schema.RelationshipName; + ForeignKey = null; // SalesForce doesn't provide it, defaults to "Id" + } + + Fields = Array.Empty(); + IsEnum = (schema.Enum != null && schema.Enum.Any()) || (list != null && list.Any()); - if (schema != null) + if (IsEnum) { - Description = schema.Description; - - string summary = schema.GetSummary(); - string title = schema.Title; - - DisplayName = string.IsNullOrEmpty(title) ? summary : title; - ExplicitInput = schema.GetExplicitInput(); - Capabilities = schema.GetColumnCapabilities(); - Relationships = schema.GetRelationships(); // x-ms-relationships - KeyType = schema.GetKeyType(); - KeyOrder = schema.GetKeyOrder(); - Permission = schema.GetPermission(); - - // We only support one reference for now - // SalesForce only - if (schema.ReferenceTo != null && schema.ReferenceTo.Count == 1) + if (list != null && list.Any()) { - ExternalTables = new List(schema.ReferenceTo); - RelationshipName = schema.RelationshipName; - ForeignKey = null; // SalesForce doesn't provide it, defaults to "Id" + EnumValues = list.Select, FormulaValue>(kvp => isNumber ? FormulaValue.New(decimal.Parse(kvp.Key.Value, CultureInfo.InvariantCulture)) : FormulaValue.New(kvp.Key)).ToArray(); + EnumDisplayNames = list.Select(list => list.Value.Value).ToArray(); } - - Fields = Array.Empty(); - IsEnum = schema.Enum != null && schema.Enum.Any(); - - if (IsEnum) + else { EnumValues = schema.Enum.Select(oaa => { @@ -175,16 +180,41 @@ internal ConnectorType(ISwaggerSchema schema, ISwaggerParameter openApiParameter // x-ms-enum-display-name EnumDisplayNames = schema.Extensions != null && schema.Extensions.TryGetValue(XMsEnumDisplayName, out IOpenApiExtension enumNames) && enumNames is IList oaa - ? oaa.Cast().Select(oas => oas.Value).ToArray() - : Array.Empty(); - } - else - { - // those values are null/empty even if x-ms-dynamic-* could be present and would define possible values - EnumValues = Array.Empty(); - EnumDisplayNames = Array.Empty(); + ? oaa.Cast().Select(oas => oas.Value).ToArray() + : Array.Empty(); + + // x-ms-enum-values + if (!EnumDisplayNames.Any() && formulaType is OptionSetValueType osvt) + { + List displayNames = new List(); + + // ensure we follow the EnumValues order + foreach (FormulaValue enumName in EnumValues) + { + string logicalName = enumName switch + { + StringValue sv => sv.Value, + DecimalValue dv => dv.Value.ToString(CultureInfo.InvariantCulture), + NumberValue nv => nv.Value.ToString(CultureInfo.InvariantCulture), + _ => throw new InvalidOperationException("Not supported enum type") + }; + + if (osvt.TryGetValue(logicalName, out OptionSetValue osValue)) + { + displayNames.Add(osValue.DisplayName ?? logicalName); + } + } + + EnumDisplayNames = displayNames.ToArray(); + } } } + else + { + // those values are null/empty even if x-ms-dynamic-* could be present and would define possible values + EnumValues = Array.Empty(); + EnumDisplayNames = Array.Empty(); + } AddWarning(warning); DynamicSchema = AggregateErrorsAndWarnings(openApiParameter.GetDynamicSchema()); @@ -201,14 +231,14 @@ internal ConnectorType(string error, ErrorResourceKey warning = default) FormulaType = DefaultType; } - internal ConnectorType(ISwaggerSchema schema, ConnectorCompatibility compatibility) - : this(schema, null, new SwaggerParameter(null, true, schema, null).GetConnectorType(compatibility)) + internal ConnectorType(ISwaggerSchema schema, ConnectorSettings settings) + : this(schema, null, new SwaggerParameter(null, true, schema, null).GetConnectorType(settings)) { } // Called by ConnectorFunction.GetCdpTableType - internal ConnectorType(JsonElement schema, string tableName, SymbolTable optionSets, ConnectorCompatibility compatibility, IList referencedEntities, string datasetName, string name, string connectorName, ICdpTableResolver resolver, ServiceCapabilities serviceCapabilities, bool isTableReadOnly) - : this(SwaggerJsonSchema.New(schema), null, new SwaggerParameter(null, true, SwaggerJsonSchema.New(schema), null).GetConnectorType(tableName, optionSets, compatibility)) + internal ConnectorType(JsonElement schema, string tableName, SymbolTable optionSets, ConnectorSettings settings, IList referencedEntities, string datasetName, string name, string connectorName, ICdpTableResolver resolver, ServiceCapabilities serviceCapabilities, bool isTableReadOnly) + : this(SwaggerJsonSchema.New(schema), null, new SwaggerParameter(null, true, SwaggerJsonSchema.New(schema), null).GetConnectorType(tableName, optionSets, settings)) { Name = name; @@ -282,7 +312,7 @@ internal DisplayNameProvider DisplayNameProvider { get { - _displayNameProvider ??= new SingleSourceDisplayNameProvider(Fields.Select(field => new KeyValuePair(new DName(field.Name), new DName(field.DisplayName ?? field.Name)))); + _displayNameProvider ??= DisplayNameUtility.MakeUnique(Fields.Select(field => new KeyValuePair(field.Name, field.DisplayName ?? field.Name))); return _displayNameProvider; } } diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Capabilities/ServiceCapabilities.cs b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Capabilities/ServiceCapabilities.cs index 02d35ad4c0..d793165466 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Capabilities/ServiceCapabilities.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/Capabilities/ServiceCapabilities.cs @@ -176,7 +176,7 @@ public static TableDelegationInfo ToDelegationInfo(ServiceCapabilities serviceCa }) as Core.Entities.ColumnCapabilitiesBase, ComplexColumnCapabilities ccc => new Core.Entities.ComplexColumnCapabilities() as Core.Entities.ColumnCapabilitiesBase, _ => throw new NotImplementedException() - }); + }) ?? new Dictionary(); Dictionary columnWithRelationships = connectorType.Fields.Where(f => f.ExternalTables?.Any() == true).Select(f => (f.Name, f.ExternalTables.First())).ToDictionary(tpl => tpl.Name, tpl => tpl.Item2); string[] primaryKeyNames = connectorType.Fields.Where(f => f.KeyType == ConnectorKeyType.Primary).OrderBy(f => f.KeyOrder).Select(f => f.Name).ToArray(); diff --git a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/CdpTableResolver.cs b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/CdpTableResolver.cs index e8c0499cf1..f6ea4849b5 100644 --- a/src/libraries/Microsoft.PowerFx.Connectors/Tabular/CdpTableResolver.cs +++ b/src/libraries/Microsoft.PowerFx.Connectors/Tabular/CdpTableResolver.cs @@ -95,7 +95,7 @@ public async Task ResolveTableAsync(string tableName, Cancellatio var parts = _uriPrefix.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); string connectorName = (parts.Length > 1) ? parts[1] : string.Empty; - ConnectorType connectorType = ConnectorFunction.GetCdpTableType(this, connectorName, _tabularTable.TableName, "Schema/Items", FormulaValue.New(text), ConnectorCompatibility.CdpCompatibility, _tabularTable.DatasetName, + ConnectorType connectorType = ConnectorFunction.GetCdpTableType(this, connectorName, _tabularTable.TableName, "Schema/Items", FormulaValue.New(text), ConnectorSettings.DefaultCdp, _tabularTable.DatasetName, out string name, out string displayName, out TableDelegationInfo delegationInfo, out IEnumerable optionSets); OptionSets = optionSets; diff --git a/src/libraries/Microsoft.PowerFx.Core/Entities/External/TableDelegationInfo.cs b/src/libraries/Microsoft.PowerFx.Core/Entities/External/TableDelegationInfo.cs index 269b0b3509..d05ba68d06 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Entities/External/TableDelegationInfo.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Entities/External/TableDelegationInfo.cs @@ -23,6 +23,9 @@ public abstract class TableDelegationInfo // Used to indicate whether this table has selectable columns public SelectionRestrictions SelectionRestriction { get; init; } + [Obsolete("preview")] + public SummarizeCapabilities SummarizeCapabilities { get; init; } + // Defines ungroupable columns public GroupRestrictions GroupRestriction { get; init; } @@ -266,6 +269,36 @@ public SelectionRestrictions() } } + [Obsolete("preview")] + public class SummarizeCapabilities + { + public virtual bool IsSummarizableProperty(string propertyName) + { + return false; + } + + public virtual bool IsSummarizableMethod(SummarizeMethod method) + { + return false; + } + + public SummarizeCapabilities() + { + } + } + + [Obsolete("preview")] + public enum SummarizeMethod + { + None, + Sum, + Average, + Min, + Max, + Count, + CountRows + } + public sealed class FilterRestrictions { // List of required properties diff --git a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationCapability.cs b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationCapability.cs index 7dd0adcb0c..73581b390e 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationCapability.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationCapability.cs @@ -88,7 +88,10 @@ internal struct DelegationCapability { DelegationMetadataOperatorConstants.AsType, new DelegationCapability(AsType) }, { DelegationMetadataOperatorConstants.ArrayLookup, new DelegationCapability(ArrayLookup) }, { DelegationMetadataOperatorConstants.Distinct, new DelegationCapability(Distinct) }, - { DelegationMetadataOperatorConstants.Join, new DelegationCapability(Join) } + { DelegationMetadataOperatorConstants.JoinInner, new DelegationCapability(JoinInner) }, + { DelegationMetadataOperatorConstants.JoinLeft, new DelegationCapability(JoinLeft) }, + { DelegationMetadataOperatorConstants.JoinRight, new DelegationCapability(JoinRight) }, + { DelegationMetadataOperatorConstants.JoinFull, new DelegationCapability(JoinFull) } }, isThreadSafe: true); // Supported delegatable operations. @@ -140,10 +143,13 @@ internal struct DelegationCapability public static readonly BigInteger AsType = BigInteger.Pow(2, 44); // 0x100000000000 public static readonly BigInteger ArrayLookup = BigInteger.Pow(2, 45); // 0x200000000000 public static readonly BigInteger Distinct = BigInteger.Pow(2, 46); // 0x400000000000 - public static readonly BigInteger Join = BigInteger.Pow(2, 47); // 0x800000000000 + public static readonly BigInteger JoinInner = BigInteger.Pow(2, 47); // 0x800000000000 + public static readonly BigInteger JoinLeft = BigInteger.Pow(2, 48); // 0x1000000000000 + public static readonly BigInteger JoinRight = BigInteger.Pow(2, 49); // 0x2000000000000 + public static readonly BigInteger JoinFull = BigInteger.Pow(2, 50); // 0x4000000000000 // Please update it as max value changes. - private static BigInteger maxSingleCapabilityValue = Join; + private static BigInteger maxSingleCapabilityValue = JoinFull; // Indicates support all functionality. public static BigInteger SupportsAll @@ -481,10 +487,28 @@ internal string DebugString sb.Append(nameof(Distinct)); } - if (HasCapability(Join)) + if (HasCapability(JoinInner)) { AddCommaIfNeeded(sb); - sb.Append(nameof(Join)); + sb.Append(nameof(JoinInner)); + } + + if (HasCapability(JoinLeft)) + { + AddCommaIfNeeded(sb); + sb.Append(nameof(JoinLeft)); + } + + if (HasCapability(JoinRight)) + { + AddCommaIfNeeded(sb); + sb.Append(nameof(JoinRight)); + } + + if (HasCapability(JoinFull)) + { + AddCommaIfNeeded(sb); + sb.Append(nameof(JoinFull)); } return sb.ToString(); diff --git a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationMetadataOperatorConstants.cs b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationMetadataOperatorConstants.cs index cf28bcc21e..fe4319a41f 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationMetadataOperatorConstants.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationMetadataOperatorConstants.cs @@ -52,7 +52,10 @@ internal static class DelegationMetadataOperatorConstants public const string AsType = "astype"; public const string ArrayLookup = "arraylookup"; public const string Distinct = "distinct"; - public const string Join = "join"; + public const string JoinInner = "joininner"; + public const string JoinLeft = "joinleft"; + public const string JoinRight = "joinright"; + public const string JoinFull = "joinfull"; } public enum DelegationOperator @@ -98,6 +101,9 @@ public enum DelegationOperator Astype, Arraylookup, Distinct, - Join + JoinInner, + JoinLeft, + JoinRight, + JoinFull } } diff --git a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/DelegationValidationStrategy.cs b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/DelegationValidationStrategy.cs index 651d818197..a4acb19e44 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/DelegationValidationStrategy.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/DelegationValidationStrategy.cs @@ -424,45 +424,19 @@ protected virtual bool IsValidAsyncOrImpureNode(TexlNode node, TexlBinding bindi Contracts.AssertValue(binding); var isAsync = binding.IsAsync(node); - var isPure = binding.IsPure(node); - if (!isAsync && isPure) - { - return true; - } - - // Async predicates and impure nodes are not supported unless Features say otherwise. // Let CallNodes for delegatable async functions be marked as being Valid to allow // expressions with delegatable async function calls to be delegated - // Impure nodes should only be marked valid when Feature is enabled. - if (!isPure && !binding.Features.AllowImpureNodeDelegation) + if (!isAsync) { - TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.ImpureNode, node, binding, trackingFunction ?? Function, DelegationTelemetryInfo.CreateImpureNodeTelemetryInfo(node, binding)); + return true; } else { - if (!isAsync) - { - return true; - } - else if (binding.Features.AllowAsyncDelegation) - { - // If the feature is enabled, enable delegation for - // async call, first name and dotted name nodes. - return (node is CallNode) || (node is FirstNameNode) || (node is DottedNameNode); - } - } - - if (isAsync) - { - TrackingProvider.Instance.SetDelegationTrackerStatus(DelegationStatus.AsyncPredicate, node, binding, trackingFunction ?? Function, DelegationTelemetryInfo.CreateAsyncNodeTelemetryInfo(node, binding)); + // Enable delegation for async call, first name, and dotted name nodes. + return (node is CallNode) || (node is FirstNameNode) || (node is DottedNameNode); } - - var telemetryMessage = string.Format(CultureInfo.InvariantCulture, "Kind:{0}, isAsync:{1}, isPure:{2}", node.Kind, isAsync, isPure); - SuggestDelegationHintAndAddTelemetryMessage(node, binding, telemetryMessage); - - return false; } } } diff --git a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/InOpDelegationStrategy.cs b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/InOpDelegationStrategy.cs index 1152512a09..618183ae70 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/InOpDelegationStrategy.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/InOpDelegationStrategy.cs @@ -202,7 +202,7 @@ public override bool IsOpSupportedByTable(OperationCapabilityMetadata metadata, /* Left node can be first name, row scope lambda or a lookup column */ (_binaryOpNode.Left.Kind == NodeKind.FirstName || binding.IsFullRecordRowScopeAccess(_binaryOpNode.Left) || (_binaryOpNode.Left.Kind == NodeKind.DottedName && binding.GetType((_binaryOpNode.Left as DottedNameNode).Left).HasExpandInfo)) && /* Right has to be a single column table */ - ((_binaryOpNode.Right.Kind == NodeKind.Table || binding.GetType(_binaryOpNode.Right)?.IsColumn == true) && (binding.Features.AllowAsyncDelegation || !binding.IsAsync(_binaryOpNode.Right))); + (_binaryOpNode.Right.Kind == NodeKind.Table || binding.GetType(_binaryOpNode.Right)?.IsColumn == true); if (!(isRHSFirstName || isRHSRecordScope || isCdsInTableDelegation)) { diff --git a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/OpDelegationStrategy.cs b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/OpDelegationStrategy.cs index 2f5098d18a..8ea609d978 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/OpDelegationStrategy.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Functions/Delegation/DelegationStrategies/OpDelegationStrategy.cs @@ -99,13 +99,12 @@ private bool IsSupportedNode(TexlNode node, OperationCapabilityMetadata metadata // Filter(Accounts, 'Account Name' in ["Foo", Bar"]) - Direct table use // Set(Names, ["Foo", Bar"]); Filter(Accounts, 'Account Name' in Names) - Using variable of type table // ClearCollect(Names, Accounts); Filter(Accounts, 'Account Name' in Names.'Account Name') - using column from collection. - // This won't be delegated if the AllowAsyncDelegation- Filter(Accounts, 'Account Name' in Accounts.'Account Name') as Accounts.'Account Name' is async. + // Filter(Accounts, 'Account Name' in Accounts.'Account Name') as Accounts.'Account Name' is async. if (isRHSNode && opDelStrategy is BinaryOpDelegationStrategy { Op: BinaryOp.In } && !binding.IsRowScope(node) && binding.GetType(node).IsTable && binding.GetType(node).IsColumn - && (binding.Features.AllowAsyncDelegation || !binding.IsAsync(node)) && opDelStrategy.IsOpSupportedByTable(metadata, node, binding)) { return true; diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Config/Features.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Config/Features.cs index f15d6e54f4..abf908f462 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Config/Features.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Config/Features.cs @@ -48,16 +48,6 @@ public sealed class Features /// internal bool RestrictedIsEmptyArguments { get; init; } - /// - /// Allow delegation for async calls (delegate using awaited call result). - /// - internal bool AllowAsyncDelegation { get; init; } - - /// - /// Allow delegation for impure nodes. - /// - internal bool AllowImpureNodeDelegation { get; init; } - /// /// Updates the FirstN/LastN functions to require a second argument, instead of /// defaulting to 1. @@ -131,8 +121,6 @@ internal Features(Features other) PowerFxV1CompatibilityRules = other.PowerFxV1CompatibilityRules; PrimaryOutputPropertyCoercionDeprecated = other.PrimaryOutputPropertyCoercionDeprecated; IsUserDefinedTypesEnabled = other.IsUserDefinedTypesEnabled; - AllowImpureNodeDelegation = other.AllowImpureNodeDelegation; - AllowAsyncDelegation = other.AllowAsyncDelegation; AsTypeLegacyCheck = other.AsTypeLegacyCheck; JsonFunctionAcceptsLazyTypes = other.JsonFunctionAcceptsLazyTypes; IsLookUpReductionDelegationEnabled = other.IsLookUpReductionDelegationEnabled; diff --git a/src/libraries/Microsoft.PowerFx.Core/Public/Values/DelegationParameters.cs b/src/libraries/Microsoft.PowerFx.Core/Public/Values/DelegationParameters.cs index 9e3c9db056..a4a4f2dde8 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Public/Values/DelegationParameters.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Public/Values/DelegationParameters.cs @@ -70,8 +70,11 @@ public enum DelegationParameterFeatures // $orderBy Sort = 1 << 3, - // $apply - Apply = 1 << 4, + // $apply = join(table As name) + ApplyJoin = 1 << 4, + + // $apply = groupby((field1, ..), field with sum as TotalSum) + ApplyGroupBy = 1 << 5, /* To be implemented later when needed diff --git a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Summarize.cs b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Summarize.cs index b4d64bffcf..f285151580 100644 --- a/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Summarize.cs +++ b/src/libraries/Microsoft.PowerFx.Core/Texl/Builtins/Summarize.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Linq; using Microsoft.PowerFx.Core.App.ErrorContainers; using Microsoft.PowerFx.Core.Errors; using Microsoft.PowerFx.Core.Functions; @@ -109,8 +108,9 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp { isValid = false; errors.EnsureError(DocumentErrorSeverity.Severe, args[0], TexlStrings.ErrSummarizeDataSourceContainsThisGroupColumn); - } - + } + + var newDisplayNameProvider = new Dictionary(); var atLeastOneGroupByColumn = false; for (int i = 1; i < args.Length; i++) @@ -150,7 +150,9 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp isValid = false; errors.EnsureError(DocumentErrorSeverity.Severe, arg, TexlStrings.ErrSummarizeThisGroupColumnName); continue; - } + } + + newDisplayNameProvider[columnName] = new DName(displayName); } atLeastOneGroupByColumn = true; @@ -199,7 +201,9 @@ public override bool CheckTypes(CheckTypesContext context, TexlNode[] args, DTyp { isValid = false; errors.EnsureError(DocumentErrorSeverity.Severe, args[1], TexlStrings.ErrSummarizeNoGroupBy); - } + } + + returnType = DType.AttachOrDisableDisplayNameProvider(returnType, DisplayNameProvider.New(newDisplayNameProvider)); Contracts.Assert(returnType.IsTable); return isValid; diff --git a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryTable.cs b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryTable.cs index 36697e5401..a89e8a0f98 100644 --- a/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryTable.cs +++ b/src/libraries/Microsoft.PowerFx.Interpreter/Functions/LibraryTable.cs @@ -546,16 +546,16 @@ public static async ValueTask JoinTables(EvalVisitor runner, EvalV switch (joinType.Option) { case "Full": - rows = await LazyJoinAsync(runner, context, leftTable, rightTable, predicate, outerLeft: true, outerRight: true, scopeNameResolver, leftRenaming, rightRenaming).ConfigureAwait(false); + rows = await LazyJoinAsync(runner, context, irContext, leftTable, rightTable, predicate, outerLeft: true, outerRight: true, scopeNameResolver, leftRenaming, rightRenaming).ConfigureAwait(false); break; case "Inner": - rows = await LazyJoinAsync(runner, context, leftTable, rightTable, predicate, outerLeft: false, outerRight: false, scopeNameResolver, leftRenaming, rightRenaming).ConfigureAwait(false); + rows = await LazyJoinAsync(runner, context, irContext, leftTable, rightTable, predicate, outerLeft: false, outerRight: false, scopeNameResolver, leftRenaming, rightRenaming).ConfigureAwait(false); break; case "Left": - rows = await LazyJoinAsync(runner, context, leftTable, rightTable, predicate, outerLeft: true, outerRight: false, scopeNameResolver, leftRenaming, rightRenaming).ConfigureAwait(false); + rows = await LazyJoinAsync(runner, context, irContext, leftTable, rightTable, predicate, outerLeft: true, outerRight: false, scopeNameResolver, leftRenaming, rightRenaming).ConfigureAwait(false); break; case "Right": - rows = await LazyJoinAsync(runner, context, leftTable, rightTable, predicate, outerLeft: false, outerRight: true, scopeNameResolver, leftRenaming, rightRenaming).ConfigureAwait(false); + rows = await LazyJoinAsync(runner, context, irContext, leftTable, rightTable, predicate, outerLeft: false, outerRight: true, scopeNameResolver, leftRenaming, rightRenaming).ConfigureAwait(false); break; default: throw new InvalidOperationException(); @@ -566,7 +566,8 @@ public static async ValueTask JoinTables(EvalVisitor runner, EvalV private static async Task[]> LazyJoinAsync( EvalVisitor runner, - EvalVisitorContext context, + EvalVisitorContext context, + IRContext irContext, TableValue leftSource, TableValue rightSource, LambdaFormulaValue predicate, @@ -576,15 +577,13 @@ private static async Task[]> LazyJoinAsync( RecordValue leftRenaming, RecordValue rightRenaming) { - var innerRows = new List>(); - var outerDict = new Dictionary, bool>(); - - // Keep track of which rows have been included in the inner join. - // Using a dictionary to avoid duplicates and to make it easier to check if a row is in the inner join. - var innerDict = new Dictionary, bool>(); + var resultRows = new List>(); + var recordContext = IRContext.NotInSource(((TableType)irContext.ResultType).ToRecord()); + // Inner and Left loops foreach (var leftRow in leftSource.Rows) { + var hasMatch = false; foreach (var rightRow in rightSource.Rows) { runner.CheckCancel(); @@ -596,68 +595,60 @@ private static async Task[]> LazyJoinAsync( if (result.IsValue) { var fields = new List(); - var leftRenamed = (RecordValue)await RenameColumns(runner, context, IRContext.NotInSource(leftRow.Value.Type), BuildRenamingArgs(leftRow.Value, leftRenaming)).ConfigureAwait(false); - - foreach (var field in leftRenamed.OriginalFields) - { - fields.Add(new NamedValue(field.Name, field.Value)); - } + var leftRecordValueRenamed = (RecordValue)await RenameColumns(runner, context, recordContext, BuildRenamingArgs(leftRow.Value, leftRenaming)).ConfigureAwait(false); - foreach (var field in rightRenaming.OriginalFields) - { - var fieldName = (StringValue)field.Value; - fields.Add(new NamedValue(fieldName.Value, rightRow.Value.GetField(field.Name))); - } + fields.AddRange(leftRecordValueRenamed.OriginalFields); + fields.AddRange(rightRenaming.OriginalFields.Select(field => new NamedValue(((StringValue)field.Value).Value, rightRow.Value.GetField(field.Name)))); - innerRows.Add(DValue.Of(FormulaValue.NewRecordFromFields(fields))); + resultRows.Add(DValue.Of(FormulaValue.NewRecordFromFields(fields))); } else if (result.IsError) { // Lambda evaluation resulted in an error. Include the error. - innerRows.Add(result); + resultRows.Add(result); } - innerDict[leftRow] = true; - innerDict[rightRow] = true; + hasMatch = true; + } + } - if (outerLeft) - { - if (outerDict.ContainsKey(leftRow)) - { - outerDict.Remove(leftRow); - } - } + if (!hasMatch && outerLeft) + { + // leftRow is value since it would have been added to the resultRows in the inner loop. + var recordValueRenamed = (RecordValue)await RenameColumns(runner, context, recordContext, BuildRenamingArgs(leftRow.Value, leftRenaming)).ConfigureAwait(false); + resultRows.Add(DValue.Of(recordValueRenamed)); + } + } - if (outerRight) - { - if (outerDict.ContainsKey(rightRow)) - { - outerDict.Remove(rightRow); - } - } + // Right loop + if (outerRight) + { + foreach (var rightRow in rightSource.Rows) + { + var hasMatch = false; + foreach (var leftRow in leftSource.Rows) + { + runner.CheckCancel(); - continue; - } + var result = await LazyCheckPredicateAsync(runner, context, scopeNameResolver, leftRow, rightRow, predicate).ConfigureAwait(false); - if (outerLeft) - { - if (!innerDict.ContainsKey(leftRow)) + if (result != null) { - outerDict[leftRow] = true; + hasMatch = true; + break; } } - if (outerRight) + if (!hasMatch) { - if (!innerDict.ContainsKey(rightRow)) - { - outerDict[rightRow] = true; - } + // rightRow is value since it would have been added to the resultRows in the inner loop. + var recorValueRenamed = (RecordValue)await RenameColumns(runner, context, recordContext, BuildRenamingArgs(rightRow.Value, rightRenaming)).ConfigureAwait(false); + resultRows.Add(DValue.Of(recorValueRenamed)); } - } + } } - return innerRows.Concat(outerDict.Keys).ToArray(); + return resultRows.ToArray(); } private static FormulaValue[] BuildRenamingArgs(RecordValue row, RecordValue renaming) @@ -684,21 +675,29 @@ private static async Task> LazyCheckPredicateAsync( var leftScopeName = new DName(((StringValue)scopeNameResolver.GetField(FunctionJoinScopeInfo.LeftRecord.Value)).Value); var rightScopeName = new DName(((StringValue)scopeNameResolver.GetField(FunctionJoinScopeInfo.RightRecord.Value)).Value); - var scopeValue = FormulaValue.NewRecordFromFields( - new NamedValue(leftScopeName, leftRow.Value), - new NamedValue(rightScopeName, rightRow.Value)); - - SymbolContext childContext = context.SymbolContext.WithScopeValues(scopeValue); - if (leftRow.IsError) { return leftRow; } - + else if (leftRow.IsBlank) + { + return null; + } + if (rightRow.IsError) { return rightRow; - } + } + else if (rightRow.IsBlank) + { + return null; + } + + var scopeValue = FormulaValue.NewRecordFromFields( + new NamedValue(leftScopeName, leftRow.Value), + new NamedValue(rightScopeName, rightRow.Value)); + + SymbolContext childContext = context.SymbolContext.WithScopeValues(scopeValue); var result = await predicate.EvalInRowScopeAsync(context.NewScope(childContext)).ConfigureAwait(false); var include = false; diff --git a/src/strings/PowerFxResources.en-US.resx b/src/strings/PowerFxResources.en-US.resx index aaecaa686b..bd38c3afe3 100644 --- a/src/strings/PowerFxResources.en-US.resx +++ b/src/strings/PowerFxResources.en-US.resx @@ -3225,9 +3225,6 @@ A new or existing collection to augment. - - A record or table to collect. A record will be appended to the collection. A table will have its rows appended to the collection. - Clears the collection first and adds one or more items to the specified collection. The items can be from a different table or collection (e.g. ClearCollect(collection, source_collection)), or one or more records ClearCollect(collection, {key1: val1, key2: val2, ...}, ...). {Locked=ClearCollect(collection, source_collection)} {Locked=ClearCollect(collection, {key1: val1, key2: val2, ...}, ...)} Description of 'ClearCollect' function. diff --git a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/CompatibilityTests.cs b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/CompatibilityTests.cs index 7655a6d4b4..4532660223 100644 --- a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/CompatibilityTests.cs +++ b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/CompatibilityTests.cs @@ -33,9 +33,9 @@ public void CompatibilityTest() string text = (string)LoggingTestServer.GetFileText(@"Responses\Compatibility GetSchema.json"); - ConnectorType ctCdp = ConnectorFunction.GetCdpTableType(tableResolver, "name", null, "schema/items", StringValue.New(text), ConnectorCompatibility.CdpCompatibility, "dataset", out _, out _, out _, out _); - ConnectorType ctPa = ConnectorFunction.GetCdpTableType(tableResolver, "name", null, "schema/items", StringValue.New(text), ConnectorCompatibility.PowerAppsCompatibility, "dataset", out _, out _, out _, out _); - ConnectorType ctSw = ConnectorFunction.GetCdpTableType(tableResolver, "name", null, "schema/items", StringValue.New(text), ConnectorCompatibility.SwaggerCompatibility, "dataset", out _, out _, out _, out _); + ConnectorType ctCdp = ConnectorFunction.GetCdpTableType(tableResolver, "name", null, "schema/items", StringValue.New(text), new ConnectorSettings(null) { Compatibility = ConnectorCompatibility.CdpCompatibility }, "dataset", out _, out _, out _, out _); + ConnectorType ctPa = ConnectorFunction.GetCdpTableType(tableResolver, "name", null, "schema/items", StringValue.New(text), new ConnectorSettings(null) { Compatibility = ConnectorCompatibility.PowerAppsCompatibility }, "dataset", out _, out _, out _, out _); + ConnectorType ctSw = ConnectorFunction.GetCdpTableType(tableResolver, "name", null, "schema/items", StringValue.New(text), new ConnectorSettings(null) { Compatibility = ConnectorCompatibility.SwaggerCompatibility }, "dataset", out _, out _, out _, out _); string cdp = ctCdp.FormulaType.ToStringWithDisplayNames(); string pa = ctPa.FormulaType.ToStringWithDisplayNames(); diff --git a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/InternalTesting.cs b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/InternalTesting.cs index 91c3f81afa..6db4a59bb1 100644 --- a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/InternalTesting.cs +++ b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/InternalTesting.cs @@ -1374,7 +1374,7 @@ public static string GetString(this OpenApiSchema schema) { StringBuilder sb = new StringBuilder(); SymbolTable optionSets = new SymbolTable(); - schema.GetStringInternal(new ConnectorTypeGetterSettings(0, null, optionSets), sb); + schema.GetStringInternal(new ConnectorTypeGetterSettings(new ConnectorSettings(null), null, optionSets), sb); return sb.ToString(); } diff --git a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/Microsoft.PowerFx.Connectors.Tests.Shared.projitems b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/Microsoft.PowerFx.Connectors.Tests.Shared.projitems index 96867a3738..4e0403dfc9 100644 --- a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/Microsoft.PowerFx.Connectors.Tests.Shared.projitems +++ b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/Microsoft.PowerFx.Connectors.Tests.Shared.projitems @@ -287,6 +287,7 @@ + diff --git a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/PowerPlatformConnectorTests.cs b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/PowerPlatformConnectorTests.cs index 579c063303..77c7cf72fe 100644 --- a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/PowerPlatformConnectorTests.cs +++ b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/PowerPlatformConnectorTests.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Data; using System.Linq; using System.Net; using System.Net.Http; @@ -21,7 +22,6 @@ using Microsoft.PowerFx.Core.Types; using Microsoft.PowerFx.Functions; using Microsoft.PowerFx.Intellisense; -using Microsoft.PowerFx.Syntax; using Microsoft.PowerFx.Types; using Xunit; using Xunit.Abstractions; @@ -45,6 +45,188 @@ private static void AssertEqual(string expected, string actual) Assert.Equal(expected.Replace("\r", string.Empty), actual.Replace("\r", string.Empty)); } + [Theory] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, true, false)] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, false, false)] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, true, true)] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, false, true)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, false)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, false)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, true)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, true)] + [InlineData(ConnectorCompatibility.CdpCompatibility, true, false)] + [InlineData(ConnectorCompatibility.CdpCompatibility, false, false)] + [InlineData(ConnectorCompatibility.CdpCompatibility, true, true)] + [InlineData(ConnectorCompatibility.CdpCompatibility, false, true)] + public void MSNWeather_OptionSets(ConnectorCompatibility connectorCompatibility, bool supportXMsEnumValues, bool returnEnumsAsPrimitive) + { + using var testConnector = new LoggingTestServer(@"Swagger\MSNWeather.json", _output); + List functions = OpenApiParser.GetFunctions( + new ConnectorSettings("MSNWeather") + { + Compatibility = connectorCompatibility, + SupportXMsEnumValues = supportXMsEnumValues, + ReturnEnumsAsPrimitive = returnEnumsAsPrimitive + }, + testConnector._apiDocument).ToList(); + + ConnectorFunction currentWeather = functions.First(f => f.Name == "CurrentWeather"); + + Assert.Equal(2, currentWeather.RequiredParameters.Length); + Assert.Equal("Location", currentWeather.RequiredParameters[0].Name); + Assert.Equal(FormulaType.String, currentWeather.RequiredParameters[0].FormulaType); + + Assert.Equal("units", currentWeather.RequiredParameters[1].Name); + Assert.Equal("units", currentWeather.RequiredParameters[1].ConnectorType.Name); + Assert.Null(currentWeather.RequiredParameters[1].ConnectorType.DisplayName); + Assert.True(currentWeather.RequiredParameters[1].ConnectorType.IsEnum); + + if (connectorCompatibility == ConnectorCompatibility.CdpCompatibility || supportXMsEnumValues) + { + if (returnEnumsAsPrimitive) + { + Assert.Equal(FormulaType.String, currentWeather.RequiredParameters[1].FormulaType); + } + else + { + Assert.Equal(FormulaType.OptionSetValue, currentWeather.RequiredParameters[1].FormulaType); + } + + // Dictionary is used here, so we need to reorder + Assert.Equal("Imperial,Metric", string.Join(",", currentWeather.RequiredParameters[1].ConnectorType.Enum.OrderBy(kvp => kvp.Key).Select(kvp => kvp.Key))); + Assert.Equal("I,C", string.Join(",", currentWeather.RequiredParameters[1].ConnectorType.Enum.OrderBy(kvp => kvp.Key).Select(kvp => (kvp.Value as StringValue).Value))); + + Assert.Equal("Imperial,Metric", string.Join(",", currentWeather.RequiredParameters[1].ConnectorType.EnumDisplayNames)); + } + else + { + Assert.Equal(FormulaType.String, currentWeather.RequiredParameters[1].FormulaType); + } + + Assert.Equal("I,C", string.Join(",", currentWeather.RequiredParameters[1].ConnectorType.EnumValues.Select(fv => (fv as StringValue).Value))); + } + + [Theory] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, true, false)] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, false, false)] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, true, true)] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, false, true)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, false)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, false)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, true)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, true)] + [InlineData(ConnectorCompatibility.CdpCompatibility, true, false)] + [InlineData(ConnectorCompatibility.CdpCompatibility, false, false)] + [InlineData(ConnectorCompatibility.CdpCompatibility, true, true)] + [InlineData(ConnectorCompatibility.CdpCompatibility, false, true)] + + // Option set with numeric logical names + public void DimeScheduler_OptionSets(ConnectorCompatibility connectorCompatibility, bool supportXMsEnumValues, bool returnEnumsAsPrimitive) + { + using var testConnector = new LoggingTestServer(@"Swagger\Dime.Scheduler.json", _output); + List functions = OpenApiParser.GetFunctions( + new ConnectorSettings("DimeScheduler") + { + Compatibility = connectorCompatibility, + SupportXMsEnumValues = supportXMsEnumValues, + ReturnEnumsAsPrimitive = returnEnumsAsPrimitive + }, + testConnector._apiDocument).ToList(); + + ConnectorFunction actionUriUpsert = functions.First(f => f.Name == "actionUriUpsert"); + + Assert.Equal(5, actionUriUpsert.OptionalParameters.Length); + Assert.Equal("uriType", actionUriUpsert.OptionalParameters[2].Name); + Assert.True(actionUriUpsert.OptionalParameters[2].ConnectorType.IsEnum); + + if (connectorCompatibility == ConnectorCompatibility.CdpCompatibility || supportXMsEnumValues) + { + if (returnEnumsAsPrimitive) + { + Assert.Equal(FormulaType.Decimal, actionUriUpsert.OptionalParameters[2].FormulaType); + } + else + { + Assert.Equal(FormulaType.OptionSetValue, actionUriUpsert.OptionalParameters[2].FormulaType); + } + + // Dictionary is used here, so we need to reorder + Assert.Equal("Planning Board,Appointment,Task,Map", string.Join(",", actionUriUpsert.OptionalParameters[2].ConnectorType.Enum.Select(kvp => kvp.Key))); + Assert.Equal("0,1,2,3", string.Join(",", actionUriUpsert.OptionalParameters[2].ConnectorType.Enum.Select(kvp => (kvp.Value as DecimalValue).Value))); + + Assert.Equal("Planning Board,Appointment,Task,Map", string.Join(",", actionUriUpsert.OptionalParameters[2].ConnectorType.EnumDisplayNames)); + } + else + { + Assert.Equal(FormulaType.Decimal, actionUriUpsert.OptionalParameters[2].FormulaType); + } + + Assert.Equal("0,1,2,3", string.Join(",", actionUriUpsert.OptionalParameters[2].ConnectorType.EnumValues.Select(fv => (fv as DecimalValue).Value))); + } + + [Theory] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, true, false)] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, false, false)] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, true, true)] + [InlineData(ConnectorCompatibility.SwaggerCompatibility, false, true)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, false)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, false)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, true, true)] + [InlineData(ConnectorCompatibility.PowerAppsCompatibility, false, true)] + [InlineData(ConnectorCompatibility.CdpCompatibility, true, false)] + [InlineData(ConnectorCompatibility.CdpCompatibility, false, false)] + [InlineData(ConnectorCompatibility.CdpCompatibility, true, true)] + [InlineData(ConnectorCompatibility.CdpCompatibility, false, true)] + public void ACSL_OptionSets(ConnectorCompatibility connectorCompatibility, bool supportXMsEnumValues, bool returnEnumsAsPrimitive) + { + using var testConnector = new LoggingTestServer(@"Swagger\Azure Cognitive Service for Language v2.2.json", _output); + List functions = OpenApiParser.GetFunctions( + new ConnectorSettings("ACSL") + { + Compatibility = connectorCompatibility, + SupportXMsEnumValues = supportXMsEnumValues, + ReturnEnumsAsPrimitive = returnEnumsAsPrimitive + }, + testConnector._apiDocument).ToList(); + + ConnectorFunction analyzeConversationTranscriptSubmitJob = functions.Single(f => f.Name == "AnalyzeConversationTranscriptSubmitJob"); + + // AnalyzeConversationTranscript_SubmitJob defined at line 1226 of swagger file + // body parameter at line 1240, defined at line 2557(TranscriptJobsInput) + // analysisInput parameter at line 2566, defined at line 2573(TranscriptMultiLanguageConversationAnalysisInput) + // conversations parameter at line 2577, defined at line 2580(TranscriptConversation) + // conversationItems parameter at line 2585, defined at line 2624(TranscriptConversationItem) + // role parameter at line 2641 is having extension x-ms-enum with modelAsString set to true + ConnectorType connectorType = analyzeConversationTranscriptSubmitJob.RequiredParameters[0].ConnectorType; + ConnectorType role = connectorType.Fields[0].Fields[0].Fields[0].Fields[connectorCompatibility == ConnectorCompatibility.Default ? 4 : 3]; + Assert.Equal("role", role.Name); + + // Type is always a string here as to be an optionset, we need (ConnectorCompatibility = CdpCompatibility or SupportXMsEnumValues = true) AND (modelAsString = false) + Assert.Equal(FormulaType.String, role.FormulaType); + Assert.True(role.IsEnum); + + Assert.Equal( + connectorCompatibility != ConnectorCompatibility.Default + ? "![conversations:![conversationItems:*[audioTimings:*[duration:w, offset:w, word:s], id:s, itn:s, language:s, lexical:s, maskedItn:s, participantId:s, role:s, text:s], domain:s, language:s]]" + : "![conversations:![conversationItems:*[audioTimings:*[duration:w, offset:w, word:s], id:s, itn:s, language:s, lexical:s, maskedItn:s, modality:s, participantId:s, role:s, text:s], domain:s, language:s]]", + connectorType.FormulaType._type.ToString()); + + if (connectorCompatibility == ConnectorCompatibility.CdpCompatibility || supportXMsEnumValues) + { + // Dictionary is used here, so we need to reorder + Assert.Equal("agent,customer,generic", string.Join(",", role.Enum.Select(kvp => kvp.Key))); + Assert.Equal("agent,customer,generic", string.Join(",", role.Enum.Select(kvp => (kvp.Value as StringValue).Value))); + Assert.Equal("agent,customer,generic", string.Join(",", role.EnumDisplayNames.OrderBy(x => x))); + } + else + { + Assert.Empty(role.Enum); + Assert.Empty(role.EnumDisplayNames); + } + + Assert.Equal("agent,customer,generic", string.Join(",", role.EnumValues.Select(fv => (fv as StringValue).Value))); + } + // Exercise calling the MSNWeather connector against mocked Swagger and Response.json. [Theory] [InlineData(true)] @@ -1841,16 +2023,16 @@ public async Task SendEmail() public async Task AiSensitivityTest() { using LoggingTestServer testConnector = new LoggingTestServer(@"Swagger\SendMail.json", _output); - OpenApiDocument apiDoc = testConnector._apiDocument; - + OpenApiDocument apiDoc = testConnector._apiDocument; + ConnectorSettings connectorSettings = new ConnectorSettings("exob") - { + { Compatibility = ConnectorCompatibility.SwaggerCompatibility, AllowUnsupportedFunctions = true, IncludeInternalFunctions = true, - ReturnUnknownRecordFieldsAsUntypedObjects = true + ReturnUnknownRecordFieldsAsUntypedObjects = true }; - + List functions = OpenApiParser.GetFunctions(connectorSettings, apiDoc).OrderBy(f => f.Name).ToList(); ConnectorFunction sendmail = functions.First(f => f.Name == "SendEmailV3"); @@ -2055,7 +2237,7 @@ public async Task DVDynamicReturnType() string ft = returnType.FormulaType.ToStringWithDisplayNames(); string expected = - "!['@odata.nextLink'`'Next link':s, value:*[Array:!['@odata.id'`'OData Id':s, _createdby_value`'Created By (Value)':s, '_createdby_value@Microsoft.Dynamics.CRM.lookuplogicalname'`'Created " + + "!['@odata.nextLink'`'Next link':s, value:*[Array:!['@odata.id'`'OData Id':s, _createdby_value`'Created By (Value)':s, '_createdby_value@Microsoft.Dynamics.CRM.lookuplogicalname'`'Created " + "By (Type)':s, _createdbyexternalparty_value`'Created By (External Party) (Value)':s, '_createdbyexternalparty_value@Microsoft.Dynamics.CRM.lookuplogicalname'`'Created By (External Party) " + "(Type)':s, _createdonbehalfby_value`'Created By (Delegate) (Value)':s, '_createdonbehalfby_value@Microsoft.Dynamics.CRM.lookuplogicalname'`'Created By (Delegate) (Type)':s, _defaultpricelevelid_value`'" + "Price List (Value)':s, '_defaultpricelevelid_value@Microsoft.Dynamics.CRM.lookuplogicalname'`'Price List (Type)':s, _masterid_value`'Master ID (Value)':s, '_masterid_value@Microsoft.Dynamics.CRM.lookup" + @@ -2217,6 +2399,25 @@ public async Task SQL_ExecuteStoredProc_Scoped() Assert.Equal(expected, actual); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ExchangeOnlineTest2(bool useDefaultBodyNameForSinglePropertyObject) + { + using var testConnector = new LoggingTestServer(@"Swagger\ExcelOnlineBusiness.swagger.json", _output); + List functions = OpenApiParser.GetFunctions( + new ConnectorSettings("Excel") + { + Compatibility = ConnectorCompatibility.Default, + UseDefaultBodyNameForSinglePropertyObject = useDefaultBodyNameForSinglePropertyObject + }, + testConnector._apiDocument).ToList(); + + ConnectorFunction patchItem = functions.First(f => f.Name == "PatchItem"); + + Assert.Equal(!useDefaultBodyNameForSinglePropertyObject ? "dynamicProperties" : "item", patchItem.OptionalParameters[2].Name); + } + public class HttpLogger : HttpClient { private readonly ITestOutputHelper _console; diff --git a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/Swagger/Dime.Scheduler.json b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/Swagger/Dime.Scheduler.json new file mode 100644 index 0000000000..54f9b7f417 --- /dev/null +++ b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/Swagger/Dime.Scheduler.json @@ -0,0 +1,7921 @@ +{ + "swagger": "2.0", + "info": { + "title": "Dime.Scheduler", + "description": "Dime.Scheduler is a resource and project planning solution that extends the capabilities of ERP, CRM and other business systems with powerful graphical scheduling tools.", + "version": "2.0", + "contact": { + "name": "Dime.Scheduler Support", + "url": "https://docs.dimescheduler.com", + "email": "support@dimescheduler.com" + }, + "x-ms-api-annotation": { + "status": "Preview" + }, + "license": { + "name": "Commercial", + "url": "https://www.dimescheduler.com/terms" + } + }, + "x-ms-connector-metadata": [ + { + "propertyName": "Website", + "propertyValue": "https://www.dimescheduler.com" + }, + { + "propertyName": "Privacy Policy", + "propertyValue": "https://www.dimescheduler.com/privacy" + }, + { + "propertyName": "Categories", + "propertyValue": "Business Management;Data" + } + ], + "host": "api.dimescheduler.com", + "schemes": [ + "https" + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "paths": { + "/webhooks/AppointmentCreated": { + "x-ms-notification-content": { + "description": "Appointment details for webhook", + "schema": { + "$ref": "#/definitions/appointment-incoming" + } + }, + "post": { + "responses": { + "201": { + "description": "Created." + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "summary": "When an appointment is created", + "description": "This trigger is used for listening to new appointments scheduled in Dime.Scheduler.", + "operationId": "CreateAppointment", + "x-ms-trigger": "single", + "x-ms-trigger-hint": "To see this trigger work, create an appointment in Dime.Scheduler", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "sourceApp": { + "type": "string", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "title": "Source App", + "x-ms-visibility": "important" + }, + "name": { + "type": "string", + "description": "Provide a descriptive name to identify the purpose of this flow in Dime.Scheduler.", + "title": "Name", + "x-ms-visibility": "important" + }, + "notificationURL": { + "type": "string", + "description": "Notification URL where the appointment data will be posted.", + "title": "notificationURL", + "x-ms-visibility": "internal", + "x-ms-notification-url": true + }, + "resource": { + "type": "string", + "description": "resource", + "title": "Resource", + "default": "Appointments", + "x-ms-visibility": "internal" + }, + "changeType": { + "description": "Changes to listen on", + "x-ms-visibility": "internal", + "type": "array", + "default": [ + "Create" + ], + "items": { + "type": "string" + } + } + }, + "required": [ + "notificationURL", + "resource", + "changeType", + "sourceApp" + ] + } + } + ], + "x-ms-visibility": "important" + } + }, + "/webhooks/AppointmentCreated/{hook_id}": { + "delete": { + "summary": "Deletes the new appointment webhook", + "description": "Deletes the new appointment webhook", + "operationId": "DeleteCreateAppointmentTrigger", + "x-ms-visibility": "internal", + "responses": { + "200": { + "description": "OK" + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "parameters": [ + { + "name": "hook_id", + "in": "path", + "required": true, + "type": "string", + "x-ms-url-encoding": "single", + "x-ms-summary": "ID", + "description": "Specify the ID of the WebHook" + } + ] + } + }, + "/webhooks/AppointmentUpdated": { + "x-ms-notification-content": { + "description": "Appointment details for webhook", + "schema": { + "$ref": "#/definitions/appointment-incoming" + } + }, + "post": { + "responses": { + "201": { + "description": "Created." + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden. " + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "summary": "When an appointment is updated", + "description": "This trigger is used for listening to new appointments scheduled in Dime.Scheduler.", + "operationId": "UpdateAppointment", + "x-ms-trigger": "single", + "x-ms-trigger-hint": "To see this trigger work, update an appointment in Dime.Scheduler", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "sourceApp": { + "type": "string", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "title": "Source App", + "x-ms-visibility": "important" + }, + "notificationURL": { + "type": "string", + "description": "Notification URL where the appointment data will be posted.", + "title": "notificationURL", + "x-ms-visibility": "internal", + "x-ms-notification-url": true + }, + "resource": { + "type": "string", + "description": "resource", + "title": "Resource", + "default": "Appointments", + "x-ms-visibility": "internal" + }, + "changeType": { + "description": "Changes to listen on", + "x-ms-visibility": "internal", + "type": "array", + "default": [ + "Update" + ], + "items": { + "type": "string" + } + } + }, + "required": [ + "notificationURL", + "resource", + "changeType", + "sourceApp" + ] + } + } + ], + "x-ms-visibility": "important" + } + }, + "/webhooks/AppointmentUpdated/{hook_id}": { + "delete": { + "summary": "Deletes the new appointment webhook", + "description": "Deletes the new appointment webhook", + "operationId": "DeleteUpdateAppointmentTrigger", + "x-ms-visibility": "internal", + "responses": { + "200": { + "description": "OK" + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "parameters": [ + { + "name": "hook_id", + "in": "path", + "required": true, + "type": "string", + "x-ms-url-encoding": "single", + "x-ms-summary": "ID", + "description": "Specify the ID of the WebHook" + } + ] + } + }, + "/webhooks/AppointmentDeleted": { + "x-ms-notification-content": { + "description": "Appointment details for webhook", + "schema": { + "$ref": "#/definitions/appointment-incoming" + } + }, + "post": { + "responses": { + "201": { + "description": "Created." + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden. " + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "summary": "When an appointment is deleted", + "description": "This trigger is used for listening to appointments that have been removed in Dime.Scheduler.", + "operationId": "DeleteAppointment", + "x-ms-trigger": "single", + "x-ms-trigger-hint": "To see this trigger work, delete an appointment in Dime.Scheduler", + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "type": "object", + "properties": { + "sourceApp": { + "type": "string", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "title": "Source App", + "x-ms-visibility": "important" + }, + "notificationURL": { + "type": "string", + "description": "Notification URL where the appointment data will be posted.", + "title": "notificationURL", + "x-ms-visibility": "internal", + "x-ms-notification-url": true + }, + "resource": { + "type": "string", + "description": "resource", + "title": "Resource", + "default": "Appointments", + "x-ms-visibility": "internal" + }, + "changeType": { + "description": "Changes to listen on", + "x-ms-visibility": "internal", + "type": "array", + "default": [ + "Delete" + ], + "items": { + "type": "string" + } + } + }, + "required": [ + "sourceApp", + "notificationURL", + "resource", + "changeType" + ] + } + } + ], + "x-ms-visibility": "important" + } + }, + "/webhooks/AppointmentDeleted/{hook_id}": { + "delete": { + "summary": "Deletes the new appointment webhook", + "description": "Deletes the new appointment webhook", + "operationId": "DeleteDeletedAppointmentTrigger", + "x-ms-visibility": "internal", + "responses": { + "200": { + "description": "OK" + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "parameters": [ + { + "name": "hook_id", + "in": "path", + "required": true, + "type": "string", + "x-ms-url-encoding": "single", + "x-ms-summary": "ID", + "description": "Specify the ID of the WebHook" + } + ] + } + }, + "/resourcetype": { + "get": { + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Response to successful retrieval resource types", + "x-ms-summary": "Success response", + "schema": { + "$ref": "#/definitions/resourcetypelist" + } + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "x-ms-visibility": "internal", + "summary": "Gets the list of available resource types in Dime.Scheduler", + "description": "Fetches the list of resource types", + "operationId": "GetResourceTypes", + "tags": [ + "resource" + ] + } + }, + "/categories": { + "get": { + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Response to successful retrieval categories", + "x-ms-summary": "Success response", + "schema": { + "$ref": "#/definitions/categorylist" + } + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "x-ms-visibility": "internal", + "summary": "Gets the list of available categories in Dime.Scheduler", + "description": "Fetches the list of categories", + "operationId": "GetCategories", + "tags": [ + "indicator" + ] + }, + "post": { + "summary": "Add or update a category", + "description": "Add or update a category, which is the visual indicator that renders the background of the appointment.", + "operationId": "categoryUpsert", + "tags": [ + "indicator" + ], + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/category" + } + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a category", + "description": "Remove a category, which is the visual indicator that renders the background of the appointment.", + "operationId": "categoryDelete", + "tags": [ + "indicator" + ], + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/category" + } + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/timeMarker": { + "get": { + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Response to successful retrieval time markers", + "x-ms-summary": "Success response", + "schema": { + "$ref": "#/definitions/timemarkerlist" + } + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "x-ms-visibility": "internal", + "summary": "Gets the list of available time markers in Dime.Scheduler", + "description": "Fetches the list of time markers", + "operationId": "GetTimeMarkers", + "tags": [ + "indicator" + ] + }, + "post": { + "summary": "Add or update a time marker", + "description": "Add or update a time marker, which is the visual indicator that renders the underscore of the appointment.", + "operationId": "Timemarker", + "tags": [ + "indicator" + ], + "parameters": [ + { + "name": "timeMarkerUpsert", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/timeMarker" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a time marker", + "description": "Remove a time marker, which is the visual indicator that renders the underscore of the appointment.", + "operationId": "timeMarkerDelete", + "tags": [ + "indicator" + ], + "parameters": [ + { + "name": "timeMarker", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/timeMarker" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/pin": { + "post": { + "summary": "Add or update a pin", + "description": "Add or update a pin, which is the visual indicator that renders the colors of the markers on the map.", + "operationId": "pinUpsert", + "tags": [ + "indicator" + ], + "parameters": [ + { + "name": "pin", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/pin" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a pin", + "description": "Remove a pin, which is the visual indicator that renders the colors of the markers on the map.", + "operationId": "pinDelete", + "tags": [ + "indicator" + ], + "parameters": [ + { + "name": "pin", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/pin" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/resource": { + "get": { + "responses": { + "200": { + "description": "Response to successful retrieval resources", + "x-ms-summary": "Success response", + "schema": { + "$ref": "#/definitions/resourcelist" + } + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "x-ms-visibility": "internal", + "summary": "Gets the list of available resources in Dime.SCheduler", + "description": "Fetches the list of resources", + "operationId": "GetResources", + "tags": [ + "resource" + ] + }, + "post": { + "summary": "Add or update a resource", + "description": "Add or update a resource.", + "operationId": "resourceUpsert", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resource", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resource" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a resource", + "description": "Remove a resource.", + "operationId": "resourceDelete", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resource", + "in": "body", + "schema": { + "$ref": "#/definitions/resource" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/actionUri": { + "post": { + "summary": "Add or update an action link", + "description": "Add or update an action link.", + "operationId": "actionUriUpsert", + "parameters": [ + { + "name": "actionUri", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/actionUri" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove an action link", + "description": "Remove an action link.", + "operationId": "actionUriDelete", + "parameters": [ + { + "name": "actionUri", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/actionUri" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/appointment": { + "post": { + "summary": "Add an appointment", + "description": "Add an appointment.", + "operationId": "appointmentUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointment-outgoing-new" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "put": { + "summary": "Update an appointment", + "description": "Update an appointment.", + "operationId": "appointmentUpdate", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointment-outgoing" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove an appointment", + "description": "Remove an appointment.", + "operationId": "appointmentDelete", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "body", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointment-outgoing" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/appointmentCategory": { + "post": { + "summary": "Set the category of an appointment", + "description": "Set the category of an appointment.", + "operationId": "appointmentCategoryUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentCategory", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointmentCategory" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/appointmentContainer": { + "post": { + "summary": "Add or update an appointment container", + "description": "Add or update an appointment container.", + "operationId": "appointmentContainerUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentContainer", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointmentContainer" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove an appointment container", + "description": "Remove an appointment container.", + "operationId": "appointmentContainerDelete", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentContainer", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointmentContainer" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/appointmentContent": { + "post": { + "summary": "Set the content of the appointment", + "description": "Set the content of the appointment.", + "operationId": "appointmentContentUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentContent", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointmentContent" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/appointmentImportance": { + "post": { + "summary": "Set the priority of an appointment", + "description": "Set the priority of an appointment.", + "operationId": "appointmentImportanceUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentImportance", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointmentImportance" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/appointmentLocked": { + "post": { + "summary": "Set the appointment's locked status", + "description": "Set the appointment's locked status.", + "operationId": "appointmentLockedUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentLocked", + "in": "body", + "schema": { + "$ref": "#/definitions/appointmentLocked" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/appointmentPlanningQuantity": { + "post": { + "summary": "Set the appointment's planning quantity", + "description": "Set the appointment's planning quantity.", + "operationId": "appointmentPlanningQuantityUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentPlanningQuantity", + "in": "body", + "schema": { + "$ref": "#/definitions/appointmentPlanningQuantity" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/appointmentTimeMarker": { + "post": { + "summary": "Set the time marker of an appointment", + "description": "Set the time marker of an appointment", + "operationId": "appointmentTimemarkerUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentTimeMarker", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointmentTimeMarker" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/appointmentUri": { + "post": { + "summary": "Add or update an appointment link", + "description": "Add or update an appointment link.", + "operationId": "appointmentUriUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentUri", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointmentUri" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove an appointment link", + "description": "Remove an appointment link.", + "operationId": "appointmentUriDelete", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "appointmentUri", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/appointmentUri" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/assignment": { + "post": { + "summary": "Add or update an assignment", + "description": "Add or update an assignment, which is the allocation of a resource to an appointment.", + "operationId": "assignmentUpsert", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "assignment", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/assignment" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove an assignment", + "description": "Remove an assignment, which is the allocation of a resource to an appointment.", + "operationId": "assignmentDelete", + "tags": [ + "appointment" + ], + "parameters": [ + { + "name": "assignment", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/assignment" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/caption": { + "post": { + "summary": "Add or update a caption", + "description": "Add or update a caption.", + "operationId": "captionUpsert", + "parameters": [ + { + "name": "caption", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/caption" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a caption", + "description": "Remove a caption.", + "operationId": "captionDelete", + "parameters": [ + { + "name": "caption", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/caption" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/calendar": { + "get": { + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Response to successful retrieval calendars", + "x-ms-summary": "Success response", + "schema": { + "$ref": "#/definitions/calendarlist" + } + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "x-ms-visibility": "internal", + "summary": "Gets the list of available calendars in Dime.Scheduler", + "description": "Fetches the list of calendars", + "operationId": "GetCalendars" + } + }, + "/container": { + "post": { + "summary": "Add or update a container", + "description": "Add or update a container.", + "operationId": "containerUpsert", + "parameters": [ + { + "name": "container", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/container" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a container", + "description": "Remove a container.", + "operationId": "containerDelete", + "parameters": [ + { + "name": "container", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/container" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/filterGroup": { + "get": { + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Response to successful retrieval filter groups", + "x-ms-summary": "Success response", + "schema": { + "$ref": "#/definitions/filtergrouplist" + } + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "x-ms-visibility": "internal", + "summary": "Gets the list of available filter groups in Dime.Scheduler", + "description": "Fetches the list of filter groups", + "operationId": "GetFilterGroups", + "tags": [ + "filters" + ] + }, + "post": { + "summary": "Add or update a filter group", + "description": "Add or update a filter group.", + "operationId": "filterGroupUpsert", + "tags": [ + "filters" + ], + "parameters": [ + { + "name": "filterGroup", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/filterGroup" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a filter group", + "description": "Remove a filter group.", + "operationId": "filterGroupDelete", + "tags": [ + "filters" + ], + "parameters": [ + { + "name": "filterGroup", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/filterGroup" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/filterValue": { + "get": { + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "Response to successful retrieval filter values", + "x-ms-summary": "Success response", + "schema": { + "$ref": "#/definitions/filtervaluelist" + } + }, + "401": { + "description": "Unauthenticated." + }, + "403": { + "description": "Access forbidden." + }, + "429": { + "description": "Resource exhausted. More than expected number of webhooks have been created." + }, + "500": { + "description": "Internal server error." + } + }, + "x-ms-visibility": "internal", + "summary": "Gets the list of available filter values in Dime.Scheduler", + "description": "Fetches the list of filter values", + "operationId": "GetFilterValues", + "tags": [ + "filters" + ] + }, + "post": { + "summary": "Add or update a filter value", + "description": "Add or update a filter value.", + "operationId": "filterValueUpsert", + "tags": [ + "filters" + ], + "parameters": [ + { + "name": "filterValue", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/filterValue" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a filter value", + "description": "Remove a filter value.", + "operationId": "filterValueDelete", + "tags": [ + "filters" + ], + "parameters": [ + { + "name": "filterValue", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/filterValue" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/job": { + "post": { + "summary": "Add or update a job", + "description": "Add or update a job.", + "operationId": "jobUpsert", + "tags": [ + "task" + ], + "parameters": [ + { + "name": "job", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/job" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a job", + "description": "Remove a job.", + "operationId": "jobDelete", + "tags": [ + "task" + ], + "parameters": [ + { + "name": "job", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/job-delete" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/notification": { + "post": { + "summary": "Add or update a notification", + "description": "Add or update a notification.", + "operationId": "notificationUpsert", + "parameters": [ + { + "name": "notification", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/notification" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a notification", + "description": "Remove a notification.", + "operationId": "notificationDelete", + "parameters": [ + { + "name": "notification", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/notification" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/resourceCalendar": { + "post": { + "summary": "Add or update a calendar for a resource", + "description": "Add or update a calendar for a resource.", + "operationId": "resourceCalendarUpsert", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceCalendar", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceCalendar" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a calendar for a resource", + "description": "Remove a calendar for a resource.", + "operationId": "resourceCalendarDelete", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceCalendar", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceCalendar" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/resourceCapacity": { + "post": { + "summary": "Set the capacity of a resource", + "description": "Set the capacity of a resource.", + "operationId": "resourceCapacityUpsert", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceCapacity", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceCapacity" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove the capacity of a resource", + "description": "Remove the capacity of a resource.", + "operationId": "resourceCapacityDelete", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceCapacity", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceCapacity" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/resourceFilterValue": { + "post": { + "summary": "Set the filter value of a resource", + "description": "Set the filter value of a resource.", + "operationId": "resourceFilterValueUpsert", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceFilterValue", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceFilterValue" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove the filter value of a resource", + "description": "Remove the filter value of a resource.", + "operationId": "resourceFilterValueDelete", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceFilterValue", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceFilterValue" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/resourceGpsTracking": { + "post": { + "summary": "Set the live location of a resource", + "description": "Set the live location of a resource.", + "operationId": "resourceGpstrackingUpsert", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceGpsTracking", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceGpsTracking" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove the live location of a resource", + "description": "Remove the live location of a resource.", + "operationId": "resourceGpstrackingDelete", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceGpsTracking", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceGpsTracking" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/resourceUri": { + "post": { + "summary": "Set the uri of a resource", + "description": "Set the uri of a resource.", + "operationId": "resourceUriUpsert", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceUri", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceUri" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove the uri of a resource", + "description": "Remove the uri of a resource.", + "operationId": "resourceUriDelete", + "tags": [ + "resource" + ], + "parameters": [ + { + "name": "resourceUri", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/resourceUri" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/task": { + "post": { + "summary": "Add or update a task", + "description": "Add or update a task.", + "operationId": "taskUpsert", + "tags": [ + "task" + ], + "parameters": [ + { + "name": "task", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/task" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a task", + "description": "Remove a task.", + "operationId": "taskDelete", + "tags": [ + "task" + ], + "parameters": [ + { + "name": "task", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/task-delete" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/taskContainer": { + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Add or update a task container", + "description": "Add or update a task container.", + "operationId": "taskContainerUpsert", + "tags": [ + "task" + ], + "parameters": [ + { + "name": "taskContainer", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/taskContainer" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Remove a task container", + "description": "Remove a task container.", + "operationId": "taskContainerDelete", + "tags": [ + "task" + ], + "parameters": [ + { + "name": "taskContainer", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/taskContainer" + } + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/taskFilterValue": { + "post": { + "summary": "Add or update a task filter value", + "description": "Add or update a task filter value.", + "operationId": "taskFiltervalueUpsert", + "tags": [ + "task" + ], + "parameters": [ + { + "name": "taskFilterValue", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/taskFilterValue" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + }, + "delete": { + "summary": "Remove a task filter value", + "description": "Remove a task filter value.", + "operationId": "taskFiltervalueDelete", + "tags": [ + "task" + ], + "parameters": [ + { + "name": "taskFilterValue", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/taskFilterValue" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + }, + "/taskLocked": { + "post": { + "summary": "Set the task's locked status", + "description": "Set the task's locked status.", + "operationId": "taskLockedUpsert", + "tags": [ + "task" + ], + "parameters": [ + { + "name": "taskLocked", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/taskLocked" + }, + "description": "JSON request body containing the contents of the requested entity to be posted." + } + ], + "responses": { + "200": { + "$ref": "#/responses/200" + }, + "400": { + "$ref": "#/responses/400" + }, + "500": { + "$ref": "#/responses/500" + }, + "default": { + "$ref": "#/responses/default" + } + } + } + } + }, + "definitions": { + "actionUri": { + "type": "object", + "required": [ + "uri" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "uriType": { + "x-ms-summary": "URI type", + "format": "int32", + "type": "integer", + "description": "The scope of the action URI", + "x-ms-enum-values": [ + { + "displayName": "Planning Board", + "value": 0 + }, + { + "displayName": "Appointment", + "value": 1 + }, + { + "displayName": "Task", + "value": 2 + }, + { + "displayName": "Map", + "value": 3 + } + ], + "enum": [ + 0, + 1, + 2, + 3 + ] + }, + "uri": { + "x-ms-summary": "URI", + "description": "The URI to call upon invocation", + "type": "string" + }, + "description": { + "x-ms-summary": "Description", + "description": "The display text of the action URI", + "maxLength": 255, + "type": "string" + }, + "default": { + "x-ms-summary": "Default", + "type": "boolean" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "uriType": 0, + "uri": "string", + "description": "string", + "default": true + } + }, + "appointment-outgoing": { + "type": "object", + "properties": { + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "description": "The unique identifier that is associated with the job.", + "maxLength": 50, + "type": "string" + }, + "taskNo": { + "x-ms-summary": "Task no.", + "description": "The unique identifier that is associated with the task.", + "maxLength": 50, + "type": "string" + }, + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "subject": { + "x-ms-summary": "Subject", + "description": "The appointment's subject", + "type": "string" + }, + "body": { + "x-ms-summary": "Body", + "description": "The appointment's body", + "type": "string" + }, + "start": { + "x-ms-summary": "Start", + "description": "The start date of the appointment", + "format": "date-time", + "type": "string" + }, + "end": { + "x-ms-summary": "End", + "description": "The end date of the appointment", + "format": "date-time", + "type": "string" + }, + "timeMarkerId": { + "type": "integer", + "x-ms-summary": "Time Marker", + "description": "Specifies the color of the horizontal bar at the bottom of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "x-ms-dynamic-values": { + "operationId": "GetTimeMarkers", + "value-path": "id", + "value-title": "name" + } + }, + "categoryId": { + "type": "integer", + "x-ms-summary": "Category", + "description": "Specifies the background color of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "x-ms-dynamic-values": { + "operationId": "GetCategories", + "value-path": "id", + "value-title": "name" + } + }, + "importance": { + "x-ms-summary": "Importance", + "type": "integer", + "default": 0, + "x-ms-enum-values": [ + { + "displayName": "Medium", + "value": 0 + }, + { + "displayName": "High", + "value": 1 + }, + { + "displayName": "Low", + "value": 2 + } + ], + "enum": [ + 0, + 1, + 2 + ] + }, + "locked": { + "x-ms-summary": "Locked", + "type": "boolean" + }, + "replaceResource": { + "x-ms-summary": "Replace resource", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "backOfficeId": { + "x-ms-summary": "Back office id", + "maxLength": 100, + "type": "string", + "x-ms-visibility": "advanced" + }, + "backOfficeParentId": { + "x-ms-summary": "Back office parent id", + "maxLength": 100, + "type": "string", + "x-ms-visibility": "advanced" + }, + "unitOfMeasure": { + "x-ms-summary": "Unit of measure", + "maxLength": 20, + "type": "string", + "x-ms-visibility": "advanced" + }, + "unitOfMeasureConversion": { + "x-ms-summary": "Unit of measure conversion", + "format": "double", + "type": "number", + "x-ms-visibility": "advanced" + }, + "planningQuantity": { + "x-ms-summary": "Planning quantity", + "format": "double", + "type": "number", + "x-ms-visibility": "advanced" + }, + "useFixedPlanningQuantity": { + "x-ms-summary": "Use fixed planning quantity", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "roundToUnitOfMeasure": { + "x-ms-summary": "Round to unit of measure", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + } + }, + "appointment-outgoing-new": { + "type": "object", + "required": [ + "sourceApp", + "sourceType", + "jobNo", + "taskNo", + "resourceNo", + "start", + "end" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "description": "The unique identifier that is associated with the job.", + "maxLength": 50, + "type": "string" + }, + "taskNo": { + "x-ms-summary": "Task no.", + "description": "The unique identifier that is associated with the task.", + "maxLength": 50, + "type": "string" + }, + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "subject": { + "x-ms-summary": "Subject", + "description": "The appointment's subject", + "type": "string" + }, + "body": { + "x-ms-summary": "Body", + "description": "The appointment's body", + "type": "string" + }, + "start": { + "x-ms-summary": "Start", + "description": "The start date. Use ISO 8601 standard. For example 2023-11-16T10:09:21Z", + "format": "date-time", + "type": "string" + }, + "end": { + "x-ms-summary": "End", + "description": "The end date. Use ISO 8601 standard. For example 2023-11-16T10:09:21Z", + "format": "date-time", + "type": "string" + }, + "timeMarkerId": { + "type": "integer", + "description": "Specifies the color of the horizontal bar at the bottom of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "x-ms-summary": "Time Marker", + "x-ms-dynamic-values": { + "operationId": "GetTimeMarkers", + "value-path": "id", + "value-title": "name" + } + }, + "categoryId": { + "type": "integer", + "x-ms-summary": "Category", + "description": "Specifies the background color of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "x-ms-dynamic-values": { + "operationId": "GetCategories", + "value-path": "id", + "value-title": "name" + } + }, + "importance": { + "x-ms-summary": "Importance", + "type": "integer", + "default": 0, + "x-ms-enum-values": [ + { + "displayName": "Medium", + "value": 0 + }, + { + "displayName": "High", + "value": 1 + }, + { + "displayName": "Low", + "value": 2 + } + ], + "enum": [ + 0, + 1, + 2 + ] + }, + "locked": { + "x-ms-summary": "Locked", + "description": "Set to true to make the appointment immutable.", + "type": "boolean" + }, + "replaceResource": { + "x-ms-summary": "Replace resource", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "backOfficeId": { + "x-ms-summary": "Back office id", + "maxLength": 100, + "type": "string", + "x-ms-visibility": "advanced" + }, + "backOfficeParentId": { + "x-ms-summary": "Back office parent id", + "maxLength": 100, + "type": "string", + "x-ms-visibility": "advanced" + }, + "unitOfMeasure": { + "x-ms-summary": "Unit of measure", + "maxLength": 20, + "type": "string", + "x-ms-visibility": "advanced" + }, + "unitOfMeasureConversion": { + "x-ms-summary": "Unit of measure conversion", + "format": "double", + "type": "number", + "x-ms-visibility": "advanced" + }, + "planningQuantity": { + "x-ms-summary": "Planning quantity", + "format": "double", + "type": "number", + "x-ms-visibility": "advanced" + }, + "useFixedPlanningQuantity": { + "x-ms-summary": "Use fixed planning quantity", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "roundToUnitOfMeasure": { + "x-ms-summary": "Round to unit of measure", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + } + }, + "appointment-incoming": { + "type": "object", + "properties": { + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "id": { + "format": "int64", + "type": "integer" + }, + "ExternalId": { + "type": "integer" + }, + "Subject": { + "type": "string", + "description": "The appointment's subject" + }, + "Body": { + "type": "string", + "description": "The appointment's body" + }, + "StartDate": { + "type": "string", + "format": "date-time", + "title": "Start date", + "description": "The appointment's start date" + }, + "EndDate": { + "type": "string", + "format": "date-time", + "title": "End date", + "description": "The appointment's end date" + }, + "Importance": { + "type": "integer", + "description": "The priority of this appointment" + }, + "AppointmentGuid": { + "type": "string", + "description": "The appointment's GUID" + }, + "Locked": { + "type": "boolean", + "description": "Set to true if the appointment is immutable." + }, + "PlanningUOM": { + "type": "string", + "title": "Planning unit of measure", + "description": "Planning unit of measure" + }, + "PlanningQty": { + "format": "double", + "type": "number", + "title": "Planning quantity", + "description": "Planning quantity" + }, + "UseFixPlanningQty": { + "type": "boolean", + "title": "Use fixed planning quantity", + "description": "Set to true to use fixed planning quantity" + }, + "RoundToUOM": { + "type": "boolean", + "title": "Round to unit of measure", + "description": "Set to true when round to unit of measure" + }, + "LastModifiedDate": { + "type": "string", + "title": "Last modified date" + }, + "LastModifiedUser": { + "type": "string", + "title": "Last modified user" + }, + "IsRecurrenceException": { + "type": "boolean", + "title": "Is recurrence exception" + }, + "CapacityIndicator": { + "type": "boolean", + "title": "Capacity indicator" + }, + "AppointmentFieldValues": { + "type": "array", + "items": {} + }, + "AppointmentUrls": { + "type": "array", + "items": {} + }, + "AppointmentContainers": { + "type": "array", + "items": {} + }, + "Notifications": { + "type": "array", + "items": {} + }, + "CreatedDate": { + "type": "string", + "title": "Created on" + }, + "CreatedUser": { + "type": "string", + "title": "Created by" + }, + "Task": { + "type": "object", + "properties": { + "TaskNo": { + "type": "string", + "title": "Task No" + }, + "Job": { + "type": "object", + "properties": { + "SourceApp": { + "type": "string", + "title": "Job source app" + }, + "SourceType": { + "type": "string", + "title": "Job source type" + }, + "JobNo": { + "type": "string", + "title": "Job No" + } + } + } + } + }, + "Category": { + "type": "object", + "properties": { + "DisplayName": { + "type": "string", + "title": "Category name" + }, + "Color": { + "type": "string", + "title": "Category color" + } + } + }, + "TimeMarker": { + "type": "object", + "properties": { + "Name": { + "type": "string", + "title": "Time marker name" + }, + "Color": { + "type": "string", + "title": "Time marker color" + } + } + }, + "Assignments": { + "type": "array", + "description": "The list of resources assigned to the appointment.", + "items": { + "type": "object", + "properties": { + "ResourceId": { + "type": "integer", + "x-ms-visibility": "internal" + }, + "Resource": { + "type": "object", + "description": "The resource", + "properties": { + "ResourceType": { + "type": "object", + "properties": { + "DisplayName": { + "type": "string", + "title": "Resource type name" + } + } + }, + "SourceApp": { + "type": "string", + "title": "Resource source app", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to." + }, + "SourceType": { + "type": "string", + "title": "Resource source type", + "description": "A discriminator that describes the type of entity that this record represents." + }, + "DisplayName": { + "type": "string", + "title": "Resource display name" + }, + "Department": { + "type": "string", + "title": "Resource department" + }, + "ResourceNo": { + "type": "string", + "title": "Resource Number" + }, + "Email": { + "type": "string", + "title": "Resource email" + } + } + } + } + } + } + }, + "example": { + "appointmentGuid": "04cd4567-1295-4226-86bd-5b1e99d7bab8", + "sourceApp": "MYCRMAPP", + "sourceType": "DEMO", + "jobNo": "DS_DEMO", + "taskNo": "DS_DEMO_15MIN", + "resourceNo": "JOHNDOE", + "subject": "Dime.Scheduler 15 minute introduction", + "body": "Dime.Scheduler 15 minute introduction. Teams meeting.", + "start": "2022-10-01T15:00:00Z", + "end": "2022-10-01T15:15:00Z" + } + }, + "appointmentCategory": { + "type": "object", + "required": [ + "appointmentNo", + "category" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string", + "x-ms-visibility": "advanced" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string", + "x-ms-visibility": "advanced" + }, + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "category": { + "x-ms-summary": "Category", + "maxLength": 100, + "type": "string", + "description": "Specifies the background color of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "x-ms-dynamic-values": { + "operationId": "GetCategories", + "value-path": "name", + "value-title": "name" + } + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "category": "string", + "appointmentGuid": "string" + } + }, + "appointmentContainer": { + "type": "object", + "required": [ + "appointment", + "container" + ], + "properties": { + "container": { + "x-ms-summary": "Container", + "description": "The container code to assign this appointment to", + "maxLength": 100, + "type": "string" + }, + "appointment": { + "x-ms-summary": "Appointment", + "description": "The appointment's identifier", + "maxLength": 100, + "type": "string" + } + }, + "example": { + "container": "string", + "appointment": "string" + } + }, + "appointmentContent": { + "type": "object", + "required": [ + "appointmentNo" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string", + "x-ms-visibility": "advanced" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string", + "x-ms-visibility": "advanced" + }, + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "subject": { + "x-ms-summary": "Subject", + "description": "The appointment's subject", + "type": "string" + }, + "body": { + "x-ms-summary": "Body", + "description": "The appointment's body", + "type": "string" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "appointmentGuid": "string", + "subject": "string", + "body": "string" + } + }, + "appointmentImportance": { + "type": "object", + "required": [ + "appointmentNo", + "importance" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string", + "x-ms-visibility": "advanced" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string", + "x-ms-visibility": "advanced" + }, + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "importance": { + "x-ms-summary": "Importance", + "description": "The appointment's priority", + "format": "int32", + "default": 0, + "x-ms-enum-values": [ + { + "displayName": "Medium", + "value": 0 + }, + { + "displayName": "High", + "value": 1 + }, + { + "displayName": "Low", + "value": 2 + } + ], + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "importance": 0, + "appointmentGuid": "string" + } + }, + "appointmentLocked": { + "type": "object", + "required": [ + "appointmentNo", + "locked" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string", + "x-ms-visibility": "advanced" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string", + "x-ms-visibility": "advanced" + }, + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "locked": { + "x-ms-summary": "Locked", + "description": "True to lock the appointment, and false to unlock.", + "type": "boolean" + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "locked": true, + "appointmentGuid": "string" + } + }, + "appointmentPlanningQuantity": { + "type": "object", + "required": [ + "appointmentNo", + "quantity" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string", + "x-ms-visibility": "advanced" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string", + "x-ms-visibility": "advanced" + }, + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "quantity": { + "x-ms-summary": "Quantity", + "description": "The planning quantity value", + "format": "double", + "type": "number" + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "quantity": 0, + "appointmentGuid": "string" + } + }, + "appointmentTimeMarker": { + "type": "object", + "required": [ + "appointmentNo", + "timeMarker" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string", + "x-ms-visibility": "advanced" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string", + "x-ms-visibility": "advanced" + }, + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "timeMarker": { + "x-ms-summary": "Time marker", + "description": "Specifies the color of the horizontal bar at the bottom of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "maxLength": 100, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetTimeMarkers", + "value-path": "name", + "value-title": "name" + } + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "timeMarker": "string", + "appointmentGuid": "string" + } + }, + "appointmentUri": { + "type": "object", + "required": [ + "appointmentNo", + "uri", + "description" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "uri": { + "x-ms-summary": "URI", + "description": "The absolute URI", + "maxLength": 1000, + "type": "string" + }, + "description": { + "x-ms-summary": "Description", + "description": "The display text for the URI", + "maxLength": 255, + "type": "string" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "appointmentGuid": "string", + "uri": "string", + "description": "string" + } + }, + "assignment": { + "type": "object", + "required": [ + "appointmentNo", + "resourceNo", + "sourceApp", + "sourceType" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "The appointment's identifier", + "type": "string" + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "appointmentGuid": "string", + "resourceNo": "string" + } + }, + "calendarlist": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "x-ms-summary": "id", + "maxLength": 100, + "type": "integer" + }, + "name": { + "x-ms-summary": "name", + "maxLength": 100, + "type": "string" + }, + "code": { + "x-ms-summary": "Code", + "maxLength": 100, + "type": "string" + } + }, + "example": {} + } + }, + "caption": { + "type": "object", + "required": [ + "context" + ], + "properties": { + "context": { + "x-ms-summary": "Context", + "format": "int32", + "default": 1, + "x-ms-enum-values": [ + { + "displayName": "Resource", + "value": 1 + }, + { + "displayName": "Appointment", + "value": 2 + }, + { + "displayName": "Appointment Field Value", + "value": 3 + }, + { + "displayName": "Database Field", + "value": 6 + }, + { + "displayName": "Task Details", + "value": 7 + }, + { + "displayName": "Context", + "value": 10 + }, + { + "displayName": "Target Pane", + "value": 11 + }, + { + "displayName": "Target Pane Group", + "value": 12 + }, + { + "displayName": "Task", + "value": 13 + }, + { + "displayName": "Job", + "value": 14 + } + ], + "enum": [ + 1, + 2, + 3, + 6, + 7, + 10, + 11, + 12, + 13, + 14 + ], + "type": "integer" + }, + "sourceTable": { + "x-ms-summary": "Source table", + "description": "The entity name. Choose between Job, Resource, Task, Appointment", + "maxLength": 255, + "type": "string" + }, + "fieldName": { + "x-ms-summary": "Field name", + "description": "The field's identifier", + "maxLength": 255, + "type": "string" + }, + "language": { + "x-ms-summary": "Language", + "description": "The language code", + "maxLength": 10, + "type": "string" + }, + "text": { + "x-ms-summary": "Text", + "description": "The custom caption", + "maxLength": 100, + "type": "string" + } + }, + "example": { + "context": 0, + "sourceTable": "string", + "fieldName": "string", + "language": "string", + "text": "string" + } + }, + "category": { + "type": "object", + "required": [ + "name", + "displayName" + ], + "properties": { + "name": { + "x-ms-summary": "Name", + "description": "Specifies the background color of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "maxLength": 100, + "type": "string" + }, + "displayName": { + "x-ms-summary": "Display name", + "description": "Specifies the background color of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "maxLength": 100, + "type": "string" + }, + "color": { + "x-ms-summary": "Color", + "description": "The hex color code", + "maxLength": 7, + "type": "string" + } + }, + "example": { + "name": "OOO", + "displayName": "Out of office", + "color": "#7f61ff" + } + }, + "categorylist": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "x-ms-summary": "id", + "maxLength": 100, + "type": "string" + }, + "name": { + "x-ms-summary": "Name", + "maxLength": 100, + "type": "string" + }, + "displayName": { + "x-ms-summary": "Display name", + "maxLength": 100, + "type": "string" + }, + "color": { + "x-ms-summary": "Color", + "maxLength": 7, + "type": "string" + } + } + }, + "example": { + "name": "OOO", + "displayName": "Out of office", + "color": "#7f61ff" + } + }, + "container": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "x-ms-summary": "Name", + "description": "The container's name", + "maxLength": 100, + "type": "string" + }, + "handleDate": { + "x-ms-summary": "Handle date", + "description": "The handle date. Use ISO 8601 standard. For example 2023-11-16T10:09:21Z", + "format": "date-time", + "type": "string" + }, + "handleLocked": { + "x-ms-summary": "Handle locked", + "description": "True to fix the relative position of the handle bar to the container members.", + "type": "boolean" + } + }, + "example": { + "name": "Project Icarus", + "handleDate": "2022-01-01T10:00", + "handleLocked": true + } + }, + "filterGroup": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "id": { + "x-ms-summary": "Id", + "format": "int32", + "type": "integer", + "x-ms-visibility": "internal" + }, + "name": { + "x-ms-summary": "Name", + "description": "The name that describes the group of filter values.", + "maxLength": 50, + "type": "string" + }, + "columnNo": { + "x-ms-summary": "Column no.", + "format": "int32", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "dataFilter": { + "x-ms-summary": "Date filter", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "id": 0, + "name": "Driver's license", + "columnNo": 0, + "dataFilter": true + } + }, + "filtergrouplist": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "x-ms-summary": "Id", + "format": "int32", + "type": "integer" + }, + "name": { + "x-ms-summary": "Name", + "maxLength": 50, + "type": "string" + }, + "columnNo": { + "x-ms-summary": "Column no.", + "format": "int32", + "type": "integer" + }, + "dataFilter": { + "x-ms-summary": "Date filter", + "type": "boolean" + } + } + }, + "example": { + "id": 0, + "name": "Driver's license", + "columnNo": 0, + "dataFilter": true + } + }, + "filterValue": { + "type": "object", + "required": [ + "group", + "value" + ], + "properties": { + "group": { + "x-ms-summary": "Group", + "description": "The name of the filter group. For example: Skill, Region, Language.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetFilterGroups", + "value-path": "Name", + "value-title": "Name" + } + }, + "value": { + "x-ms-summary": "Value", + "description": "The name that describes this filter value. For example: French, English, Spanish.", + "maxLength": 100, + "type": "string" + } + }, + "example": { + "group": "Driver's license", + "value": "Class B" + } + }, + "filtervaluelist": { + "type": "array", + "items": { + "type": "object", + "properties": { + "group": { + "x-ms-summary": "Group", + "maxLength": 50, + "type": "string" + }, + "value": { + "x-ms-summary": "Value", + "maxLength": 100, + "type": "string" + } + }, + "example": { + "group": "Driver's license", + "value": "Class B" + } + } + }, + "job": { + "type": "object", + "required": [ + "sourceApp", + "sourceType", + "jobNo", + "shortDescription" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "description": "The unique identifier that is associated with the job.", + "maxLength": 50, + "type": "string" + }, + "shortDescription": { + "x-ms-summary": "Short description", + "description": "Summary of the scope of this job", + "maxLength": 50, + "type": "string" + }, + "description": { + "x-ms-summary": "Description", + "description": "Describes the scope of this job", + "type": "string" + }, + "type": { + "x-ms-summary": "Type", + "description": "The type of job", + "maxLength": 50, + "type": "string" + }, + "name": { + "x-ms-summary": "Name", + "description": "The job's name", + "maxLength": 255, + "type": "string" + }, + "timeMarker": { + "type": "string", + "x-ms-summary": "Time Marker", + "description": "Specifies the color of the horizontal bar at the bottom of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "x-ms-dynamic-values": { + "operationId": "GetTimeMarkers", + "value-path": "name", + "value-title": "name" + } + }, + "category": { + "type": "string", + "x-ms-summary": "Category", + "description": "Specifies the background color of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "x-ms-dynamic-values": { + "operationId": "GetCategories", + "value-path": "name", + "value-title": "name" + } + }, + "pin": { + "x-ms-summary": "Pin", + "description": "Specifies the color of the marker on the map", + "maxLength": 100, + "type": "string" + }, + "customerNo": { + "x-ms-summary": "Customer no.", + "description": "The customer number", + "maxLength": 20, + "type": "string" + }, + "customerName": { + "x-ms-summary": "Customer name", + "description": "The customer name", + "maxLength": 50, + "type": "string" + }, + "customerAddress": { + "x-ms-summary": "Customer address", + "description": "The customer address", + "type": "string" + }, + "customerAddressGeoLong": { + "x-ms-summary": "Customer address longitude", + "description": "The customer's address longitude coordinate", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "customerAddressGeoLat": { + "x-ms-summary": "Customer address latitude", + "description": "The customer's address latitude coordinate", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "customerPhone": { + "x-ms-summary": "Customer phone", + "description": "The customer's phone number", + "maxLength": 50, + "type": "string" + }, + "customerEmail": { + "x-ms-summary": "Customer e-mail", + "description": "The customer's email address", + "maxLength": 50, + "type": "string", + "format": "email" + }, + "contactNo": { + "x-ms-summary": "Contact no.", + "description": "The customer's contact number", + "maxLength": 20, + "type": "string" + }, + "contactName": { + "x-ms-summary": "Contact name", + "description": "The customer's contact name", + "maxLength": 50, + "type": "string" + }, + "contactAddress": { + "x-ms-summary": "Contact address", + "description": "The customer's contact address", + "type": "string" + }, + "contactAddressGeoLong": { + "x-ms-summary": "Contact address longitude", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "contactAddressGeoLat": { + "x-ms-summary": "Contact address latitude", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "contactPhone": { + "x-ms-summary": "Contact phone", + "description": "The customer's contact phone", + "maxLength": 50, + "type": "string" + }, + "contactEmail": { + "x-ms-summary": "Contact e-mail", + "description": "The customer's contact email address", + "maxLength": 50, + "type": "string", + "format": "email" + }, + "siteNo": { + "x-ms-summary": "Site no.", + "description": "The job's site number", + "maxLength": 20, + "type": "string" + }, + "siteName": { + "x-ms-summary": "Site name", + "description": "The job's site name", + "maxLength": 50, + "type": "string" + }, + "siteAddress": { + "x-ms-summary": "Site address", + "description": "The job's site address. This field is used in geocoding.", + "type": "string" + }, + "siteAddressGeoLong": { + "x-ms-summary": "Site address longitude", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "siteAddressGeoLat": { + "x-ms-summary": "Site address latitude", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "sitePhone": { + "x-ms-summary": "Site phone", + "description": "The job's site phone number", + "maxLength": 50, + "type": "string" + }, + "siteEmail": { + "x-ms-summary": "Site e-mail", + "description": "The job's site email address", + "maxLength": 50, + "type": "string", + "format": "email" + }, + "siteRegion": { + "x-ms-summary": "Site region", + "description": "The job's site region. This field is used in geocoding.", + "maxLength": 10, + "type": "string" + }, + "siteStreet": { + "x-ms-summary": "Site street", + "description": "The job's site street. This field is used in geocoding.", + "maxLength": 255, + "type": "string" + }, + "siteStreetNo": { + "x-ms-summary": "Site street no.", + "description": "The job's site street number. This field is used in geocoding.", + "maxLength": 20, + "type": "string" + }, + "sitePostcode": { + "x-ms-summary": "Site post code", + "description": "The job's site ZIP number. This field is used in geocoding.", + "maxLength": 20, + "type": "string" + }, + "siteCity": { + "x-ms-summary": "Site city", + "description": "The job's site city. This field is used in geocoding.", + "maxLength": 50, + "type": "string" + }, + "siteCounty": { + "x-ms-summary": "Site county", + "description": "The job's site county. This field is used in geocoding.", + "maxLength": 50, + "type": "string" + }, + "siteState": { + "x-ms-summary": "Site state", + "description": "The job's site state. This field is used in geocoding.", + "maxLength": 50, + "type": "string" + }, + "siteCountry": { + "x-ms-summary": "Site country", + "description": "The job's site country. This field is used in geocoding.", + "maxLength": 50, + "type": "string" + }, + "siteFromNo": { + "x-ms-summary": "Site from no.", + "description": "The job's site from number.", + "maxLength": 20, + "type": "string" + }, + "siteFromName": { + "x-ms-summary": "Site from name", + "description": "The job's site from name.", + "maxLength": 50, + "type": "string" + }, + "siteFromAddress": { + "x-ms-summary": "Site from address", + "description": "The job's site from address.", + "type": "string" + }, + "siteFromAddressGeoLong": { + "x-ms-summary": "Site from longitude", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "siteFromAddressGeoLat": { + "x-ms-summary": "Site from latitude", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "siteFromPhone": { + "x-ms-summary": "Site from phone", + "description": "The job's site from phone number.", + "maxLength": 50, + "type": "string" + }, + "siteFromEmail": { + "x-ms-summary": "Site from e-mail", + "description": "The job's site from email address.", + "maxLength": 50, + "type": "string", + "format": "email" + }, + "siteFromRegion": { + "x-ms-summary": "Site from region", + "description": "The job's site from region.", + "maxLength": 10, + "type": "string" + }, + "siteFromStreet": { + "x-ms-summary": "Site from street", + "description": "The job's site from street.", + "maxLength": 255, + "type": "string" + }, + "siteFromStreetNo": { + "x-ms-summary": "Site from street no.", + "description": "The job's site from street no.", + "maxLength": 20, + "type": "string" + }, + "siteFromPostcode": { + "x-ms-summary": "Site from post code", + "description": "The job's site from ZIP code.", + "maxLength": 20, + "type": "string" + }, + "siteFromCity": { + "x-ms-summary": "Site from city", + "description": "The job's site from city.", + "maxLength": 50, + "type": "string" + }, + "siteFromCounty": { + "x-ms-summary": "Site from county", + "description": "The job's site from county.", + "maxLength": 50, + "type": "string" + }, + "siteFromState": { + "x-ms-summary": "Site from state", + "description": "The job's site from state.", + "maxLength": 50, + "type": "string" + }, + "siteFromCountry": { + "x-ms-summary": "Site from country", + "description": "The job's site from country.", + "maxLength": 50, + "type": "string" + }, + "billNo": { + "x-ms-summary": "Bill no.", + "description": "The job's billing number.", + "maxLength": 20, + "type": "string" + }, + "billName": { + "x-ms-summary": "Bill name", + "description": "The job's billing name.", + "maxLength": 50, + "type": "string" + }, + "billAddress": { + "x-ms-summary": "Bill address", + "description": "The job's billing address.", + "type": "string" + }, + "billAddressGeoLong": { + "x-ms-summary": "Bill address longitude", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "billAddressGeoLat": { + "x-ms-summary": "Bill address latitude", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "billPhone": { + "x-ms-summary": "Bill phone", + "description": "The job's billing phone number.", + "maxLength": 50, + "type": "string" + }, + "billEmail": { + "x-ms-summary": "Bill e-mail", + "description": "The job's billing email address.", + "maxLength": 50, + "type": "string", + "format": "email" + }, + "billRegion": { + "x-ms-summary": "Bill region", + "description": "The job's billing region.", + "maxLength": 10, + "type": "string" + }, + "importance": { + "x-ms-summary": "Importance", + "description": "The job's priority.", + "format": "int32", + "default": 0, + "x-ms-enum-values": [ + { + "displayName": "Medium", + "value": 0 + }, + { + "displayName": "High", + "value": 1 + }, + { + "displayName": "Low", + "value": 2 + } + ], + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "creationDateTime": { + "x-ms-summary": "Creation datetime", + "description": "Created on.", + "format": "date-time", + "type": "string" + }, + "customerReference": { + "x-ms-summary": "Customer reference", + "description": "The customer's reference", + "maxLength": 50, + "type": "string" + }, + "language": { + "x-ms-summary": "Language", + "description": "The job's language.", + "maxLength": 10, + "type": "string" + }, + "responsible": { + "x-ms-summary": "Responsible", + "description": "The job's responsible.", + "maxLength": 50, + "type": "string" + }, + "creator": { + "x-ms-summary": "Creator", + "description": "The job's creator.", + "maxLength": 50, + "type": "string" + }, + "freeText1": { + "x-ms-summary": "Free text field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText2": { + "x-ms-summary": "Free text field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText3": { + "x-ms-summary": "Free text field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText4": { + "x-ms-summary": "Free text field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText5": { + "x-ms-summary": "Free text field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText6": { + "x-ms-summary": "Free text field #6", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText7": { + "x-ms-summary": "Free text field #7", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText8": { + "x-ms-summary": "Free text field #8", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText9": { + "x-ms-summary": "Free text field #9", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText10": { + "x-ms-summary": "Free text field #10", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText11": { + "x-ms-summary": "Free text field #11", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText12": { + "x-ms-summary": "Free text field #12", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText13": { + "x-ms-summary": "Free text field #13", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText14": { + "x-ms-summary": "Free text field #14", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText15": { + "x-ms-summary": "Free text field #15", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText16": { + "x-ms-summary": "Free text field #16", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText17": { + "x-ms-summary": "Free text field #17", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText18": { + "x-ms-summary": "Free text field #18", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText19": { + "x-ms-summary": "Free text field #19", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText20": { + "x-ms-summary": "Free text field #20", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeDecimal1": { + "x-ms-summary": "Free decimal field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal2": { + "x-ms-summary": "Free decimal field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal3": { + "x-ms-summary": "Free decimal field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal4": { + "x-ms-summary": "Free decimal field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal5": { + "x-ms-summary": "Free decimal field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDate1": { + "x-ms-summary": "Free date field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate2": { + "x-ms-summary": "Free date field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate3": { + "x-ms-summary": "Free date field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate4": { + "x-ms-summary": "Free date field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate5": { + "x-ms-summary": "Free date field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeBit1": { + "x-ms-summary": "Free boolean field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit2": { + "x-ms-summary": "Free boolean field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit3": { + "x-ms-summary": "Free boolean field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit4": { + "x-ms-summary": "Free boolean field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit5": { + "x-ms-summary": "Free boolean field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "enableManualSelection": { + "x-ms-summary": "Enable manual selection", + "type": "boolean" + }, + "availableInGantt": { + "x-ms-summary": "Available in Gantt chart", + "type": "boolean" + }, + "startDate": { + "x-ms-summary": "Start date", + "format": "date-time", + "type": "string" + }, + "endDate": { + "x-ms-summary": "End date", + "format": "date-time", + "type": "string" + }, + "allowDependencies": { + "x-ms-summary": "Allow dependencies", + "type": "boolean" + }, + "note": { + "x-ms-summary": "Note", + "type": "string" + }, + "overRuleGanttPlanning": { + "x-ms-summary": "Overrule Gantt chart planning", + "type": "boolean" + }, + "checkAppointments": { + "x-ms-summary": "Check appointments", + "description": "True to check before removing whether appointments have been planned for this record.", + "type": "boolean", + "default": true + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "jobNo": "string", + "shortDescription": "string", + "description": "string", + "type": "string", + "name": "string", + "category": "string", + "timeMarker": "string", + "pin": "string", + "customerNo": "string", + "customerName": "string", + "customerAddress": "string", + "customerAddressGeoLong": "string", + "customerAddressGeoLat": "string", + "customerPhone": "string", + "customerEmail": "string", + "contactNo": "string", + "contactName": "string", + "contactAddress": "string", + "contactAddressGeoLong": "string", + "contactAddressGeoLat": "string", + "contactPhone": "string", + "contactEmail": "string", + "siteNo": "string", + "siteName": "string", + "siteAddress": "string", + "siteAddressGeoLong": "string", + "siteAddressGeoLat": "string", + "sitePhone": "string", + "siteEmail": "string", + "siteRegion": "string", + "siteStreet": "string", + "siteStreetNo": "string", + "sitePostcode": "string", + "siteCity": "string", + "siteCounty": "string", + "siteState": "string", + "siteCountry": "string", + "siteFromNo": "string", + "siteFromName": "string", + "siteFromAddress": "string", + "siteFromAddressGeoLong": "string", + "siteFromAddressGeoLat": "string", + "siteFromPhone": "string", + "siteFromEmail": "string", + "siteFromRegion": "string", + "siteFromStreet": "string", + "siteFromStreetNo": "string", + "siteFromPostcode": "string", + "siteFromCity": "string", + "siteFromCounty": "string", + "siteFromState": "string", + "siteFromCountry": "string", + "billNo": "string", + "billName": "string", + "billAddress": "string", + "billAddressGeoLong": "string", + "billAddressGeoLat": "string", + "billPhone": "string", + "billEmail": "string", + "billRegion": "string", + "importance": 0, + "creationDateTime": "string", + "customerReference": "string", + "language": "string", + "responsible": "string", + "creator": "string", + "freeText1": "string", + "freeText2": "string", + "freeText3": "string", + "freeText4": "string", + "freeText5": "string", + "freeText6": "string", + "freeText7": "string", + "freeText8": "string", + "freeText9": "string", + "freeText10": "string", + "freeText11": "string", + "freeText12": "string", + "freeText13": "string", + "freeText14": "string", + "freeText15": "string", + "freeText16": "string", + "freeText17": "string", + "freeText18": "string", + "freeText19": "string", + "freeText20": "string", + "freeDecimal1": 0, + "freeDecimal2": 0, + "freeDecimal3": 0, + "freeDecimal4": 0, + "freeDecimal5": 0, + "freeDate1": "string", + "freeDate2": "string", + "freeDate3": "string", + "freeDate4": "string", + "freeDate5": "string", + "freeBit1": true, + "freeBit2": true, + "freeBit3": true, + "freeBit4": true, + "freeBit5": true, + "enableManualSelection": true, + "availableInGantt": true, + "startDate": "string", + "endDate": "string", + "allowDependencies": true, + "note": "string", + "overRuleGanttPlanning": true, + "checkAppointments": true + } + }, + "job-delete": { + "type": "object", + "required": [ + "sourceApp", + "sourceType", + "jobNo" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "description": "The unique identifier that is associated with the job.", + "maxLength": 50, + "type": "string" + }, + "checkAppointments": { + "x-ms-summary": "Check appointments", + "description": "True to check before removing whether appointments have been planned for this record.", + "type": "boolean", + "default": true + } + } + }, + "notification": { + "type": "object", + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "appointmentId": { + "x-ms-summary": "Appointment id", + "description": "The unique number to identify this appointment", + "format": "int64", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "maxLength": 50, + "description": "Optional. Specify the job number to create a notification for all tasks and appointments that belong to this job.", + "type": "string" + }, + "taskNo": { + "x-ms-summary": "Task no.", + "maxLength": 50, + "description": "Optional. Specify the task number to create a notification for all appointments that belong to this task.", + "type": "string" + }, + "appointmentNo": { + "x-ms-summary": "Appointment No", + "description": "Optional. Specify the appointment number to create a notification for this particular appointment.", + "type": "string" + }, + "type": { + "x-ms-summary": "Type", + "description": "The severity of this notification.", + "type": "integer", + "format": "int32", + "default": 0, + "x-ms-enum-values": [ + { + "displayName": "Info", + "value": 0 + }, + { + "displayName": "Warning", + "value": 1 + }, + { + "displayName": "Error", + "value": 2 + } + ], + "enum": [ + 0, + 1, + 2, + 3 + ] + }, + "code": { + "x-ms-summary": "Code", + "maxLength": 20, + "type": "string", + "description": "The notification code." + }, + "text": { + "x-ms-summary": "Text", + "type": "string", + "description": "The notification message." + }, + "date": { + "x-ms-summary": "Date", + "format": "date-time", + "type": "string", + "description": "Optional. The date stamp for this notification." + }, + "appointmentGuid": { + "x-ms-summary": "Appointment GUID", + "description": "The GUID to identify this appointment", + "format": "uuid", + "type": "string", + "x-ms-visibility": "advanced" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "connectorId": { + "x-ms-summary": "Connector id", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "connectorId": "string", + "type": 0, + "code": "string", + "text": "string", + "date": "string", + "jobNo": "string", + "taskNo": "string", + "appointmentGuid": "string" + } + }, + "pin": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "x-ms-summary": "Name", + "description": "The name of the marker.", + "maxLength": 100, + "type": "string" + }, + "color": { + "x-ms-summary": "Color", + "description": "The marker's hex color code", + "maxLength": 7, + "type": "string" + } + }, + "example": { + "name": "Delivery trucks", + "color": "#4a877c" + } + }, + "resource": { + "type": "object", + "required": [ + "resourceNo" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "resourceTypeId": { + "x-ms-summary": "Resource type", + "description": "Categorizes the resources", + "format": "int32", + "type": "integer", + "x-ms-dynamic-values": { + "operationId": "GetResourceTypes", + "value-path": "id", + "value-title": "displayName" + } + }, + "resourceName": { + "x-ms-summary": "Resource name", + "description": "The resource name", + "maxLength": 100, + "type": "string" + }, + "displayName": { + "x-ms-summary": "Display name", + "description": "The resource's display name", + "maxLength": 100, + "type": "string" + }, + "department": { + "x-ms-summary": "Department", + "description": "The resource's department", + "maxLength": 50, + "type": "string" + }, + "email": { + "x-ms-summary": "E-mail", + "description": "The resource's email address. This field is used in the bi-directional Exchange connector.", + "maxLength": 100, + "type": "string", + "format": "email" + }, + "phone": { + "x-ms-summary": "Phone", + "description": "The resource's phone number", + "maxLength": 50, + "type": "string" + }, + "mobilePhone": { + "x-ms-summary": "Mobile phone", + "description": "The resource's mobile phone number", + "maxLength": 50, + "type": "string" + }, + "replacementResource": { + "x-ms-summary": "Replacement resource", + "description": "A boolean to represent if this resource is to be replaced.", + "type": "boolean" + }, + "fieldServiceEmail": { + "x-ms-summary": "Field service e-mail", + "description": "The resource's field service email", + "maxLength": 100, + "type": "string", + "format": "email" + }, + "personalEmail": { + "x-ms-summary": "Person e-mail", + "description": "The resource's personal email", + "maxLength": 100, + "type": "string", + "format": "email" + }, + "gpsTrackingResourceNo": { + "x-ms-summary": "GPS tracking no.", + "description": "The resource's GPS tracking number", + "maxLength": 50, + "type": "string" + }, + "homeAddress": { + "x-ms-summary": "Home address", + "description": "The resource's home address. This field is used in geocoding.", + "type": "string" + }, + "homeAddressGeoLong": { + "x-ms-summary": "Home address longitude", + "format": "float", + "type": "number", + "x-ms-visibility": "advanced" + }, + "homeAddressGeoLat": { + "x-ms-summary": "Home address latitude", + "format": "float", + "type": "number", + "x-ms-visibility": "advanced" + }, + "homePhone": { + "x-ms-summary": "Home phone", + "description": "The resource's home phone.", + "maxLength": 50, + "type": "string" + }, + "homeEmail": { + "x-ms-summary": "Home e-mail", + "description": "The resource's home email.", + "maxLength": 50, + "type": "string", + "format": "email" + }, + "homeStreet": { + "x-ms-summary": "Home street", + "description": "The resource's home street.", + "maxLength": 255, + "type": "string" + }, + "homeStreetNo": { + "x-ms-summary": "Home street no.", + "description": "The resource's home street number. This field is used in geocoding.", + "maxLength": 20, + "type": "string" + }, + "homePostcode": { + "x-ms-summary": "Home post code", + "description": "The resource's home ZIP code. This field is used in geocoding.", + "maxLength": 20, + "type": "string" + }, + "homeCity": { + "x-ms-summary": "Home city", + "description": "The resource's home city. This field is used in geocoding.", + "maxLength": 50, + "type": "string" + }, + "homeCounty": { + "x-ms-summary": "Home county", + "description": "The resource's home county. This field is used in geocoding.", + "maxLength": 50, + "type": "string" + }, + "homeState": { + "x-ms-summary": "Home state", + "description": "The resource's home state. This field is used in geocoding.", + "maxLength": 50, + "type": "string" + }, + "homeCountry": { + "x-ms-summary": "Home country", + "description": "The resource's home country. This field is used in geocoding.", + "maxLength": 50, + "type": "string" + }, + "homeRegion": { + "x-ms-summary": "Home region", + "description": "The resource's home region. This field is used in geocoding.", + "maxLength": 10, + "type": "string" + }, + "teamCode": { + "x-ms-summary": "Team code", + "description": "The resource's team code", + "maxLength": 20, + "type": "string" + }, + "teamName": { + "x-ms-summary": "Team name", + "description": "The resource's team name", + "maxLength": 100, + "type": "string" + }, + "teamType": { + "x-ms-summary": "Team type", + "description": "The resource's team type", + "maxLength": 20, + "type": "string" + }, + "teamSort": { + "x-ms-summary": "Team sort", + "description": "The resource's team sorting", + "format": "int32", + "type": "integer" + }, + "teamMemberType": { + "x-ms-summary": "Team member type", + "description": "The resource's team member type", + "maxLength": 20, + "type": "string" + }, + "teamMemberSort": { + "x-ms-summary": "Team member sort", + "description": "The resource's team member sorting", + "format": "int32", + "type": "integer" + }, + "doNotShow": { + "x-ms-summary": "Do not show", + "description": "Set to true to hide the resource from the planning board. Set to false to exclude this resource from the license count.", + "type": "boolean" + }, + "exchangeIntegrationEnabled": { + "x-ms-summary": "Enable Exchange integration", + "description": "Set to true to synchronize the planning to the resource's Exchange calendar. This field is used in the Exchange connector.", + "type": "boolean" + }, + "resourceGpsTrackingEnabled": { + "x-ms-summary": "Enable resource GPS tracking", + "description": "Set to true to enable track and trace for this resource on the map.", + "type": "boolean" + }, + "inServiceFrom": { + "x-ms-summary": "In service from", + "description": "In service from date", + "format": "date-time", + "type": "string" + }, + "inServiceTill": { + "x-ms-summary": "In service until", + "description": "In service until date", + "format": "date-time", + "type": "string" + }, + "url1": { + "x-ms-summary": "URL 1", + "description": "A custom URI for this resource.", + "maxLength": 1000, + "type": "string" + }, + "urlDescription1": { + "x-ms-summary": "URL description #1", + "description": "A custom URI for this resource.", + "maxLength": 255, + "type": "string" + }, + "url2": { + "x-ms-summary": "URL 2", + "description": "A custom URI for this resource.", + "maxLength": 1000, + "type": "string" + }, + "urlDescription2": { + "x-ms-summary": "URL description #2", + "description": "A custom URI for this resource.", + "maxLength": 255, + "type": "string" + }, + "url3": { + "x-ms-summary": "URL 3", + "description": "A custom URI for this resource.", + "maxLength": 1000, + "type": "string" + }, + "urlDescription3": { + "x-ms-summary": "URL description #3", + "description": "A custom URI for this resource.", + "maxLength": 255, + "type": "string" + }, + "bulkPlanning": { + "x-ms-summary": "Bulk planning", + "description": "True to enable bulk planning.", + "type": "boolean" + }, + "bulkCapacity": { + "x-ms-summary": "Bulk capacity", + "description": "Bulk planning capacity", + "format": "double", + "type": "number" + }, + "pin": { + "x-ms-summary": "The pin indicator", + "description": "Specifies the color of the marker on the map", + "maxLength": 100, + "type": "string" + }, + "freeText1": { + "x-ms-summary": "Free text field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText2": { + "x-ms-summary": "Free text field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText3": { + "x-ms-summary": "Free text field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText4": { + "x-ms-summary": "Free text field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText5": { + "x-ms-summary": "Free text field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText6": { + "x-ms-summary": "Free text field #6", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText7": { + "x-ms-summary": "Free text field #7", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText8": { + "x-ms-summary": "Free text field #8", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText9": { + "x-ms-summary": "Free text field #9", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText10": { + "x-ms-summary": "Free text field #10", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText11": { + "x-ms-summary": "Free text field #11", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText12": { + "x-ms-summary": "Free text field #12", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText13": { + "x-ms-summary": "Free text field #13", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText14": { + "x-ms-summary": "Free text field #14", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText15": { + "x-ms-summary": "Free text field #15", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText16": { + "x-ms-summary": "Free text field #16", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText17": { + "x-ms-summary": "Free text field #17", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText18": { + "x-ms-summary": "Free text field #18", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText19": { + "x-ms-summary": "Free text field #19", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText20": { + "x-ms-summary": "Free text field #20", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeDecimal1": { + "x-ms-summary": "Free decimal field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal2": { + "x-ms-summary": "Free decimal field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal3": { + "x-ms-summary": "Free decimal field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal4": { + "x-ms-summary": "Free decimal field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal5": { + "x-ms-summary": "Free decimal field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDate1": { + "x-ms-summary": "Free decimal field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate2": { + "x-ms-summary": "Free decimal field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate3": { + "x-ms-summary": "Free decimal field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate4": { + "x-ms-summary": "Free decimal field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate5": { + "x-ms-summary": "Free decimal field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeBit1": { + "x-ms-summary": "Free boolean field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit2": { + "x-ms-summary": "Free boolean field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit3": { + "x-ms-summary": "Free boolean field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit4": { + "x-ms-summary": "Free boolean field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit5": { + "x-ms-summary": "Free boolean field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + } + }, + "example": { + "resourceNo": "string", + "sourceApp": "string", + "sourceType": "string", + "resourceType": "string", + "resourceTypeId": 0, + "resourceName": "string", + "displayName": "string", + "department": "string", + "email": "string", + "phone": "string", + "mobilePhone": "string", + "replacementResource": true, + "fieldServiceEmail": "string", + "personalEmail": "string", + "gpsTrackingResourceNo": "string", + "homeAddress": "string", + "homeAddressGeoLong": 0, + "homeAddressGeoLat": 0, + "homePhone": "string", + "homeEmail": "string", + "homeStreet": "string", + "homeStreetNo": "string", + "homePostcode": "string", + "homeCity": "string", + "homeCounty": "string", + "homeState": "string", + "homeCountry": "string", + "homeRegion": "string", + "teamCode": "string", + "teamName": "string", + "teamType": "string", + "teamSort": 0, + "teamMemberType": "string", + "teamMemberSort": 0, + "doNotShow": true, + "inServiceFrom": "string", + "inServiceTill": "string", + "exchangeIntegrationEnabled": true, + "url1": "string", + "urlDescription1": "string", + "url2": "string", + "urlDescription2": "string", + "url3": "string", + "urlDescription3": "string", + "bulkPlanning": true, + "bulkCapacity": 0, + "resourceGpsTrackingEnabled": true, + "pin": "string", + "freeText1": "string", + "freeText2": "string", + "freeText3": "string", + "freeText4": "string", + "freeText5": "string", + "freeText6": "string", + "freeText7": "string", + "freeText8": "string", + "freeText9": "string", + "freeText10": "string", + "freeText11": "string", + "freeText12": "string", + "freeText13": "string", + "freeText14": "string", + "freeText15": "string", + "freeText16": "string", + "freeText17": "string", + "freeText18": "string", + "freeText19": "string", + "freeText20": "string", + "freeDecimal1": 0, + "freeDecimal2": 0, + "freeDecimal3": 0, + "freeDecimal4": 0, + "freeDecimal5": 0, + "freeDate1": "string", + "freeDate2": "string", + "freeDate3": "string", + "freeDate4": "string", + "freeDate5": "string", + "freeBit1": true, + "freeBit2": true, + "freeBit3": true, + "freeBit4": true, + "freeBit5": true + } + }, + "resourcelist": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "x-ms-summary": "ID", + "maxLength": 30, + "type": "integer" + }, + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "resourceTypeId": { + "x-ms-summary": "Resource type", + "description": "The resource type", + "format": "int32", + "type": "integer" + }, + "resourceName": { + "x-ms-summary": "Resource name", + "maxLength": 100, + "type": "string" + }, + "displayName": { + "x-ms-summary": "Display name", + "maxLength": 100, + "type": "string" + }, + "department": { + "x-ms-summary": "Department", + "maxLength": 50, + "type": "string" + }, + "email": { + "x-ms-summary": "E-mail", + "maxLength": 100, + "type": "string", + "format": "email" + }, + "phone": { + "x-ms-summary": "Phone", + "maxLength": 50, + "type": "string" + }, + "mobilePhone": { + "x-ms-summary": "Mobile phone", + "maxLength": 50, + "type": "string" + }, + "replacementResource": { + "x-ms-summary": "Replacement resource", + "type": "boolean" + }, + "fieldServiceEmail": { + "x-ms-summary": "Field service e-mail", + "maxLength": 100, + "type": "string", + "format": "email" + }, + "personalEmail": { + "x-ms-summary": "Person e-mail", + "maxLength": 100, + "type": "string", + "format": "email" + }, + "gpsTrackingResourceNo": { + "x-ms-summary": "GPS tracking no.", + "maxLength": 50, + "type": "string" + }, + "homeAddress": { + "x-ms-summary": "Home address", + "type": "string" + }, + "homeAddressGeoLong": { + "x-ms-summary": "Home address longitude", + "format": "float", + "type": "number", + "x-ms-visibility": "advanced" + }, + "homeAddressGeoLat": { + "x-ms-summary": "Home address latitude", + "format": "float", + "type": "number", + "x-ms-visibility": "advanced" + }, + "homePhone": { + "x-ms-summary": "Home phone", + "maxLength": 50, + "type": "string" + }, + "homeEmail": { + "x-ms-summary": "Home e-mail", + "maxLength": 50, + "type": "string", + "format": "email" + }, + "homeStreet": { + "x-ms-summary": "Home street", + "maxLength": 255, + "type": "string" + }, + "homeStreetNo": { + "x-ms-summary": "Home street no.", + "maxLength": 20, + "type": "string" + }, + "homePostcode": { + "x-ms-summary": "Home post code", + "maxLength": 20, + "type": "string" + }, + "homeCity": { + "x-ms-summary": "Home city", + "maxLength": 50, + "type": "string" + }, + "homeCounty": { + "x-ms-summary": "Home county", + "maxLength": 50, + "type": "string" + }, + "homeState": { + "x-ms-summary": "Home state", + "maxLength": 50, + "type": "string" + }, + "homeCountry": { + "x-ms-summary": "Home country", + "maxLength": 50, + "type": "string" + }, + "homeRegion": { + "x-ms-summary": "Home region", + "maxLength": 10, + "type": "string" + }, + "teamCode": { + "x-ms-summary": "Team code", + "maxLength": 20, + "type": "string" + }, + "teamName": { + "x-ms-summary": "Team name", + "maxLength": 100, + "type": "string" + }, + "teamType": { + "x-ms-summary": "Team type", + "maxLength": 20, + "type": "string" + }, + "teamSort": { + "x-ms-summary": "Team sort", + "format": "int32", + "type": "integer" + }, + "teamMemberType": { + "x-ms-summary": "Team member type", + "maxLength": 20, + "type": "string" + }, + "teamMemberSort": { + "x-ms-summary": "Team member sort", + "format": "int32", + "type": "integer" + }, + "doNotShow": { + "x-ms-summary": "Do not show", + "type": "boolean" + }, + "exchangeIntegrationEnabled": { + "x-ms-summary": "Enable exchange integration", + "type": "boolean" + }, + "resourceGpsTrackingEnabled": { + "x-ms-summary": "Enable resource GPS tracking", + "type": "boolean" + }, + "inServiceFrom": { + "x-ms-summary": "In service from", + "format": "date-time", + "type": "string" + }, + "inServiceTill": { + "x-ms-summary": "In service until", + "format": "date-time", + "type": "string" + }, + "url1": { + "x-ms-summary": "URL 1", + "maxLength": 1000, + "type": "string" + }, + "urlDescription1": { + "x-ms-summary": "URL description #1", + "maxLength": 255, + "type": "string" + }, + "url2": { + "x-ms-summary": "URL 2", + "maxLength": 1000, + "type": "string" + }, + "urlDescription2": { + "x-ms-summary": "URL description #2", + "maxLength": 255, + "type": "string" + }, + "url3": { + "x-ms-summary": "URL 3", + "maxLength": 1000, + "type": "string" + }, + "urlDescription3": { + "x-ms-summary": "URL description #3", + "maxLength": 255, + "type": "string" + }, + "bulkPlanning": { + "x-ms-summary": "Bulk planning", + "type": "boolean" + }, + "bulkCapacity": { + "x-ms-summary": "Bulk capacity", + "format": "double", + "type": "number" + }, + "pin": { + "x-ms-summary": "The pin indicator", + "description": "Specifies the color of the marker on the map", + "maxLength": 100, + "type": "string" + }, + "freeText1": { + "x-ms-summary": "Free text field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText2": { + "x-ms-summary": "Free text field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText3": { + "x-ms-summary": "Free text field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText4": { + "x-ms-summary": "Free text field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText5": { + "x-ms-summary": "Free text field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText6": { + "x-ms-summary": "Free text field #6", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText7": { + "x-ms-summary": "Free text field #7", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText8": { + "x-ms-summary": "Free text field #8", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText9": { + "x-ms-summary": "Free text field #9", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText10": { + "x-ms-summary": "Free text field #10", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText11": { + "x-ms-summary": "Free text field #11", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText12": { + "x-ms-summary": "Free text field #12", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText13": { + "x-ms-summary": "Free text field #13", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText14": { + "x-ms-summary": "Free text field #14", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText15": { + "x-ms-summary": "Free text field #15", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText16": { + "x-ms-summary": "Free text field #16", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText17": { + "x-ms-summary": "Free text field #17", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText18": { + "x-ms-summary": "Free text field #18", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText19": { + "x-ms-summary": "Free text field #19", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText20": { + "x-ms-summary": "Free text field #20", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeDecimal1": { + "x-ms-summary": "Free decimal field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal2": { + "x-ms-summary": "Free decimal field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal3": { + "x-ms-summary": "Free decimal field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal4": { + "x-ms-summary": "Free decimal field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal5": { + "x-ms-summary": "Free decimal field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDate1": { + "x-ms-summary": "Free decimal field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate2": { + "x-ms-summary": "Free decimal field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate3": { + "x-ms-summary": "Free decimal field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate4": { + "x-ms-summary": "Free decimal field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate5": { + "x-ms-summary": "Free decimal field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeBit1": { + "x-ms-summary": "Free boolean field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit2": { + "x-ms-summary": "Free boolean field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit3": { + "x-ms-summary": "Free boolean field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit4": { + "x-ms-summary": "Free boolean field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit5": { + "x-ms-summary": "Free boolean field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + } + }, + "example": { + "resourceNo": "string", + "sourceApp": "string", + "sourceType": "string", + "resourceType": "string", + "resourceTypeId": 0, + "resourceName": "string", + "displayName": "string", + "department": "string", + "email": "string", + "phone": "string", + "mobilePhone": "string", + "replacementResource": true, + "fieldServiceEmail": "string", + "personalEmail": "string", + "gpsTrackingResourceNo": "string", + "homeAddress": "string", + "homeAddressGeoLong": 0, + "homeAddressGeoLat": 0, + "homePhone": "string", + "homeEmail": "string", + "homeStreet": "string", + "homeStreetNo": "string", + "homePostcode": "string", + "homeCity": "string", + "homeCounty": "string", + "homeState": "string", + "homeCountry": "string", + "homeRegion": "string", + "teamCode": "string", + "teamName": "string", + "teamType": "string", + "teamSort": 0, + "teamMemberType": "string", + "teamMemberSort": 0, + "doNotShow": true, + "inServiceFrom": "string", + "inServiceTill": "string", + "exchangeIntegrationEnabled": true, + "url1": "string", + "urlDescription1": "string", + "url2": "string", + "urlDescription2": "string", + "url3": "string", + "urlDescription3": "string", + "bulkPlanning": true, + "bulkCapacity": 0, + "resourceGpsTrackingEnabled": true, + "pin": "string", + "freeText1": "string", + "freeText2": "string", + "freeText3": "string", + "freeText4": "string", + "freeText5": "string", + "freeText6": "string", + "freeText7": "string", + "freeText8": "string", + "freeText9": "string", + "freeText10": "string", + "freeText11": "string", + "freeText12": "string", + "freeText13": "string", + "freeText14": "string", + "freeText15": "string", + "freeText16": "string", + "freeText17": "string", + "freeText18": "string", + "freeText19": "string", + "freeText20": "string", + "freeDecimal1": 0, + "freeDecimal2": 0, + "freeDecimal3": 0, + "freeDecimal4": 0, + "freeDecimal5": 0, + "freeDate1": "string", + "freeDate2": "string", + "freeDate3": "string", + "freeDate4": "string", + "freeDate5": "string", + "freeBit1": true, + "freeBit2": true, + "freeBit3": true, + "freeBit4": true, + "freeBit5": true + } + } + }, + "resourceCalendar": { + "type": "object", + "required": [ + "code", + "resourceNo", + "calendarCode", + "startDate", + "endDate" + ], + "properties": { + "code": { + "x-ms-summary": "Code", + "description": "The resource calendar code", + "type": "string" + }, + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "calendarCode": { + "x-ms-summary": "Calendar code", + "description": "The resource calendar", + "maxLength": 255, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetCalendars", + "value-path": "code", + "value-title": "name" + } + }, + "startDate": { + "x-ms-summary": "Start date", + "description": "The start date. Use ISO 8601 standard. For example 2023-11-16T10:09:21Z", + "format": "date-time", + "type": "string" + }, + "endDate": { + "x-ms-summary": "End date", + "description": "The end date. Use ISO 8601 standard. For example 2023-11-16T10:09:21Z", + "format": "date-time", + "type": "string" + } + }, + "example": { + "code": "string", + "resourceNo": "string", + "calendarCode": "string", + "startDate": "string", + "endDate": "string" + } + }, + "resourceCapacity": { + "type": "object", + "required": [ + "resourceNo" + ], + "properties": { + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "date": { + "x-ms-summary": "Date", + "description": "The date to set the resource's capacity. Use ISO 8601 standard. For example 2023-11-16T10:09:21Z", + "format": "date-time", + "type": "string" + }, + "capacityInSeconds": { + "x-ms-summary": "Capacity in seconds", + "description": "The capacity in seconds", + "format": "int64", + "type": "integer" + }, + "quantity": { + "x-ms-summary": "Quantity", + "description": "The quantity.", + "format": "double", + "type": "number" + }, + "unitOfMeasure": { + "x-ms-summary": "Unit of measure", + "description": "Unit of measure", + "maxLength": 20, + "type": "string" + }, + "unitOfMeasureConversion": { + "x-ms-summary": "Unit of measure conversion", + "description": "Unit of measure conversion", + "format": "double", + "type": "number" + } + }, + "example": { + "resourceNo": "string", + "date": "string", + "capacityInSeconds": 0, + "quantity": 0, + "unitOfMeasure": "string", + "unitOfMeasureConversion": 0 + } + }, + "resourceFilterValue": { + "type": "object", + "required": [ + "resourceNo", + "filterGroup", + "filterValue" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "type": "string" + }, + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "filterGroup": { + "x-ms-summary": "Filter group", + "description": "The filter group", + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetFilterGroups", + "value-path": "Name", + "value-title": "Name" + } + }, + "filterValue": { + "x-ms-summary": "Filter value", + "description": "The filter value", + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetFilterValues", + "value-path": "Value", + "value-title": "Value" + } + }, + "transferToTemp": { + "x-ms-summary": "Transfer to temp", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "resourceNo": "string", + "filterGroup": "string", + "filterValue": "string" + } + }, + "resourceGpsTracking": { + "type": "object", + "required": [ + "resourceNo", + "latitude", + "longitude" + ], + "properties": { + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "gpsTrackingResourceNo": { + "x-ms-summary": "GPS tracking resource no.", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "latitude": { + "x-ms-summary": "Latitude", + "description": "The latitude of this resource.", + "format": "double", + "type": "number" + }, + "longitude": { + "x-ms-summary": "Longitude", + "description": "The longitude of this resource.", + "format": "double", + "type": "number" + }, + "speed": { + "x-ms-summary": "Speed", + "format": "int32", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "date": { + "x-ms-summary": "Date", + "format": "date-time", + "type": "string", + "x-ms-visibility": "advanced" + }, + "rowId": { + "x-ms-summary": "Row id", + "maxLength": 100, + "type": "string", + "x-ms-visibility": "advanced" + }, + "power": { + "x-ms-summary": "Power", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + } + }, + "example": { + "resourceNo": "string", + "gpsTrackingResourceNo": "string", + "latitude": 0, + "longitude": 0, + "speed": 0, + "date": "string", + "rowId": "string", + "power": "string" + } + }, + "resourcetypelist": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "x-ms-summary": "id", + "maxLength": 100, + "type": "string" + }, + "name": { + "x-ms-summary": "name", + "maxLength": 100, + "type": "string" + }, + "displayName": { + "x-ms-summary": "Display name", + "maxLength": 100, + "type": "string" + } + }, + "example": {} + } + }, + "resourceUri": { + "type": "object", + "required": [ + "resourceNo" + ], + "properties": { + "resourceNo": { + "x-ms-summary": "Resource no.", + "description": "The unique identifier that is associated with the resource.", + "maxLength": 50, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetResources", + "value-path": "resourceNo", + "value-title": "displayName" + } + }, + "uri": { + "x-ms-summary": "URI", + "maxLength": 1000, + "type": "string" + }, + "description": { + "x-ms-summary": "Description", + "maxLength": 255, + "type": "string" + } + }, + "example": { + "resourceNo": "string", + "uri": "string", + "description": "string" + } + }, + "task": { + "type": "object", + "required": [ + "sourceApp", + "sourceType", + "jobNo", + "taskNo", + "description", + "shortDescription" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "description": "The unique identifier that is associated with the job.", + "maxLength": 50, + "type": "string" + }, + "createJob": { + "x-ms-summary": "Create job", + "description": "Use this field to create a job for this task.", + "type": "boolean" + }, + "taskNo": { + "x-ms-summary": "Task no.", + "description": "The unique identifier that is associated with the task.", + "maxLength": 50, + "type": "string" + }, + "taskType": { + "x-ms-summary": "Task type", + "description": "Specify the component where planning will take place: Gantt chart or planning board.", + "format": "int32", + "default": 0, + "x-ms-enum-values": [ + { + "displayName": "Planning", + "value": 0 + }, + { + "displayName": "Project", + "value": 1 + } + ], + "enum": [ + 0, + 1 + ], + "type": "integer" + }, + "shortDescription": { + "x-ms-summary": "Short description", + "description": "Summary of the scope of this task", + "maxLength": 50, + "type": "string" + }, + "description": { + "x-ms-summary": "Description", + "description": "Describes the scope of this task", + "maxLength": 200, + "type": "string" + }, + "name": { + "x-ms-summary": "Name", + "description": "The task name", + "maxLength": 255, + "type": "string" + }, + "type": { + "x-ms-summary": "Type", + "description": "The task type", + "maxLength": 20, + "type": "string" + }, + "importance": { + "x-ms-summary": "Importance", + "description": "The task's priority", + "format": "int32", + "default": 0, + "x-ms-enum-values": [ + { + "displayName": "Medium", + "value": 0 + }, + { + "displayName": "High", + "value": 1 + }, + { + "displayName": "Low", + "value": 2 + } + ], + "enum": [ + 0, + 1, + 2 + ], + "type": "integer" + }, + "timeMarker": { + "type": "string", + "x-ms-summary": "Time Marker", + "description": "Specifies the color of the horizontal bar at the bottom of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "x-ms-dynamic-values": { + "operationId": "GetTimeMarkers", + "value-path": "name", + "value-title": "name" + } + }, + "category": { + "type": "string", + "x-ms-summary": "Category", + "description": "Specifies the background color of the appointment in the planning board. Used to represent any kind of status or property that applies to your business.", + "x-ms-dynamic-values": { + "operationId": "GetCategories", + "value-path": "name", + "value-title": "name" + } + }, + "pin": { + "x-ms-summary": "Pin", + "description": "Specifies the color of the marker on the map", + "maxLength": 100, + "type": "string" + }, + "requiredTotalDurationInSeconds": { + "x-ms-summary": "Required total duration (in seconds)", + "description": "Specifies the required total duration (= the budget) in seconds", + "format": "int64", + "type": "integer" + }, + "expectedResponseDateTime": { + "x-ms-summary": "Expected response date", + "description": "The expected response date", + "format": "date-time", + "type": "string" + }, + "actualResponseDateTime": { + "x-ms-summary": "Actual response date", + "description": "The actual response date", + "format": "date-time", + "type": "string" + }, + "requestedStartDate": { + "x-ms-summary": "Requested start date", + "description": "Overrides the appointment's start date when dropping a task to the planning board.", + "format": "date-time", + "type": "string" + }, + "requestedEndDate": { + "x-ms-summary": "Requested end date", + "description": "Overrides the appointment's end date when dropping a task to the planning board.", + "format": "date-time", + "type": "string" + }, + "requestedStartTime": { + "x-ms-summary": "Requested start time", + "description": "Overrides the appointment's start time when dropping a task to the planning board.", + "type": "string" + }, + "requestedEndTime": { + "x-ms-summary": "Requested end time", + "description": "Overrides the appointment's end time when dropping a task to the planning board.", + "type": "string" + }, + "appointmentEarliestAllowed": { + "x-ms-summary": "Earliest allowed time", + "description": "Specifies the earliest date allowed for the task", + "format": "date-time", + "type": "string" + }, + "appointmentLatestAllowed": { + "x-ms-summary": "Latest allowed time", + "description": "Specifies the latest date allowed for the task", + "format": "date-time", + "type": "string" + }, + "confirmedStartDate": { + "x-ms-summary": "Confirmed start date", + "description": "Confirmed start date", + "format": "date-time", + "type": "string" + }, + "confirmedEndDate": { + "x-ms-summary": "Confirmed end date", + "description": "Confirmed end date", + "format": "date-time", + "type": "string" + }, + "actualStartDate": { + "x-ms-summary": "Actual start date", + "description": "Actual start date", + "format": "date-time", + "type": "string" + }, + "actualEndDate": { + "x-ms-summary": "Actual end date", + "description": "Actual end date", + "format": "date-time", + "type": "string" + }, + "serviceNo": { + "x-ms-summary": "Service no.", + "description": "Service no.", + "maxLength": 50, + "type": "string" + }, + "serviceGroup": { + "x-ms-summary": "Service group", + "description": "Service group", + "maxLength": 20, + "type": "string" + }, + "serviceClass": { + "x-ms-summary": "Service class", + "description": "Service class", + "maxLength": 20, + "type": "string" + }, + "serviceSerialNo": { + "x-ms-summary": "Service serial no.", + "description": "Service serial no.", + "maxLength": 50, + "type": "string" + }, + "serviceName": { + "x-ms-summary": "Service name", + "description": "Service name", + "maxLength": 50, + "type": "string" + }, + "irisFault": { + "x-ms-summary": "IRIS fault", + "description": "IRIS fault", + "maxLength": 10, + "type": "string" + }, + "irisSymptom": { + "x-ms-summary": "IRIS symptom", + "description": "IRIS symptom", + "maxLength": 10, + "type": "string" + }, + "irisArea": { + "x-ms-summary": "IRIS area", + "description": "IRIS area", + "maxLength": 10, + "type": "string" + }, + "irisReason": { + "x-ms-summary": "IRIS reason", + "description": "IRIS reason", + "maxLength": 10, + "type": "string" + }, + "irisResolution": { + "x-ms-summary": "IRIS resolution", + "description": "IRIS resolution", + "maxLength": 10, + "type": "string" + }, + "skill1": { + "x-ms-summary": "Skill #1", + "description": "Skill #1", + "maxLength": 10, + "type": "string" + }, + "skill2": { + "x-ms-summary": "Skill #2", + "description": "Skill #2", + "maxLength": 10, + "type": "string" + }, + "skill3": { + "x-ms-summary": "Skill #3", + "description": "Skill #3", + "maxLength": 10, + "type": "string" + }, + "contractNo": { + "x-ms-summary": "Contract number", + "description": "Contract number", + "maxLength": 20, + "type": "string" + }, + "contractType": { + "x-ms-summary": "Contract type", + "description": "Contract type", + "maxLength": 30, + "type": "string" + }, + "contractDescription": { + "x-ms-summary": "Contract description", + "description": "Contract description", + "type": "string" + }, + "contractStartDate": { + "x-ms-summary": "Contract start date", + "description": "Contract start date", + "format": "date-time", + "type": "string" + }, + "contractEndDate": { + "x-ms-summary": "Contract end date", + "description": "Contract end date", + "format": "date-time", + "type": "string" + }, + "partsWarrantyStartDate": { + "x-ms-summary": "Parts warranty start date", + "description": "Parts warranty start date", + "format": "date-time", + "type": "string" + }, + "partsWarrantyEndDate": { + "x-ms-summary": "Parts warranty end date", + "description": "Parts warranty end date", + "format": "date-time", + "type": "string" + }, + "laborWarrantyStartDate": { + "x-ms-summary": "Labor warranty start date", + "description": "Labor warranty start date", + "format": "date-time", + "type": "string" + }, + "laborWarrantyEndDate": { + "x-ms-summary": "Labor warranty end date", + "description": "Labor warranty end date", + "format": "date-time", + "type": "string" + }, + "status": { + "x-ms-summary": "Status", + "description": "Status", + "maxLength": 20, + "type": "string" + }, + "locationDescription": { + "x-ms-summary": "Location description", + "description": "Location description", + "type": "string" + }, + "duration": { + "x-ms-summary": "Duration", + "description": "Duration", + "type": "string" + }, + "durationInSeconds": { + "x-ms-summary": "Duration in seconds", + "description": "Duration in seconds", + "format": "int64", + "type": "integer" + }, + "subject": { + "x-ms-summary": "Subject", + "description": "The appointment's subject", + "type": "string" + }, + "body": { + "x-ms-summary": "Body", + "description": "The appointment's body", + "type": "string" + }, + "infiniteTask": { + "x-ms-summary": "Is infinite task", + "description": "Setting this to true will pin this task on the open tasks grid.", + "type": "boolean" + }, + "taskOpenAsOf": { + "x-ms-summary": "Open from date", + "description": "Open from date", + "format": "date-time", + "type": "string" + }, + "taskOpenTill": { + "x-ms-summary": "Open until date", + "description": "Open until date", + "format": "date-time", + "type": "string" + }, + "requiredTotalDuration": { + "x-ms-summary": "Required total duration", + "description": "Required total duration", + "type": "string" + }, + "requiredNoResources": { + "x-ms-summary": "Required number of resources", + "description": "Required number of resources", + "format": "int32", + "type": "integer" + }, + "freeText1": { + "x-ms-summary": "Free text field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText2": { + "x-ms-summary": "Free text field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText3": { + "x-ms-summary": "Free text field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText4": { + "x-ms-summary": "Free text field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText5": { + "x-ms-summary": "Free text field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText6": { + "x-ms-summary": "Free text field #6", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText7": { + "x-ms-summary": "Free text field #7", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText8": { + "x-ms-summary": "Free text field #8", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText9": { + "x-ms-summary": "Free text field #9", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText10": { + "x-ms-summary": "Free text field #10", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText11": { + "x-ms-summary": "Free text field #11", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText12": { + "x-ms-summary": "Free text field #12", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText13": { + "x-ms-summary": "Free text field #13", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText14": { + "x-ms-summary": "Free text field #14", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText15": { + "x-ms-summary": "Free text field #15", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText16": { + "x-ms-summary": "Free text field #16", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText17": { + "x-ms-summary": "Free text field #17", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText18": { + "x-ms-summary": "Free text field #18", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText19": { + "x-ms-summary": "Free text field #19", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeText20": { + "x-ms-summary": "Free text field #20", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "maxLength": 100, + "type": "string" + }, + "freeDecimal1": { + "x-ms-summary": "Free decimal field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal2": { + "x-ms-summary": "Free decimal field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal3": { + "x-ms-summary": "Free decimal field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal4": { + "x-ms-summary": "Free decimal field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDecimal5": { + "x-ms-summary": "Free decimal field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "double", + "type": "number" + }, + "freeDate1": { + "x-ms-summary": "Free date field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate2": { + "x-ms-summary": "Free date field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate3": { + "x-ms-summary": "Free date field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate4": { + "x-ms-summary": "Free date field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeDate5": { + "x-ms-summary": "Free date field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "format": "date-time", + "type": "string" + }, + "freeBit1": { + "x-ms-summary": "Free boolean field #1", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit2": { + "x-ms-summary": "Free boolean field #2", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit3": { + "x-ms-summary": "Free boolean field #3", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit4": { + "x-ms-summary": "Free boolean field #4", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "freeBit5": { + "x-ms-summary": "Free boolean field #5", + "description": "A field that is unmapped by default that can be used at your discretion. Use captions to change the title of this field.", + "type": "boolean" + }, + "url1": { + "x-ms-summary": "URL 1", + "description": "Custom URI for this task", + "maxLength": 1000, + "type": "string" + }, + "urlDescription1": { + "x-ms-summary": "URL 1 description", + "description": "Custom URI for this task", + "maxLength": 255, + "type": "string" + }, + "url2": { + "x-ms-summary": "URL 2", + "description": "Custom URI for this task", + "maxLength": 1000, + "type": "string" + }, + "urlDescription2": { + "x-ms-summary": "URL 2 description", + "description": "Custom URI for this task", + "maxLength": 255, + "type": "string" + }, + "url3": { + "x-ms-summary": "URL 3", + "description": "Custom URI for this task", + "maxLength": 1000, + "type": "string" + }, + "urlDescription3": { + "x-ms-summary": "URL 3 description", + "description": "Custom URI for this task", + "maxLength": 255, + "type": "string" + }, + "certificateNo": { + "x-ms-summary": "Certificate no.", + "description": "Custom URI for this task", + "type": "string" + }, + "doNotCountAppointmentResource": { + "x-ms-summary": "Do not count appointment resources", + "description": "Do not count appointment resources", + "type": "boolean" + }, + "isComplete": { + "x-ms-summary": "Is complete", + "description": "Is complete", + "type": "boolean" + }, + "planningUOM": { + "x-ms-summary": "Planning unit of measure", + "description": "Planning unit of measure", + "maxLength": 20, + "type": "string" + }, + "planningQty": { + "x-ms-summary": "Planning quantity", + "description": "Planning quantity", + "format": "double", + "type": "number" + }, + "useFixPlanningQty": { + "x-ms-summary": "Use fixed planning quantity", + "description": "Use fixed planning quantity", + "type": "boolean" + }, + "roundToUOM": { + "x-ms-summary": "Round to unit of measure", + "description": "Round to unit of measure", + "type": "boolean" + }, + "appointmentTemplate": { + "x-ms-summary": "Appointment template", + "description": "Appointment template", + "maxLength": 100, + "type": "string" + }, + "bulkPlanningQty": { + "x-ms-summary": "Bulk planning quantity", + "description": "Bulk planning quantity", + "format": "double", + "type": "number" + }, + "calendarCode": { + "x-ms-summary": "Calendar", + "description": "Calendar", + "maxLength": 255, + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetCalendars", + "value-path": "code", + "value-title": "name" + } + }, + "startDate": { + "x-ms-summary": "Gantt: Start date", + "description": "Gantt: Start date", + "format": "date-time", + "type": "string", + "x-ms-visibility": "advanced" + }, + "endDate": { + "x-ms-summary": "Gantt: End date", + "description": "Gantt: End date", + "format": "date-time", + "type": "string", + "x-ms-visibility": "advanced" + }, + "percentDone": { + "x-ms-summary": "Gantt: Percentage done", + "description": "Gantt: Percentage done", + "format": "int32", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "schedulingMode": { + "x-ms-summary": "Gantt: Scheduling mode", + "description": "Gantt: Scheduling mode", + "format": "int32", + "default": 0, + "x-ms-visibility": "advanced", + "x-ms-enum-values": [ + { + "displayName": "Normal", + "value": 0 + }, + { + "displayName": "Fixed duration", + "value": 1 + }, + { + "displayName": "Effort-driven", + "value": 2 + }, + { + "displayName": "Dynamic assignment", + "value": 3 + } + ], + "enum": [ + 0, + 1, + 2, + 3 + ], + "type": "integer" + }, + "baseLineStartDate": { + "x-ms-summary": "Gantt: Baseline start date", + "description": "Gantt: Baseline start date", + "format": "date-time", + "type": "string", + "x-ms-visibility": "advanced" + }, + "baseLineEndDate": { + "x-ms-summary": "Gantt: Baseline end date", + "description": "Gantt: Baseline end date", + "format": "date-time", + "type": "string", + "x-ms-visibility": "advanced" + }, + "baseLinePercentDone": { + "x-ms-summary": "Gantt: Baseline percent done", + "description": "Gantt: Baseline percent done", + "format": "int32", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "deadLine": { + "x-ms-summary": "Gantt: Deadline", + "description": "Gantt: Deadline", + "format": "date-time", + "type": "string", + "x-ms-visibility": "advanced" + }, + "index": { + "x-ms-summary": "Gantt: Index", + "description": "Gantt: Index", + "format": "int32", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "constraintType": { + "x-ms-summary": "Gantt: Constraint type", + "description": "Gantt: Constraint type", + "format": "int32", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "constraintDatetime": { + "x-ms-summary": "Gantt: Constraint datetime", + "description": "Gantt: Constraint datetime", + "format": "date-time", + "type": "string", + "x-ms-visibility": "advanced" + }, + "parentTaskNo": { + "x-ms-summary": "Gantt: Parent task no.", + "description": "Gantt: Parent task no.", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "predecessorTaskNo": { + "x-ms-summary": "Gantt: Predecessor task no.", + "description": "Gantt: Predecessor task no.", + "maxLength": 50, + "type": "string", + "x-ms-visibility": "advanced" + }, + "predecessorLag": { + "x-ms-summary": "Gantt: Predecessor lag", + "description": "Gantt: Predecessor lag", + "format": "int32", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "manuallyScheduled": { + "x-ms-summary": "Gantt: Manually scheduled", + "description": "Gantt: Manually scheduled", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "note": { + "x-ms-summary": "Gantt: Note", + "description": "Gantt: Note", + "type": "string", + "x-ms-visibility": "advanced" + }, + "overRuleGanttPlanning": { + "x-ms-summary": "Gantt: Overrule Gantt planning", + "description": "Gantt: Overrule Gantt planning", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "ignoreCalendars": { + "x-ms-summary": "Ignore calendars", + "description": "Ignore calendars", + "type": "boolean", + "x-ms-visibility": "advanced" + }, + "containerName": { + "x-ms-summary": "Container name", + "description": "Container name", + "maxLength": 255, + "type": "string", + "x-ms-visibility": "advanced" + }, + "containerIndex": { + "x-ms-summary": "Container index", + "description": "Container index", + "format": "int32", + "type": "integer", + "x-ms-visibility": "advanced" + }, + "checkAppointments": { + "x-ms-summary": "Check appointments", + "description": "True to check before removing whether appointments have been planned for this record.", + "type": "boolean", + "default": true, + "x-ms-visibility": "advanced" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "description": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "jobNo": "string", + "taskNo": "string", + "taskType": 0, + "shortDescription": "string", + "description": "string", + "name": "string", + "type": "string", + "category": "string", + "timeMarker": "string", + "pin": "string", + "serviceNo": "string", + "serviceGroup": "string", + "serviceClass": "string", + "serviceSerialNo": "string", + "serviceName": "string", + "irisFault": "string", + "irisSymptom": "string", + "irisArea": "string", + "irisReason": "string", + "irisResolution": "string", + "skill1": "string", + "skill2": "string", + "skill3": "string", + "contractNo": "string", + "contractType": "string", + "contractDescription": "string", + "contractStartDate": "string", + "contractEndDate": "string", + "partsWarrantyStartDate": "string", + "partsWarrantyEndDate": "string", + "laborWarrantyStartDate": "string", + "laborWarrantyEndDate": "string", + "importance": 0, + "status": "string", + "expectedResponseDateTime": "string", + "actualResponseDateTime": "string", + "requestedStartDate": "string", + "requestedEndDate": "string", + "requestedStartTime": { + "ticks": 0, + "days": 0, + "hours": 0, + "milliseconds": 0, + "minutes": 0, + "seconds": 0, + "totalDays": 0, + "totalHours": 0, + "totalMilliseconds": 0, + "totalMinutes": 0, + "totalSeconds": 0 + }, + "requestedEndTime": { + "ticks": 0, + "days": 0, + "hours": 0, + "milliseconds": 0, + "minutes": 0, + "seconds": 0, + "totalDays": 0, + "totalHours": 0, + "totalMilliseconds": 0, + "totalMinutes": 0, + "totalSeconds": 0 + }, + "confirmedStartDate": "string", + "confirmedEndDate": "string", + "actualStartDate": "string", + "actualEndDate": "string", + "locationDescription": "string", + "duration": { + "ticks": 0, + "days": 0, + "hours": 0, + "milliseconds": 0, + "minutes": 0, + "seconds": 0, + "totalDays": 0, + "totalHours": 0, + "totalMilliseconds": 0, + "totalMinutes": 0, + "totalSeconds": 0 + }, + "durationInSeconds": 0, + "subject": "string", + "body": "string", + "infiniteTask": true, + "taskOpenAsOf": "string", + "taskOpenTill": "string", + "requiredTotalDuration": { + "ticks": 0, + "days": 0, + "hours": 0, + "milliseconds": 0, + "minutes": 0, + "seconds": 0, + "totalDays": 0, + "totalHours": 0, + "totalMilliseconds": 0, + "totalMinutes": 0, + "totalSeconds": 0 + }, + "requiredNoResources": 0, + "appointmentEarliestAllowed": "string", + "appointmentLatestAllowed": "string", + "freeText1": "string", + "freeText2": "string", + "freeText3": "string", + "freeText4": "string", + "freeText5": "string", + "freeText6": "string", + "freeText7": "string", + "freeText8": "string", + "freeText9": "string", + "freeText10": "string", + "freeText11": "string", + "freeText12": "string", + "freeText13": "string", + "freeText14": "string", + "freeText15": "string", + "freeText16": "string", + "freeText17": "string", + "freeText18": "string", + "freeText19": "string", + "freeText20": "string", + "freeDecimal1": 0, + "freeDecimal2": 0, + "freeDecimal3": 0, + "freeDecimal4": 0, + "freeDecimal5": 0, + "freeDate1": "string", + "freeDate2": "string", + "freeDate3": "string", + "freeDate4": "string", + "freeDate5": "string", + "freeBit1": true, + "freeBit2": true, + "freeBit3": true, + "freeBit4": true, + "freeBit5": true, + "url1": "string", + "urlDescription1": "string", + "url2": "string", + "urlDescription2": "string", + "url3": "string", + "urlDescription3": "string", + "certificateNo": "string", + "requiredTotalDurationInSeconds": 0, + "doNotCountAppointmentResource": true, + "isComplete": true, + "planningUOM": "string", + "planningQty": 0, + "useFixPlanningQty": true, + "roundToUOM": true, + "appointmentTemplate": "string", + "bulkPlanningQty": 0, + "startDate": "string", + "endDate": "string", + "percentDone": 0, + "schedulingMode": 0, + "baseLineStartDate": "string", + "baseLineEndDate": "string", + "baseLinePercentDone": 0, + "deadLine": "string", + "index": 0, + "constraintType": 0, + "constraintDatetime": "string", + "parentTaskNo": "string", + "calendarCode": "string", + "predecessorTaskNo": "string", + "predecessorLag": 0, + "manuallyScheduled": true, + "note": "string", + "overRuleGanttPlanning": true, + "ignoreCalendars": true, + "containerName": "string", + "containerIndex": 0, + "checkAppointments": true + } + }, + "task-delete": { + "type": "object", + "required": [ + "sourceApp", + "sourceType", + "jobNo", + "taskNo" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "description": "The unique identifier that is associated with the job.", + "maxLength": 50, + "type": "string" + }, + "taskNo": { + "x-ms-summary": "Task no.", + "description": "The unique identifier that is associated with the task.", + "maxLength": 50, + "type": "string" + }, + "checkAppointments": { + "x-ms-summary": "Check appointments", + "description": "True to check before removing whether appointments have been planned for this record.", + "type": "boolean", + "default": true + } + } + }, + "taskContainer": { + "type": "object", + "required": [ + "sourceApp", + "sourceType", + "jobNo", + "taskNo", + "name" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "description": "The unique identifier that is associated with the job.", + "maxLength": 50, + "type": "string" + }, + "taskNo": { + "x-ms-summary": "Task no.", + "description": "The unique identifier that is associated with the task.", + "maxLength": 50, + "type": "string" + }, + "name": { + "x-ms-summary": "Name", + "description": "The container name", + "maxLength": 255, + "type": "string" + }, + "index": { + "x-ms-summary": "Index", + "description": "The index of the task in the container.", + "format": "int32", + "type": "integer" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "jobNo": "string", + "taskNo": "string", + "name": "string", + "index": 0 + } + }, + "taskFilterValue": { + "type": "object", + "required": [ + "sourceApp", + "sourceType", + "jobNo", + "taskNo", + "filterValue", + "filterGroup" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "description": "The unique identifier that is associated with the job.", + "maxLength": 50, + "type": "string" + }, + "taskNo": { + "x-ms-summary": "Task no.", + "description": "The unique identifier that is associated with the task.", + "maxLength": 50, + "type": "string" + }, + "filterGroup": { + "x-ms-summary": "Filter group", + "description": "The filter group", + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetFilterGroups", + "value-path": "Name", + "value-title": "Name" + } + }, + "filterValue": { + "x-ms-summary": "Filter value", + "description": "The filter value", + "type": "string", + "x-ms-dynamic-values": { + "operationId": "GetFilterValues", + "value-path": "Value", + "value-title": "Value" + } + }, + "transferToTemp": { + "x-ms-summary": "Transfer to temp", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "jobNo": "string", + "taskNo": "string", + "filterGroup": "string", + "filterValue": "string" + } + }, + "taskLocked": { + "type": "object", + "required": [ + "sourceApp", + "sourceType", + "jobNo", + "taskNo" + ], + "properties": { + "sourceApp": { + "x-ms-summary": "Source application", + "description": "A unique identifier that lets Dime.Scheduler know to which back-office system this record belongs to.", + "maxLength": 30, + "type": "string" + }, + "sourceType": { + "x-ms-summary": "Source type", + "description": "A discriminator that describes the type of entity that this record represents.", + "maxLength": 10, + "type": "string" + }, + "jobNo": { + "x-ms-summary": "Job no.", + "description": "The unique identifier that is associated with the job.", + "maxLength": 50, + "type": "string" + }, + "taskNo": { + "x-ms-summary": "Task no.", + "description": "The unique identifier that is associated with the task.", + "maxLength": 50, + "type": "string" + }, + "locked": { + "x-ms-summary": "Locked", + "type": "boolean" + }, + "sentFromBackOffice": { + "x-ms-summary": "Sent from back-office", + "type": "boolean", + "x-ms-visibility": "advanced" + } + }, + "example": { + "sourceApp": "string", + "sourceType": "string", + "jobNo": "string", + "taskNo": "string", + "locked": true + } + }, + "timeMarker": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "x-ms-summary": "Name", + "description": "The name of this visual indicator.", + "maxLength": 100, + "type": "string" + }, + "color": { + "x-ms-summary": "Color", + "description": "The hex color code", + "maxLength": 7, + "type": "string" + } + }, + "example": { + "name": "Underway for delivery", + "color": "#99bj2z" + } + }, + "timemarkerlist": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "x-ms-summary": "id", + "maxLength": 100, + "type": "string" + }, + "name": { + "x-ms-summary": "Name", + "maxLength": 100, + "type": "string" + }, + "color": { + "x-ms-summary": "Color", + "maxLength": 7, + "type": "string" + } + } + }, + "example": { + "name": "OOO", + "displayName": "Out of office", + "color": "#7f61ff" + } + }, + "timeSpan": { + "type": "object", + "properties": { + "ticks": { + "format": "int64", + "type": "integer" + }, + "days": { + "format": "int32", + "type": "integer" + }, + "hours": { + "format": "int32", + "type": "integer" + }, + "milliseconds": { + "format": "int32", + "type": "integer" + }, + "minutes": { + "format": "int32", + "type": "integer" + }, + "seconds": { + "format": "int32", + "type": "integer" + }, + "totalDays": { + "format": "double", + "type": "number" + }, + "totalHours": { + "format": "double", + "type": "number" + }, + "totalMilliseconds": { + "format": "double", + "type": "number" + }, + "totalMinutes": { + "format": "double", + "type": "number" + }, + "totalSeconds": { + "format": "double", + "type": "number" + } + } + }, + "SendErrorResponseBody": { + "type": "string" + }, + "SendSuccessResponseBody": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "title": "Successful", + "x-ms-summary": "Successful", + "description": "Successful", + "x-ms-visibility": "advanced" + }, + "message": { + "type": "string", + "title": "Response message", + "x-ms-summary": "Response message", + "description": "Response message.", + "x-ms-visibility": "advanced" + }, + "status": { + "type": "number", + "title": "Status code", + "x-ms-summary": "Status code", + "description": "The status code", + "x-ms-visibility": "advanced" + }, + "phrase": { + "type": "string", + "title": "Status code phrase", + "x-ms-summary": "Status code phrase", + "description": "Status code phrase", + "x-ms-visibility": "advanced" + } + } + } + }, + "parameters": {}, + "responses": { + "200": { + "description": "Response to successful sending record", + "x-ms-summary": "Success response", + "schema": { + "$ref": "#/definitions/SendSuccessResponseBody" + } + }, + "400": { + "description": "The request was invalid.", + "x-ms-summary": "The request was invalid.", + "schema": { + "$ref": "#/definitions/SendErrorResponseBody" + } + }, + "500": { + "description": "An error occurred on the server.", + "x-ms-summary": "An error occurred on the server.", + "schema": { + "$ref": "#/definitions/SendErrorResponseBody" + } + }, + "default": { + "description": "Response to successful sending record", + "x-ms-summary": "Success response" + } + }, + "securityDefinitions": { + "apiKey": { + "type": "apiKey", + "name": "X-API-KEY", + "in": "header" + } + }, + "security": [], + "tags": [] +} \ No newline at end of file diff --git a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/ThreadingTests.cs b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/ThreadingTests.cs index 2885ce6fb3..34f2651a9e 100644 --- a/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/ThreadingTests.cs +++ b/src/tests/Microsoft.PowerFx.Connectors.Tests.Shared/ThreadingTests.cs @@ -21,7 +21,7 @@ public void CheckConnector() var bugsFieldType = new HashSet(); var bugNames = new HashSet() { - "ConnectorFunction._slash", + "ConnectorFunction._slash", "ColumnCapabilities.DefaultFilterFunctionSupport" }; diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/DisplayNameTests.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/DisplayNameTests.cs index 33adf9f1c5..a8fddb1970 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/DisplayNameTests.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/DisplayNameTests.cs @@ -10,6 +10,7 @@ using Microsoft.PowerFx.Core.Glue; using Microsoft.PowerFx.Core.Parser; using Microsoft.PowerFx.Core.Tests; +using Microsoft.PowerFx.Core.Texl.Builtins; using Microsoft.PowerFx.Core.Types; using Microsoft.PowerFx.Core.Utils; using Microsoft.PowerFx.Intellisense; @@ -787,5 +788,39 @@ public void RenameParameterTextFirst(string expr, string expected, bool find) Assert.Equal(expected, renamer.ApplyRename(expr)); } } + + [Fact] + public void SummarizeDisplayNameTest() + { + var expression = "First(Summarize(DS, logicalField, logicalField2))."; + var record = RecordType.Empty().Add("logicalField", FormulaType.Number, "DisplayField").Add("logicalField2", FormulaType.String, "DisplayFiled2"); + + var symbol = new SymbolTable(); + symbol.AddVariable("DS", record.ToTable()); + symbol.AddFunction(new SummarizeFunction()); + + var config = new PowerFxConfig + { + SymbolTable = symbol + }; + + var engine = new Engine(config); + + var logicalCheck = engine.Check(expression + "logicalField"); + var displayCheck = engine.Check(expression + "DisplayField"); + + Assert.True(logicalCheck.IsSuccess); + Assert.True(displayCheck.IsSuccess); + + // Check if intellisense suggests the display name. + var intellisenseResult = engine.Suggest(expression, RecordType.Empty(), expression.Length); + + Assert.NotNull(intellisenseResult); + Assert.NotNull(intellisenseResult.Suggestions); + + var suggestions = intellisenseResult.Suggestions.Select(sugg => sugg.DisplayText.Text); + Assert.Contains("DisplayField", suggestions); + Assert.Contains("DisplayFiled2", suggestions); + } } } diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Join.txt b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Join.txt index 724a898d31..57b0b5319b 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Join.txt +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/ExpressionTestCases/Join.txt @@ -68,4 +68,10 @@ Table({a:1,b:1},{a:1,b:1},Error({Kind:ErrorKind.Div0})) Errors: Error 61-63: The '{ a:1 }' value is invalid in this context. It should be a reference to either 'T1' or 'T2' scope name.|Error 13-15: At least one 'T2' column must be declared to compose the join result.|Error 0-4: The function 'Join' has some invalid arguments. >> Join([{a:1}],[{a:1}],true,JoinType.Inner,{a:1}.a As AAA) -Errors: Error 49-51: The '{ a:1 }' value is invalid in this context. It should be a reference to either 'LeftRecord' or 'RightRecord' scope name.|Error 5-12: At least one 'RightRecord' column must be declared to compose the join result.|Error 0-4: The function 'Join' has some invalid arguments. \ No newline at end of file +Errors: Error 49-51: The '{ a:1 }' value is invalid in this context. It should be a reference to either 'LeftRecord' or 'RightRecord' scope name.|Error 5-12: At least one 'RightRecord' column must be declared to compose the join result.|Error 0-4: The function 'Join' has some invalid arguments. + +>> Join([10,20], Table({Value:20}, Blank()), LeftRecord.Value=RightRecord.Value, JoinType.Left, RightRecord.Value As R2) +Table({R2:Blank(),Value:10},{R2:20,Value:20}) + +>> Join([10,20], Table({Value:20}, If(1/0, {Value:25})), LeftRecord.Value=RightRecord.Value, JoinType.Left, RightRecord.Value As R2) +Table(Error({Kind:ErrorKind.Div0}),{R2:20,Value:20},Error({Kind:ErrorKind.Div0})) \ No newline at end of file diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/PublicSurfaceTests.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/PublicSurfaceTests.cs index 6a9a8368f3..352871be4b 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/PublicSurfaceTests.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/PublicSurfaceTests.cs @@ -202,6 +202,8 @@ public void PublicSurface_Tests() "Microsoft.PowerFx.Core.Entities.IRefreshable", "Microsoft.PowerFx.Core.Entities.SelectionRestrictions", "Microsoft.PowerFx.Core.Entities.SortRestrictions", + "Microsoft.PowerFx.Core.Entities.SummarizeCapabilities", + "Microsoft.PowerFx.Core.Entities.SummarizeMethod", "Microsoft.PowerFx.Core.Entities.TableDelegationInfo", "Microsoft.PowerFx.Core.Functions.Delegation.DelegationOperator", "Microsoft.PowerFx.Core.Localization.ErrorResourceKey", diff --git a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs index 57c5d41baa..7301c0178f 100644 --- a/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs +++ b/src/tests/Microsoft.PowerFx.Core.Tests.Shared/TestRunnerTests/InternalSetup.cs @@ -29,13 +29,7 @@ private bool TryUpdateFeatures(string featureName, bool featureValue) { switch (featureName) { - // When we move to C# 12 we can use nameof(Features.AllowAsyncDelegation): - case "AllowAsyncDelegation": - this.Features = new Features(this.Features) { AllowAsyncDelegation = featureValue }; - return true; - case "AllowImpureNodeDelegation": - this.Features = new Features(this.Features) { AllowImpureNodeDelegation = featureValue }; - return true; + // When we move to C# 12 we can use nameof(Features.AsTypeLegacyCheck): case "AsTypeLegacyCheck": this.Features = new Features(this.Features) { AsTypeLegacyCheck = featureValue }; return true; diff --git a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/MutationScripts/Join.txt b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/MutationScripts/Join.txt index 302a13c223..a80011fc29 100644 --- a/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/MutationScripts/Join.txt +++ b/src/tests/Microsoft.PowerFx.Interpreter.Tests.Shared/MutationScripts/Join.txt @@ -41,10 +41,10 @@ Table({Country:"USA",Id:"AAA111",Name:"Contoso",RowId:1},{Country:"USA",Id:"AAA1 // Full >> Join(t1, t2, LeftRecord.Id = RightRecord.SupplierId, JoinType.Full, RightRecord.RowId As RowId) -Table({Country:"USA",Id:"AAA111",Name:"Contoso",RowId:1},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:3},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:4},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:6},{Country:"CAN",Id:"BBB222",Name:"Fabrikam",RowId:2},{Country:"CAN",Id:"BBB222",Name:"Fabrikam",RowId:5},{Country:"USA",Id:"FFF666",Name:"Dunder Mifflin",RowId:Blank()},{Country:"MEX",Id:"EEE555",Name:"ACME INC.",RowId:Blank()},{Country:Blank(),Id:Blank(),Name:Blank(),RowId:7},{Country:Blank(),Id:Blank(),Name:Blank(),RowId:8}) +Table({Country:"USA",Id:"AAA111",Name:"Contoso",RowId:1},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:3},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:4},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:6},{Country:"CAN",Id:"BBB222",Name:"Fabrikam",RowId:2},{Country:"CAN",Id:"BBB222",Name:"Fabrikam",RowId:5},{Country:"MEX",Id:"EEE555",Name:"ACME INC.",RowId:Blank()},{Country:"USA",Id:"FFF666",Name:"Dunder Mifflin",RowId:Blank()},{Country:Blank(),Id:Blank(),Name:Blank(),RowId:7},{Country:Blank(),Id:Blank(),Name:Blank(),RowId:8}) >> Join(t1 As x1, t2 As x2, x1.Id = x2.SupplierId, JoinType.Full, x2.RowId As RowId) -Table({Country:"USA",Id:"AAA111",Name:"Contoso",RowId:1},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:3},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:4},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:6},{Country:"CAN",Id:"BBB222",Name:"Fabrikam",RowId:2},{Country:"CAN",Id:"BBB222",Name:"Fabrikam",RowId:5},{Country:"USA",Id:"FFF666",Name:"Dunder Mifflin",RowId:Blank()},{Country:"MEX",Id:"EEE555",Name:"ACME INC.",RowId:Blank()},{Country:Blank(),Id:Blank(),Name:Blank(),RowId:7},{Country:Blank(),Id:Blank(),Name:Blank(),RowId:8}) +Table({Country:"USA",Id:"AAA111",Name:"Contoso",RowId:1},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:3},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:4},{Country:"USA",Id:"AAA111",Name:"Contoso",RowId:6},{Country:"CAN",Id:"BBB222",Name:"Fabrikam",RowId:2},{Country:"CAN",Id:"BBB222",Name:"Fabrikam",RowId:5},{Country:"MEX",Id:"EEE555",Name:"ACME INC.",RowId:Blank()},{Country:"USA",Id:"FFF666",Name:"Dunder Mifflin",RowId:Blank()},{Country:Blank(),Id:Blank(),Name:Blank(),RowId:7},{Country:Blank(),Id:Blank(),Name:Blank(),RowId:8}) // Renaming columns with 'As' keyword >> Join(t1, t2, LeftRecord.Id = RightRecord.SupplierId, JoinType.Inner, LeftRecord.Id As SupId, LeftRecord.Name As SupName, RightRecord.Fruit As FruitName)