atr/templates/project-view.html (290 lines of code) (raw):

{% extends "layouts/base.html" %} {% block title %} Project ~ ATR {% endblock title %} {% block description %} Information regarding an Apache Project. {% endblock description %} {% block content %} <div class="row"> <div class="col-md"> <h1>{{ project.display_name }}</h1> </div> {% if project.is_retired %} <div class="col-sm-auto"> <span class="badge text-bg-secondary">retired</span> </div> {% endif %} </div> <div class="card mb-4"> <div class="card-header bg-light"> <h3 class="mb-2">Project label</h3> </div> <div class="card-body"> <code class="fs-6">{{ project.name }}</code> </div> </div> {% set is_admin = is_admin_fn(current_user.uid) %} {% set is_committee_member = is_committee_member_fn(project.committee, current_user.uid) %} <div class="card mb-4"> <div class="card-header bg-light"> <h3 class="mb-2">PMC</h3> </div> <div class="card-body"> <div class="d-flex flex-wrap gap-3 small mb-1"> <a href="{{ as_url(routes.committees.view, name=project.committee.name) }}">{{ project.committee.display_name }}</a> </div> </div> </div> <div class="card mb-4"> <div class="card-header bg-light"> <h3 class="mb-2">Description</h3> </div> <div class="card-body"> <div class="d-flex flex-wrap gap-3 small mb-1"> <span class="fs-6">{{ project.description }}</span> </div> </div> </div> <div class="card mb-4"> <div class="card-header bg-light"> <h3 class="mb-2">Signing keys</h3> </div> <div class="card-body"> <div class="row row-cols-1 g-4"> {% for key in project.public_signing_keys %} <div class="col"> <div class="card h-100 border"> <div class="card-body"> <table class="table mb-0"> <tbody> <tr> <th class="border-0">Fingerprint</th> <td class="text-break border-0">{{ key.fingerprint }}</td> </tr> <tr> <th class="border-0">Type</th> <td class="text-break border-0">{{ algorithms[key.algorithm] }} ({{ key.length }} bits)</td> </tr> <tr> <th class="border-0">Created</th> <td class="text-break border-0">{{ key.created.strftime("%Y-%m-%d %H:%M:%S") }}</td> </tr> <tr> <th class="border-0">Expires</th> <td class="text-break border-0"> {% if key.expires %} {% set days_until_expiry = (key.expires - now).days %} {% if days_until_expiry < 0 %} <span class="text-danger fw-bold"> {{ key.expires.strftime("%Y-%m-%d %H:%M:%S") }} <span class="badge bg-danger text-white ms-2">Expired</span> </span> {% elif days_until_expiry <= 30 %} <span class="text-warning fw-bold"> {{ key.expires.strftime("%Y-%m-%d %H:%M:%S") }} <span class="badge bg-warning text-dark ms-2">Expires in {{ days_until_expiry }} days</span> </span> {% else %} {{ key.expires.strftime("%Y-%m-%d %H:%M:%S") }} {% endif %} {% else %} Never {% endif %} </td> </tr> <tr> <th class="border-0">User ID</th> <td class="text-break border-0">{{ key.declared_uid or 'Not specified' }}</td> </tr> </tbody> </table> </div> </div> </div> {% endfor %} </div> </div> </div> <div class="card mb-4"> <div class="card-header bg-light d-flex justify-content-between align-items-center"> <h3 class="mb-0">Release policy</h3> {% if not project.is_retired %} {% if project.release_policy and (is_committee_member or is_admin) %} <div> <a class="btn btn-primary btn-sm" href="{{ as_url(routes.projects.release_policy_edit, project_name=project.name) }}"><i class="bi bi-pencil-square"></i></a> </div> {% elif (is_committee_member or is_admin) %} <div> <a class="btn btn-primary btn-sm" href="{{ as_url(routes.projects.release_policy_add, project_name=project.name) }}"><i class="bi bi-plus"></i></a> </div> {% endif %} {% endif %} </div> <div class="card-body"> {% if project.release_policy %} {% set rp = project.release_policy %} <div class="card h-100 border"> <div class="card-body"> <table class="table mb-0"> <tbody> <tr> <th class="border-0 w-25">Email</th> <td class="text-break border-0"> <a href="mailto:{{ vp.mailto_addresses[0] }}">{{ vp.mailto_addresses[0] }}</a> </td> </tr> <tr> <th class="border-0">Manual vote process</th> <td class="text-break border-0">{{ vp.manual_vote }}</td> </tr> <tr> <th class="border-0">Minimum voting period</th> <td class="text-break border-0">{{ vp.min_hours }}h</td> </tr> <tr> <th class="border-0">Release checklist</th> <td class="text-break border-0"> {% if vp.release_checklist|length > 0 %} <textarea readonly class="form-control font-monospace" rows="10">{{ vp.release_checklist }}</textarea> {% else %} None {% endif %} </td> </tr> <tr> <th class="border-0">Start vote template</th> <td class="text-break border-0"> {% if vp.start_vote_template|length > 0 %} <textarea readonly class="form-control font-monospace" rows="10">{{ vp.start_vote_template }}</textarea> {% else %} None {% endif %} </td> </tr> <tr> <th class="border-0">Announce release template</th> <td class="text-break border-0"> {% if vp.announce_release_template|length > 0 %} <textarea readonly class="form-control font-monospace" rows="10">{{ vp.announce_release_template }}</textarea> {% else %} None {% endif %} </td> </tr> <tr> <th class="border-0">Pause for RM</th> <td class="text-break border-0">{{ vp.pause_for_rm }}</td> </tr> </tbody> </table> </div> </div> {% else %} <div>None defined.</div> {% endif %} </div> </div> {% if (is_committee_member or is_admin) %} {% if candidate_drafts|length > 0 %} <h2>Draft candidate releases</h2> <div class="d-flex flex-wrap gap-2 mb-4"> {% for draft in candidate_drafts %} <a href="{{ as_url(routes.draft.view, project_name=project.name, version_name=draft.version) }}" class="btn btn-sm btn-outline-secondary py-2 px-3" title="View draft {{ project.name }} {{ draft.version }}"> {{ project.name }} {{ draft.version }} {% set file_count = number_of_release_files(draft) %} <span class="badge bg-secondary ms-2">{{ file_count }} {% if file_count == 1 %} file {% else %} files {% endif %} </span> </a> {% endfor %} </div> {% endif %} {% if candidates|length > 0 %} <h2>Candidate releases</h2> <div class="d-flex flex-wrap gap-2 mb-4"> {% for candidate in candidates %} <a href="{{ as_url(routes.candidate.view, project_name=project.name, version_name=candidate.version) }}" class="btn btn-sm btn-outline-info py-2 px-3" title="View candidate {{ project.name }} {{ candidate.version }}"> {{ project.name }} {{ candidate.version }} {% set file_count = number_of_release_files(candidate) %} <span class="badge bg-info ms-2">{{ file_count }} {% if file_count == 1 %} file {% else %} files {% endif %} </span> </a> {% endfor %} </div> {% endif %} {% if previews|length > 0 %} <h2>Preview releases</h2> <div class="d-flex flex-wrap gap-2 mb-4"> {% for preview in previews %} <a href="{{ as_url(routes.preview.view, project_name=project.name, version_name=preview.version) }}" class="btn btn-sm btn-outline-warning py-2 px-3" title="View preview {{ project.name }} {{ preview.version }}"> {{ project.name }} {{ preview.version }} {% set file_count = number_of_release_files(preview) %} <span class="badge bg-warning ms-2">{{ file_count }} {% if file_count == 1 %} file {% else %} files {% endif %} </span> </a> {% endfor %} </div> {% endif %} {% if full_releases|length > 0 %} <h2>Full releases</h2> <div class="d-flex flex-wrap gap-2 mb-4"> {% for release in full_releases %} <a href="{{ as_url(routes.release.view, project_name=project.name, version_name=release.version) }}" class="btn btn-sm btn-outline-success py-2 px-3" title="View release {{ project.name }} {{ release.version }}"> {{ project.name }} {{ release.version }} {% set file_count = number_of_release_files(release) %} <span class="badge bg-success ms-2">{{ file_count }} {% if file_count == 1 %} file {% else %} files {% endif %} </span> </a> {% endfor %} </div> {% endif %} {% endif %} {% if project.created_by == current_user.uid %} <h2>Actions</h2> <div class="mt-3"> <form method="post" action="{{ as_url(routes.projects.delete) }}" class="d-inline-block m-0" onsubmit="return confirm('Are you sure you want to delete the project \'{{ project.display_name }}\'? This cannot be undone.');"> <input type="hidden" name="project_name" value="{{ project.name }}" /> <button type="submit" class="btn btn-sm btn-outline-danger" title="Delete {{ project.display_name }}"> <i class="bi bi-trash"></i> Delete project </button> </form> </div> {% endif %} {% endblock content %} {% block javascripts %} {{ super() }} {% endblock javascripts %}