diff --git a/dp_wizard/app/__init__.py b/dp_wizard/app/__init__.py index c5b3a0e..435e38d 100644 --- a/dp_wizard/app/__init__.py +++ b/dp_wizard/app/__init__.py @@ -4,7 +4,7 @@ from shiny import App, ui, reactive from dp_wizard.utils.argparse_helpers import get_cli_info -from dp_wizard.app import analysis_panel, dataset_panel, results_panel +from dp_wizard.app import analysis_panel, dataset_panel, results_panel, feedback_panel logging.basicConfig(level=logging.INFO) @@ -15,6 +15,7 @@ dataset_panel.dataset_ui(), analysis_panel.analysis_ui(), results_panel.results_ui(), + feedback_panel.feedback_ui(), id="top_level_nav", ), title="DP Wizard", @@ -69,6 +70,11 @@ def server(input, output, session): # pragma: no cover weights=weights, epsilon=epsilon, ) + feedback_panel.feedback_server( + input, + output, + session, + ) session.on_ended(ctrl_c_reminder) return server diff --git a/dp_wizard/app/feedback_panel.py b/dp_wizard/app/feedback_panel.py new file mode 100644 index 0000000..4084d44 --- /dev/null +++ b/dp_wizard/app/feedback_panel.py @@ -0,0 +1,32 @@ +from shiny import ui +from htmltools import HTML + + +def feedback_ui(): + return ui.nav_panel( + "Feedback", + ui.div( + HTML( + """ + + """ + ) + ), + value="feedback_panel", + ) + + +def feedback_server( + input, + output, + session, +): # pragma: no cover + pass diff --git a/tests/test_app.py b/tests/test_app.py index 9bc82ff..3e9e6bd 100644 --- a/tests/test_app.py +++ b/tests/test_app.py @@ -120,3 +120,10 @@ def expect_no_error(): download = download_info.value script = download.path().read_text() assert "privacy_unit = dp.unit_of(contributions=42)" in script + + # -- Feedback -- + page.get_by_text("Feedback").click() + iframe = page.locator("#feedback-iframe") + expect(iframe).to_be_visible() + expect(iframe.content_frame.get_by_text("DP Wizard Feedback")).to_be_visible() + # Text comes from iframe, so this does introduce a dependency on an outside service.