Skip to content

Feature: #2471 notification on_close #2519

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: develop
Choose a base branch
from

Conversation

Andre-Pestana0
Copy link

@Andre-Pestana0 Andre-Pestana0 commented Mar 31, 2025

What type of PR is this? (check all applicable)

  • Refactor
  • Feature
  • Bug Fix
  • Optimization
  • Documentation Update

Description

Implementation of a way to now if a notification was closed or not, including a callback function for the notification and the reason behind it.

def notify(
    state: State,
    notification_type: str = "info",
    message: str = "",
    system_notification: t.Optional[bool] = None,
    duration: t.Optional[int] = None,
    id: str = "",
    on_close: t.Optional[t.Callable[[State, str, str], None]] = None,
) -> t.Optional[str]:


def close_notification(state: State, id: str, reason:str) -> None:

Related Tickets & Documents

How to reproduce the issue

Please replace this line with instructions on how to reproduce the issue or test the feature.

Other branches or releases that this needs to be backported

Describe which projects this change will impact and that needs to be backported.

Checklist

We encourage you to keep the code coverage percentage at 80% and above.

  • This solution meets the acceptance criteria of the related issue.
  • The related issue checklist is completed.
  • This PR adds unit tests for the developed code. If not, why?
  • End-to-End tests have been added or updated. If not, why?
  • The documentation has been updated, or a dedicated issue created. (If applicable)
  • The release notes have been updated? (If applicable)

@Andre-Pestana0
Copy link
Author

Andre-Pestana0 commented Mar 31, 2025

Hello there, I have some doubts that I would like to share.

First and foremost this is my work until now:

  • I have added a callback to notify "on_close" and inside of it Im expecting a user to send the state, notification_id and reason for closing the notification.
def notify(
    state: State,
    notification_type: str = "info",
    message: str = "",
    system_notification: t.Optional[bool] = None,
    duration: t.Optional[int] = None,
    id: str = "",
    on_close: t.Optional[t.Callable[[State, str, str], None]] = None,
) -> t.Optional[str]:

....


    def _notify(
        self,
        notification_type: str = "I",
        message: str = "",
        system_notification: t.Optional[bool] = None,
        duration: t.Optional[int] = None,
        notification_id: t.Optional[str] = None,
        on_close: t.Optional[t.Callable[[State, str, str], None]] = None,
    ):
        if notification_id and on_close:
            self._notification_callbacks[notification_id] = on_close  # A dictonary was created in order to store the callback

  • I have added the reason to on_close:
def close_notification(state: State, id: str, reason:str) -> None:
...



    def _close_notification(
        self,
        notification_id: str,
        reason: str = "forced", 
    ):
        if notification_id:
            self.__send_ws_notification(
                type="",  # Empty string indicates closing
                message="",  # No need for a message when closing
                system_notification=False,  # System notification not needed for closing
                duration=0,  # No duration since it's an immediate close
                notification_id=notification_id,
            )

            if notification_id in self._notification_callbacks:
                callback = self._notification_callbacks.pop(notification_id)  
                callback(self, notification_id, reason)

The final result can be seen by the following code and prints:

from taipy.gui import Gui, notify, close_notification

#Callback function
def on_close(state, notification_id, reason):
    print(f"Notification {notification_id} closed due to {reason}")

# Function to trigger a notification
def send_notification(state):
    notify(state, "info", "This is a test notification!", None, None, "3", on_close)

# Function to close the notification
def close_test_notification(state):
    close_notification(state, "3", "forced")

if __name__ == "__main__":
    page = """
# Notification Demo

Click the button to trigger a notification:

<|button|text=Send Notification|on_action=send_notification|>

Click the button to close the notification:

<|button|text=Close Notification|on_action=close_test_notification|>
"""
Gui(page).run()

Image

Image

My question

I don't understand if the changes requested are these or if the reasons"forced" and "timeout" should be something that the user never has to actually state

Copy link
Member

@FredLL-Avaiga FredLL-Avaiga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please do not commit file that are not related to the PR
I suppose this PR is missing a front-end part ?
How should that part be handled ?

main.py Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file shouldn't be committed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file shouldn't be committed

@Andre-Pestana0
Copy link
Author

Andre-Pestana0 commented Mar 31, 2025

please do not commit file that are not related to the PR I suppose this PR is missing a front-end part ? How should that part be handled ?

Hello there @FredLL-Avaiga, thank you for the reply
Regarding the files that are not meant to be committed I will make sure that in the final version those will not be included.
I sent this PR in order to clarify this doubt:

I don't understand if the changes requested are these or if the reasons"forced" and "timeout" should be something that the user never has to actually state

For now there are no front-end modifications, I just wanted to clarify my previous question so that I am aware on what needs to be done

@Andre-Pestana0
Copy link
Author

Hello there @FabienLelaquais,
First and foremost sorry for bothering,
I have a question regarding this issue and I was wondering if you could give some insight.

I don't understand if the changes requested are the ones that I made (the user inputs the reason whenever he closes the notification), or if the reasons "forced" and "timeout" should be something that the user never has to actually state.

You also said this:

It could make sense for the app to know about this, in order to potentially show other notifications that would be unreadable should too many notifications be visible yet.

However, when I try create multiple notifications there is a limit of 5 notifications that are displayed simultaneously, and whenever there is a sixth notification, one of the older notifications will be removed (in a First In First Out manner) .
I don't know if i am missing something, but it seems that that problem would not occur (but again, I might be missing something)

Looking forward to hearing from you

@FabienLelaquais
Copy link
Member

FabienLelaquais commented Apr 1, 2025

Hello there

Hi @Andre-Pestana0
And thank you for your involvement in this thing. And also, don't apologize for asking questions: that's the only path to a proposal that you and us can agree on.

Now.
"I don't understand if the changes requested are the ones that I made"
Well the point of this issue is to let the application know if and when a notification was closed, and why.
When the app creates a notification, now it appears on the front-end, and the app can forget about it.
I tried to come up with a rationale as to why the application would want to know when closing a notification happens, and you pointed out that my use case makes little sense (since no more than five consecutive notifications are visible anyway).
So let's forget about that use case and imagine another one, such as a notification that a developer really wants to make sure the user acknowledges and interacts with (by closing it). That could be a notification about a severe problem that the app needs the user to know about and fix.
So when the user closes (manually) the notification (that in this case would have been created with an illimited time out period), then the application needs to be notified that this happens. The "why" is the cherry on the cake: because the front-end side 'knows' why a notification is closed (timeout vs manual close), it's easy to let the back end know as well. That is what I called the "reason": depending on the cause of the notification being closed, the "reason" is set - by the front-end code - to "timeout" or "forced" (indicating a manual interaction).
At the end of the day, it is the user interaction (click the close box, or wait for timeout) that sets the 'reason', not the programmer.

Does that makes sense?

@Andre-Pestana0
Copy link
Author

it is the user interaction (click the close box, or wait for timeout) that sets the 'reason', not the programm

@FabienLelaquais
It makes total sense!
Thank you so much for the clarification!

@Andre-Pestana0
Copy link
Author

Andre-Pestana0 commented Apr 10, 2025

Hello there @FredLL-Avaiga @FabienLelaquais
First and foremost apologies for including the main.py and the package-lock.json. I guarantee they will not be present in the final version

I think I'm almost at the solution, but I'm missing something...
I already have defined in the frontend the reason for the deletion of the notification (forced or timeout) and I'm using the disptach function to send this info to the backend.

const notificationClosed = useCallback(
        (event: SyntheticEvent | null, reason: CloseReason, key?: SnackbarKey) => {
            const final_reason = reason === "timeout" ? "timeout" : "forced";
            if (key) {
                dispatch(createDeleteNotificationAction(key.toString(), final_reason));
            }
            snackbarIds.current = Object.fromEntries(
                Object.entries(snackbarIds.current).filter(([id]) => id !== key)
            );
        },
        [dispatch] 
    );

I have been trying to understand how to to gather this data from the backend, but with no success.
Could you give some guidance?
Thank you very much for your time

taipy/gui/gui.py Outdated
):
if notification_id and on_close:
self._notification_callbacks[notification_id] = on_close
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on_close should be transformed into a string so that it can be managed by the front-end. (check the builder code for inspiration)
so that there is a dispatch from the front-end to the back-end only if on_close is defined.

taipy/gui/gui.py Outdated
@@ -2411,19 +2414,24 @@ def _notify(
system_notification: t.Optional[bool] = None,
duration: t.Optional[int] = None,
notification_id: t.Optional[str] = None,
on_close: t.Optional[t.Callable[[State, str, str], None]] = None,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

on_close can also be a string (name of a function)

(event: SyntheticEvent | null, reason: CloseReason, key?: SnackbarKey) => {
const final_reason = reason === "timeout" ? "timeout" : "forced";
if (key) {
dispatch(createDeleteNotificationAction(key.toString(), final_reason));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to use another dispatch here: sendAction if on_close is defined

return {
type: Types.DeleteNotification,
snackbarId,
reason,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need

@FredLL-Avaiga FredLL-Avaiga changed the title Issue 2471 notification Feature: #2471 notification on_close Apr 14, 2025
@FredLL-Avaiga FredLL-Avaiga self-requested a review April 14, 2025 16:45
@Andre-Pestana0
Copy link
Author

Andre-Pestana0 commented Apr 14, 2025

Hello @FredLL-Avaiga,

Thank you so much for your reply. I will make sure to implement the requested changes.

Sorry for bringing this up again, but I'm still having some difficulty understanding how the communication between the frontend and backend is happening. I understand that by using the dispatch function, I'll be sending information to the frontend, but I'm not quite sure how to inspect what data is being sent and how to retrieve that same data from the backend (but understanding how is it being sent will help me figure out this part).

Could you please help me understand how I can view the data being sent from the frontend to the backend?

I've tried using console.log, which helped a bit, but I'm still missing some details. I appreciate your help and hope I’m not burdening you with too many questions.

Thank you again!

@FredLL-Avaiga
Copy link
Member

Hello @FredLL-Avaiga,

Thank you so much for your reply. I will make sure to implement the requested changes.

Sorry for bringing this up again, but I'm still having some difficulty understanding how the communication between the frontend and backend is happening. I understand that by using the dispatch function, I'll be sending information to the frontend, but I'm not quite sure how to inspect what data is being sent.

Could you please help me understand how I can view the data being sent from the frontend to the backend?

I've tried using console.log, which helped a bit, but I'm still missing some details. I appreciate your help and hope I’m not burdening you with too many questions.

Thank you again!

In this case, you want to trigger a back-end callback from the front-end.
we provide a action for this: createSendActionNameAction

You can find an example of its use in the Button component

@Andre-Pestana0
Copy link
Author

Hello there @FredLL-Avaiga,

I've been working on the notification callback for on_close and this is what I’ve done so far:

Backend:

  • The callback function is now saved properly in _notification_callbacks, and the backend accepts both strings and callables for on_close.

Frontend:

  • The notificationClosed function fires as expected when a notification is closed.
  • However, the callback argument in notificationClosed is always undefined, even though I believe the backend is sending a valid string for on_close.

At one point, I was able to make this work, but after making some changes, the callback stopped being passed correctly. The on_close value in the frontend is always undefined.

I suspect the issue might be happening during the transition from the backend to the frontend. I’ve checked the backend and confirmed that the on_close_str is not None before sending the notification.

Would appreciate any pointers on what might be causing this or what I might have missed.

Thank you so much for your time!

Copy link
Member

@FredLL-Avaiga FredLL-Avaiga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you need to change the createNotificationAction to handle the on_close callback name

.gitignore Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we want the package-lock.json to be committed when it is changed willingly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you didn't want to commit this ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I tried to add it to the gitignore for now so it wouldn't commit that

taipy/gui/gui.py Outdated
@@ -369,6 +369,8 @@ def __init__(
The returned HTML content can therefore use both the variables stored in the *state*
and the parameters provided in the call to `get_user_content_url()^`.
"""
# Notification callbacks
self._notification_callbacks = {}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove this
the callback name should be sent to the front-end and come back from the front-end

console.log(callback)
if (key) {
if (true) { //Should be if(callback) but callback is always undefined
createSendActionNameAction(notification?.notificationId, module, "on_notification_closed", final_reason);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be dispatch(createSendActionNameAction(...))

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you very much

const notificationClosed = useCallback(
(event: SyntheticEvent | null, reason: CloseReason, key?: SnackbarKey, callback?: string) => {
const final_reason = reason === "timeout" ? "timeout" : "forced";
console.log(callback)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not commit console calls

@@ -864,13 +895,21 @@ export const createNotificationAction = (notification: NotificationMessage): Tai
snackbarId: notification.snackbarId
});

export const createDeleteNotificationAction = (snackbarId: string): TaipyDeleteNotificationAction => {
export const createDeleteNotificationAction = (snackbarId: string, callback?: string): TaipyDeleteNotificationAction => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no need for callback here

@Andre-Pestana0
Copy link
Author

Hello there.

I believe I did almost all of the requested changes.
I had not realized that I removed the dispatch, and that was the reason the connection front-end backend stopped working.
Now i can the callback is activated from the frontend.

image

My only problem now is regarding the callback that is always undefined

Notification.tsx

const notificationClosed = useCallback(
        (event: SyntheticEvent | null, reason: CloseReason, key?: SnackbarKey, callback?: string) => {
            const final_reason = reason === "timeout" ? "timeout" : "forced";
            console.log(callback)
            if (key) {
                if (true) { //Should be if(callback) but callback is always undefined
                    dispatch(createSendActionNameAction(notification?.notificationId, module, "on_notification_closed", final_reason));               
                }
                dispatch(createDeleteNotificationAction(key.toString()));
            }
            snackbarIds.current = Object.fromEntries(
                Object.entries(snackbarIds.current).filter(([id]) => id !== key)
            );
        },
        [dispatch, module, notification?.notificationId] 
    );

gui.py

def _notify(
        self,
        notification_type: str = "I",
        message: str = "",
        system_notification: t.Optional[bool] = None,
        duration: t.Optional[int] = None,
        notification_id: t.Optional[str] = None,
        on_close: t.Optional[t.Union[str, t.Callable[[State, str, str], None]]] = "",
        ):
        on_close_str = None

        if notification_id and on_close:
            if isinstance(on_close, str):
                func = self._get_user_function(on_close)
                if callable(func):
                    on_close_str = on_close
                else:
                    _warn(f"Notification on_close callback '{on_close}' is not a valid function.")
            else:
                _warn(f"Invalid on_close value for notification {notification_id}: {on_close}")

        self.__send_ws_notification(
            notification_type,
            message,
            self._get_config("system_notification", False) if system_notification is None else system_notification,
            self._get_config("notification_duration", 3000) if duration is None else duration,
            notification_id,
            on_close_str,  
        )
        return notification_id

In the gui.py i have done some prints and I am positive that "on_close_str" is indeed a valid string.

I have tried to use notification?.on_close (on the front-end) but that also comes as undefined

Is there anything else I'm missing?
Thank you so much for your time

taipy/gui/gui.py Outdated
)
return notification_id

def _close_notification(
self,
notification_id: str,
reason: t.Optional[str] = "timeout",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

default value should not be timeout but user_action

taipy/gui/gui.py Outdated
Comment on lines 2453 to 2456
if notification_id in self._notification_callbacks:
callback = self._notification_callbacks.pop(notification_id)
callback(self, notification_id, reason)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this

Comment on lines 880 to 886
export const createSendAction = (name: string): TaipySendAction => {
return {
type: Types.Action,
name,
};
};

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use createSendActionNameAction

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and add optionals reason and on close to NotificationMessage

taipy/gui/gui.py Outdated
@@ -1458,14 +1458,15 @@ def __send_ws_download(self, content: str, name: str, on_action: str, module: st
)

def __send_ws_notification(
self, type: str, message: str, system_notification: bool, duration: int, notification_id: t.Optional[str] = None
self, type: str, message: str, system_notification: bool, duration: int, notification_id: t.Optional[str] = None, reason: t.Optional[str] = None
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need to add on_close_str here

) -> None:
payload = {
"type": _WsType.ALERT.value,
"nType": type,
"message": message,
"system": system_notification,
"duration": duration,
"reason": reason,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and there too (on_close_str)

@Andre-Pestana0
Copy link
Author

Andre-Pestana0 commented Apr 17, 2025

Hello there, thank you for the reply.
I believe the issues that were pointed out were tackled.

  • on_close will handle functions
  • default value of reason: changed to user_action
  • NotificationMessage has the requested parameters
  • on_close_str was added to __send_ws_notification

Im trying to call notification.on_close on the front-end but it still is undefined. Once again I checked that on_close_str is a valid string that is sent in the backend

I added a print("payload", payload) just to check if the payload had the correct information, and it has. My callback is called on_notification_closed and you can see it at the end.

image

Thank you so much for your time.

Copy link
Member

@FredLL-Avaiga FredLL-Avaiga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suppose you still need to change the case Types.SetNotification ...

@Andre-Pestana0
Copy link
Author

Hello there,

Thank you so much for your help, i had to do that and add on_close here:

export const createNotificationAction = (notification: NotificationMessage): TaipyNotificationAction => ({
    type: Types.SetNotification,
    nType: getNotificationType(notification.nType),
    message: notification.message,
    system: notification.system,
    duration: notification.duration,
    notificationId: notification.notificationId,
    snackbarId: notification.snackbarId,
    on_close: notification?.on_close,
});

Now everything is working!
If you just could please check if the the last changes are to your liking, then I would update my branch, add tests and finally remove everything that shouldn't be commited (main.py, etc...)

Thank you so much for your time

Copy link
Member

@FredLL-Avaiga FredLL-Avaiga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost there
Well done

if (callback) {
dispatch(createSendActionNameAction(notification?.notificationId, module, callback, final_reason));
}
dispatch(createDeleteNotificationAction(key.toString()));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is needed here

@@ -114,6 +116,7 @@ interface TaipyNotificationAction extends TaipyBaseAction, NotificationMessage {

interface TaipyDeleteNotificationAction extends TaipyBaseAction {
snackbarId: string;
callback?: string;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not needed

@@ -861,7 +865,8 @@ export const createNotificationAction = (notification: NotificationMessage): Tai
system: notification.system,
duration: notification.duration,
notificationId: notification.notificationId,
snackbarId: notification.snackbarId
snackbarId: notification.snackbarId,
on_close: notification?.on_close,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in ts files, we use camelCase and not snake_case

taipy/gui/gui.py Outdated
else:
_warn(f"Notification on_close callback '{on_close}' is not a valid function.")

elif callable(on_close):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use _is_function from utils

_warn(f"Notification on_close callback '{on_close}' is not a valid function.")

elif callable(on_close):
on_close_str = on_close.__name__
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lambda functions are not handled

@Andre-Pestana0
Copy link
Author

Andre-Pestana0 commented Apr 23, 2025

Hello there @FredLL-Avaiga
I think I tackled everything.
Thank you so much for your time!

Copy link
Member

@FredLL-Avaiga FredLL-Avaiga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any test ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not commit this file

.gitignore Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do not commit this file

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will not include in the final version

};
const notificationClosed = useCallback(
(event: SyntheticEvent | null, reason: CloseReason, key?: SnackbarKey, callback?: string) => {
const final_reason = reason === "timeout" ? "timeout" : "forced";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be integrated in the dispatch

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Integrated

const notificationClosed = useCallback(
(event: SyntheticEvent | null, reason: CloseReason, key?: SnackbarKey, callback?: string) => {
const final_reason = reason === "timeout" ? "timeout" : "forced";
if (key && callback) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why test key ?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was removed

@@ -122,7 +124,8 @@ def close_notification(state: State, id: str) -> None:
"""
if state and isinstance(state._gui, Gui):
# Send the close command with the notification_id
state._gui._close_notification(id) # type: ignore[attr-defined]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

clean up please

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@Andre-Pestana0 Andre-Pestana0 force-pushed the issue-2471-notification branch from 6e728cb to 5e24ea1 Compare April 23, 2025 15:11
@Andre-Pestana0
Copy link
Author

Hello there @FredLL-Avaiga
I will remove all the undesired files whenever the current solution and tests are to your liking.
Thank you for your time

Copy link
Member

@FredLL-Avaiga FredLL-Avaiga left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to test the action creation, but we need to test
1/ on the backend, on_close and reason are present in the payload when set
2/ on the frontend, a callback action is created when onClose is specified and a notification is closed (by system or user)

You also need to change your PR to remove the files that shouldn't be modified (.gitignore, package-lock.json, main.py)

mockDispatch(action);
});

expect(mockDispatch).toHaveBeenCalledWith(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you're only testing the createSendActionNAmeAction here ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Let the application know that a notification was closed
3 participants