superseeded_by = lazy_property(get_superseeded_by, set_superseeded_by)
+ @lazy_property
+ def preceeding_jobs(self):
+ """
+ A list of jobs that came before this one
+ """
+ jobs = self.backend.jobs._get_jobs("""
+ WITH RECURSIVE preceeding_jobs AS (
+ SELECT
+ jobs.*
+ FROM
+ jobs
+ WHERE
+ jobs.superseeded_by = %s
+
+ UNION ALL
+
+ SELECT
+ jobs.*
+ FROM
+ jobs
+ INNER JOIN
+ preceeding_jobs ON preceeding_jobs.id = jobs.superseeded_by
+ )
+
+ SELECT
+ *
+ FROM
+ preceeding_jobs jobs
+ WHERE
+ jobs.deleted_at IS NULL
+ ORDER BY
+ jobs.created_at DESC
+ """, self.id)
+
+ return list(jobs)
+
+ @property
+ def all_jobs(self):
+ """
+ This includes this job and all preceeding jobs
+ """
+ return [self] + self.preceeding_jobs
+
@property
def created_at(self):
"""
<div class="level-right">
<div class="level-item">
<div class="buttons are-small">
- {% if job.has_log() or job.is_running() %}
- <a class="button is-light" href="/jobs/{{ job.uuid }}/log">
- {{ _("View Log") }}
- </a>
+ {% if any((j.has_log() for j in job.all_jobs)) or job.is_running() %}
+ {% if job.preceeding_jobs %}
+ <div class="dropdown is-up is-right">
+ <div class="dropdown-trigger">
+ <a class="button is-light"
+ aria-haspopup="true" aria-controls="dropdown-logs-{{ job.uuid }}">
+ <span>{{ _("View Logs") }}</span>
+
+ <span class="icon is-small">
+ <i class="fas fa-angle-up" aria-hidden="true"></i>
+ </span>
+ </a>
+ </div>
+ <div class="dropdown-menu" id="dropdown-logs-{{ job.uuid }}" role="menu">
+ <div class="dropdown-content">
+ {% for j in reversed(job.all_jobs) %}
+ <a class="dropdown-item" href="/jobs/{{ j.uuid }}/log"
+ {% if not j.has_log() %}disabled{% end %}>
+ {{ locale.format_date(j.created_at) }}
+ </a>
+ {% end %}
+ </div>
+ </div>
+ </div>
+ {% else %}
+ <a class="button is-light" href="/jobs/{{ job.uuid }}/log">
+ {{ _("View Log") }}
+ </a>
+ {% end %}
{% end %}
{% if job.can_be_retried() %}