${data.overview.description}
+ ${descriptionContent}diff --git a/connectors/openmetadata/transformer.py b/connectors/openmetadata/transformer.py index 6452478..4100e46 100644 --- a/connectors/openmetadata/transformer.py +++ b/connectors/openmetadata/transformer.py @@ -319,6 +319,7 @@ def metric_to_display_dict(raw_metric: Dict[str, Any]) -> Dict[str, Any]: Parse raw OpenMetadata metric for metric list display in webapp. Returns a lightweight dict for listing metrics (not full detail). + Description is stripped of HTML and truncated for list view. Args: raw_metric: Raw metric dict from OpenMetadata API @@ -332,10 +333,15 @@ def metric_to_display_dict(raw_metric: Dict[str, Any]) -> Dict[str, Any]: description = raw_metric.get("description", "") or "" tags = raw_metric.get("tags", []) + # Strip HTML and truncate for list excerpt + clean_desc = strip_html(description) + if len(clean_desc) > 150: + clean_desc = clean_desc[:147] + "..." + return { "name": name, "display_name": display_name, - "description": description, + "description": clean_desc, "grain": extract_grain(raw_metric), "category": extract_category(tags), "path": f"catalog:{fqn}", @@ -376,6 +382,7 @@ def metric_to_detail_dict(raw_metric: Dict[str, Any], category_colors: Optional[ }, "overview": { "description": strip_html(description), + "description_html": description, "key_insights": [], }, "validation": None, diff --git a/webapp/app.py b/webapp/app.py index 14b5d79..cbce3cd 100644 --- a/webapp/app.py +++ b/webapp/app.py @@ -829,7 +829,7 @@ def _build_om_metric_detail(raw_metric: dict) -> dict: "category": category, "category_color": category_colors.get(category, "#6B7280"), "metadata": {"type": metric_type, "unit": unit, "grain": grain, "time_column": ""}, - "overview": {"description": description.strip(), "key_insights": []}, + "overview": {"description": description.strip(), "description_html": description.strip(), "key_insights": []}, "validation": None, "dimensions": dimensions, "notes": {"all": [], "key_insights": []}, diff --git a/webapp/static/css/metric_modal.css b/webapp/static/css/metric_modal.css index dad9e98..175385a 100644 --- a/webapp/static/css/metric_modal.css +++ b/webapp/static/css/metric_modal.css @@ -330,6 +330,46 @@ font-weight: 500; } +/* OpenMetadata HTML description (rendered from catalog) */ +.om-description { + font-size: 15px; + line-height: 1.7; + color: #374151; +} + +.om-description p { + margin: 0 0 12px 0; +} + +.om-description p:last-child { + margin-bottom: 0; +} + +.om-description strong { + color: #111827; + font-weight: 600; +} + +.om-description ul, +.om-description ol { + margin: 8px 0 12px 0; + padding-left: 24px; +} + +.om-description li { + margin-bottom: 4px; + line-height: 1.6; +} + +.om-description code { + background: #F3F4F6; + color: #0073D1; + padding: 2px 6px; + border-radius: 3px; + font-family: 'Monaco', 'Menlo', monospace; + font-size: 13px; +} + /* Dimension Pills */ .metric-dimensions { display: flex; diff --git a/webapp/static/js/metric_modal.js b/webapp/static/js/metric_modal.js index 9e56f81..d6cc0b3 100644 --- a/webapp/static/js/metric_modal.js +++ b/webapp/static/js/metric_modal.js @@ -148,12 +148,17 @@ function renderMetricModal(data) { function renderOverviewTab(data) { const keyInsights = data.notes.key_insights || data.notes.all.slice(0, 5); + // Prefer rendered HTML from catalog over stripped plain text + const descriptionContent = data.overview.description_html + ? `
${escapeHtml(data.overview.description)}
`; + return `${data.overview.description}
+ ${descriptionContent}