Skip to content
Merged
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ testing*
test-datasets/
.nf-test/
test.tap
.nf-test.log
.nf-test.log
examples/
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,15 @@ You can override the default requirements using command-line parameters:
nextflow run seqeralabs/nf-canary \
--fusion \
--fusion_kernel_version_min "5.10" \
--fusion_memory_gb_min 8 \
--fusion_disk_gb_min 100
--fusion_memory_capacity_gb_min 8 \
--fusion_disk_capacity_gb_min 100
```

Available parameters:

- `--fusion_kernel_version_min` - Minimum Linux kernel version (e.g., "5.10")
- `--fusion_memory_gb_min` - Minimum memory in GB (e.g., 8)
- `--fusion_disk_gb_min` - Minimum disk space in GB (e.g., 100)
- `--fusion_memory_capacity_gb_min` - Minimum memory in GB (e.g., 8)
- `--fusion_disk_capacity_gb_min` - Minimum disk space in GB (e.g., 100)
- `--fusion_cache_path` - Path for Fusion cache directory (default: `/tmp`)
- `--fusion_read_write_buckets` - Comma-separated list of read-write bucket URIs
- `--fusion_read_only_buckets` - Comma-separated list of read-only bucket URIs
102 changes: 82 additions & 20 deletions assets/templates/fusion_report_template.html
Original file line number Diff line number Diff line change
Expand Up @@ -551,6 +551,31 @@
font-size: 14.4px;
color: var(--black);
}
.has-tooltip {
position: relative;
}
.check-tooltip {
display: none;
position: absolute;
left: 0;
bottom: calc(100% + 6px);
background: var(--neutral-10);
color: #fff;
font-size: 12px;
font-weight: 400;
line-height: 1.4;
padding: 6px 10px;
border-radius: 4px;
white-space: normal;
width: max-content;
max-width: 280px;
z-index: 10;
box-shadow: 0 2px 8px rgba(0,0,0,.15);
pointer-events: none;
}
.has-tooltip:hover .check-tooltip {
display: block;
}
.card-summary-meta {
font-size: 12.8px;
color: #545555;
Expand Down Expand Up @@ -737,6 +762,27 @@
font-family: var(--font-mono);
font-size: 12.8px;
}
.dk-error {
grid-column: 1 / -1;
color: var(--clr-fail);
font-family: var(--font-mono);
font-size: 12px;
padding: 3px 8px;
background: var(--row-fail);
border-radius: 3px;
margin-top: -2px;
margin-bottom: 4px;
}
.dk-error .error-short { display: inline; }
.dk-error .error-long { display: none; word-break: break-all; }
.dk-error.expanded .error-short { display: none; }
.dk-error.expanded .error-long { display: inline; }
.dk-error .error-link {
color: var(--primary);
cursor: pointer;
font-family: var(--font-body);
font-size: 11px;
}

.remediation-callout {
margin-top: 16px;
Expand Down Expand Up @@ -1094,13 +1140,14 @@
</head>
<body>
{% macro check_row(check_name, check_data) %}
{% set actual = check_data.details|extract_actual %}
{% set ref = check_data.details|extract_reference %}
{% set actual = extract_actual(check_data.details, check_data.value_key) %}
{% set ref = extract_reference(check_data.details, check_data.requirement_key) %}
{% set actual_val = actual or ('Detected' if check_data.status == 'pass' else '—') %}
{% set display_status = 'warn' if check_data.status == 'fail' and check_data.category == 'warning' else check_data.status %}
{% set display_status = 'warn' if check_data.status == 'fail' and check_data.severity == 'warning' else check_data.status %}
<tr class="check-row row-{{ display_status }} {% if check_data.details or check_data.remediation %}has-details{% endif %}">
<td class="col-expand">{% if check_data.details or check_data.remediation %}<span class="expand-btn" aria-hidden="true"><svg viewBox="0 0 5 8" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 0.947L3.053 4L0 7.06L0.94 8L4.94 4L0.94 0L0 0.947Z" fill="currentColor"/></svg></span>{% endif %}</td>
<td class="check-cell-name">{{ check_name|humanize_check }}</td>
{% set desc = check_description(check_name, check_catalog) %}
<td class="check-cell-name{% if desc %} has-tooltip{% endif %}">{{ humanize_check(check_name, check_catalog) }}{% if desc %}<span class="check-tooltip">{{ desc }}</span>{% endif %}</td>
<td class="mono col-hide-mobile" title="{{ actual_val }}">{{ actual_val }}</td>
<td class="col-status">
<span class="check-status-badge status-{{ display_status }}">
Expand All @@ -1123,7 +1170,7 @@
<div class="detail-header">Details</div>
<div class="check-details-grid">
{% if check_data.details is mapping %} {% for key, val in check_data.details.items() %}
<span class="dk-key">{{ detail_label(key, check_data.category|default('')) }}</span>
<span class="dk-key">{{ detail_label(key, check_data.severity|default(''), check_data.requirement_key) }}</span>
<span class="dk-val">{{ format_detail_value(val, key) }}</span>
{% endfor %} {% else %}
<pre style="grid-column: 1 / -1">{{ check_data.details|tojson(indent=2) }}</pre>
Expand Down Expand Up @@ -1171,7 +1218,7 @@ <h1 class="header-title">Fusion Filesystem Diagnostics</h1>
<!-- Overview + Recommendations (side-by-side) -->
{% if doctor_report.check_summary or doctor_report.summary %} {% set summary = doctor_report.check_summary
or doctor_report.summary %}
{% set total_checks = (summary.passed|default(0)) + (summary.failed|default(0)) + (summary.skipped|default(0)) %}
{% set total_checks = (summary.passed|default(0)) + (summary.failed|default(0)) %}
{% set passed_count = summary.passed|default(0) %}
{% set warn_count = warnings_count|default(0) %}
{% set critical_count = [summary.failed|default(0) - warn_count, 0]|max %}
Expand Down Expand Up @@ -1258,13 +1305,13 @@ <h2 class="card-title"><i class="mdi mdi-lightbulb-outline" aria-hidden="true"><
{% for rec in recommendations %}
<li class="rec-item">
<div class="rec-badge-wrapper">
<span class="rec-badge badge-{% if rec.category == 'critical' %}fail{% else %}warn{% endif %}">
{% if rec.category == 'critical' %}
<span class="rec-badge badge-{% if rec.severity == 'critical' %}fail{% else %}warn{% endif %}">
{% if rec.severity == 'critical' %}
<svg class="rec-badge-icon" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M7 0a7 7 0 110 14A7 7 0 017 0zM5.03 4.97a.75.75 0 00-1.06 1.06L5.94 7 3.97 8.97a.75.75 0 101.06 1.06L7 8.06l1.97 1.97a.75.75 0 101.06-1.06L8.06 7l1.97-1.97a.75.75 0 10-1.06-1.06L7 5.94 5.03 4.97z"/></svg>
{% else %}
<svg class="rec-badge-icon" viewBox="0 0 14 14" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-hidden="true"><path d="M7.93345 8.16667H5.8828V3.73333H7.93345M7.93345 11.6667H5.8828V9.56667H7.93345M0.397486 12.1008C0.218159 12.4313 0.457429 12.8333 0.833437 12.8333H13.1626C13.5396 12.8333 13.7788 12.4294 13.5975 12.0989L7.40068 0.797318C7.21194 0.453087 6.71706 0.454176 6.52983 0.799234L0.397486 12.1008Z"/></svg>
{% endif %}
{{ rec.category|capitalize }}
{{ rec.severity|capitalize }}
</span>
</div>
<span class="rec-text">{{ rec.remediation|inline_code }}</span>
Expand Down Expand Up @@ -1330,14 +1377,15 @@ <h2 class="card-title"><i class="mdi mdi-server" aria-hidden="true"></i>Storage
</thead>
<tbody>
{% for check_data in disk_checks %}
{% set actual = check_data.details|extract_actual %}
{% set ref = check_data.details|extract_reference %}
{% set actual = extract_actual(check_data.details, check_data.value_key) %}
{% set ref = extract_reference(check_data.details, check_data.requirement_key) %}
{% set path_val = check_data.details.path|default(check_data.details.mount_point|default('—')) if check_data.details else '—' %}
{% set actual_val = actual or ('Detected' if check_data.status == 'pass' else '—') %}
{% set display_status = 'warn' if check_data.status == 'fail' and check_data.category == 'warning' else check_data.status %}
{% set display_status = 'warn' if check_data.status == 'fail' and check_data.severity == 'warning' else check_data.status %}
<tr class="check-row row-{{ display_status }}">
<td class="col-expand"><span class="expand-btn mobile-only-expand" aria-hidden="true"><svg viewBox="0 0 5 8" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 0.947L3.053 4L0 7.06L0.94 8L4.94 4L0.94 0L0 0.947Z" fill="currentColor"/></svg></span></td>
<td class="check-cell-name" title="{{ path_val }}">{{ path_val }}</td>
{% set desc = check_description(check_data.check, check_catalog) %}
<td class="check-cell-name{% if desc %} has-tooltip{% endif %}">{{ path_val }}{% if desc %}<span class="check-tooltip">{{ desc }}</span>{% endif %}</td>
<td class="mono col-hide-mobile" title="{{ actual_val }}">{{ actual_val }}</td>
<td class="col-status">
<span class="check-status-badge status-{{ display_status }}">
Expand Down Expand Up @@ -1389,13 +1437,14 @@ <h2 class="card-title"><i class="mdi mdi-pail-outline" aria-hidden="true"></i>Ob
<tbody>
{% for check_data in bucket_checks %}
{% set has_expandable = (check_data.sub_checks and check_data.status != 'pass') or check_data.remediation %}
{% set display_status = 'warn' if check_data.status == 'fail' and check_data.category == 'warning' else check_data.status %}
{% set display_status = 'warn' if check_data.status == 'fail' and check_data.severity == 'warning' else check_data.status %}
{% set uri_val = check_data.details.uri if check_data.details else '—' %}
<tr class="check-row row-{{ display_status }}{% if has_expandable %} has-details{% endif %}">
<td class="col-expand">{% if has_expandable %}<span class="expand-btn" aria-hidden="true"><svg viewBox="0 0 5 8" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 0.947L3.053 4L0 7.06L0.94 8L4.94 4L0.94 0L0 0.947Z" fill="currentColor"/></svg></span>{% else %}<span class="expand-btn mobile-only-expand" aria-hidden="true"><svg viewBox="0 0 5 8" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M0 0.947L3.053 4L0 7.06L0.94 8L4.94 4L0.94 0L0 0.947Z" fill="currentColor"/></svg></span>{% endif %}</td>
<td class="check-cell-name bucket-uri-cell" title="{{ uri_val }}">
{% set desc = check_description(check_data.check, check_catalog) %}
<td class="check-cell-name bucket-uri-cell{% if desc %} has-tooltip{% endif %}" title="{{ uri_val }}">
<span class="access-tag {% if check_data.check == 'bucket_access_ro' %}access-ro{% else %}access-rw{% endif %}"><span class="access-full">{% if check_data.check == 'bucket_access_ro' %}Read-only{% else %}Read-write{% endif %}</span><span class="access-short">{% if check_data.check == 'bucket_access_ro' %}RO{% else %}RW{% endif %}</span></span>
{{ uri_val }}
{{ uri_val }}{% if desc %}<span class="check-tooltip">{{ desc }}</span>{% endif %}
</td>
<td class="mono col-hide-mobile">{% if check_data.sub_checks %}{% set sc_passed = check_data.sub_checks|selectattr('status', 'equalto', 'pass')|list|length %}{{ sc_passed }}/{{ check_data.sub_checks|length }} checks passed{% else %}—{% endif %}</td>
<td class="col-status">
Expand All @@ -1421,16 +1470,21 @@ <h2 class="card-title"><i class="mdi mdi-pail-outline" aria-hidden="true"></i>Ob
</div>
</div>
{% if check_data.sub_checks and check_data.status != 'pass' %}
{% set sc_catalog = check_catalog.get(check_data.check, {}).get('sub_checks', {}) %}
<div class="check-details">
<div class="detail-header">Details</div>
<div class="check-details-grid">
{% for sc in check_data.sub_checks %}{% if sc.message %}
<span class="dk-key">{{ (sc.check or sc.name or '')|humanize_check }}</span>
{% for sc in check_data.sub_checks %}{% if sc.status != 'skip' %}
{% set sc_name = sc.check or sc.name or '' %}
<span class="dk-key" title="{{ check_description(sc_name, sc_catalog) }}">{{ humanize_check(sc_name, sc_catalog) }}</span>
<span class="dk-val">{% if sc.status == 'pass' %}Yes{% else %}No{% endif %}</span>
{% if sc.status != 'pass' and sc.message %}
{% set trimmed = sc.message|trim_sub_msg %}
{% if trimmed|length > 80 %}
<span class="dk-val"><details class="error-detail"><summary><span class="error-short">{{ trimmed|truncate_error }}</span><span class="error-long">{{ trimmed }}</span> <span class="error-link">full error</span></summary></details></span>
<span class="dk-error"><span class="error-short">{{ trimmed|truncate_error }} <span class="error-link error-toggle">full error</span></span><span class="error-long">{{ trimmed }} <span class="error-link error-toggle">show less</span></span></span>
{% else %}
<span class="dk-val">{{ trimmed }}</span>
<span class="dk-error">{{ trimmed }}</span>
{% endif %}
{% endif %}
{% endif %}{% endfor %}
</div>
Expand Down Expand Up @@ -1792,6 +1846,14 @@ <h3 class="card-title"><i class="mdi mdi-speedometer" aria-hidden="true"></i>{{
}
});

// Toggle full/short error messages
document.querySelectorAll(".error-toggle").forEach(function (link) {
link.addEventListener("click", function (e) {
e.stopPropagation();
link.closest(".dk-error").classList.toggle("expanded");
});
});

// Localize timestamps
document.querySelectorAll("time.local-time").forEach(function (el) {
try {
Expand Down
Loading
Loading