Fix metric display: use displayName in list, render HTML in modal

List view:
- Show display_name ("M1 + VFM Operational") instead of name ("M1PlusVFMOperational")
- Strip HTML and truncate description for clean list excerpts

Modal detail:
- Render original HTML from catalog instead of stripped plain text
- Add .om-description CSS class for structured HTML (bold labels, lists, code)
- Pass description_html alongside plain text description for backwards compat
This commit is contained in:
Petr 2026-03-16 22:11:58 +01:00
parent ad525a96aa
commit 9be22fdc82
5 changed files with 56 additions and 4 deletions

View file

@ -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,

View file

@ -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": []},

View file

@ -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;

View file

@ -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
? `<div class="om-description">${data.overview.description_html}</div>`
: `<p>${escapeHtml(data.overview.description)}</p>`;
return `
<div id="tabOverview" class="metric-tab-content">
<div class="metric-section">
<h3 class="metric-section-header">What it measures</h3>
<div class="metric-section-content">
<p>${data.overview.description}</p>
${descriptionContent}
</div>
</div>

View file

@ -1415,7 +1415,7 @@
{% for metric in category.metrics %}
<div class="table-row" onclick="openMetricModal('{{ metric.path }}')">
<div class="table-row-left">
<div class="table-row-name">{{ metric.name }}</div>
<div class="table-row-name">{{ metric.display_name }}</div>
<div class="table-row-desc">{{ metric.description }}</div>
</div>
<div class="table-row-right">