{% extends "layouts/content.html" %}
{% load humanize %}
{% load static %}
{% load utils %}

{% block styles %}
  <style>
    code {
      margin: 0px;
      padding-top: 0px;
      padding-bottom: 0px;
      border: 0px;
      color: black;
      white-space: pre-wrap;
      display: block;
      position: relative;
    }
    .results {
      border: 1px solid black;
      white-space: normal;
    }
    .results_failed {
      border: 2px solid red;
    }
    .exception {
      border: 1px solid red;
    }

    .failure_comment {
      white-space: pre-wrap;
      word-wrap: break-word;
    }

    .feedback {
      color: #555;
      background-color: #e7f0e6;
      border-right: 1px solid grey;
    }

    .btn-keyboard {
      color: #fff;
      background-color: #333;
      border-color: #333;
    }

    .btn-keyboard:hover {
      color: #fff;
      background-color: #000;
      border-color: #000;
    }

    .btn-keyboard.focus {
      color: #fff;
    }

    .btn-feedback {
      color: #555;
      background-color: #e7f0e6;
    }

    .btn-feedback:hover {
      color: #555;
      background-color: #e0f0d9;
    }

    .btn-feedback.focus {
      color: #444;
      background-color: #e0f0d9;
    }

    #actions-table {
      right: 0px;
      background-color: #eee;
      border: 1px solid #ddd;
      border-radius: 4px;
      padding: 3px;
      z-index: 1;
    }
    .actions-table-fixed {
      position: absolute;
    }
    .actions-table-floating {
      position: fixed;
      right: 0px;
      top: 70px;
    }
    #actions-list-div {
      overflow: auto;
      overscroll-behavior: contain;
      max-height: 75vh;
    }

    .tr-danger {
      color: #c9302c;
      font-weight: bold;
    }
    .tr-warning {
      color: #ec971f;
      font-weight: bold;
    }
    .tickLabel {
      transform: rotate(-30deg);
    }

    .text-white {
      color: white;
    }
    .text-white:hover {
      color: white;
    }
    code > .lava-log-line-url {
      position: absolute;
      text-align: end;
      padding-right: 3px;
      right: 100%;
      opacity: 0;
      user-select: none;
    }
    code:hover > .lava-log-line-url{
      opacity: 1;
    }
    .lava-action-on-screen {
      font-weight: bold;
    }
  </style>
{% endblock %}

{% block content %}
{% if validation_errors %}
<div class="alert alert-warning alert-dismissible">
  <button type="button" class="close" data-dismiss="alert" aria-hidden="true">&times;</button>
  <strong>Invalid job definition:</strong>
  <p>{{ validation_errors }}</p>
</div>
{% endif %}

<div class="row" id="top">
  <div class="col-md-6">
    <dl class="dl-horizontal">
      <dt>Description</dt>
      <dd>{{ job.description|default:"<i>not set</i>" }}</dd>
      <dt>Device-type</dt>
{% if job.requested_device_type %}
      <dd><a href="{{ job.requested_device_type.get_absolute_url }}">{{ job.requested_device_type }}</a> <a href="{% url 'lava.scheduler.device_type_report' job.requested_device_type %}"><span class="glyphicon glyphicon-stats"></span></a></dd>
{% else %}
      <dd>...</dd>
{% endif %}
      <dt>Submitter</dt>
      <dd><a href="mailto:{{ job.submitter.email }}">{{ job.submitter.get_full_name|default:job.submitter.username }}</a></dd>
      <dt>Created</dt>
      <dd title="{{ job.submit_time }}">{{ job.submit_time|naturaltime }}</dd>
      <dt>Priority</dt>
      <dd>{{ job.get_priority_display }}</dd>
      <dt>Visibility</dt>
      <dd>{{ job.is_public|yesno:"Public,Private,Not set" }}{% if job.viewing_groups.all %} ({{ job.viewing_groups.all|join:', ' }}){% endif %}</dd>
      {% if job_tags %}
      <dt>Required Tags</dt>
      <dd>
      {% for tag in job_tags %}
        {% if tag.description %}
        <abbr title="{{ tag.description }}">{{ tag.name }}</abbr>{% if not forloop.last %},{% endif %}
        {% else %}
        {{ tag.name }}{% if not forloop.last %},{% endif %}
        {% endif %}
      {% endfor %}
      </dd>
      {% endif %}

    </dl>
  </div>
  <div class="col-md-6">
    <dl class="dl-horizontal">
      <dt>#{{ job.sub_id|default:job.id }}</dt>
      {% if job.state != job.STATE_FINISHED %}
      <dd><span id="jobstatus">{{ job.get_state_display }}</span>
      {% elif job.health == job.HEALTH_UNKNOWN %}
      <dd><span class="label label-default">{{ job.get_health_display }}</span>
      {% elif job.health == job.HEALTH_COMPLETE %}
      <dd><span class="label label-success">{{ job.get_health_display }}</span>
      {% elif job.health == job.HEALTH_INCOMPLETE %}
      <dd><span class="label label-danger">{{ job.get_health_display }}</span>
      {% else %}
      <dd><span class="label label-warning">{{ job.get_health_display }}</span>
      {% endif %}
      {% if job.is_multinode %}
        <div class="btn-group">
          <button type="button" class="btn btn-xs btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">sub jobs <span class="caret"></span></button>
          <ul class="dropdown-menu">
            {% for subjob in job.sub_jobs_list %}
            {% if subjob.id == job.id %}
            <li class="disabled"><a href="#">#{{ subjob.sub_id|default:job.id }} ({{ subjob.device_role }})</a></li>
            {% else %}
            <li><a href="{% url 'lava.scheduler.job.detail' subjob.id %}">#{{ subjob.sub_id|default:job.id }} ({{ subjob.device_role }}): <span id="subjob_{{ subjob.id }}">{{ subjob.get_state_display }}</span></a></li>
            {% endif %}
            {% endfor %}
          </ul>
        </div>
      {% endif %}
      </dd>
      <dt>Device</dt>
      {% if job.actual_device %}
      <dd id="actual_device"><a href="{{ job.actual_device.get_absolute_url }}">{{ job.actual_device.hostname }}</a> <a
      href="{% url 'lava.scheduler.device_report' job.actual_device.pk %}"><span class="glyphicon glyphicon-stats"></span></a></dd>
      {% else %}
      <dd id="actual_device">...</dd>
      {% endif %}
      <dt>Started</dt>
      <dd id="started" title="{{ job.start_time }}">{% if job.start_time %}{{ job.start_time|naturaltime }}{% else %}...{% endif %}</dd>
      <dt>Duration</dt>
      {% if job.state != job.STATE_FINISHED %}
      <dd id="duration">...</dd>
      {% else %}
      <dd id="duration" title="{{ job.duration }}">{{ job.end_time|timeuntil:job.start_time }}</dd>
      {% endif %}
      {% if job.results_link %}
      <dt>Results</dt>
      <dd><a href="{{ job.results_link }}" class="btn btn-success btn-xs">&nbsp;<span class="glyphicon glyphicon-signal"></span>&nbsp;</a></dd>
      {% endif %}
    </dl>
  </div>
</div>

{% if lava_job_result %}
<div class="alert alert-danger">
  <p><strong>{{ lava_job_result.error_type }} error:</strong> {{ lava_job_result.error_msg }}</p>
</div>
{% endif %}
{% if invalid_log_data %}
<div class="alert alert-warning">
  <p><strong>Unable to parse invalid logs:</strong> This is maybe a bug in LAVA that should be reported.</p>
</div>
{% endif %}

<div id="failure_block" {% if job.failure_comment and job.health != job.HEALTH_COMPLETE %}class="collapse in"{% else %}class="collapse"{% endif %}">
  <pre class="alert alert-danger failure_comment"><strong>Job alert: </strong>{{ job.failure_comment }}</pre>
</div>

<div class="alert alert-danger" id="size-warning" {% if not size_warning %}style="display: none;"{% endif %}>
<p><strong>This log file is too large to view</strong>, (over {{ size_limit|filesizeformat }}).
    It can only be downloaded:
<a href="{% url 'lava.scheduler.job.log_file.plain' job.pk %}"><span class="glyphicon glyphicon-save-file"></span> Plain log</a></p>
</div>
<div id="actions-table" class="hidden-xs hidden-sm hidden-md actions-table-fixed">
  <h4>Pipeline <span id="actions-table-arrow" class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span></h4>
  <div id="actions-list-div">
    <ul class="list-unstyled" id="actions-list" style="display: none;">
    </ul>
  </div>
</div>

<ul class="nav nav-tabs">
  <li class="active"><a href="#Log" data-toggle="tab">Summary</a></li>
  <li><a href="#Timing" id="TimingButton" data-toggle="tab">Timing</a></li>
  <li class="pull-right"><a href="#bottom">End of page <span class="glyphicon glyphicon-chevron-down"></span></a></li>
  <li class="pull-right" id="alert-link" {% if not job.failure_comment or job.health != job.HEALTH_COMPLETE %}style="display:none"{% endif %}><a href="#failure_block" data-toggle="collapse" aria-expanded="false" aria-controls="failure_block">Show alert <span class="glyphicon glyphicon-chevron-up"></span></a></li>
</ul>

<div class="tab-content">
  <div class="tab-pane active" id="Log">
{% if not size_warning %}
    <div class="btn-group" data-toggle="buttons" id="logbuttons">
      <label class="btn btn-default" id="debug_label" for="debug"><input type="checkbox" id="debug" autocomplete="off">debug</label>
      <label class="btn btn-info" id="info_label" for="info"><input type="checkbox" id="info" autocomplete="off">info</label>
      <label class="btn btn-warning" id="warning_label" for="warning"><input type="checkbox" id="warning" autocomplete="off">warning</label>
      <label class="btn btn-danger" id="error_label" for="error"><input type="checkbox" id="error" autocomplete="off">error</label>
      <label class="btn btn-keyboard" id="keyboard_label" for="keyboard"><input type="checkbox" id="keyboard" autocomplete="off">input</label>
      <label class="btn btn-success" id="target_label" for="target"><input type="checkbox" id="target" autocomplete="off">output</label>
      <label class="btn btn-feedback" id="feedback_label" for="feedback"><input type="checkbox" id="feedback" autocomplete="off">feedback</label>
      <label class="btn btn-primary" id="results_label" for="results"><input type="checkbox" id="results" autocomplete="off">results</label>
    </div>
{% endif %}

    <div class="btn-group pull-right">
      {% if job.is_multinode %}
      <a class="btn btn-info" href="{% url 'lava.scheduler.job.multinode_definition' job.pk %}">Multinode</a>
      {% else %}
      <a class="btn btn-info" href="{% url 'lava.scheduler.job.definition' job.pk %}">Definition</a>
      {% endif %}
      {% if show_cancel %}
        {% if job.is_multinode %}
      <a class="btn btn-warning" id="cancel" href="{% url 'lava.scheduler.job.cancel' job.id %}">Cancel</a>
        {% else %}
      <a class="btn btn-warning" id="cancel" href="{% url 'lava.scheduler.job.cancel' job.pk %}">Cancel</a>
        {% endif %}
      {% elif show_fail %}
        {% if job.is_multinode %}
      <a class="btn btn-danger" id="fail" title="This should not be used if lava-run is still running" href="{% url 'lava.scheduler.job.fail' job.id %}">Fail</a>
        {% else %}
      <a class="btn btn-danger" id="fail" title="This should not be used if lava-run is still running" href="{% url 'lava.scheduler.job.fail' job.pk %}">Fail</a>
        {% endif %}
      {% endif %}
      {% if show_resubmit %}
      <a class="btn btn-primary" href="{% url 'lava.scheduler.job.resubmit' job.pk %}">Resubmit</a>
      {% endif %}
      <div class="btn-group">
        <button type="button" class="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Actions <span class="caret"></span></button>
        <ul class="dropdown-menu">
          {% if job.is_multinode %}
          <li><a href="{% url 'lava.scheduler.job.definition' job.pk %}">Definition</a></li>
          {% endif %}
          <li><a href="{% url 'lava.scheduler.job.log_file.plain' job.pk %}"><span class="glyphicon glyphicon-save-file"></span> Plain log</a></li>
          <li><a href="{% url 'lava.scheduler.job.configuration' job.pk %}"><span class="glyphicon glyphicon-book"></span> Configuration</a></li>
          <li><a href="{% url 'lava.scheduler.job.description.yaml' job.pk %}"><span class="glyphicon glyphicon-eye-open"></span> Description</a></li>
          <li role="separator" class="divider"></li>
          <li><a href="{% url 'lava.scheduler.job.toggle_favorite' job.pk %}"><span class="glyphicon glyphicon-star{% if not is_favorite %}-empty{% endif %}"></span> {{ is_favorite|yesno:"Remove from favorites,Add to favorites" }}</a></li>
          <li><a href="#" data-toggle="modal" data-target="#similar_jobs_modal"><span class="glyphicon glyphicon-search"></span> Similar jobs</a></li>
          {% if show_failure or user.is_superuser %}
          <li role="separator" class="divider"></li>
          {% if show_failure %}
          <li><a href="{% url 'lava.scheduler.job.annotate_failure' job.pk %}">Comment</a></li>
          {% endif %}
          {% if user.is_superuser %}
          <li><a href="{% url 'admin:lava_scheduler_app_testjob_change' job.pk %}">Admin this TestJob</a></li>
          {% endif %}
          {% endif %}
        </ul>
      </div>
    </div>

    <div id="sectionlogs">
      <img id="log-messages" src="{% static "lava_scheduler_app/images/ajax-loader.gif" %}" />
    </div>
    {% if not size_warning %}
    <p class="pull-right"><a href="#top">Top of page <span class="glyphicon glyphicon-chevron-up"></span></a></p>
    {% if job.state == job.STATE_FINISHED %}
    <p><a href="{{ STATIC_URL }}docs/v2/debugging.html">Please read the triage guidelines</a> for help on debugging failures in the test job, test definitions or in individual test cases.</p>
    {% endif %}
    {% endif %}
  </div>

  <div class="tab-pane" id="Timing">
    <h2>Job Timings</h2>
    <p>This section helps test writers to check for actions with a duration which
       is much shorter than the requested timeout.  Reducing these timeouts
       will allow failures to be identified more quickly.</p>
    <p>The graph only shows actions that are longer than 1 second. The full list
       is anyway available in the table.</p>

    <div id="timing_block">Loading the data...</div>
  </div>

</div>

{% include "_similar_jobs.html" %}
<div id="bottom"></div>
{% endblock %}

{% block scripts %}
<script>
  var condition_choices = JSON.parse($("#id_condition_choices").val());
  var content_types = JSON.parse($("#id_available_content_types").val());
</script>
<script src="{% static "lava_server/js/jquery.typeahead.js" %}"></script>
<script src="{% static "lava_scheduler_app/js/similar-jobs.js" %}"></script>
<script src="{% static "lava_scheduler_app/js/jquery.flot.js" %}"></script>
<script>
  var logs_position = 0;
  let current_log_div = null;
  const progress_node = document.getElementById('log-messages');
  const logs_section = document.getElementById('sectionlogs');
  const actions_list = document.getElementById('actions-list');
  const actions_table = document.getElementById('actions-table');
  const action_id_regexp = /^start: (?<action_level>[\d.]+) (?<action_name>[\w_-]+)/;

  let log_div_to_action = new Map();
  function logs_observer_callback (entries, observer) {
    for (const observed_entry of entries) {
      const action_table_entry = log_div_to_action.get(observed_entry.target);
      if (!action_table_entry) {
        continue;
      }
      if (observed_entry.isIntersecting) {
        action_table_entry.classList.add('lava-action-on-screen');
        if (actions_table.classList.contains('actions-table-floating')) {
          action_table_entry.scrollIntoView({block: "center", behavior: "smooth"});
        }
      } else {
        action_table_entry.classList.remove('lava-action-on-screen');
      }
    }
  }

  const logs_observer = new IntersectionObserver(logs_observer_callback);

  function render_logs(logs_data) {
    const logs_fragment = document.createDocumentFragment();
    const actions_fragment = document.createDocumentFragment();
    // Loop on all new code blocks
    for (const [i, d] of logs_data.entries()) {
        const level = d['lvl'];
        const id = "L" + (logs_position + i);
        const msg = d['msg']
        const dt = d['dt']

        const code_node = document.createElement('code');
        code_node.id = id;
        code_node.title = dt;
        // Base HTML class switch
        switch(level) {
          case 'debug':
          case 'feedback':
            code_node.classList.add(level);
            break;
          case 'input':
            code_node.classList.add('keyboard');
            break;
          case 'target':
            code_node.classList.add('target', 'bg-success');
            break;
          case 'results':
            code_node.classList.add('results', 'bg-primary');
            break;
          case 'error':
          case 'exception':
            code_node.classList.add(level, 'bg-danger');
            break;
          default:
            code_node.classList.add(level, `bg-${level}`)
        }
        // Floating line link
        const line_link = document.createElement('a');
        line_link.setAttribute('href', `#${id}`);
        line_link.textContent = id;
        line_link.className = 'lava-log-line-url';
        code_node.appendChild(line_link);
        // Content switch
        switch(level) {
          case 'results':
            if (msg['result'] == 'fail') {
              code_node.classList.add('results_failed');
            }
            const results_node = document.createElement('a');
            const base_url = '{% url 'lava.results.testjob' job=job.pk %}';
            results_node.className = 'text-white';
            results_node.setAttribute('href', `${base_url}/${msg['definition']}/${msg['case']}`);
            for (let [key, value] of Object.entries(msg)) {
              if (key == 'extra') {
                value = '...';
              }
              if (key == 'starttc') {
                results_node.setAttribute('id', `results_${value}`);
              }
              results_node.appendChild(document.createTextNode(`${key}: ${value}`));
              results_node.appendChild(document.createElement('br'));
            }
            code_node.appendChild(results_node);
            break;
          case 'input':
            const kbd_node = document.createElement('kbd');
            kbd_node.textContent = msg;
            code_node.appendChild(kbd_node);
            break;
          case 'info':
          case 'debug':
            const new_div_node = add_to_action_list(actions_fragment, msg, id);
            if (new_div_node) {
              logs_fragment.appendChild(new_div_node);
              current_log_div = new_div_node;
            }
          default:
            code_node.appendChild(document.createTextNode(msg));
        }
        if (current_log_div) {
          current_log_div.appendChild(code_node);
        } else {
          logs_fragment.appendChild(code_node);
        }
    }
    logs_position += logs_data.length;
    actions_list.appendChild(actions_fragment);
    progress_node.before(logs_fragment);
  };
  function add_to_action_list(fragment, line, id_to_href) {
    const match = action_id_regexp.exec(line);
    if (!match) {
      return null;
    }
    const groups = match.groups;
    const action_level = groups.action_level;
    const action_name = groups.action_name;
    const div_node = document.createElement('div');

    const new_action_list_entry = document.createElement('li');
    fragment.appendChild(new_action_list_entry);
    const new_action_link = document.createElement('a');
    new_action_link.setAttribute('href', `#${id_to_href}`);
    new_action_link.textContent = `${action_level} - ${action_name}`;
    new_action_list_entry.appendChild(new_action_link);

    log_div_to_action.set(div_node, new_action_list_entry);
    logs_observer.observe(div_node);
    return div_node;
  };

  document.addEventListener('DOMContentLoaded', function render_logs_initial() {
    const logs_initial = JSON.parse(document.getElementById('logs-initial').textContent);
    render_logs(logs_initial);
{% if job.state == job.STATE_FINISHED %}
    $('#log-messages').css('display', 'none');
{% endif %}
  });

  $(document).ready(
    function() {
{% if not size_warning %}
      // Create a new CSS sheet and use it
      var sheet = (function() {
        var style = document.createElement("style");
        // WebKit hack :(
        style.appendChild(document.createTextNode(""));
        document.head.appendChild(style);
        return style.sheet;
      })();

      // Create the list of styles
      // Debug are deactivated by default
      var styles = {
        'debug': sheet.insertRule('.debug { display: block }', 0),
        'keyboard': sheet.insertRule('.keyboard { display: block }', 1),
        'info': sheet.insertRule('.info { display: block }', 2),
        'warning': sheet.insertRule('.warning { display: block }', 3),
        'error': sheet.insertRule('.error { display: block }', 4),
        'target': sheet.insertRule('.target { display: block }', 5),
        'results': sheet.insertRule('.results { display: block }', 6),
        'feedback': sheet.insertRule('.feedback { display: block }', 7),
      };

      // Handle click events on buttons
      $("#logbuttons label").click(function(e) {
        var label = e.target.htmlFor;
        var input = $('input#' + label);
        var rule;
        if (input.is(':checked')) {
          rule = '.' + label + ' { display: block }';
          $('label#' + label + '_label').css('text-decoration', 'None');
        } else {
          rule = '.' + label + ' { display: none }';
          $('label#' + label + '_label').css('text-decoration', 'line-through');
        }
        // Remove old style and insert the new one
        var index = styles[label];
        sheet.deleteRule(index);
        sheet.insertRule(rule, index);
      });

      // Open the affix if the user click on the button
      var actions_table_toggle = true;
      function toggle_actions_table() {
        if(actions_table_toggle) {
          $('#actions-list').css('display', 'block');
          $('#actions-table-arrow').removeClass('glyphicon-arrow-up');
          $('#actions-table-arrow').addClass('glyphicon-arrow-down');
          const highlighted_action = document.querySelector("#actions-list > .lava-action-on-screen");
          if (highlighted_action) {
            highlighted_action.scrollIntoView({block: "center"})
          }
        } else {
          $('#actions-list').css('display', 'none');
          $('#actions-table-arrow').removeClass('glyphicon-arrow-down');
          $('#actions-table-arrow').addClass('glyphicon-arrow-up');
        }
        actions_table_toggle = !actions_table_toggle;
      }

      $('#actions-table h4').click(toggle_actions_table);
      if (window.innerWidth > 1580) {
        // Screen is wide enough so that actions table does
        // not overlap with any other element.
        toggle_actions_table();
      }

      // Move the actions-table
      var actions_table = $('#actions-table');
      var actions_table_top = window.scrollY +
                      $('#actions-table h4')[0].getBoundingClientRect().top - 70;
      // Place it correctly if the page is reloaded while not at the top
      if (document.body.scrollTop > actions_table_top ||
          document.documentElement.scrollTop > actions_table_top) {
        actions_table.addClass("actions-table-floating");
      }
      $(window).scroll(function(e) {
        if (document.body.scrollTop > actions_table_top ||
            document.documentElement.scrollTop > actions_table_top) {
          actions_table.addClass("actions-table-floating");
        } else {
          actions_table.removeClass("actions-table-floating");
        }
      });
{% endif %}

      // Load the timing on demand
      var timing_already_loaded = false;
      $("#TimingButton").click(function(e) {
        if (timing_already_loaded) { return; }
        $.ajax({
          url: '{% url 'lava.scheduler.job.timing' pk=job.pk %}',
          error: function(xhr, txt_status, error) {
            $('#timing_block').html("<p><strong>Unable to load the timing!</strong</p>");
          },
          success: function(data, success, xhr) {
            if (data['graph'].length == 0) {
              $('#timing_block').html("<p>Unable to parse the log file.</p>");
              return;
            }
            $('#timing_block').html(data['timing']);
            // Generate the graph
            var durations = [];
            var timeouts = [];
            var levels = [];
            for(var i = 0; i < data['graph'].length; i++) {
              if (data['graph'][i][2] <= 1) { continue; }
              durations.push([i, data['graph'][i][2]]);
              timeouts.push([i, data['graph'][i][3]]);
              levels.push([i, data['graph'][i][0]]);
            }

            var ddata = [
              {'label': 'duration', 'data': durations, 'color': '#FF0000'},
              {'label': 'timeout', 'data': timeouts, 'color': '#0000FF'},
            ];

            $.plot($("#timings"), ddata, {
              series: {
                lines: { show: true, fill: true, steps: false },
              },
              xaxis: {
                ticks: levels,
              },
            });
          }
        });
        timing_already_loaded = true;
      })
    });

{% if job.state != job.STATE_FINISHED %}
  // Add a timer for the log updates
  pollTimer = setTimeout(poll, 5000);
{% endif %}

  var poll_status = 1;
  var poll_logs = 1;

  function poll() {
    // Update job status
    if(poll_status) {
      $.ajax({
        url: '{% url 'lava.scheduler.job_status' pk=job.pk %}',
        success: function(data, success, xhr) {
          $('#actual_device').html(data['actual_device']);
          $('#started').html(data['started']);
          $('#jobstatus').html(data['job_state']);
          $('#duration').html(data['duration']);
          for(var i = 0; i < data['subjobs'].length; i++) {
            var d = data['subjobs'][i];
            $('#subjob_' + d[0]).html(d[1]);
          }
          if ('X-JobState' in data) {
            $('#cancel').css('display', 'none');
            $('#fail').css('display', 'none');
            poll_status = 0;
          }
          if (data['failure_comment']) {
            if (data['job_health'] == 1) {
              // Collapse if job health is COMPLETE (1).
              $("#failure_block").removeClass('in');
              // Allow to show by clicking the Alert link.
              $("#alert-link").show();
            } else {
              $("#failure_block").addClass('in');
            }
            $(".failure_comment").html('<strong>Job alert: </strong>' + data['failure_comment']);
          }
        }
      });
    }

    // Update logs
    if(poll_logs) {
      $.ajax({
        url: '{% url 'lava.scheduler.job.log_incremental' pk=job.pk %}?line=' + logs_position,
        success: function(data, success, xhr) {
          // Do we have to scroll down ?
          var scroll_down = false;
          if((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
            scroll_down = true;
          }

          render_logs(data);

          // Relaunch the timer
          if(xhr.getResponseHeader('X-Size-Warning')) {
            $('#log-messages').css('display', 'none');
            $('#sectionlogs').css('display', 'none');
            $('#size-warning').css('display', 'block');
            poll_logs = 0;
          } else if(xhr.getResponseHeader('X-Is-Finished')) {
            $('#log-messages').css('display', 'none');
            poll_logs = 0;
          }

          // Scroll down
          if (scroll_down) {
            document.getElementById('bottom').scrollIntoView();
          }
        }
      });
    }
    if(poll_status || poll_logs) {
      pollTimer = setTimeout(poll, 5000);
    }
  };
</script>
{{ log_data }}
{% endblock scripts %}
