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:
@@ -1,9 +1,9 @@
|
||||
"""Per-tool manifest registry.
|
||||
|
||||
Single source of truth for what tools exist, their display strings, and
|
||||
the tier (which controls whether a tool ships in a given build SKU). The
|
||||
home-page sidebar consumes this list; future per-tool packaging will
|
||||
filter it via the ``tier`` field.
|
||||
Single source of truth for what tools exist, their display strings, the
|
||||
left-nav section they belong to, and the tier (which controls whether a
|
||||
tool ships in a given build SKU). The home-page sidebar consumes this
|
||||
list; future per-tool packaging will filter it via the ``tier`` field.
|
||||
|
||||
Adding a tool: append one ``Tool`` entry. Page filenames must match the
|
||||
``page_slug`` so Streamlit's automatic page discovery picks them up.
|
||||
@@ -22,6 +22,10 @@ from typing import Literal
|
||||
|
||||
Tier = Literal["core", "pro", "enterprise"]
|
||||
Status = Literal["Ready", "Coming Soon"]
|
||||
# Sidebar grouping. The Review gate is its own section; cleaners,
|
||||
# transformations, and automations group the tools by what the user is
|
||||
# trying to accomplish rather than by implementation detail.
|
||||
Section = Literal["review", "cleaners", "transformations", "automations"]
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@@ -34,102 +38,127 @@ class Tool:
|
||||
description: str # One-sentence card body.
|
||||
page_slug: str # Streamlit page filename without ".py" (e.g. "1_Deduplicator").
|
||||
status: Status # "Ready" or "Coming Soon" — drives the card badge color.
|
||||
section: Section # Sidebar group this tool belongs to.
|
||||
tier: Tier = "core" # Build-time gating hook; every tool is "core" today.
|
||||
|
||||
|
||||
# Order in this list IS the order shown in each sidebar section, so
|
||||
# arranging it carefully matters: within "cleaners" we lead with the
|
||||
# operations a non-technical user is most likely to need (filling
|
||||
# blanks, flagging outliers) before progressing to format cleanup,
|
||||
# dedup, and the final quality report.
|
||||
TOOLS: list[Tool] = [
|
||||
Tool(
|
||||
tool_id="01_deduplicator",
|
||||
icon="🔍",
|
||||
name="Deduplicator",
|
||||
description=(
|
||||
"Fuzzy matching, normalization, survivor selection, and "
|
||||
"interactive review."
|
||||
),
|
||||
page_slug="1_Deduplicator",
|
||||
status="Ready",
|
||||
),
|
||||
Tool(
|
||||
tool_id="02_text_cleaner",
|
||||
icon="✂️",
|
||||
name="Text Cleaner",
|
||||
description=(
|
||||
"Whitespace trim, multi-space collapse, Unicode normalization, "
|
||||
"BOM and line-ending handling."
|
||||
),
|
||||
page_slug="2_Text_Cleaner",
|
||||
status="Ready",
|
||||
),
|
||||
Tool(
|
||||
tool_id="03_format_standardizer",
|
||||
icon="📐",
|
||||
name="Format Standardizer",
|
||||
description=(
|
||||
"Standardize dates, currencies, names, phone numbers, and addresses."
|
||||
),
|
||||
page_slug="3_Format_Standardizer",
|
||||
status="Ready",
|
||||
),
|
||||
Tool(
|
||||
tool_id="04_missing_handler",
|
||||
icon="🕳️",
|
||||
name="Missing Value Handler",
|
||||
name="Fix Missing Values",
|
||||
description=(
|
||||
"Detect disguised nulls, missingness analysis, and imputation strategies."
|
||||
),
|
||||
page_slug="4_Missing_Values",
|
||||
status="Ready",
|
||||
),
|
||||
Tool(
|
||||
tool_id="05_column_mapper",
|
||||
icon="🗂️",
|
||||
name="Column Mapper",
|
||||
description="Rename columns, enforce a target schema, and coerce types.",
|
||||
page_slug="5_Column_Mapper",
|
||||
status="Ready",
|
||||
section="cleaners",
|
||||
),
|
||||
Tool(
|
||||
tool_id="06_outlier_detector",
|
||||
icon="📊",
|
||||
name="Outlier Detector",
|
||||
name="Find Unusual Values",
|
||||
description=(
|
||||
"Z-score, IQR, and MAD detection with domain-rule violations and "
|
||||
"winsorization."
|
||||
),
|
||||
page_slug="6_Outlier_Detector",
|
||||
status="Coming Soon",
|
||||
section="cleaners",
|
||||
),
|
||||
Tool(
|
||||
tool_id="07_multi_file_merger",
|
||||
icon="📎",
|
||||
name="Multi-File Merger",
|
||||
description="Combine multiple CSV/Excel files with schema alignment.",
|
||||
page_slug="7_Multi_File_Merger",
|
||||
status="Coming Soon",
|
||||
tool_id="02_text_cleaner",
|
||||
icon="✂️",
|
||||
name="Clean Text",
|
||||
description=(
|
||||
"Whitespace trim, multi-space collapse, Unicode normalization, "
|
||||
"BOM and line-ending handling."
|
||||
),
|
||||
page_slug="2_Text_Cleaner",
|
||||
status="Ready",
|
||||
section="cleaners",
|
||||
),
|
||||
Tool(
|
||||
tool_id="03_format_standardizer",
|
||||
icon="📐",
|
||||
name="Standardize Formats",
|
||||
description=(
|
||||
"Standardize dates, currencies, names, phone numbers, and addresses."
|
||||
),
|
||||
page_slug="3_Format_Standardizer",
|
||||
status="Ready",
|
||||
section="cleaners",
|
||||
),
|
||||
Tool(
|
||||
tool_id="01_deduplicator",
|
||||
icon="🔍",
|
||||
name="Find Duplicates",
|
||||
description=(
|
||||
"Fuzzy matching, normalization, survivor selection, and "
|
||||
"interactive review."
|
||||
),
|
||||
page_slug="1_Deduplicator",
|
||||
status="Ready",
|
||||
section="cleaners",
|
||||
),
|
||||
Tool(
|
||||
tool_id="08_validator_reporter",
|
||||
icon="✅",
|
||||
name="Validator & Reporter",
|
||||
name="Quality Check",
|
||||
description=(
|
||||
"Validate against rules and generate PDF/Excel quality reports."
|
||||
),
|
||||
page_slug="8_Validator_Reporter",
|
||||
status="Coming Soon",
|
||||
section="cleaners",
|
||||
),
|
||||
Tool(
|
||||
tool_id="05_column_mapper",
|
||||
icon="🗂️",
|
||||
name="Map Columns",
|
||||
description="Rename columns, enforce a target schema, and coerce types.",
|
||||
page_slug="5_Column_Mapper",
|
||||
status="Ready",
|
||||
section="transformations",
|
||||
),
|
||||
Tool(
|
||||
tool_id="07_multi_file_merger",
|
||||
icon="📎",
|
||||
name="Combine Files",
|
||||
description="Combine multiple CSV/Excel files with schema alignment.",
|
||||
page_slug="7_Multi_File_Merger",
|
||||
status="Coming Soon",
|
||||
section="transformations",
|
||||
),
|
||||
Tool(
|
||||
tool_id="09_pipeline_runner",
|
||||
icon="⚙️",
|
||||
name="Pipeline Runner",
|
||||
name="Automated Workflows",
|
||||
description=(
|
||||
"Chain tools in recommended order and pass output between steps."
|
||||
),
|
||||
page_slug="9_Pipeline_Runner",
|
||||
status="Ready",
|
||||
section="automations",
|
||||
),
|
||||
]
|
||||
|
||||
|
||||
# Display labels for each sidebar section. Kept here so i18n falls back
|
||||
# to a sensible English string if a translation pack is missing the key.
|
||||
SECTION_LABELS: dict[Section, str] = {
|
||||
"review": "Data Review",
|
||||
"cleaners": "Data Cleaners",
|
||||
"transformations": "Transformations",
|
||||
"automations": "Automations",
|
||||
}
|
||||
|
||||
|
||||
def tools_for_tier(*tiers: Tier) -> list[Tool]:
|
||||
"""Subset filter for build-time slicing.
|
||||
|
||||
@@ -142,6 +171,11 @@ def tools_for_tier(*tiers: Tier) -> list[Tool]:
|
||||
return [t for t in TOOLS if t.tier in keep]
|
||||
|
||||
|
||||
def tools_in_section(section: Section) -> list[Tool]:
|
||||
"""Return the tools in *section*, preserving registry order."""
|
||||
return [t for t in TOOLS if t.section == section]
|
||||
|
||||
|
||||
def tool_by_id(tool_id: str) -> Tool | None:
|
||||
return next((t for t in TOOLS if t.tool_id == tool_id), None)
|
||||
|
||||
@@ -167,3 +201,12 @@ def tool_description(tool_id: str) -> str:
|
||||
fallback = tool.description if tool else ""
|
||||
translated = _t(f"tools.{tool_id}.description")
|
||||
return translated if translated != f"tools.{tool_id}.description" else fallback
|
||||
|
||||
|
||||
def section_label(section: Section) -> str:
|
||||
"""Return the localized sidebar section header."""
|
||||
from src.i18n import t as _t
|
||||
fallback = SECTION_LABELS[section]
|
||||
key = f"nav.section_{section}"
|
||||
translated = _t(key)
|
||||
return translated if translated != key else fallback
|
||||
|
||||
Reference in New Issue
Block a user