feat(gui): sidebar sections + non-technical tool labels
Sidebar nav now groups tools under Data Review / Data Cleaners / Transformations / Automations via st.navigation, replacing the flat auto-discovered list. Tool display names switch to action-first phrasing (Find Duplicates, Fix Missing Values, Find Unusual Values, Standardize Formats, Clean Text, Quality Check, Map Columns, Combine Files, Automated Workflows) in EN + ES packs and on each page's H1. The Data Cleaners section follows the requested order: Missing Values → Outliers → Text Cleaner → Format Standardizer → Deduplicator → Quality Check. (Text Cleaner kept inside cleaners since the request didn't list it but the tool still ships.) Registry now carries a section field; helpers added: tools_in_section(), section_label(). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -168,11 +168,11 @@ class TestHomeToolGridLocalization:
|
||||
English names. Pin a few representative ones."""
|
||||
|
||||
@pytest.mark.parametrize("needle", [
|
||||
"Eliminador de duplicados",
|
||||
"Limpiador de texto",
|
||||
"Estandarizador de formatos",
|
||||
"Gestor de valores faltantes",
|
||||
"Mapeador de columnas",
|
||||
"Buscar duplicados",
|
||||
"Limpiar texto",
|
||||
"Estandarizar formatos",
|
||||
"Corregir valores faltantes",
|
||||
"Mapear columnas",
|
||||
])
|
||||
def test_es_tool_name_on_home_grid(self, home_app, needle):
|
||||
with_language(home_app, "es")
|
||||
|
||||
@@ -113,13 +113,13 @@ class TestGrouping:
|
||||
labels = [e.label for e in app.expander]
|
||||
# Two unique tools → two expanders. Each label carries the
|
||||
# tool's display name + finding count.
|
||||
text_cleaner_expanders = [lbl for lbl in labels if "Text Cleaner" in lbl]
|
||||
format_expanders = [lbl for lbl in labels if "Format Standardizer" in lbl]
|
||||
text_cleaner_expanders = [lbl for lbl in labels if "Clean Text" in lbl]
|
||||
format_expanders = [lbl for lbl in labels if "Standardize Formats" in lbl]
|
||||
assert len(text_cleaner_expanders) == 1, (
|
||||
f"expected one Text Cleaner expander; got: {labels}"
|
||||
f"expected one Clean Text expander; got: {labels}"
|
||||
)
|
||||
assert len(format_expanders) == 1, (
|
||||
f"expected one Format Standardizer expander; got: {labels}"
|
||||
f"expected one Standardize Formats expander; got: {labels}"
|
||||
)
|
||||
|
||||
def test_tool_names_localize_in_spanish(self):
|
||||
@@ -127,7 +127,7 @@ class TestGrouping:
|
||||
app = _harness(findings, lang="es")
|
||||
app.run()
|
||||
labels = [e.label for e in app.expander]
|
||||
assert any("Limpiador de texto" in lbl for lbl in labels), (
|
||||
assert any("Limpiar texto" in lbl for lbl in labels), (
|
||||
f"Spanish tool name missing; expanders: {labels}"
|
||||
)
|
||||
|
||||
@@ -140,7 +140,7 @@ class TestGrouping:
|
||||
app.run()
|
||||
labels = [e.label for e in app.expander]
|
||||
# Pack template: "{tool} — {n} finding(s)"
|
||||
text_cleaner_label = next(l for l in labels if "Text Cleaner" in l)
|
||||
text_cleaner_label = next(l for l in labels if "Clean Text" in l)
|
||||
assert "3" in text_cleaner_label, (
|
||||
f"expected count '3' in expander label; got {text_cleaner_label!r}"
|
||||
)
|
||||
@@ -163,7 +163,7 @@ class TestOpenToolButton:
|
||||
# raw markdown. We probe both.
|
||||
text = collected_text(app)
|
||||
# Pack template: "Open {tool} →"
|
||||
assert "Open Text Cleaner" in text
|
||||
assert "Open Clean Text" in text
|
||||
|
||||
def test_open_tool_label_spanish(self):
|
||||
findings = [_make_finding(tool="02_text_cleaner")]
|
||||
@@ -171,7 +171,7 @@ class TestOpenToolButton:
|
||||
app.run()
|
||||
text = collected_text(app)
|
||||
# Pack template: "Abrir {tool} →"
|
||||
assert "Abrir Limpiador de texto" in text
|
||||
assert "Abrir Limpiar texto" in text
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -45,7 +45,7 @@ class TestGateNoUpload:
|
||||
text = collected_text(app)
|
||||
# The dedup page title is the unambiguous signal that the gate
|
||||
# didn't short-circuit.
|
||||
assert "Deduplicator" in text
|
||||
assert "Find Duplicates" in text
|
||||
|
||||
def test_no_upload_no_gate_warning(self, app_factory):
|
||||
app = app_factory(GATED_PAGE)
|
||||
|
||||
@@ -40,9 +40,9 @@ def lite_license(monkeypatch, tmp_path):
|
||||
|
||||
class TestLiteUnlockedPages:
|
||||
@pytest.mark.parametrize("slug,signal", [
|
||||
("1_Deduplicator", "Deduplicator"),
|
||||
("2_Text_Cleaner", "Text Cleaner"),
|
||||
("3_Format_Standardizer", "Format Standardizer"),
|
||||
("1_Deduplicator", "Find Duplicates"),
|
||||
("2_Text_Cleaner", "Clean Text"),
|
||||
("3_Format_Standardizer", "Standardize Formats"),
|
||||
])
|
||||
def test_unlocked_pages_render_body(
|
||||
self, lite_license, app_factory, slug, signal, small_csv_bytes,
|
||||
|
||||
@@ -53,17 +53,17 @@ PAGE_SLUGS = [
|
||||
# When a page gains real Spanish translation, flip its 'es' entry to
|
||||
# the localized substring — the test surface stays the same.
|
||||
EXPECTED_SUBSTRINGS: dict[str, dict[str, str]] = {
|
||||
"0_Review": {"en": "Review", "es": "Review"},
|
||||
"1_Deduplicator": {"en": "Deduplicator", "es": "Deduplicator"},
|
||||
"2_Text_Cleaner": {"en": "Text Cleaner", "es": "Text Cleaner"},
|
||||
"3_Format_Standardizer": {"en": "Format", "es": "Format"},
|
||||
"4_Missing_Values": {"en": "Missing", "es": "Missing"},
|
||||
"5_Column_Mapper": {"en": "Column", "es": "Column"},
|
||||
"6_Outlier_Detector": {"en": "Outlier", "es": "Outlier"},
|
||||
"7_Multi_File_Merger": {"en": "Merger", "es": "Merger"},
|
||||
"8_Validator_Reporter": {"en": "Validator", "es": "Validator"},
|
||||
"9_Pipeline_Runner": {"en": "Pipeline", "es": "Pipeline"},
|
||||
"99_Close": {"en": "Close DataTools", "es": "Cerrar DataTools"},
|
||||
"0_Review": {"en": "Review", "es": "Review"},
|
||||
"1_Deduplicator": {"en": "Find Duplicates", "es": "Find Duplicates"},
|
||||
"2_Text_Cleaner": {"en": "Clean Text", "es": "Clean Text"},
|
||||
"3_Format_Standardizer": {"en": "Standardize", "es": "Standardize"},
|
||||
"4_Missing_Values": {"en": "Fix Missing", "es": "Fix Missing"},
|
||||
"5_Column_Mapper": {"en": "Map Columns", "es": "Map Columns"},
|
||||
"6_Outlier_Detector": {"en": "Unusual", "es": "Unusual"},
|
||||
"7_Multi_File_Merger": {"en": "Combine Files", "es": "Combine Files"},
|
||||
"8_Validator_Reporter": {"en": "Quality Check", "es": "Quality Check"},
|
||||
"9_Pipeline_Runner": {"en": "Automated", "es": "Automated"},
|
||||
"99_Close": {"en": "Close DataTools", "es": "Cerrar DataTools"},
|
||||
}
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ class TestHomePageRenders:
|
||||
with_language(home_app, "es")
|
||||
home_app.run()
|
||||
text = collected_text(home_app)
|
||||
assert "Eliminador de duplicados" in text
|
||||
assert "Buscar duplicados" in text
|
||||
|
||||
|
||||
class TestEveryPageRenders:
|
||||
|
||||
@@ -78,7 +78,7 @@ class TestTextCleanerWorkflow:
|
||||
app.run()
|
||||
assert not app.exception
|
||||
text = collected_text(app)
|
||||
assert "Text Cleaner" in text
|
||||
assert "Clean Text" in text
|
||||
|
||||
def test_preview_or_clean_button_present(self, app_factory, small_csv_bytes):
|
||||
"""The text cleaner ships a primary action (label varies by
|
||||
@@ -106,7 +106,7 @@ class TestFormatStandardizerWorkflow:
|
||||
app.run()
|
||||
assert not app.exception
|
||||
text = collected_text(app)
|
||||
assert "Format Standardizer" in text
|
||||
assert "Standardize Formats" in text
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -148,7 +148,7 @@ class TestPipelineRunnerWorkflow:
|
||||
app.run()
|
||||
assert not app.exception
|
||||
text = collected_text(app)
|
||||
assert "Pipeline" in text
|
||||
assert "Automated Workflows" in text
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -194,9 +194,9 @@ class TestReviewWorkflow:
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@pytest.mark.parametrize("slug,name", [
|
||||
("6_Outlier_Detector", "Outlier"),
|
||||
("7_Multi_File_Merger", "Merger"),
|
||||
("8_Validator_Reporter", "Validator"),
|
||||
("6_Outlier_Detector", "Unusual Values"),
|
||||
("7_Multi_File_Merger", "Combine Files"),
|
||||
("8_Validator_Reporter", "Quality Check"),
|
||||
])
|
||||
class TestComingSoonStubs:
|
||||
def test_stub_renders(self, app_factory, slug, name):
|
||||
|
||||
Reference in New Issue
Block a user