Table of Contents

Notification center

The notification center is an optional module that allows you to send user notifications and persist them.
It automatically handles the display of toasts and provides a button that displays the amount of unread notifications and opens the notification center in a sidebar.

In the notification center, users find all the notifications they received, including the ones received when they were not connected.
Notifications can manually be removed from the notification center.
Users can also enable the Do not disturb mode to disable toasts on their end.

Warning

Toast displayed using method ShowToast in UI code do not appear in the notification center and are not affected by the Do not disturb mode.

Adding module NeosNotificationCenter to your cluster

To be able to use the notification center, you need to add module NeosNotificationCenter to the referenced modules of your cluster.
See this article.

Adding permissions to access the notification center

Once the module has been added to you cluster, you need to give permission to users to access it; otherwise users will not see the notification center button.
This is done by enabling function Notification center on your user roles.
See this article for more information about user permissions.

Adding the notification center in a template

The notification center is a UI component that only displays a button.
It can be added in a UI template using the following code:

<neos-notification-center button-variant="primary" />

Attribute button-variant is not required, but it allows to set the style of the button.

Warning

If the notification is present multiple times in a screen, multiple toasts will be displayed each time the user receives a notification.

Sending a notification

User notifications sent to the notification center can only be sent from server code.

Creating a user notification category

User notifications are grouped by category when displayed in the notification center.
A category has a unique name, a caption and an icon.
Optionally, you can set a default value indicating whether notifications of this category display a toast as well as their default duration. By default, the notifications of a category display a toast for 3 seconds.

string uniqueName = "MyCategory";
LocalizableString caption = new LocalizableString(new Dictionary<string, string>()
{
    { "en", "My category" },
    { "fr", "Ma catégorie" },
});
string iconName = Images.MyCategoryIcon.Name;
int defaultToastDurationInSeconds = 5;

UserNotificationCategory category =
    new UserNotificationCategory(uniqueName, caption)
        .WithIcon(iconName)
        .WithToast(true, defaultToastDurationInSeconds);

Registering a user notification category for easy reusability

Since user notification categories are not supposed to change after they have been defined for the first time, we recommend registering them once when the module is loaded by Neos.
To do so, create a Startup.cs file in your module with the following code:

using GroupeIsa.Neos.Application.Notifications;

/// <summary>
/// Represents the assembly startup.
/// </summary>
[ExcludeFromCodeCoverage]
public static class Startup
{
    /// <summary>
    /// Configures services for dependency injection.
    /// </summary>
    /// <param name="services">The services collection.</param>
    /// <remarks>
    /// This method is automatically called when the assembly is loaded.
    /// </remarks>
    public static void ConfigureServices(IServiceCollection services)
    {
        services.AddUserNotificationCategory(
            "MyCategory",
            Resources.MyModule.ResourceManager,
            nameof(Resources.MyModule.MyCategoryCaption), // String resource
            "MyCategoryIcon",
            true,
            5);
        services.AddUserNotificationCategory(
            "MyOtherCategory",
            Resources.MyModule.ResourceManager,
            nameof(Resources.MyModule.MyOtherCategoryWithoutToastCaption), // String resource
            null,
            false);
    }
}

This avoids having to create or get a UserNotificationCategory object each time you send a new user notification. Instead you just need to pass the name of the category to the user notification options.

Creating user notification options

User notification options allows you to configure the user notification you will send.
They contain a title, a message and a severity.
By default, it displays a toast for 3 seconds.
The toast can be disabled or its duration can be changed, either globally on the category, or on a case-by-case basis in notification options.
A duration of 0 means the toast stays displayed until the user manually closes it.

string registeredCategoryName = "MyRegisteredCategory";

LocalizableString title = new LocalizableString(new Dictionary<string, string>()
{
    { "en", "My user notification" },
    { "fr", "Ma notification utilisateur" },
});
LocalizableString message = new LocalizableString(new Dictionary<string, string>()
{
    { "en", "My user notification message" },
    { "fr", "Mon message de notification utilisateur" },
});
UserNotificationSeverity severity = UserNotificationSeverity.Success;
int toastDuration = 5;
string iconName = Images.MyNotificationIcon.Name;

UserNotificationOptions notification1Options = new UserNotificationOptions(
        title,
        message,
        registeredCategoryName) // Registered category, we only need to pass its name
    .WithSeverity(severity)
    .WithToast(true, toastDuration)
    .WithIcon(iconName);

UserNotificationOptions notification2Options = new UserNotificationOptions(
        title,
        message,
        new UserNotificationCategory(...)) // Unregistered category, we need to create or get a UserNotificationCategory object
    .WithSeverity(severity)
    .WithToast(false);

Adding actions to a user notification

You can set actions that add buttons in on a notification.
An action is defined by a type, a caption and metadata used when executing the action.
Actions can be of the following types:

  • Navigation to a UI view
    Metadata:

    • name of the UI view
    • ID for displaying only one specific element (optional)
    • parameters to passe to the UI view (optional)
    • frame ID for uniquely identifying the frame that opens the UI view (optional)

    Metadata keys:

    • UIViewName
    • Id
    • Parameters
    • FrameId
  • Opening a URL in a new tab of the browser
    Metadata: URL to open
    Metadata key: Url

  • Downloading a file
    Metadata: partial URL of the file
    Metadata key: FilePartialUrl

  • Printing a file
    Metadata: partial URL of the file
    Metadata key: FilePartialUrl

In the notification center, actions are hidden. They can be displayed by expending a notification.
If one of the actions of the notification has been set as the main action, this action is executed when clicking on the notification.

LocalizableString navigateActionCaption = new LocalizableString(new Dictionary<string, string>()
{
    { "en", "Navigate" },
    { "fr", "Naviguer" },
});
LocalizableString downloadActionCaption = new LocalizableString(new Dictionary<string, string>()
{
    { "en", "Download" },
    { "fr", "Télécharger" },
});
LocalizableString printActionCaption = new LocalizableString(new Dictionary<string, string>()
{
    { "en", "Print" },
    { "fr", "Imprimer" },
});

string uiViewToOpen = "SalesUI";
int saleId = 10;
bool isOnlineSale = false;
string salesman = "Marcel";
string frameId = $"SalesUI_{10}";

string urlToOpen = "https://www.youtube.com/watch?v=5Jr-_Za5yQM";

Guid exportFileIdentifier = Guid.NewGuid();
string exportFilePartialUrl = $"$neos/exports/download/{exportFileIdentifier}";

Guid reportFileIdentifier = Guid.NewGuid();
string reportFilePartialUrl = $"reporting/download/{reportFileIdentifier}";

notification1Options
    .WithAction(
        new UserNotificationAction()
            .WithCaption(navigateActionCaption)
            .WithIsMainAction()
            .WithNavigation(
                uiViewToOpen,
                [new UserNotificationActionMetadata("SaleId", saleId)], // ID (optional)
                [
                    new UserNotificationActionMetadata("Online", isOnlineSale),
                    new UserNotificationActionMetadata("Salesman", salesman)
                ], // Parameters (optional)
                frameId)) // Frame ID (optional)
    .WithAction(
        new UserNotificationAction()
            .WithIcon(Images.Web.Name)
            .WithUrlOpening(urlToOpen))
    .WithAction(
        new UserNotificationAction()
            .WithCaption(downloadActionCaption)
            .WithFileDownload(exportFilePartialUrl))
    .WithAction(
        new UserNotificationAction()
            .WithCaption(printActionCaption)
            .WithIcon(Images.Print.Name)
            .WithFilePrinting(reportFilePartialUrl));

notification2Options
    .WithAction(
        new UserNotificationAction()
            .WithIcon(Images.DownloadExport.Name)
            .WithExportDownload(exportFileIdentifier)) // Additional method for exports, same as WithFileDownload but only the export file identifier is needed
    .WithAction(
        new UserNotificationAction()
            .WithIcon(Images.DownloadReport.Name)
            .WithReportDownload(reportFileIdentifier)) // Additional method for reports, same as WithFileDownload but only the report file identifier is needed
    .WithAction(
        new UserNotificationAction()
            .WithIcon(Images.PrintReport.Name)
            .WithReportPrinting(reportFileIdentifier)); // Additional method for reports, same as WithFilePrinting but only the report file identifier is needed

For more information about managing files in Neos, see this article.

Sending a user notification

When a notification is sent, we must set its recipients.
We can send it to one or several specific users, but we can also sent it to all the users of a tenant.
Use methods ToCurrentUser, ToUser, ToAllUsersInCurrentTenant or ToAllUsersInTenant on notification options to set recipients.

Important

If you do not call any of these methods on notification options to set the recipients, an exception will be thrown when sending the notification.

ITenants _tenants; // Injected
IUserInfoAccessor _userInfoAccessor; // Injected

string currentTenantId = _tenants.MultitenancyEnabled
    ? _tenants.GetCurrentTenantIdentifier()
    : NeosTenantInfo.DefaultTenantId;

notification1Options.ToUser(currentTenantId, _userInfoAccessor.User.Identifier);
notification2Options.ToAllUsersInTenant(currentTenantId);

In this example, the current tenant and the current user are obtained by injecting ITenants and IUserInfoAccessor in the constructor of the class thanks to dependency injection.

If you only want to send the notification to the current user or all the users of the current tenant, you can use the following methods:

notification1Options.ToCurrentUser();
notification2Options.ToAllUsersInCurrentTenant();

This example does exactly the same thing as the previous one.

You can then send the user notification using IUserNotification:

IUserNotification _userNotification; // Injected

await _userNotification.SendNotificationAsync(notificationOptions, cancellationToken);

IUserNotification must be injected in the constructor of the class.

Important

If you call IUserNotification.SendNotificationAsync in a cluster that does not include module NeosNotificationCenter nor a custom implementation of IUserNotification, an exception will be thrown.

Managing localizable strings for user notification and category captions

Since user notifications are sent from the server, possibly to multiple users using different languages, using localizable strings as captions is crucial.
See this article for more information about getting localizable strings in server code.

Implementing you own notification center

If you want to create your own implementation of a notification center instead of using module NeosNotificationCenter, you will need to create a class that implements IUserNotification in one our your modules.

Then, in the Application C# project of the module, create a Startup.cs file with the following code:

[ExcludeFromCodeCoverage]
public static class Startup
{
    /// <summary>
    /// Configures services for dependency injection.
    /// </summary>
    /// <param name="services">Services collection.</param>
    /// <remarks>
    /// This method is automatically called when the assembly is loaded.
    /// </remarks>
    public static void ConfigureServices(IServiceCollection services)
    {
        services.Replace(
            new ServiceDescriptor(
                typeof(IUserNotification),
                typeof(MyUserNotificationImplementation),
                ServiceLifetime.Scoped));
    }
}

This will replace the standard implementation by your own implementation.

Finally, you will need to created the user interface components that display the notifications to the users.

Warning

When an export or a report are generated, Neos calls methods IUserNotification.SendExportCompletedNotificationAsync, IUserNotification.SendExportCompletionErrorNotificationAsync, IUserNotification.SendReportGeneratedNotificationAsync or IUserNotification.SendReportGenerationErrorNotificationAsync to notify the user.
This means that once you have replaced the standard implementation of IUserNotification by your own, your implementation will have to handle export and report generation notifications; otherwise users will not know when their exports and reports have been generated nor be able to download and print them.

Receiving a message from the Tenant Management

The module provides an implementation for receiving messages published by the Tenant Management. The module displays messages in the form of warning toasts. It will remain open until the user manually closes it.

To find out more about this functionality, you can consult the documentation on communication from Tenant Management.

Forwarding nested cluster notifications to main cluster

If your cluster is configured as a nested cluster, you can forward its user notifications to the main cluster.

To enable this behavior, set the nested cluster option ForwardUserNotificationsToMainCluster to true.

For configuration details, see the nested clusters configuration documentation.