AL Language extension for Microsoft Dynamics 365 Business Central version 14.3.1327807 (New version)

[ESP] En el siguiente enlace puedes ver leer los cambios relacionados a la versión vigente:

[ENG] En el siguiente link, you can read the changes related to the current version:


14.3

Yaml-support in JsonObject

Support for YAML is add to the JsonObject. YAML can be read into a JsonObject and be manipulated using the JsonObject API.

Two new methods are added to read YAML into a JsonObject instance:

[Ok :=] ReadFromYaml(String)
[Ok :=] ReadFromYaml(InStream)

And two new methods are added to write a JsonObject instance as YAML:

[Ok :=] WriteToYaml(String)
[Ok :=] WriteToYaml(OutStream)

AppSourceCop


14.2

Resources in extensions

Resource files can now be packaged as part of an extension. To add resources to your extension, the following property has to be set in your app.json:

"resourceFolders": [<list of folders that contain resources>]

The folders should be listed relative to the root of your project. For example:

"resourceFolders": ["Resources"]

This will include all files under the folder ‘resources’. The resource folders themselves can contain additional subfolders. For example, you could have the following folder structure:

MyApp
| - Resources/
  | - Images/
    | - MyImage.png
  | - Configuration/
    | - MyConfiguration.json
| - src/
  | - MyCodeunit.codeunit.al

Access to these resources is done through the NavApp.GetResource("resource name": Text; var instream: Instream; [optional] encoding: TextEncoding) method. The name of a resource is its path from the root of its resource folder. So for the folder structure above, you can do:

procedure MyProc()
var
    resultStream: Instream;
    jsonText: Text;
begin
    NavApp.GetResource("Images/MyImage.png", resultStream);
    // Do stuff with the blob in the resultStream object

    NavApp.GetResource("Configuration/MyConfiguration.json", resultStream, TextEncoding::UTF8);
    jsonText := resultStream.Read(jsonText);
end

There are also the methods NavApp.GetResourceAsText("resource name": Text; [optional] encoding: TextEncoding): Text and NavApp.GetResourceAsJson("resource name": Text; [optional] encoding: TextEncoding): JsonObject that directly retrieves resources as Text or JsonObject types.

The method NavApp.ListResources([optional] filter: Text) is also provided to allow for iteration over resources. The filter value for the method can contain wildcards. If it does not contain wildcards, then any resources with the filter text within its name will be returned. For example:

/**
* For the following resource structure:
* Resources/
*     Images/
*         SampleImage1.png
*         SampleImage2.png
*         SampleImage3.jpg
*         TemplateImage.jpg
*     Snippet/
*         SampleSnippet.txt
*         TemplateSnippet.txt
*/

// This will return: ["Images/SampleImage1.png","Images/SampleImage2.png","Images/SampleImage3.jpg", "SampleSnippet.txt"]
NavApp.ListResources("Sample");

// This will return: ["Images/SampleImage1.png","Images/SampleImage2.png"]
NavApp.ListResources("Images/*.png")

Resources can only be accessed within the scope of the app that contains them. This means that there is no way to access the resources of another app.

AppSourceCop

Miscellaneous


14.1

Miscellaneous


14.0

Github Issues

AppSourceCop

Miscellaneous

Defining a positive list of elements in page customizations

Profiles and page customizations can be used to tailor the interface for users of a specific role. Since page customizations can hide elements such as controls, actions, or views, they are suited for defining a negative list of elements. However, any visible element that is not referenced by the page customization would be shown on the page, including elements defined in other extensions.

For instance, the following code reduces the Customer Card to only the customer’s Name and the promoted Email action.

pagecustomization MyCustomerCardCust customizes "Customer Card"
{
    ClearActions = true; // Hide all actions on the page
    ClearLayout = true; // Hide all layout elements on the page

    layout
    {
        modify(Name) { Visible = true; } // Show the Name
    }

    actions
    {
        modify(Email_Promoted) { Visible = true; } // Show the Email action
    }
}

Deprecate legacy report layout functions

Support for profile extension objects

profileextension MyProfileExt extends "O365 SALES"
{
    Caption = 'Profile Extension Caption';
    ProfileDescription = 'Profile Extension Description';
    Enabled = true;
    Promoted = true;
    RoleCenter = 9027;
    Customizations = SalesOrderCustomization, SalesQuoteCustomization;
}

Introduced new type PageStyle

The type can be used to get the valid values for StyleExpr, found on page controls. Here is an example of how to use it:

layout
{
    area(Content)
    {
        field(Name; rec.Name)
        {
            StyleExpr = nameStyle;
        }
    }
}

var nameStyle : Text;

local procedure ChangeNameStyle(newPageStyle : PageStyle)
begin
    nameStyle := format(newPageStyle);
end;

New command – Package full dependency tree for active project

We have added a new command that packages the active project and its entire dependency tree. Its purpose is to assist local development by allowing a developer to forcefully rebuild all the packages required for a single project.

This keyword

We have added support for the this keyword for self-reference on all objects. The main benefits are

  • Allow codeunits to pass a reference to this as an argument to another method.
  • Improve readability by signaling that a referenced symbol is a member on the object itself.

Support for extending interfaces

It is now possible to extend one or more existing interfaces when you declare an interface. When implementing an interface that extends other interfaces the implementor must also implement all methods from all extended interfaces.

The syntax is

interface IFoo
{
    procedure Foo();
}

interface IBar
{
    procedure Bar();
}

interface IFooBar extends IFoo, IBar
{
    procedure FooBar();
}

codeunit 10 TheImplementor implements IFooBar
{
    // Must implement IFoo, IBar, IFooBar
}

In the example above the TheImplementor can be used as both IFooIBar, and IFooBar. The feature also works with the testing and casting operators.

The as operator

The as operator is used for casting an instance of an interface to a specific interface. If the source interface does not implement the target interface, it will throw an error at runtime. Here’s an example:

procedure CastInterface(intf: Interface IFoo): Interface IBar
begin
    exit(intf as IBar); // Throws an error if 'intf' doesn't implement 'IBar'
end;

Similarly, the as keyword works with variants:

procedure CastInterface(v: Variant): Interface IBar
begin
    exit(v as IBar); // Throws an error if 'v' doesn't implement 'IBar'
end;

The is operator

The is operator allows you to test whether an instance of an interface or the content of a variant supports a specific interface. Here’s the syntax for using the is keyword:

procedure TestInterface(intf: Interface IFoo)
begin
    if intf is IBar then
        Message('I also support IBar');
end;

You can also use the is operator with variants:

procedure TestVariant(v: Variant)
begin
    if v is IBar then
        Message('I support IBar');
end;

New Date/Time/DateTime methods

We have modernized the Date/Time/DateTime APIs for extracting sub-components of the types.

TypeNew methodExistingDescription
DateMyDate.DayDate2DMY(MyDate, 1)Gets the day of month from MyDate
DateMyDate.MonthDate2DMY(MyDate, 2)Gets the month from MyDate
DateMyDate.YearDate2DMY(MyDate, 3)Gets the year from MyDate
DateMyDate.DayOfWeekDate2DWY(MyDate, 1)Gets the day of week from MyDate
DateMyDate.YearDate2DWY(MyDate, 2)Gets the week number from MyDate
TimeMyTime.HourEvaluate(i, Format(Time, 2, '<HOURS24>'))Gets the hours MyTime (0..23).
TimeMyTime.MinuteEvaluate(i, Format(Time, 2, '<MINUTES>'))Gets the hours MyTime (0..59).
TimeMyTime.SecondEvaluate(i, Format(Time, 2, '<SECONDS>'))Gets the hours MyTime (0..59).
TimeMyTime.MillisecondEvaluate(i, Format(Time, 3, '<THOUSANDS>'))Gets the hours MyTime (0..999).
DateTimeMyDateTime.DateDT2Date(MyDateTime)Gets the date part of MyDateTime
DateTimeMyDateTime.TimeDT2Time(MyDateTime)Gets the time part of MyDateTime

There are no changes to the existing APIs.

Wildcard search in AL Explorer

We have improved the search functionality in AL Explorer by supporting * and ? wildcards.

* means zero or more characters ? means any single character

Here are some examples

PatternDescriptionExamples
Customer*Starts with Customer‘Customer Card’, ‘Customer’
*CardEnds with Card‘Customer Card’, ‘Item Card’, ‘SomeCard’
Customer*CardStarts with Customer and ends with Card‘Customer Card’, ‘Customer Accounts Card’
*Customer*Customer anywhere‘Customer’, ‘Apply Customer Entries’

Ternary operator ?: in AL

We have added the ternary (conditional) operator to the AL language. The ternary operator ? : known from other programming languages streamlines conditional operations in code, enhances readability, and reduces verbosity. It’s particularly useful for simple conditions, promoting code clarity, and intent-focused programming.

The following examples show how the code in GetBooleanText() can be rewritten using the ternary operator to be less verbose and more succint.

Without the ternary operator

procedure GetBooleanText(b: Boolean): Text;
begin
    if b then
        exit('True')
    else
        exit('False');
end;

With the ternary operator

procedure GetBooleanString(b: Boolean): Text;
begin
    exit(b ? 'True' : 'False');
end;

Support for SaveAsJson on the Query object

We have added support for SaveAsJson on the Query object. This functionality is now available alongside the existing SaveAsXml and SaveAsCsv methods.

procedure Test();
var
    result : Boolean;
    os: OutStream;
begin
    result := Query.SaveAsJson(10, os);
end;

Pull extension source from Git when opening Visual Studio Code from the web client

This feature allows users to pull source code from a Git repository or a specific build using the source metadata in the extension’s manifest. This is particularly useful if access to extension code is blocked by IP resource exposure protection.

From the Extension Management list and Page Inspector (Extensions tab) pages, a new “Open Source in VS Code” option is available in the context menu for an extension. When selected, Visual Studio Code will open and prompt you to clone or open the Git repository for the extension and synchronize it with the commit version used to compile it, using the repo metadata included in the extension. It will also remember the local path where the repository is located for easier access. This feature empowers support, consultants, and developers to navigate code, hotfix builds, or sync to get the latest changes for investigation or development.


Más información / More information:

Deja un comentario