Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 54 additions & 1 deletion src/rtichoke/_report_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,57 @@ def _sanitize_nan_values(obj: Any) -> Any:
return obj


def _summary_report_density_css() -> str:
"""Generate layout density CSS for browser summary reports."""
return (
".rtichoke-report {\n"
" max-width: 1040px;\n"
" gap: 1.5rem;\n"
"}\n"
".rtichoke-report__section {\n"
" gap: 1.25rem;\n"
"}\n"
".rtichoke-report__group {\n"
" gap: 0.875rem;\n"
"}\n"
".rtichoke-report__component,\n"
".rtichoke-report__tabpanel {\n"
" gap: 0.5rem;\n"
"}\n"
".rtichoke-report .rtichoke-viz-chart {\n"
" min-height: 500px;\n"
" height: 500px;\n"
"}\n"
".rtichoke-report .rtichoke-calibration {\n"
" min-height: 550px;\n"
" height: 550px;\n"
"}\n"
".rtichoke-report__tabpanel .rtichoke-report__component-title {\n"
" display: none;\n"
"}\n"
".rtichoke-report__nav {\n"
" background-color: transparent;\n"
" border: none;\n"
" border-bottom: 1px solid #e5e7eb;\n"
" border-radius: 0;\n"
" padding: 0.5rem 0;\n"
"}\n"
".rtichoke-report .rtichoke-summary-metrics {\n"
" border: none;\n"
" background: transparent;\n"
" box-shadow: none;\n"
"}\n"
".rtichoke-report .rtichoke-summary-metrics__title {\n"
" display: none;\n"
"}\n"
".rtichoke-report .rtichoke-summary-metrics__table th,\n"
".rtichoke-report .rtichoke-summary-metrics__table td {\n"
" padding: 0.35rem 0.65rem;\n"
" border-bottom: 1px solid #e5e7eb;\n"
"}\n"
)


class RtichokeBrowserReport:
"""A complete canonical ReportSpec rendered by shared ``rtichoke_viz``."""

Expand Down Expand Up @@ -76,6 +127,7 @@ def write_html(self, path: str | Path) -> Path:
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
{viz_css}
{_summary_report_density_css()}
</style>
<title>rtichoke report</title>
</head>
Expand All @@ -89,7 +141,8 @@ def write_html(self, path: str | Path) -> Path:
);
document.querySelector("#rtichoke-report").append({render_fn}(spec, {{
sectionGroupPresentation: "tabs",
groupPresentation: "stacked"
groupPresentation: "tabs",
sectionComponentPresentation: "tabs"
}}));
</script>
</body>
Expand Down
5 changes: 4 additions & 1 deletion tests/test_report_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,10 @@ def test_browser_report_uses_real_producers_and_only_shared_render_report(tmp_pa
assert viz_css in html
assert '<link rel="stylesheet" href="./rtichoke-viz.css">' not in html
assert 'sectionGroupPresentation: "tabs"' in html
assert 'groupPresentation: "stacked"' in html
assert 'groupPresentation: "tabs"' in html
assert 'sectionComponentPresentation: "tabs"' in html
assert 'groupPresentation: "stacked"' not in html
assert ".rtichoke-report {\n max-width: 1040px;" in html
assert _embedded_report(html) == report
assert [item["id"] for item in report["sections"][0]["items"]] == [
"performance-table",
Expand Down
60 changes: 60 additions & 0 deletions tests/test_summary_report_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,10 @@ def test_browser_summary_report_is_opt_in_and_uses_real_canonical_components(
assert '<link rel="stylesheet" href="./rtichoke-viz.css">' not in html
assert "<style>" in html
assert 'sectionGroupPresentation: "tabs"' in html
assert 'groupPresentation: "tabs"' in html
assert 'sectionComponentPresentation: "tabs"' in html
assert 'groupPresentation: "stacked"' not in html
assert ".rtichoke-report {\n max-width: 1040px;" in html


def test_browser_summary_report_executes_when_opened_directly(tmp_path):
Expand Down Expand Up @@ -447,6 +451,62 @@ def test_browser_summary_report_prediction_distribution_components_render(tmp_pa
assert bbox_ppcr["width"] > 0
assert bbox_ppcr["height"] > 0

# 4. Component-level tab set verification: Calibration Smooth & Discrete
calib_smooth_tab = page.locator(
"button[aria-controls='panel-calibration-calibration-smooth']"
)
calib_discrete_tab = page.locator(
"button[aria-controls='panel-calibration-calibration']"
)
assert calib_smooth_tab.is_visible()
assert calib_discrete_tab.is_visible()

# Click Smooth tab and verify component & non-zero chart SVG dimensions
calib_smooth_tab.click()
smooth_comp = page.locator("[data-component-id='calibration-smooth']")
smooth_comp.wait_for()
assert smooth_comp.is_visible()
smooth_svg = smooth_comp.locator("svg").first
smooth_svg.wait_for()
smooth_bbox = smooth_svg.bounding_box()
assert smooth_bbox is not None
assert smooth_bbox["width"] > 0
assert smooth_bbox["height"] > 0

# Click Discrete tab and verify component & non-zero chart SVG dimensions
calib_discrete_tab.click()
discrete_comp = page.locator("[data-component-id='calibration']")
discrete_comp.wait_for()
assert discrete_comp.is_visible()
discrete_svg = discrete_comp.locator("svg").first
discrete_svg.wait_for()
discrete_bbox = discrete_svg.bounding_box()
assert discrete_bbox is not None
assert discrete_bbox["width"] > 0
assert discrete_bbox["height"] > 0

# 5. Component-level tab set verification: Discrimination Curve Tabs (ROC, Lift, PR, Gains)
disc_ppcr_group_tab = page.locator(
"button[aria-controls='discrimination-ppcr']"
)
disc_ppcr_group_tab.click()

lift_comp_tab = page.locator(
"button[aria-controls='panel-discrimination-ppcr-lift-2']"
)
assert lift_comp_tab.is_visible()
lift_comp_tab.click()

lift_comp = page.locator("[data-component-id='lift-2']")
lift_comp.wait_for()
assert lift_comp.is_visible()
lift_svg = lift_comp.locator("svg").first
lift_svg.wait_for()
lift_bbox = lift_svg.bounding_box()
assert lift_bbox is not None
assert lift_bbox["width"] > 0
assert lift_bbox["height"] > 0

assert len(errors) == 0, f"Console errors found: {errors}"
browser.close()

Expand Down
Loading