Page 2610 Feature Management in 27

App
System Application
Namespace
System.Environment.Configuration
Source table
2000000211

Events, 1

Versions171819202122232425262728latest

Source242526272829

Source in 27

src/System Application/App/Feature Key/src/FeatureManagement.Page.al373 lines, Copyright (c) Microsoft Corporation. MIT

// ------------------------------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See License.txt in the project root for license information.
// ------------------------------------------------------------------------------------------------

namespace System.Environment.Configuration;

using System.Agents;

/// <summary>
/// Page that enables a user to pick which new features to use
/// </summary>
page 2610 "Feature Management"
{
    PageType = List;
    Caption = 'Feature Management';
    ApplicationArea = All;
    UsageCategory = Administration;
    AboutTitle = 'Managing change';
    AboutText = 'Some new features are turned off when Business Central is updated to a newer version. These features are optional for a period of time until they are automatically enabled for all users in a later software update according to the [Release Plan](https://go.microsoft.com/fwlink/?linkid=2227906). You can prepare in advance by enabling these features for all users on the right environment at the right time that suits your schedule.';
    AdditionalSearchTerms = 'new features,feature key,opt in,turn off features,enable features,early access,preview';
    SourceTable = "Feature Key";
    PromotedActionCategories = 'New,Process,Report,Data Update';
    InsertAllowed = false;
    DeleteAllowed = false;
    LinksAllowed = false;
    Extensible = false;
    Permissions = tabledata "Feature Data Update Status" = r,
                  tabledata "Feature Key" = rm;

    layout
    {
        area(Content)
        {
            repeater(FeatureKeys)
            {
                field(FeatureDescription; Rec.Description)
                {
                    Caption = 'Feature';
                    ToolTip = 'Specifies the name of the new capability or change in design.';
                    ApplicationArea = All;
                    Editable = false;
                    Width = 60;
                }
                field(LearnMore; LearnMoreLbl)
                {
                    ShowCaption = false;
                    ApplicationArea = All;
                    Editable = false;
                    Caption = 'Learn more';
                    ToolTip = 'View a detailed description of new capabilities and behaviors that are available when the feature is enabled (opens in a new tab).';

                    trigger OnDrillDown()
                    begin
                        Hyperlink(Rec."Learn More Link");
                    end;
                }
                field(MandatoryBy; Rec."Mandatory By")
                {
                    Caption = 'Automatically enabled from';
                    ToolTip = 'Specifies a future software version and approximate date when this feature is automatically enabled for all users and cannot be disabled. Until this future version, the feature is optional.';
                    ApplicationArea = All;
                    Editable = false;
                }
                field("Mandatory By Version"; Rec."Mandatory By Version")
                {
                    Caption = 'Automatically enabled from version';
                    ToolTip = 'Specifies a future software version when this feature is automatically enabled for all users and cannot be disabled. Until this future version, the feature is optional.';
                    ApplicationArea = All;
                    Editable = false;
                }
                field(EnabledFor; Rec.Enabled)
                {
                    Caption = 'Enabled for';
                    ToolTip = 'Specifies whether the feature is enabled for all users or for none. The change takes effect the next time each user signs in.';
                    ApplicationArea = All;
                    Editable = (not Rec."Is One Way") or (Rec.Enabled = Rec.Enabled::None);
                    StyleExpr = EnabledForStyle;

                    trigger OnValidate()
                    var
                        Confirmed: Boolean;
                    begin
                        case Rec.Enabled of
                            Rec.Enabled::None:
                                begin
                                    if Rec."Is One Way" then
                                        Error(OneWayAlreadyEnabledErr);
                                    FeatureManagementFacade.OnAfterFeatureDisableConfirmed(Rec);
                                end;
                            else begin
                                if Rec."Is One Way" then
                                    Confirmed := Confirm(OneWayWarningMsg)
                                else
                                    Confirmed := true;
                                if not Confirmed then
                                    Error('');

                                FeatureManagementFacade.OnAfterFeatureEnableConfirmed(Rec);

                                if not FeatureManagementFacade.Update(FeatureDataUpdateStatus) then
                                    Error('');
                            end;
                        end;
                        FeatureManagementFacade.AfterValidateEnabled(Rec);
                        UpdateStyle();
                        CurrPage.Update(true);
                    end;
                }
                field(TryItOut; TryItOut)
                {
                    Caption = 'Get started';
                    ApplicationArea = All;
                    Editable = false;
                    Enabled = Rec."Can Try";
#pragma warning disable AA0219
                    ToolTip = 'Starts a new session with the feature temporarily enabled (opens in a new tab). This does not affect any other users.';
#pragma warning restore AA0219
                    trigger OnDrillDown()
                    begin
                        if Rec."Can Try" then begin
                            Hyperlink(FeatureManagementFacade.GetFeatureKeyUrlForWeb(Rec.ID));
                            Message(TryItOutStartedMsg);
                        end;
                    end;
                }
                field(DataUpdateStatus; FeatureDataUpdateStatus."Feature Status")
                {
                    Caption = 'Current Company Status';
                    ApplicationArea = All;
                    Editable = false;
                    ToolTip = 'Specifies the status of data update in the current company. Until it is complete the feature is not fully enabled in the current company.';
                    StyleExpr = DataUpdateStype;
                }
                field("Start Date\Time"; FeatureDataUpdateStatus."Start Date/Time")
                {
                    Caption = 'Update Start Date/Time';
                    ApplicationArea = All;
                    Editable = false;
                    ToolTip = 'Specifies the earliest date and time when the data update task should be run.';
                }
                field("Task Id"; FeatureDataUpdateStatus."Task Id")
                {
                    ApplicationArea = All;
                    Visible = false;
                    Editable = false;
                    ToolTip = 'Specifies the id of the scheduled task.';
                }
                field("Session Id"; FeatureDataUpdateStatus."Session Id")
                {
                    ApplicationArea = All;
                    Visible = false;
                    Editable = false;
                    ToolTip = 'Specifies the session id where the task is being ran.';
                }
                field("Server Instance ID"; FeatureDataUpdateStatus."Server Instance Id")
                {
                    ApplicationArea = All;
                    Visible = false;
                    Editable = false;
                    ToolTip = 'Specifies the serviec instance id where the task is being ran.';
                }
            }
        }
    }
    actions
    {
        area(Processing)
        {
            group(DataUpdate)
            {
                Caption = 'Data Update';
                action(Schedule)
                {
                    Caption = 'Schedule';
                    ToolTip = 'Schedule or run the data update task in the current or background session.';
                    Image = Planning;
                    ApplicationArea = All;
                    Visible = CanSchedule;
                    Promoted = true;
                    PromotedIsBig = true;
                    PromotedOnly = true;
                    PromotedCategory = Category4;
                    trigger OnAction()
                    begin
                        FeatureManagementFacade.Update(FeatureDataUpdateStatus);
                    end;
                }
                action(ShowTaskLog)
                {
                    Caption = 'Show Log';
                    ToolTip = 'Show the error log entry.';
                    Image = Log;
                    ApplicationArea = All;
                    Visible = CanShowLog;
                    Promoted = true;
                    PromotedIsBig = true;
                    PromotedOnly = true;
                    PromotedCategory = Category4;
                    trigger OnAction()
                    begin
                        FeatureManagementFacade.OnShowTaskLog(FeatureDataUpdateStatus);
                    end;
                }
                action(CancelScheduling)
                {
                    Caption = 'Cancel Scheduled Job';
                    ToolTip = 'Cancel the scheduled data update task.';
                    Image = Cancel;
                    ApplicationArea = All;
                    Visible = CanCancelScheduling;
                    Promoted = true;
                    PromotedIsBig = true;
                    PromotedOnly = true;
                    PromotedCategory = Category4;
                    trigger OnAction()
                    begin
                        FeatureManagementFacade.CancelTask(FeatureDataUpdateStatus, true);
                    end;
                }
            }
        }
    }

    views
    {
        view("Try it out now")
        {
            Caption = 'Try it out now';
            Filters = where("Can Try" = const(true));
        }
    }

    trigger OnOpenPage()
    var
        AgentUtilities: Codeunit "Agent Utilities";
        FeatureIDFilter: Text;
        IgnoreFilter: Boolean;
    begin
        AgentUtilities.BlockPageFromBeingOpenedByAgent();

        OnOpenFeatureMgtPage(FeatureIDFilter, IgnoreFilter);
        if not IgnoreFilter and (FeatureIDFilter <> '') then begin
            Rec.FilterGroup(2);
            Rec.SetFilter(ID, FeatureIDFilter);
            Rec.FilterGroup(0);
        end;
    end;

    trigger OnAfterGetRecord()
    begin
        GetFeatureDataUpdateStatus();
        if Rec."Can Try" then
            TryItOut := TryItOutLbl
        else
            Clear(TryItOut);
    end;

    trigger OnAfterGetCurrRecord()
    begin
        GetFeatureDataUpdateStatus();
        if Rec."Can Try" then
            TryItOut := TryItOutLbl
        else
            Clear(TryItOut);
    end;

    var
        FeatureDataUpdateStatus: Record "Feature Data Update Status";
        FeatureManagementFacade: Codeunit "Feature Management Facade";
        LearnMoreLbl: Label 'Learn more';
        TryItOutLbl: Label 'Try it out';
        TryItOutStartedMsg: Label 'A new browser tab was opened for you to try out the feature. For now, the feature has been temporarily enabled for you only. It will remain enabled whenever you open Business Central in the browser, until you completely sign out or close the browser.';
        OneWayWarningMsg: Label 'After you enable this feature for all users, you cannot turn it off again. This is because the feature may include changes to your data and may initiate an upgrade of some database tables as soon as you enable it.\\We strongly recommend that you first enable and test this feature on a sandbox environment that has a copy of production data before doing this on a production environment.\\For detailed information about the impact of enabling this feature, you should choose No and use the Learn more link.\\Are you sure you want to enable this feature?';
        OneWayAlreadyEnabledErr: Label 'This feature has already been enabled and cannot be disabled.';
        TryItOut: Text;
        CanSchedule: Boolean;
        CanCancelScheduling: Boolean;
        CanShowLog: Boolean;
        EnabledForStyle: Text;
        DataUpdateStype: Text;

    local procedure GetFeatureDataUpdateStatus()
    begin
        FeatureManagementFacade.GetFeatureDataUpdateStatus(Rec, FeatureDataUpdateStatus);
        UpdateVisibility();
        UpdateStyle();
    end;

    local procedure IsFeatureEnabled(): Boolean;
    begin
        exit(Rec.Enabled = Rec.Enabled::"All Users");
    end;

    local procedure InitActionVisibility()
    begin
        CanSchedule := false;
        CanCancelScheduling := false;
        CanShowLog := false;
    end;

    local procedure UpdateVisibility()
    begin
        InitActionVisibility();
        if FeatureDataUpdateStatus."Data Update Required" and IsFeatureEnabled() then
            UpdateActionsVisibility();
    end;

    local procedure UpdateActionsVisibility();
    begin
        CanSchedule := false;
        CanCancelScheduling := false;
        CanShowLog := false;

        case FeatureDataUpdateStatus."Feature Status" of
            FeatureDataUpdateStatus."Feature Status"::Pending:
                CanSchedule := true;
            FeatureDataUpdateStatus."Feature Status"::Scheduled:
                CanCancelScheduling := true;
            FeatureDataUpdateStatus."Feature Status"::Updating:
                CanShowLog := true;
            FeatureDataUpdateStatus."Feature Status"::Incomplete:
                begin
                    CanSchedule := true;
                    CanShowLog := true;
                end;
            FeatureDataUpdateStatus."Feature Status"::Complete:
                CanShowLog := true;
        end;
    end;

    local procedure UpdateStyle()
    begin
        case Rec.Enabled of
            Rec.Enabled::"All Users":
                case FeatureDataUpdateStatus."Feature Status" of
                    FeatureDataUpdateStatus."Feature Status"::Enabled,
                    FeatureDataUpdateStatus."Feature Status"::Complete:
                        begin
                            EnabledForStyle := 'Favorable';
                            DataUpdateStype := 'Favorable';
                        end;

                    FeatureDataUpdateStatus."Feature Status"::Pending:
                        begin
                            EnabledForStyle := 'Ambiguous';
                            DataUpdateStype := 'Unfavorable';
                        end;
                    FeatureDataUpdateStatus."Feature Status"::Scheduled,
                    FeatureDataUpdateStatus."Feature Status"::Updating:
                        begin
                            EnabledForStyle := 'Ambiguous';
                            DataUpdateStype := 'StrongAccent';
                        end;
                    FeatureDataUpdateStatus."Feature Status"::Incomplete:
                        begin
                            EnabledForStyle := 'Unfavorable';
                            DataUpdateStype := 'Unfavorable';
                        end;
                end;
            Rec.Enabled::None:
                begin
                    EnabledForStyle := 'Subordinate';
                    DataUpdateStype := 'Subordinate';
                end;
        end;
    end;

    [IntegrationEvent(false, false)]
    local procedure OnOpenFeatureMgtPage(var FeatureIDFilter: Text; var IgnoreFilter: Boolean)
    begin
    end;
}

Events, 1

KindNameParametersObsolete
Integration eventOnOpenFeatureMgtPage(var Text, var Boolean)-