Business Central 2019 Wave 2 – How to add your own headlines

Business Central has headlines that are shown on the role centers. The default headlines only show a greeting and – under certain circumstances – a link to the documentation.

You also probably have seen the additional headlines showing sales for the week or other information. These additional headlines are part of the Essential Business Headlines extension supplied by Microsoft. Those are not only useful information, but also a good showcase on how to add your own. However, it takes a little bit to figure out how this all works. I figured, it would be easier for those of you wanting to add your own headlines, if you had a guide explaining how to do this.

What do we want to do?

We want to be able to add our own headlines to the already existing headlines. You can find the total project at the bottom of the blog post.

Standard Headline in Business Central
Standard Business Central Role Center Headlines

How do headlines work?

Each of the role centers have a headline part page integrated. When the page is opened, a task is scheduled to update the headlines. This task throws an event that you can subscribe to and add your own headline to it.

The individual headlines themselves are groups on the headlines part. Which headlines are shown and which are not is controlled by the visibility of those pages.

I am going to add three different headlines to the already existing ones. Those are not necessarily useful, but they are only to illustrate the process. The first one will show the total sales amount in the database, the second one a random customer, and the last one a random item. They look like this:

Total Sales Headline in Business Central
Total Sales amount
Random customer headline in Business Central
Random customer
Random Item Headline in Business Central
Random item

What do we need to do?

Role Center Page Headline Part extension

You have to decide for each Role Center separately, if you want to add your headlines or not. I only added it to the Business Manager role center, but the same will also then have to be done to all other role centers.

For this, we want to create a page extension to the Headline RC Business Manager page. You can define where the headlines should be shown, but I would suggest to add them to the end. The code for each group is as follows:

group(DemoHeadlineSales)
{
    Visible = DemoHeadlineSalesVisible;
    ShowCaption = false;
    Editable = false;

    field(DemoHeadlineSalesTextField; DemoHeadlineSalesText)
    {
        ApplicationArea = All;

        trigger OnDrillDown()
        var
            DemoHeadline: Codeunit "Demo Headline Management";
        begin
            DemoHeadline.OnDrillDownSales();
        end;
    }
} 

You will have to obviously create some new variables. Now – here comes the important part. You add a new event that is raised at OnOpenPage:

trigger OnOpenPage()
begin
    OnSetDemoVisibility(DemoHeadlineSalesVisible, DemoHeadlineSalesText, DemoHeadlineCustomerVisible, DemoHeadlineCustomerText, DemoHeadlineItemVisible, DemoHeadlineItemText);
end;

[IntegrationEvent(false, false)]
local procedure OnSetDemoVisibility(var DemoHeadlineSalesVisible: Boolean; var DemoHeadlineSalesText: Text[250]; var DemoHeadlineCustomerVisible: Boolean; var DemoHeadlineCustomerText: Text[250]; var DemoHeadlineItemVisible: Boolean; var DemoHeadlineItemText: Text[250])
begin
end; 

Now, when this event is raised, you will fill in the details for each of the headlines. Easy, right? Well, this comes next.

Event Subscriptions

There are quite some events to subscribe to. You can see all in the demo code, I am just going over the details for the most important ones. But here are all events that you need to subscribe to:

  • Page “My Settings” – OnBeforeLanguageChange
  • Page “My Settings” – OnBeforeWorkdateChange
  • Codeunit “RC Headlines Executor” – OnComputeHeadlines
  • Codeunit “RC Headlines Page Common” – OnIsAnyExtensionHeadlineVisible
  • Your created event for all role centers

Your OnSetVisibility event created on all Headline Role Center pages

This event is used to define the visibility of your headlines and also the texts that are displayed. However, you won’t calculate the values, they are just displayed. For this to work properly, you have to create a new table (here “Demo Headline Per User”) that defines the status of all headlines and the calculated values per user. This data is refreshed periodically – we get to that later.

Here is the code – it basically makes sure that it’s a normal session (and not a background session, for instance) and that you have read permissions to the new table. Then it reads the values and fills the variables:

[EventSubscriber(ObjectType::Page, Page::"Headline RC Business Manager", 'OnSetDemoVisibility', '', true, true)]
local procedure HeadlineRCBusinessManagerOnSetDemoVisibility(var DemoHeadlineSalesVisible: Boolean; var DemoHeadlineSalesText: Text[250]; var DemoHeadlineCustomerVisible: Boolean; var DemoHeadlineCustomerText: Text[250]; var DemoHeadlineItemVisible: Boolean; var DemoHeadlineItemText: Text[250])
var
    DemoHeadlineUser: Record "Demo Headline Per User";
begin
    if not CanRunSubscribers() then
        exit;
    if not DemoHeadlineUser.ReadPermission() then
        exit;

    TransferHeadlineToPage(DemoHeadlineUser."Headline Type"::TotalSales, DemoHeadlineSalesText, DemoHeadlineSalesVisible);
    TransferHeadlineToPage(DemoHeadlineUser."Headline Type"::RandomCustomer, DemoHeadlineCustomerText, DemoHeadlineCustomerVisible);
    TransferHeadlineToPage(DemoHeadlineUser."Headline Type"::RandomItem, DemoHeadlineItemText, DemoHeadlineItemVisible);
end;

For each one of my headlines, I am calling the function that reads the data from the new table and transfers it to the corresponding variables. You can find the full source code of this table in the demo project together with the source code for the table.

OnIsAnyExtensionHeadlineVisible

This basically should return true, if you want to show one of your headlines. If not, it should not change the value, since other extensions could set it as well. Here is the code:

[EventSubscriber(ObjectType::Codeunit, Codeunit::"RC Headlines Page Common", 'OnIsAnyExtensionHeadlineVisible', '', true, true)]
local procedure RCHeadlinesPageCommonOnIsAnyExtensionHeadlineVisibleSubscriber(var ExtensionHeadlinesVisible: Boolean; RoleCenterPageID: Integer)
var
    DemoHeadlineUser: Record "Demo Headline Per User";
    AtLeastOneHeadlineVisible: Boolean;
begin
    if not CanRunSubscribers() then
        exit;
    if not DemoHeadlineUser.ReadPermission() then
        exit;

    DemoHeadlineUser.SetRange("Headline Visible", true);
    DemoHeadlineUser.SetRange("User Id", UserSecurityId());

    case RoleCenterPageID of
        Page::"Headline RC Business Manager":
            DemoHeadlineUser.SetFilter("Headline Type", '%1|%2|%3',
            DemoHeadlineUser."Headline Type"::TotalSales,
            DemoHeadlineUser."Headline Type"::RandomCustomer,
            DemoHeadlineUser."Headline Type"::RandomItem);
    end;

    AtLeastOneHeadlineVisible := not DemoHeadlineUser.IsEmpty();
    if AtLeastOneHeadlineVisible then
        ExtensionHeadlinesVisible := true;
end; 

You can see in the case statement, you will have to write different filters for each of your role center pages, at least, if you want to be able to show different headlines on different pages. But this function doesn’t do anything other than checking our new table, if any of the extesions for this role center should be visible and then returns true.

OnComputeHeadlines

This is the event that is raised when the system wants you to recalculate the values for each headline. Again, it should call the different calculation functions based on which role center you are on right now.

[EventSubscriber(ObjectType::Codeunit, Codeunit::"RC Headlines Executor", 'OnComputeHeadlines', '', true, true)]
local procedure RCHeadlinesExecutorOnComputeHeadlinesSubscriber(RoleCenterPageID: Integer)
begin
    if not DemoHeadline.WritePermission() then
        exit;
    if not CanRunSubscribers() then
        exit;

    case RoleCenterPageID of
        Page::"Headline RC Business Manager":
            begin
                DemoHeadlineMgt.HandleSalesHeadline();
                DemoHeadlineMgt.HandleCustomerHeadline();
                DemoHeadlineMgt.HandleItemHeadline();
            end;
    end;
end; 

Additional logic

calculating the actual values

This is the most important part. You first will need to determine, how often the headlines should be updated. The Essential Business Headlines app does it every 10 minutes, so I did that as well.

DemoHeadlineUser.GetOrCreateHeadline(DemoHeadlineUser."Headline Type"::RandomCustomer);
if not NeedToUpdateHeadline(DemoHeadlineUser."Headline Computation Date", 600, DemoHeadlineUser."Headline Computation WorkDate") then
    exit;

DemoHeadlineUser.Validate("Headline Visible", false);

The NeedToUpdateHeadline function just checks, if the the last calculation is longer than 10 minutes (600 seconds) ago, it was never calculated before, or the work date changed since the last calculation,

After that, you calculate the value and define the text. In this example, I am just getting a random custom and then create the text. There are two important functions. “Emphasize”, which makes the headline text look highlighted and “clickable”. And the other one is “Truncate” to ensure that the text will fit. Here is the relevant code.

Headlines.GetHeadlineText(CustomerHeadlineTitleTxt, StrSubstNo(CustomerHeadlineTxt, 
    Headlines.Emphasize(
        Headlines.Truncate(Customer.Name, Headlines.GetMaxPayloadLength() - StrLen(CustomerHeadlineTxt) + 4 - StrLen(Customer.Name)))), HeadlineText);
DemoHeadlineUser."Headline Text" := CopyStr(HeadlineText, 1, 250);

HeadlineDetails.SetRange(Type, HeadlineDetails.Type::Customer);
HeadlineDetails.SetRange("User Id", UserSecurityId());
HeadlineDetails.DeleteAll();

InsertHeadlineDetails(Customer."No.", HeadlineDetails.Type::Customer, Customer.Name, 0);

DemoHeadlineUser.Validate("Headline Visible", true);
DemoHeadlineUser.Validate("Headline Computation Date", CurrentDateTime());
DemoHeadlineUser.Validate("Headline Computation WorkDate", WorkDate());
DemoHeadlineUser.Modify(); 

Now, instead of just adding one customer to the “Headline Details”, which is another new table, you can also add multiple records there. For instance, if you want to show the top 10 customers, you show the top customer in the headline and all 10 to the details. This way, if the user clicks on the headline, they see all 10 customers that make up the list.

Reacting on Drill Down

When a user clicks on the headline, you can show a list with all the values that you want to present to the user for this headline. From this list, the customer can then see the individual card or list page that is relevant. It is called from the “OnDrillDown” trigger for the field defined in the headline group.

procedure OnDrillDownCustomer()
var
    DemoHeadlineUser: Record "Demo Headline Per User";
    HeadlineDetails: Page "Demo Headline Details";
begin
    DemoHeadlineUser.GetOrCreateHeadline(DemoHeadlineUser."Headline Type"::RandomCustomer);
    HeadlineDetails.InitCustomer();
    HeadlineDetails.Run();
end; 

Where to go from here?

First of all, you should download the project that you can then customize and create your own headlines.

You might have to change the object ids and you need to give the objects your own prefixes. But you can use the basic structure of the project to create your own headlines. You can keep the table, might just have to add more fields for the values that you need to display and change the types of information that are displayed.

I purposely left this “Type” field in the table an option, since this is how standard code is doing it. Technically, it would make more sense to have this an extendible enum.

Just to summarize:

  1. Create a new page extension for each role center you want to extend. Use “DemoRCBusinessManager.HeadlineRCBusinessManager.pageextension.al” from the project as a guideline.
  2. Create the necessary subscribers.
  3. Create the actual handling code to calculate the values and show the headlines.

So, overall, it is not that difficult to do – it just takes time. If you have any questions, leave me a comment on here.

Happy Coding!

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.