Skip to content
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

[BUG] dcc.Clipboard functionality broken in Notification component #2830

Open
DavidKatz-il opened this issue Apr 7, 2024 · 6 comments
Open
Assignees

Comments

@DavidKatz-il
Copy link

The following code creates a notification using dash_mantine_components.Notification, with a dcc.Clipboard as its icon.
Since dash version 2.15.0, the clipboard functionality appears to be broken.
It seems that this issue is related to the following PR #2652.

from dash import Dash, html, callback, Output, Input, dcc, dash
import dash_mantine_components as dmc


@callback(
    Output("notifications-container", "children"),
    Input("notify", "n_clicks"),
    prevent_initial_call=True,
)
def notify(n_clicks):
    return dmc.Notification(
        title="Notification",
        autoClose=False,
        id="simple-notify",
        action="show",
        message=f"{n_clicks=}",
        icon=dcc.Clipboard(title="copy", content="icon text"),
    )


app = Dash(__name__)
app.layout = dmc.NotificationsProvider(
    html.Div(
        [
            dmc.Text(children=dash.__version__),
            dmc.Button("Show Notification", id="notify"),
            html.Div(id="notifications-container"),
            html.Div(id="container"),
        ]
    )
)

if __name__ == "__main__":
    app.run(debug=True)

pip list | grep dash

Works with:
dash                    2.14.0
dash-core-components    2.0.0
dash-html-components    2.0.0
dash-iconify            0.1.2
dash-mantine-components 0.12.1
dash-pivottable         0.0.2
dash-table              5.0.0
dash-testing-stub       0.0.2

Doesn't work with:
dash                    2.15.0
dash-core-components    2.0.0
dash-html-components    2.0.0
dash-iconify            0.1.2
dash-mantine-components 0.12.1
dash-pivottable         0.0.2
dash-table              5.0.0
dash-testing-stub       0.0.2

Is this issue related to dash or to dash_mantine_components?

@DavidKatz-il DavidKatz-il changed the title [BUG] [BUG] dcc.Clipboard functionality broken in Notification component Apr 7, 2024
@AnnMarieW
Copy link
Contributor

Hi @DavidKatz-il

Thanks for reporting. I could replicate this with your example. Given that it's using the same version of dmc, it's reasonable to assume that it's caused by something that changed between Dash versions 2.14 and 2.15.

I'm not sure what is causing the issue though. To narrow things down, I checked to see if it was because of dcc.Clipboard being returned in a callback or used to set a prop. This works in both Dash versions -- the callback returns a a dcc.Checklist rather than the dmc.Notification:

@callback(
    Output("notifications-container", "children"),
    Input("notify", "n_clicks"),
    prevent_initial_call=True,
)
def notify(n_clicks):
    return dcc.Checklist(
        [
            {
                "label": [
                    html.Span(dcc.Clipboard(title="copy", content="icon text", id="id1")),
                    html.Span("Python", style={"font-size": 15, "padding-left": 10}),
                ],
                "value": "Python",
            },
        ], labelStyle={"display": "flex", "align-items": "center"}
    )

Not sure what in the dmc.Notification is conflicting. Do you have any ideas?

@DavidKatz-il
Copy link
Author

DavidKatz-il commented Apr 8, 2024

Hi @AnnMarieW, Thanks for the quick response.

I noticed that it works fine with Dash callbacks.
Upon debugging in the browser, I found that in the case of dmc.Notification, this.props.n_clicks always remains 0. Consequently, it triggers this code block:

        if (
            !this.props.n_clicks ||
            this.props.n_clicks === prevProps.n_clicks
        ) {
            return;
        }

This behavior seems to have been added in PR #2652.

@AnnMarieW
Copy link
Contributor

AnnMarieW commented Apr 8, 2024

That’s helpful - thanks @DavidKatz-il !

The question is why is it not registering the n_clicks when it's in the dmc.Notification. The n_clicks works fine when it's returned in the dcc.Checklist 🤔

@AnnMarieW
Copy link
Contributor

Here's another minimal app to narrow down the issue. In this one, I've replaced the dcc.Clipboard with an html.Button If you click on the button in the notification, you will see that the callback is triggered but n_clicks remains on 1 even after clicking on the button multiple times. Given that n_clicks doesn't change then the new code in dcc.Clipboard as mentioned above makes it so the clipboard doesn't work.

So maybe it's a dmc issue? It might be due to it being in the icon prop.

from dash import Dash, html, callback, Output, Input, dcc, dash
import dash_mantine_components as dmc

app = Dash(__name__, suppress_callback_exceptions=True)

app.layout = dmc.NotificationsProvider(
    html.Div(
        [
            dmc.Text(children=dash.__version__),
            dmc.Button("Show Notification", id="notify"),
            html.Div(id="notifications-container"),
            html.Div(id="container"),
        ]
    ),
)


@callback(
    Output("notifications-container", "children"),
    Input("notify", "n_clicks"),
    prevent_initial_call=True,
)
def notify(n_clicks):
    return dmc.Notification(
        title="Notification",
        autoClose=False,
        id="simple-notify",
        action="show",
        message=f"{n_clicks=}",
        icon=html.Button("click me", id="button"),
    )


@callback(
    Output("container", "children"),
    Input("button", "n_clicks")
)
def update(n):
    print("button n_clicks:", n)
    return dash.no_update


if __name__ == "__main__":
    app.run(debug=True)

@DavidKatz-il
Copy link
Author

DavidKatz-il commented Apr 9, 2024

Additionally, the same issue occurred with the message prop.

from dash import Dash, html, callback, Output, Input, dcc, dash
import dash_mantine_components as dmc


@callback(
    Output("notifications-container", "children"),
    Input("notify", "n_clicks"),
    prevent_initial_call=True,
)
def notify(n_clicks):
    return dmc.Notification(
        title="Notification",
        autoClose=False,
        id="simple-notify",
        action="show",
        message=dcc.Clipboard(title="copy", content="message text"),
    )


app = Dash(__name__)
app.layout = dmc.NotificationsProvider(
    html.Div(
        [
            dmc.Text(children=dash.__version__),
            dmc.Button("Show Notification", id="notify"),
            html.Div(id="notifications-container"),
            html.Div(id="container"),
        ]
    )
)

if __name__ == "__main__":
    app.run(debug=True)

@T4rk1n
Copy link
Contributor

T4rk1n commented Apr 9, 2024

So maybe it's a dmc issue?

Interesting, dmc must be doing something with the props and never receive the new n_clicks value in the onClick handler.

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

No branches or pull requests

3 participants