diff --git a/solara/lab/components/confirmation_dialog.py b/solara/lab/components/confirmation_dialog.py index ce5eff44e..b677c2cb5 100644 --- a/solara/lab/components/confirmation_dialog.py +++ b/solara/lab/components/confirmation_dialog.py @@ -36,15 +36,27 @@ def delete_user(): ## Arguments - ...to be added... + * `is_open`: Indicates whether the dialog is being shown or not. + * `on_ok`: Callback to be called when the OK button is clicked. + * `on_close`: Optional callback to be called when dialog is closed. + * `content`: Message that is displayed. + * `title`: Title of the dialog. + * `ok`: If a string, this text will be displayed on the confirmation button (default is "OK"). If a Button, it will be used instead of the default button. + * `cancel`: If a string, this text will be displayed on the cancellation button (default is "Cancel"). If a Button, it will be used instead of the default + button. + * `children`: Additional components that will be shown under the dialog message, but before the buttons. + * `max_width`: Maximum width of the dialog window. + * `persistent`: ... """ is_open_reactive = solara.use_reactive(is_open) del is_open - def perform_action(): + def perform_action(callback=None): on_ok() + if callback: + callback() close() def close(): @@ -70,6 +82,12 @@ def close(): solara.Button(label=ok, on_click=perform_action) else: solara.display(ok) + action = ok.kwargs.get("on_click") + if action: + # perform both on_ok and the on_click action of the custom Button + ok.kwargs = ok.kwargs | {"on_click": lambda: perform_action(callback=action)} + else: + ok.kwargs = ok.kwargs | {"on_click": perform_action} if isinstance(cancel, str): solara.Button(label=cancel, on_click=close) else: diff --git a/tests/unit/confirmation_dialog_test.py b/tests/unit/confirmation_dialog_test.py index 7d7593eb1..8876f3157 100644 --- a/tests/unit/confirmation_dialog_test.py +++ b/tests/unit/confirmation_dialog_test.py @@ -6,7 +6,7 @@ from solara.lab.components.confirmation_dialog import ConfirmationDialog -def test_confirmation_dialog(): +def test_confirmation_dialog_ok(): is_open = solara.reactive(True) on_ok = MagicMock() el = ConfirmationDialog(is_open, on_ok=on_ok, content="Hello") @@ -18,15 +18,48 @@ def test_confirmation_dialog(): assert not is_open.value # is dialog closed? -def test_confirmation_dialog_custom_button(): +def test_confirmation_dialog_cancel(): is_open = solara.reactive(True) on_ok = MagicMock() - my_button = solara.Button(label="Not OK") # on_click? - el = ConfirmationDialog(is_open, on_ok=on_ok, ok=my_button) + el = ConfirmationDialog(is_open, on_ok=on_ok, content="Hello") + _, rc = solara.render(el, handle_error=False) + buttons = rc.find(vw.Btn) + assert len(buttons) == 2 + buttons[1].widget.click() + assert on_ok.call_count == 0 # on_ok action should not have been executed + assert not is_open.value # is dialog closed? + + +def test_confirmation_dialog_custom_button_no_onclick(): + is_open = solara.reactive(True) + on_ok = MagicMock() + my_button = solara.Button(label="Not OK") # no on_click + el = ConfirmationDialog(is_open, on_ok=on_ok, ok=my_button, content="Are you sure?") + _, rc = solara.render(el, handle_error=False) + buttons = rc.find(vw.Btn) + assert len(buttons) == 2 + assert buttons[0].widget.children == ["Not OK"] + assert buttons[1].widget.children == ["Cancel"] + buttons[0].widget.click() + assert on_ok.call_count == 1 # should still be called + + +def test_confirmation_dialog_custom_button_with_onclick(): + is_open = solara.reactive(True) + values = [] + + def on_ok(): + values.append(1) + + def on_click(): + lambda: values.append(2) + + my_button = solara.Button(label="Not OK", on_click=on_click) + el = ConfirmationDialog(is_open, on_ok=on_ok, ok=my_button, content="Are you sure?") _, rc = solara.render(el, handle_error=False) buttons = rc.find(vw.Btn) assert len(buttons) == 2 assert buttons[0].widget.children == ["Not OK"] assert buttons[1].widget.children == ["Cancel"] buttons[0].widget.click() - assert on_ok.call_count == 1 # will fail + assert values == [1, 2] # assert on_ok and on_click were both called, in that order