anzwdev / al-code-outline

AL Code Outline for Visual Studio Code
MIT License
51 stars 13 forks source link

Separate 'Sort Triggers' action #535

Closed fvet closed 3 months ago

fvet commented 9 months ago

I would love to get started with (a subset of) the 'Sort Procedures' action, however I'm only interested in applying the 'Sort Triggers' part. For sort triggers, the naturalorder sorting seems fine for us, but we do not want to apply any automatic sorting on procedures (as these normally follow a custom sorting order defined by the developer)

Is this already supported? Can we use the 'Sort Procedures' action and disable the procedure sorting part? Or does this require the introduction of a new 'Sort Triggers' action (re-using the same alOutline.triggersSortMode and alOutline.triggersNaturalOrder settings)

anzwdev commented 7 months ago

Thank you for reporting your idea. I've added new "Sort Triggers in the current Editor/Project" commands, "SortTriggers" code cleanup action and code actions. They are available in the current release.

fvet commented 7 months ago

@anzwdev I just gave the "Sort Triggers" action a short spin and would like to provide some feedback.

Update: Givin' this a second thought, it's no real issue to put global in front of trigger / procedure declarations.

image


Looking at below code, I would expect the OnInsert to be sorted before the OnDelete (as this seems like the natural order)

image

However, no sorting is applied after running the command. Am I lacking some setup?


Here's one sample

image

Before

page 71177009 "ESCA Source Documents"
{
    ApplicationArea = All;
    Caption = 'Source Documents';
    DeleteAllowed = false;
    InsertAllowed = false;
    PageType = List;
    SourceTable = "ESCA Source Document";
    UsageCategory = None;

    layout
    {
        area(Content)
        {
            repeater(General)
            {
                Editable = false;
                FreezeColumn = "Source No.";
                field("Location Code"; Rec."Location Code")
                {
                    ToolTip = 'Specifies the location code to which the line is linked.';
                    Visible = false;
                }
                field("Source Document"; Rec."Source Document")
                {
                    ToolTip = 'Specifies the type of document that the line relates to.';
                }
                field("Source No."; Rec."Source No.")
                {
                    ToolTip = 'Specifies the number of the source document that the entry originates from.';
                }
                field("External Document No."; Rec."External Document No.")
                {
                    ToolTip = 'Specifies a document number that refers to the customer''s or vendor''s numbering system.';
                }
                field("Your Reference"; Rec."Your Reference")
                {
                    ToolTip = 'Specifies the customer''s or vendor''s reference.';
                }
                field("Destination Type"; Rec."Destination Type")
                {
                    ToolTip = 'Specifies whether the type of destination associated with this line is a customer or a vendor.';
                }
                field("Destination No."; Rec."Destination No.")
                {
                    ToolTip = 'Specifies the number or code of the customer or vendor related to the line.';
                }
                field("Ship-to Code"; Rec."Ship-to Code")
                {
                    ToolTip = 'Specifies the value of the Code field.';
                }
                field("Ship-to Name"; Rec."Ship-to Name")
                {
                    ToolTip = 'Specifies the value of the Name field.';
                }
                field("Ship-to Name 2"; Rec."Ship-to Name 2")
                {
                    ToolTip = 'Specifies the value of the Name 2 field.';
                    Visible = false;
                }
                field("Ship-to Address"; Rec."Ship-to Address")
                {
                    ToolTip = 'Specifies the value of the Address field.';
                }
                field("Ship-to Address 2"; Rec."Ship-to Address 2")
                {
                    ToolTip = 'Specifies the value of the Address 2 field.';
                    Visible = false;
                }
                field("Ship-to Country/Region Code"; Rec."Ship-to Country/Region Code")
                {
                    ToolTip = 'Specifies the value of the Country/Region Code field.';
                }
                field("Ship-to County"; Rec."Ship-to County")
                {
                    ToolTip = 'Specifies the value of the County field.';
                }
                field("Ship-to Post Code"; Rec."Ship-to Post Code")
                {
                    ToolTip = 'Specifies the value of the Post Code field.';
                }
                field("Ship-to City"; Rec."Ship-to City")
                {
                    ToolTip = 'Specifies the value of the City field.';
                }
                field("Ship-to Contact"; Rec."Ship-to Contact")
                {
                    ToolTip = 'Specifies the name of the contact person at the address.';
                }
                field("Transport Information"; Rec."Transport Information")
                {
                    ToolTip = 'Specify additional information to be printed on transport documents.';
                    Visible = false;
                }
            }
        }
    }

    actions
    {
        area(Navigation)
        {
            action(Card)
            {
                Caption = 'Card';
                Image = EditLines;
                Scope = Repeater;
                ShortcutKey = 'Shift+F7';
                ToolTip = 'View or change detailed information about the record on the document.';

                #region OnAction
                trigger OnAction()
                begin
                    Rec.ShowCard();
                end;
                #endregion OnAction
            }
        }
        area(Promoted)
        {
            group(Category_Process)
            {
                Caption = 'Process';

                actionref(Card_Promoted; Card) { }
            }
        }
    }

    #region SetRecords
    internal procedure SetRecords(var SourceDocument: Record "ESCA Source Document" temporary)
    begin
        Rec.Copy(SourceDocument, true);
    end;
    #endregion SetRecords

    #region ShowPaymentMethods
    internal procedure ShowPaymentMethods()
    begin
#pragma warning disable AA0206
        PaymentMethodsVisible := true;
        ReturnReusablePackagingVisible := false;
        CreateReturnOrderVisible := false;
#pragma warning restore AA0206
    end;
    #endregion ShowPaymentMethods

    #region ShowReturnReusablePackaging
    internal procedure ShowReturnReusablePackaging()
    begin
#pragma warning disable AA0206
        PaymentMethodsVisible := false;
        ReturnReusablePackagingVisible := true;
        CreateReturnOrderVisible := false;
#pragma warning restore AA0206
    end;
    #endregion ShowReturnReusablePackaging

    internal procedure ShowCreateReturnOrder()
    begin
#pragma warning disable AA0206
        PaymentMethodsVisible := false;
        ReturnReusablePackagingVisible := false;
        CreateReturnOrderVisible := true;
#pragma warning restore AA0206
    end;

    #region SetShipmentOrReceiptDate
    internal procedure SetShipmentOrReceiptDate(NewShipmentOrReceiptDate: Date)
    begin
#pragma warning disable AA0206
        ShipmentOrReceiptDate := NewShipmentOrReceiptDate;
#pragma warning restore AA0206
    end;
    #endregion SetShipmentOrReceiptDate

    protected var
        CreateReturnOrderVisible: Boolean;
        PaymentMethodsVisible: Boolean;
        ReturnReusablePackagingVisible: Boolean;
        ShipmentOrReceiptDate: Date;
}

AFTER

page 71177009 "ESCA Source Documents"
{
    ApplicationArea = All;
    Caption = 'Source Documents';
    DeleteAllowed = false;
    InsertAllowed = false;
    PageType = List;
    SourceTable = "ESCA Source Document";
    UsageCategory = None;

    layout
    {
        area(Content)
        {
            repeater(General)
            {
                Editable = false;
                FreezeColumn = "Source No.";
                field("Location Code"; Rec."Location Code")
                {
                    ToolTip = 'Specifies the location code to which the line is linked.';
                    Visible = false;
                }
                field("Source Document"; Rec."Source Document")
                {
                    ToolTip = 'Specifies the type of document that the line relates to.';
                }
                field("Source No."; Rec."Source No.")
                {
                    ToolTip = 'Specifies the number of the source document that the entry originates from.';
                }
                field("External Document No."; Rec."External Document No.")
                {
                    ToolTip = 'Specifies a document number that refers to the customer''s or vendor''s numbering system.';
                }
                field("Your Reference"; Rec."Your Reference")
                {
                    ToolTip = 'Specifies the customer''s or vendor''s reference.';
                }
                field("Destination Type"; Rec."Destination Type")
                {
                    ToolTip = 'Specifies whether the type of destination associated with this line is a customer or a vendor.';
                }
                field("Destination No."; Rec."Destination No.")
                {
                    ToolTip = 'Specifies the number or code of the customer or vendor related to the line.';
                }
                field("Ship-to Code"; Rec."Ship-to Code")
                {
                    ToolTip = 'Specifies the value of the Code field.';
                }
                field("Ship-to Name"; Rec."Ship-to Name")
                {
                    ToolTip = 'Specifies the value of the Name field.';
                }
                field("Ship-to Name 2"; Rec."Ship-to Name 2")
                {
                    ToolTip = 'Specifies the value of the Name 2 field.';
                    Visible = false;
                }
                field("Ship-to Address"; Rec."Ship-to Address")
                {
                    ToolTip = 'Specifies the value of the Address field.';
                }
                field("Ship-to Address 2"; Rec."Ship-to Address 2")
                {
                    ToolTip = 'Specifies the value of the Address 2 field.';
                    Visible = false;
                }
                field("Ship-to Country/Region Code"; Rec."Ship-to Country/Region Code")
                {
                    ToolTip = 'Specifies the value of the Country/Region Code field.';
                }
                field("Ship-to County"; Rec."Ship-to County")
                {
                    ToolTip = 'Specifies the value of the County field.';
                }
                field("Ship-to Post Code"; Rec."Ship-to Post Code")
                {
                    ToolTip = 'Specifies the value of the Post Code field.';
                }
                field("Ship-to City"; Rec."Ship-to City")
                {
                    ToolTip = 'Specifies the value of the City field.';
                }
                field("Ship-to Contact"; Rec."Ship-to Contact")
                {
                    ToolTip = 'Specifies the name of the contact person at the address.';
                }
                field("Transport Information"; Rec."Transport Information")
                {
                    ToolTip = 'Specify additional information to be printed on transport documents.';
                    Visible = false;
                }
            }
        }
    }

    actions
    {
        area(Navigation)
        {
            action(Card)
            {
                Caption = 'Card';
                Image = EditLines;
                Scope = Repeater;
                ShortcutKey = 'Shift+F7';
                ToolTip = 'View or change detailed information about the record on the document.';

                #region OnAction
                trigger OnAction()
                begin
                    Rec.ShowCard();
                end;
                #endregion OnAction
            }
        }
        area(Promoted)
        {
            group(Category_Process)
            {
                Caption = 'Process';

                actionref(Card_Promoted; Card) { }
            }
        }
    }

    protected var
        CreateReturnOrderVisible: Boolean;
        PaymentMethodsVisible: Boolean;
        ReturnReusablePackagingVisible: Boolean;
        ShipmentOrReceiptDate: Date;

    internal procedure ShowCreateReturnOrder()
    begin
#pragma warning disable AA0206
        PaymentMethodsVisible := false;
        ReturnReusablePackagingVisible := false;
        CreateReturnOrderVisible := true;
#pragma warning restore AA0206
    end;

    #region SetRecords
    internal procedure SetRecords(var SourceDocument: Record "ESCA Source Document" temporary)
    begin
        Rec.Copy(SourceDocument, true);
    end;
    #endregion SetRecords

    #region ShowPaymentMethods
    internal procedure ShowPaymentMethods()
    begin
#pragma warning disable AA0206
        PaymentMethodsVisible := true;
        ReturnReusablePackagingVisible := false;
        CreateReturnOrderVisible := false;
#pragma warning restore AA0206
    end;
    #endregion ShowPaymentMethods

    #region ShowReturnReusablePackaging
    internal procedure ShowReturnReusablePackaging()
    begin
#pragma warning disable AA0206
        PaymentMethodsVisible := false;
        ReturnReusablePackagingVisible := true;
        CreateReturnOrderVisible := false;
#pragma warning restore AA0206
    end;
    #endregion ShowReturnReusablePackaging

    #region SetShipmentOrReceiptDate
    internal procedure SetShipmentOrReceiptDate(NewShipmentOrReceiptDate: Date)
    begin
#pragma warning disable AA0206
        ShipmentOrReceiptDate := NewShipmentOrReceiptDate;
#pragma warning restore AA0206
    end;
    #endregion SetShipmentOrReceiptDate
}
TKapitan commented 4 months ago

Hi @anzwdev, I've finally some time to try add the codecleanup actions to our projects. This "Sort Triggers" option is interesting, but I have the same problem as @fvet.

We are following (and still want to follow) the MSFT best practise and have order fields - object triggers - global variables - procedures (https://learn.microsoft.com/en-us/dynamics365/business-central/dev-itpro/compliance/apptest-bestpracticesforalcode#file-structure)

However, for some reason, the sort triggers change the order to fields - global variables - object triggers - procedures. Is there any way how to configure the required order?

anzwdev commented 4 months ago

Hi @TKapitan

I am looking at this now, I hope that I will have a solution in the next few days.

anzwdev commented 3 months ago

I've released a new version of the extension with a few changes.

  1. There is a new setting for sorting global variables section: alOutline.sortMembersGlobalVariablesSortMode. Available values are
  1. There was a bug in handling region and endregion directives around procedures and triggers
  2. By default the command is not sorting regions, methods are only sorted inside each region. That's why nothing would be sorted if you are adding region and endregion directives around each procedure and thigger. There is a setting that can ignore regions if they contain a single method inside: alOutline.sortSingleNodeRegions, just set it to true to make it work.