atr/templates/report-selected-path.html (257 lines of code) (raw):

{% extends "layouts/base.html" %} {% block title %} Report for {{ release.short_display_name }} {{ package.filename }} ~ ATR {% endblock title %} {% block description %} Show the report for the {{ release.short_display_name }} {{ package.filename }} candidate draft file. {% endblock description %} {% block content %} {% set phase = release.phase.value %} <p class="d-flex justify-content-between align-items-center"> {% if phase == "release_candidate_draft" %} <a href="{{ as_url(routes.root.index) }}" class="atr-back-link">← Back to Select a release</a> {% else %} <a href="{{ as_url(routes.vote.selected, project_name=release.project.name, version_name=release.version) }}" class="atr-back-link">← Back to Vote on {{ release.project.short_display_name }} {{ release.version }}</a> {% endif %} <span> {% if phase == "release_candidate_draft" %} <strong class="atr-phase-one atr-phase-symbol">①</strong> <span class="atr-phase-one atr-phase-label">COMPOSE</span> <span class="atr-phase-arrow">→</span> <span class="atr-phase-symbol-other">②</span> {% else %} <span class="atr-phase-symbol-other">①</span> <span class="atr-phase-arrow">→</span> <strong class="atr-phase-two atr-phase-symbol">②</strong> <span class="atr-phase-two atr-phase-label">VOTE</span> {% endif %} <span class="atr-phase-arrow">→</span> <span class="atr-phase-symbol-other">③</span> </span> </p> <h1> Report for <strong>{{ release.project.short_display_name }}</strong> <em>{{ release.version }}</em>: </h1> <div class="fs-3 bg-light p-3 border rounded mb-4"> <code>{{ package.filename }}</code> </div> <p> <strong>Note:</strong> Refresh this page to see the latest status of the verification tasks. </p> <h2>Report results</h2> {% if check_results %} {# Define status_counts here so it's available globally in this block #} {% set status_counts = { "success": check_results|selectattr("status.value", "equalto", "success")|list|length, "failure": check_results|selectattr("status.value", "equalto", "failure")|list|length, "warning": check_results|selectattr("status.value", "equalto", "warning")|list|length, "exception": check_results|selectattr("status.value", "equalto", "exception")|list|length } %} <div class="d-flex align-items-center p-3 mb-3 bg-light border rounded"> <span class="fw-bold me-3">Status summary:</span> <div class="d-flex flex-wrap gap-3"> {% for status, count in status_counts.items() %} {% if count > 0 %} <div class="d-flex align-items-center gap-2 px-3 py-2 rounded fw-medium {% if status == "success" %}bg-success-subtle border border-success-subtle {% elif status == "failure" %}bg-danger-subtle border border-danger-subtle {% elif status == "warning" %}bg-warning-subtle border border-warning-subtle {% elif status == "exception" %}bg-danger-subtle border border-danger-subtle {% endif %}"> <span class="fs-5">{{ count }}</span> <span> {%- if status == "success" -%} Passed {%- elif status == "failure" -%} Issues {%- elif status == "warning" -%} Warning {%- elif status == "exception" -%} Error {%- else -%} {{ status|title }} {%- endif -%} </span> </div> {% endif %} {% endfor %} </div> </div> {% endif %} <div class="d-flex gap-3 mb-3"> <button type="button" onclick="toggleAllDetails()" class="btn btn-secondary">Toggle all details</button> {% if is_viewing_as_admin_fn(current_user.uid) and (release.phase.value == "release_candidate_draft") %} <form method="post" action="{{ as_url(routes.draft.fresh, project_name=release.project.name, version_name=release.version) }}" class="mb-0"> <button type="submit" class="btn btn-primary">Restart all checks</button> </form> {% endif %} </div> <div class="mb-3"> {% if check_results %} {% for check_result in check_results %} <div class="border border-2 rounded p-3 mb-3"> <div class="d-flex justify-content-between align-items-center mb-2"> <span class="fw-bold">{{ function_name_from_key(check_result.checker) }}</span> <span class="badge rounded-pill {% if check_result.status.value == "success" %}bg-success {% elif check_result.status.value == "failure" %}bg-danger {% elif check_result.status.value == "warning" %}bg-warning {% elif check_result.status.value == "exception" %}bg-danger {% else %}bg-secondary{% endif %}"> {%- if check_result.status.value == "success" -%} Passed {%- elif check_result.status.value == "failure" -%} {% if status_counts['failure'] == 1 %} Issue {% else %} Issues {% endif %} {%- elif check_result.status.value == "warning" -%} {% if status_counts['warning'] == 1 %} Warning {% else %} Warnings {% endif %} {%- elif check_result.status.value == "exception" -%} {% if status_counts['exception'] == 1 %} Exception {% else %} Exceptions {% endif %} {%- else -%} {{ check_result.status.value|title }} {%- endif -%} </span> </div> <div class="small"> <div> Checked: {{ check_result.created.strftime("%Y-%m-%d %H:%M:%S UTC") if check_result.created else "Not checked" }} </div> {% if check_result.message %}<div class="mt-2">{{ check_result.message }}</div>{% endif %} {% if (check_result.data is mapping) and (check_result.data.keys()|length > 0) %} <details class="mt-2 p-2 bg-light rounded"> {% if check_result.status.value in ["failure", "exception"] %} <summary class="atr-cursor-pointer user-select-none p-2">View details</summary> {% elif check_result.status.value == "warning" %} <summary class="atr-cursor-pointer user-select-none p-2">View details</summary> {% else %} <summary class="atr-cursor-pointer user-select-none p-2">View details</summary> {% endif %} {% if check_result.checker.endswith("rat.check_licenses") %} <div class="d-flex gap-3 mb-2"> <span class="badge bg-success-subtle text-success-emphasis border border-success-subtle px-2 py-1"> <strong>{{ check_result.data.get('approved_licenses', 0) }}</strong> files with approved licenses </span> {% if check_result.data.get("unapproved_licenses", 0) > 0 %} <span class="badge bg-danger-subtle text-danger-emphasis border border-danger-subtle px-2 py-1"> <strong>{{ check_result.data.get('unapproved_licenses', 0) }}</strong> files with unapproved licenses </span> {% endif %} {% if check_result.data.get("unknown_licenses", 0) > 0 %} <span class="badge bg-warning-subtle text-warning-emphasis border border-warning-subtle px-2 py-1"> <strong>{{ check_result.data.get('unknown_licenses', 0) }}</strong> files with unknown licenses </span> {% endif %} </div> {% endif %} <table class="table table-bordered mt-2"> <tbody> {% for key, value in check_result.data.items() %} {% if key != "debug_info" %} <tr> <th class="bg-light fw-bold align-top">{{ key|replace('_', ' ') |title }}</th> <td> {% if value is boolean %} {{ "Yes" if value else "No" }} {% elif value is mapping %} <table class="table table-sm mb-0"> {% for k, v in value.items() %} <tr> <th class="bg-light fw-bold">{{ k|replace('_', ' ') |title }}</th> <td>{{ v }}</td> </tr> {% endfor %} </table> {% elif key == "unapproved_files" or key == "unknown_license_files" %} {% if value|length > 0 %} <table class="table table-sm table-bordered mb-0"> <thead> <tr> <th class="bg-light fw-bold">File</th> <th class="bg-light fw-bold">License</th> </tr> </thead> <tbody> {% for file_info in value %} <tr> <td>{{ file_info.name }}</td> <td>{{ file_info.license }}</td> </tr> {% endfor %} </tbody> </table> {% else %} None {% endif %} {% elif value is sequence and value is not string %} {{ value|join(", ") }} {% else %} {{ value }} {% endif %} </td> </tr> {% endif %} {% endfor %} {% if check_result.data.get("debug_info") is mapping %} {% for debug_key, debug_value in check_result.data.debug_info.items() %} <tr> <th class="bg-light fw-bold align-top"> <span class="text-muted">(Debug)</span> {{ debug_key|replace('_', ' ') |title }} </th> <td> {% if debug_key == 'stderr' %} <pre class="mb-0 small"><code class="small">{{ debug_value }}</code></pre> {% elif debug_value is boolean %} {{ "Yes" if debug_value else "No" }} {% elif debug_value is none %} <span class="text-muted">(None)</span> {% else %} {{ debug_value }} {% endif %} </td> </tr> {% endfor %} {% endif %} </tbody> </table> </details> {% endif %} </div> </div> {% endfor %} {% else %} <p>No verification tasks found for this file.</p> {% endif %} <h2>Metadata</h2> <div class="p-3 mb-4 bg-light border rounded"> <p> <strong>Filename:</strong> {{ package.filename }} </p> <p> <strong>Size:</strong> {{ format_file_size(package.bytes_size) }} </p> <p class="mb-0"> <strong>Uploaded:</strong> {{ package.uploaded.strftime("%Y-%m-%d %H:%M:%S UTC") }} </p> </div> </div> {% endblock content %} {% block javascripts %} {{ super() }} <script> function toggleAllDetails() { const details = document.querySelectorAll("details"); // Check if any are closed const anyClosed = Array.from(details).some(detail => !detail.open); // If any are closed, open all // Otherwise, close all details.forEach(detail => detail.open = anyClosed); } </script> {% endblock javascripts %} {% macro function_name_from_key(key) -%} {{- key.removeprefix("atr.tasks.checks.").replace("_", " ").replace(".", " ") | title -}} {%- endmacro %}