[%
USE date;
USE String;
USE HTML;
USE Math;


USE mibs=format("%.2f");

# Formatted date time, in hydra-local timezone.
# Use only where an HTML element cannot be used.
BLOCK dateTimeText;
date.format(timestamp, '%Y-%m-%d %H:%M:%S');
END;

# HTML-rendered date. Formatted in hydra-local timezone.
# It is enhanced with JavaScript to show user-local and UTC time zones.
BLOCK renderDateTime %]
<time [% HTML.attributes(
    "data-timestamp" => timestamp,
    title => date.format(timestamp, '%Y-%m-%d %H:%M:%S (%Z)'),
    datetime => date.format(timestamp, "%Y-%m-%dT%H:%M:%SZ", gmt => 1),
) %] class="date is-absolute">
[% INCLUDE dateTimeText %]
</time>
[% END;

# Relative date, as text.
# Use only where an HTML element cannot be used.
BLOCK relativeDateText;
  ago = date.now - timestamp;
  IF ago >= 0 && ago < 60; THEN;
    ago _ 's ago';
  ELSIF ago >= 0 && ago < 60 * 60; THEN;
    Math.int(ago / 60) _ 'm ago';
  ELSIF ago >= 0 && ago < 24 * 60 * 60; THEN;
    Math.int(ago / (60 * 60)) _ 'h ago';
  ELSIF ago >= 0 && ago < 7 * 24 * 60 * 60; THEN;
    Math.int(ago / (24 * 60 * 60)) _ 'd ago';
  ELSE;
    date.format(timestamp, '%Y-%m-%d');
  END;
END;

# HTML-rendered relative date.
# It is enhanced with JavaScript to show user-local and UTC time zones.
BLOCK renderRelativeDate %]
<time [% HTML.attributes(
    "data-timestamp" => timestamp,
    title => date.format(timestamp, '%Y-%m-%d %H:%M:%S (%Z)'),
    datetime => date.format(timestamp, "%Y-%m-%dT%H:%M:%SZ", gmt => 1),
) %] class="date is-relative">
[% INCLUDE relativeDateText %]
</time>
[% END;

BLOCK renderProjectName %]
<a [% IF inRow %]class="row-link"[% END %] [% HTML.attributes(href => c.uri_for('/project' project)) %]><tt>[% project | html %]</tt></a>
[% END;


BLOCK renderJobsetName %]
<a [% IF inRow %]class="row-link"[% END %] [% HTML.attributes(href => c.uri_for('/jobset' project jobset)) %]><tt>[% jobset | html %]</tt></a>
[% END;


BLOCK renderJobName %]
<a [% IF inRow %]class="row-link"[% END %] [% HTML.attributes(href => c.uri_for('/job' project jobset job)) %]>[% job | html %]</a>
[% END;


BLOCK renderFullJobsetName %]
<tt>[% INCLUDE renderProjectName inRow=0 %]:[% INCLUDE renderJobsetName %]</tt>
[% END;


BLOCK renderFullJobName %]
<tt>[% IF !hideProjectName; INCLUDE renderProjectName inRow=0 %]:[% END; IF !hideJobsetName; INCLUDE renderJobsetName inRow=0 %]:[% END; INCLUDE renderJobName %]</tt>
[% END;


BLOCK renderFullJobNameOfBuild;
  INCLUDE renderFullJobName project=build.jobset.get_column("project") jobset = build.jobset.get_column("name") job = build.get_column("job");
END;


BLOCK renderDuration;
  IF duration >= 24 * 60 * 60; duration div (24 * 60 * 60) %]d&nbsp;[% END;
  IF duration >= 60 * 60; duration div (60 * 60) % 24 %]h&nbsp;[% END;
  IF duration >= 60; duration div 60 % 60 %]m&nbsp;[% END;
  duration % 60 %]s[%
END;

BLOCK renderDrvInfo;
  drvname = step.drvpath
    .substr(11) # strip `/nix/store/`
    .split('-').slice(1).join("-") # strip hash part
    .substr(0, -4); # strip `.drv`
  IF drvname != releasename;
    IF step.type == 0; action = "Build"; ELSE; action = "Substitution"; END;
    IF drvname; %]<em> ([% HTML.escape(action) %] of [% HTML.escape(drvname) %])</em>[% END;
  END;
END;


BLOCK renderBuildListHeader %]
  <table class="table table-striped table-condensed clickable-rows">
    <thead>
      <tr>
        [% IF !hideResultInfo %]
          <th></th>
        [% END %]
        [% IF showSchedulingInfo %]
          <th></th>
        [% END %]
        <th>#</th>
        [% IF !hideJobName %]
        <th>Job</th>
        [% END %]
        <th>[% IF showSchedulingInfo %]Queued at[% ELSE %]Finished at[% END %]</th>
        <th>Package/release name</th>
        <th>System</th>
        [% IF showDescription %]
          <th>Description</th>
        [% END %]
      </tr>
    </thead>
    <tbody>
[% END;


BLOCK renderBuildListBody;
  FOREACH build IN builds; link = c.uri_for('/build' build.id) %]
    <tr>
      [% IF !hideResultInfo %]
        <td>
          [% INCLUDE renderBuildStatusIcon size=16 buildstatus=build.buildstatus %]
        </td>
      [% END %]
      [% IF showSchedulingInfo %]
        <td>[% IF busy %]<span class="badge badge-success">Started</span>[% ELSE %]<span class="badge badge-secondary">Queued</span>[% END %]</td>
      [% END %]
      <td><a class="row-link" [% HTML.attributes(href => link) %]>[% HTML.escape(build.id) %]</a></td>
      [% IF !hideJobName %]
        <td>
          <a [% HTML.attributes(href => link) %]>[% IF !hideJobsetName %][% HTML.escape(build.jobset.get_column("project")) %]:[% HTML.escape(build.jobset.get_column("name")) %]:[% END %][% HTML.escape(build.get_column("job")) %]</a>
          [% IF showStepName %]
            [% INCLUDE renderDrvInfo step=build.buildsteps releasename=build.nixname %]
          [% END %]
        </td>
      [% END %]
      <td class="nowrap">[% t = showSchedulingInfo ? build.timestamp : build.stoptime; IF t; INCLUDE renderRelativeDate timestamp=(showSchedulingInfo ? build.timestamp : build.stoptime); ELSE; "-"; END %]</td>
      <td>[% !showSchedulingInfo and build.get_column('releasename') ? HTML.escape(build.get_column('releasename')) : HTML.escape(build.nixname) %]</td>
      <td class="nowrap"><tt>[% build.system | html %]</tt></td>
      [% IF showDescription %]
        <td>[% HTML.escape(build.description) %]</td>
      [% END %]
    </tr>
  [% END;
  IF linkToAll %]
    <tr><td class="centered" colspan="5"><a [% HTML.attributes(href => linkToAll) %]><em>More...</em></a></td></tr>
  [% END;
END;


BLOCK renderBuildListFooter %]
    </tbody>
  </table>
[% END;


BLOCK renderBuildList;
  INCLUDE renderBuildListHeader;
  INCLUDE renderBuildListBody;
  INCLUDE renderBuildListFooter;
END;


BLOCK renderLink %]<a [% HTML.attributes(href => uri) %]>[% HTML.escape(title) %]</a>[% END;


BLOCK maybeLink;
  IF uri %]<a [% HTML.attributes(href => uri, class => class); IF confirmmsg +%] onclick="javascript:return confirm('[% confirmmsg %]')"[% END %]>[% HTML.escape(content) %]</a>[% ELSE; HTML.escape(content); END;
END;


BLOCK renderSelection;
  IF edit;
    IF radiobuttons; %]
      <div class="controls">
        [% FOREACH name IN options.keys.sort %]
          <label class="radio inline">
            <input type="radio" [% HTML.attributes(id => param, name => param, value => name) %]
              [% IF name == curValue; "checked='1'"; END %]>
              [% HTML.escape(options.$name) %]
            </input>
          </label>
        [% END %]
      </div>
    [% ELSE %]
      <select class="custom-select" [% HTML.attributes(id => param, name => param) %]>
        [% FOREACH name IN options.keys.sort %]
          <option [% IF name == curValue; "selected='selected'"; END; " "; HTML.attributes(value => name) %]>[% HTML.escape(options.$name) %]</option>
        [% END %]
      </select>
    [% END;
  ELSE;
    options.$curValue;
  END;
END;


BLOCK editString; %]
  <input type="text" class="string" [% HTML.attributes(id => param, name => param, value => value) %] />
[% END;


BLOCK renderFullBuildLink;
  INCLUDE renderFullJobNameOfBuild build=build %] <a [% HTML.attributes(href => c.uri_for('/build' build.id)) %]>build [% HTML.escape(build.id) %]</a>[%
END;


BLOCK renderBuildIdLink; %]
<a [% HTML.attributes(href => c.uri_for('/build' id)) %]>build [% HTML.escape(id) %]</a>
[% END;


BLOCK renderBuildLink; INCLUDE renderBuildIdLink id=build.id; END;


BLOCK renderBuildStatusIcon;
  finished = build != undef ? build.finished : 1;
  buildstatus = buildstatus != undef ? buildstatus : build.buildstatus;
  IF finished;
    IF buildstatus == 0 %]
      <img src="[% c.uri_for("/static/images/emojione-check-2714.svg") %]" height="[% size %]" width="[% size %]" title="Succeeded" alt="Succeeded" class="build-status" />
    [% ELSIF buildstatus == 1 %]
      <img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="[% size %]" width="[% size %]" title="Failed" alt="Failed" class="build-status" />
    [% ELSIF buildstatus == 2 %]
      <img src="[% c.uri_for("/static/images/emojione-gray-x-2716.svg") %]" height="[% size %]" width="[% size %]" title="Dependency failed" alt="Dependency failed" class="build-status" />
    [% ELSIF buildstatus == 3 || buildstatus == 9 %]
      <img src="[% c.uri_for("/static/images/emojione-stopsign-1f6d1.svg") %]" height="[% size %]" width="[% size %]" title="Aborted" alt="Aborted" class="build-status" />
    [% ELSIF buildstatus == 4 %]
      <img src="[% c.uri_for("/static/images/emojione-stopsign-1f6d1.svg") %]" height="[% size %]" width="[% size %]" title="Cancelled" alt="Cancelled" class="build-status" />
    [% ELSIF buildstatus == 6 %]
      <img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="[% size %]" width="[% size %]" title="Failed with output" alt="Failed with output" class="build-status" />
    [% ELSIF buildstatus == 7 %]
      <img src="[% c.uri_for("/static/images/emojione-stopsign-1f6d1.svg") %]" height="[% size %]" width="[% size %]" title="Timed out" alt="Timed out" class="build-status" />
    [% ELSIF buildstatus == 10 %]
      <img src="[% c.uri_for("/static/images/emojione-stopsign-1f6d1.svg") %]" height="[% size %]" width="[% size %]" title="Log limit exceeded" alt="Log limit exceeded" class="build-status" />
    [% ELSIF buildstatus == 11 %]
      <img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="[% size %]" width="[% size %]" title="Output size limit exceeded" alt="Output size limit exceeded" class="build-status" />
    [% ELSIF buildstatus == 12 %]
      <img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="[% size %]" width="[% size %]" title="Non-deterministic build" alt="Non-deterministic build" class="build-status" />
    [% ELSE %]
      <img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="[% size %]" width="[% size %]" title="Failed" alt="Failed" class="build-status" />
    [% END;
  ELSE %]
    <img src="[% c.uri_for("/static/images/emojione-question-2754.svg") %]" height="[% size %]" width="[% size %]" title="Queued" alt="Queued" class="build-status" />
  [% END;
END;


BLOCK renderBusyStatus;
  IF step.busy == 1 %]
    <strong>Preparing</strong>
  [% ELSIF step.busy == 10 %]
    <strong>Connecting</strong>
  [% ELSIF step.busy == 20 %]
    <strong>Sending inputs</strong>
  [% ELSIF step.busy == 30 %]
    <strong>Building</strong>
  [% ELSIF step.busy == 35 %]
    <strong>Waiting to receive outputs</strong>
  [% ELSIF step.busy == 40 %]
    <strong>Receiving outputs</strong>
  [% ELSIF step.busy == 50 %]
    <strong>Post-processing</strong>
  [% ELSE %]
    <strong>Unknown state</strong>
  [% END;
END;


BLOCK renderStatus;
  IF build.finished;
    buildstatus = build.buildstatus;
    IF icon; INCLUDE renderBuildStatusIcon size=16; END;
    IF buildstatus == 0 %]
      <strong>Success</strong>
    [% ELSIF buildstatus == 1 %]
      <span class="error">Build returned a non-zero exit code</span>
    [% ELSIF buildstatus == 2 %]
      <span class="error">A dependency of the build failed</span>
    [% ELSIF buildstatus == 4 %]
      <span class="error">Cancelled by user</span>
    [% ELSIF buildstatus == 6 %]
      <span class="error">Build failed with output</span>
    [% ELSIF buildstatus == 7 %]
      <span class="error">Timed out</span>
    [% ELSIF buildstatus == 9 %]
      <span class="error">Unsupported system type</span>
    [% ELSIF buildstatus == 10 %]
      <span class="error">Log limit exceeded</span>
    [% ELSIF buildstatus == 11 %]
      <span class="error">Output limit exceeded</span>
    [% ELSIF buildstatus == 12 %]
      <span class="error">Non-deterministic build</span>
    [% ELSE %]
      <span class="error">Aborted</span>
      (Hydra failure; see <a href="#nix-error">below</a>)
    [% END;
  ELSIF busy %]
    <strong>Build in progress</strong>[%-
  ELSE %]
    <strong>Scheduled to be built</strong>
  [% END;
END;


BLOCK renderShortInputValue;
  IF input.type == "build" || input.type == "sysbuild" %]
    <a [% HTML.attributes(href => c.uri_for('/build' input.dependency.id)) %]>[% HTML.escape(input.dependency.id) %]</a>
  [% ELSIF input.type == "string" %]
    <tt>"[% HTML.escape(input.value) %]"</tt>
  [% ELSIF input.type == "nix" || input.type == "boolean" %]
    <tt>[% HTML.escape(input.value) %]</tt>
  [% ELSE %]
    <tt>[% HTML.escape(input.uri) %][% IF input.revision %] (r[% HTML.escape(input.revision) %])[% END %]</tt>
  [% END %]
[% END;


BLOCK renderDiffUri;
  nouri = 1;
  FOREACH m IN mappers;
    base = m.baseuri;
    url = bi1.uri;
    path = url.replace(base, '');
    IF url.match(base) %]
      <a target="_blank" [% HTML.attributes(href => m.uri.replace('_path_', path).replace('_1_', bi1.revision).replace('_2_', bi2.revision)) %]>[% HTML.escape(contents) %]</a>
      [% nouri = 0;
    END;
  END;
  IF nouri;
    res = bi1.uri.split(' ');
    url = res.0;
    branch = res.1;
    IF bi1.type == "hg" || bi1.type == "git" %]
      [% IF url.substr(0, 19) == "https://github.com/";
         github_url = url.replace('\.git$', '') %]
        <a target="_blank" [% HTML.attributes(href =>
          github_url
          _ "/compare/"
          _ bi1.revision
          _ "..."
          _ bi2.revision,
        ) %]>[% HTML.escape(contents) %]</a>
      [% ELSE %]
        <a target="_blank" [% HTML.attributes(href => c.uri_for('/api/scmdiff', {
          uri = url,
          rev1 = bi1.revision,
          rev2 = bi2.revision,
          type = bi1.type,
          branch = branch
        })) %]>[% HTML.escape(contents) %]</a>
      [% END %]
    [% ELSE;
      contents;
    END;
  END;
END;


BLOCK renderInputs; %]
  <table class="table table-striped table-condensed">
    <thead>
      <tr><th>Name</th><th>Type</th><th>Value</th><th>Revision</th><th>Store path</th></tr>
    </thead>
    <tbody>
      [% FOREACH input IN inputs %]
        <tr>
          <td><tt>[% input.name | html %]</tt></td>
          <td>[% type = input.type; HTML.escape(inputTypes.$type) %]</td>
          <td>
            [% IF input.type == "build" || input.type == "sysbuild" %]
              [% INCLUDE renderFullBuildLink build=input.dependency %]
            [% ELSIF input.type == "string"  %]
              <tt>"[% HTML.escape(input.value) %]"</tt>
            [% ELSIF input.type == "nix" || input.type == "boolean" %]
              <tt>[% HTML.escape(input.value) %]</tt>
            [% ELSE %]
              <tt>[% HTML.escape(input.uri) %]</tt>
            [% END %]
          </td>
          <td>[% IF input.revision %]<tt class="rev-copy" onclick="copyToClipboard('[% input.revision | html %]', this)" title="Click to copy">[% HTML.escape(input.revision) %]</tt>[% END %]</td>
          <td><tt>[% input.path | html %]</tt></td>
        </tr>
      [% END %]
    </tbody>
  </table>
[% END;


BLOCK renderInputDiff; %]
  <table class="table table-striped table-condensed">
    [% IF !nestedDiff %]
      <tr><th>Input</th><th>Changes</th></tr>
    [% END;
    IF !nestLevel;
      nestLevel = 0;
    END;

    IF nestLevel <= 3;
      FOREACH bi1 IN inputs1;
        deletedInput = 1;
        FOREACH bi2 IN inputs2;
          IF bi1.name == bi2.name;
            IF bi1.type == bi2.type;
              IF bi1.value != bi2.value || bi1.uri != bi2.uri %]
                <tr><td><b>[% HTML.escape(bi1.name) %]</b></td><td><tt>[% INCLUDE renderShortInputValue input=bi1 %]</tt> to <tt>[% INCLUDE renderShortInputValue input=bi2 %]</tt></td></tr>
              [% ELSIF bi1.uri == bi2.uri && bi1.revision != bi2.revision %]
                [% IF bi1.type == "git" %]
                  <tr><td>
                    <b>[% HTML.escape(bi1.name) %]</b></td><td><tt>[% INCLUDE renderDiffUri contents=(bi1.frontend_revision _ ' to ' _ bi2.frontend_revision) %]</tt>
                    (<a class="rev-copy" href="javascript:void(0)" onclick="copyToClipboard('[% bi2.revision | html %]', this); return false;" title="Click to copy full revision: [% bi2.revision | html %]">copy</a>)
                  </td></tr>
                [% ELSE %]
                  <tr><td>
                    <b>[% HTML.escape(bi1.name) %]</b></td><td><tt>[% INCLUDE renderDiffUri contents=(bi1.revision _ ' to ' _ bi2.revision) %]</tt>
                    (<a class="rev-copy" href="javascript:void(0)" onclick="copyToClipboard('[% bi2.revision | html %]', this); return false;" title="Click to copy latest revision">copy</a>)
                  </td></tr>
                [% END %]
              [% ELSIF bi1.dependency.id != bi2.dependency.id || bi1.path != bi2.path %]
                <tr><td>
                  <b>[% HTML.escape(bi1.name) %]</b></td><td><tt>[% INCLUDE renderShortInputValue input=bi1 %]</tt> to <tt>[% INCLUDE renderShortInputValue input=bi2 %]</tt>
                  <br/>
                  <br/>
                  [% INCLUDE renderInputDiff inputs1=bi1.dependency.inputs inputs2=bi2.dependency.inputs nestedDiff=1 nestLevel=nestLevel+1 %]
                </td></tr>
              [% END %]
            [% ELSE %]
              <tr><td><b>[% HTML.escape(bi1.name) %]</b></td><td>Changed input type from '[% type = bi1.type; HTML.escape(inputTypes.$type) %]' to '[% type = bi2.type; HTML.escape(inputTypes.$type) %]'</td></tr>
            [% END;
            deletedInput = 0;
          END;
        END;
        IF deletedInput == 1 %]
          <tr><td><b>[% HTML.escape(bi1.name) %]</b></td><td>Input not present in this build.</td></tr>
        [% END;
      END;
    END %]
  </table>
[% END;


BLOCK renderPager %]
  <ul class="pagination">
    <li class="page-item[% IF page == 1 %] disabled[% END %]"><a class="page-link" [% HTML.attributes(href => "$baseUri?page=1") %]>&laquo; First</a></li>
    <li class="page-item[% IF page == 1 %] disabled[% END %]"><a class="page-link" [% HTML.attributes(href => "$baseUri?page=" _ (page - 1)) %]>&lsaquo; Previous</a></li>
    <li class="page-item[% IF page * resultsPerPage >= total %] disabled[% END %]"><a class="page-link" [% HTML.attributes(href => "$baseUri?page=" _ (page + 1)) %]>Next &rsaquo;</a></li>
    <li class="page-item[% IF page * resultsPerPage >= total %] disabled[% END %]"><a class="page-link" [% HTML.attributes(href => "$baseUri?page=" _ ((total - 1) div resultsPerPage + 1)) %]>Last &raquo;</a></li>
  </ul>
[% END;


BLOCK renderShortEvalInput;
  IF input.type == "build" || input.type == "sysbuild" %]
    <a [% HTML.attributes(href => c.uri_for('/build' input.get_column('dependency'))) %]>[% HTML.escape(input.get_column('dependency')) %]</a>
  [% ELSE %]
    <a class="rev-copy" href="javascript:void(0)" onclick="copyToClipboard('[% input.revision | html %]', this); return false;" title="Click to copy full revision: [% input.revision | html %]"><tt>[% input.frontend_revision | html %]</tt></a>
  [% END;
END;


BLOCK renderEvals %]
  <table class="table table-condensed table-striped clickable-rows">
    <thead>
      <tr>
        <th rowspan="2">#</th>
        [% IF !jobset && !build %]
          <th rowspan="2">Jobset</th>
        [% END %]
        <th rowspan="2" style="width: 10em">Date</th>
        <th rowspan="2">Input changes</th>
        <th colspan="4">Jobs</th>
      </tr>
      <tr>
        <th style="width: 2em">
            <img src="[% c.uri_for("/static/images/emojione-check-2714.svg") %]" height="12" width="12" title="Succeeded" alt="Succeeded" class="build-status" />
        </th>
        <th style="width: 2em">
            <img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="12" width="12" title="Failed" alt="Failed" class="build-status" />
        </th>
        <th style="width: 2em">
            <img src="[% c.uri_for("/static/images/emojione-question-2754.svg") %]" height="12" width="12" title="Queued" alt="Queued" class="build-status" />
        </th>
        <th style="width: 2em">
            <img src="[% c.uri_for("/static/images/delta.svg") %]" height="12" width="12" title="Delta" alt="Delta" class="build-status" />
        </th>
      </tr>
    </thead>
    <tbody>
      [% FOREACH e IN evals;
        eval = e.eval;
        link = c.uri_for(c.controller('JobsetEval').action_for('view'), [eval.id]) %]
        <tr>
          <td><a class="row-link" [% HTML.attributes(href => link) %]>[% HTML.escape(eval.id) %]</a></td>
          [% IF !jobset && !build %]
            <td>[% INCLUDE renderFullJobsetName project=eval.jobset.project.name jobset=eval.jobset.name %]</td>
          [% END %]
          <td class="nowrap">[% INCLUDE renderRelativeDate timestamp = eval.timestamp %]</td>
          <td>
            [% IF e.changedInputs.size > 0;
              sep='';
              FOREACH input IN e.changedInputs;
                sep; %] [% HTML.escape(input.name) %] → [% INCLUDE renderShortEvalInput input=input;
                sep=', ';
              END;
            ELSE %]
             -
            [% END %]
            [% IF eval.evaluationerror.has_error %]
              <span class="badge badge-warning">Eval Errors</span>
            [% END %]
          </td>
          <td align='right' class="nowrap">
            <span class="badge badge-success">[% HTML.escape(e.nrSucceeded) %]</span>
          </td>
          <td align="right" class="nowrap">
            [% IF e.nrFailed > 0 %]
            <span class="badge badge-danger">[% HTML.escape(e.nrFailed) %]</span>
            [% END %]
          </td>
          <td align="right" class="nowrap">
            [% IF e.nrScheduled > 0 %]
            <span class="badge badge-secondary">[% HTML.escape(e.nrScheduled) %]</span>
            [% END %]
          </td>
          <td align='right' class="nowrap">
            [% IF e.diff > 0 %]
              <span class='badge badge-success'><strong>+[% HTML.escape(e.diff) %]</strong></span>
            [% ELSIF e.diff < 0 && e.nrScheduled == 0 %]
              <span class='badge badge-danger'><strong>[% HTML.escape(e.diff) %]</strong></span>
            [% END %]
          </td>
        </tr>
      [% END;
      IF linkToAll %]
        <tr><td class="centered" colspan="7"><a [% HTML.attributes(href => linkToAll) %]><em>More...</em></a></td></tr>
      [% END %]
    </tbody>
  </table>
[% END;


BLOCK renderLogLinks %]
(<a [% IF inRow %]class="row-link"[% END %] [% HTML.attributes(href => url) %]>log</a>, <a [% HTML.attributes(href => "$url/raw") %]>raw</a>, <a [% HTML.attributes(href => "$url/tail") %]>tail</a>)
[% END;


BLOCK makeLazyTab %]
  <div [% HTML.attributes(id => tabName) %] class="tab-pane">
    <center><span class="spinner-border spinner-border-sm"/></center>
  </div>
  <script>
    [% IF callback.defined %]
    $(function() { makeLazyTab("[% HTML.escape(tabName) %]", "[% uri %]", [% callback %] ); });
    [% ELSE %]
    $(function() { makeLazyTab("[% HTML.escape(tabName) %]", "[% uri %]", null ); });
    [% END %]
  </script>
[% END;


BLOCK makePopover %]
  <button type="button" class="btn hydra-popover [% classes %]" data-toggle="popover" data-html="true" [% HTML.attributes('data-content' => content, 'data-placement' => placement || 'bottom') %]>
    [% title %]
  </button>
[% END;


BLOCK menuItem %]
  <a class="dropdown-item[% IF "${root}${curUri}" == uri %] active[% END %]"
    [% HTML.attributes(href => uri) %] [%+ IF modal %]data-toggle="modal"[% END %]
    [% IF confirmmsg %]onclick="javascript:return confirm('[% confirmmsg %]')"[% END %]>
    [% IF icon %]<i class="[% icon %] icon-black"></i> [%+ END %]
    [% title %]
  </a>
[% END;


BLOCK navItem %]
  <li class="nav-item">
    <a class="nav-link[% IF "${root}${curUri}" == uri %] active[% END %]"
      [% HTML.attributes(href => uri) %]>
      [% HTML.escape(title) %]
    </a>
  </li>
[% END;


BLOCK makeStar %]
<span class="star" data-post="[% starUri %]">[% IF starred; "★"; ELSE; "☆"; END %]</span>
[% END;


BLOCK renderJobsetOverview %]
<table class="table table-striped table-condensed clickable-rows">
  <thead>
    <tr>
      <th></th>
      <th>Name</th>
      <th>Description</th>
      <th>Last evaluated</th>
      <th style="width: 2em">
            Jobs
      </th>
      <th style="width: 2em">
            <img src="[% c.uri_for("/static/images/emojione-check-2714.svg") %]" height="12" width="12" title="Succeeded" alt="Succeeded" class="build-status" />
      </th>
      <th style="width: 2em">
            <img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="12" width="12" title="Failed" alt="Failed" class="build-status" />
      </th>
      <th style="width: 2em">
            <img src="[% c.uri_for("/static/images/emojione-question-2754.svg") %]" height="12" width="12" title="Queued" alt="Queued" class="build-status" />
      </th>
    </tr>
  </thead>
  <tbody>
    [% FOREACH j IN jobsets %]
      [% successrate = 0 %]
      <tr class="jobset [% IF j.hidden && !showHidden %] hidden-jobset [% END %] [% IF !j.enabled %] disabled-jobset [% END %]" >
        <td>
          [% IF j.get_column('nrscheduled') > 0 %]
            <img src="[% c.uri_for("/static/images/emojione-question-2754.svg") %]" height="16" width="16" title="Scheduled" alt="Scheduled" />
          [% ELSIF j.get_column('nrfailed') == 0  %]
            <img src="[% c.uri_for("/static/images/emojione-check-2714.svg") %]" height="16" width="16" title="Succeeded" alt="Succeeded" />
          [% ELSIF j.get_column('nrfailed') > 0 && j.get_column('nrsucceeded') > 0 %]
            <img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="16" width="16" title="Some Failed" alt="Some Failed" />
          [% ELSE %]
            <img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="16" width="16" title="All Failed" alt="All Failed" />
          [% END %]
        </td>
        <td><span class="[% IF !j.enabled %]disabled-jobset[% END %] [%+ IF j.hidden %]hidden-jobset[% END %]">[% IF showProject; INCLUDE renderFullJobsetName project=j.get_column('project') jobset=j.name inRow=1; ELSE; INCLUDE renderJobsetName project=j.get_column('project') jobset=j.name inRow=1; END %]</span></td>
        <td>[% HTML.escape(j.description) %]</td>
        <td>[% IF j.lastcheckedtime;
                 INCLUDE renderDateTime timestamp = j.lastcheckedtime;
                 IF j.has_error || j.fetcherrormsg; %]&nbsp;<span class = 'badge badge-warning'>Error</span>[% END;
                 ELSE; "-";
               END %]</td>
        [% IF j.get_column('nrtotal') > 0 %]
          [% successrate = ( j.get_column('nrsucceeded') / j.get_column('nrtotal') )*100 %]
          [% IF j.get_column('nrscheduled') > 0 %]
            [% class = 'badge badge-secondary' %]
          [% ELSIF successrate < 25 %]
            [% class = 'badge badge-danger' %]
          [% ELSIF successrate < 75 %]
            [% class = 'badge badge-warning' %]
          [% ELSIF successrate <= 100 %]
            [% class = 'badge badge-success' %]
          [% END %]
        [% END %]
        <td><span class="[% class %]">[% successrate FILTER format('%d') %]%</span></td>
        <td>
          [% IF j.get_column('nrsucceeded') > 0 %]
            <span class="badge badge-success">[% HTML.escape(j.get_column('nrsucceeded')) %]</span>
          [% END %]
        </td>
        <td>
          [% IF j.get_column('nrfailed') > 0 %]
            <span class="badge badge-danger">[% HTML.escape(j.get_column('nrfailed')) %]</span>
          [% END %]
        </td>
        <td>
          [% IF j.get_column('nrscheduled') > 0 %]
            <span class="badge badge-secondary">[% HTML.escape(j.get_column('nrscheduled')) %]</span>
          [% END %]
        </td>
      </tr>
    [% END %]
  </tbody>
</table>
[% END;


BLOCK includeFlot %]
  <script src="[% c.uri_for("/static/js/flot/jquery.flot.min.js") %]" type="text/javascript"></script>
  <script src="[% c.uri_for("/static/js/flot/jquery.flot.time.min.js") %]" type="text/javascript"></script>
  <script src="[% c.uri_for("/static/js/flot/jquery.flot.selection.min.js") %]" type="text/javascript"></script>
  <div id="flot-tooltip" class="flot-tooltip"></div>
[% END;


BLOCK renderYesNo %]
[% IF value %]
<span class="text-success">Yes</span>
[% ELSE %]
<span class="text-danger">No</span>
[% END %]
[% END;

BLOCK createChart %]

  <div id="[% id %]-chart" style="width: 1000px; height: 400px;"></div>
  <div id="[% id %]-overview" style="margin-top: 20px; margin-left: 50px; margin-right: 50px; width: 900px; height: 100px"></div>

  <script type="text/javascript">
    $(function() {
      showChart("[% HTML.escape(id) %]", "[% dataUrl %]", "[% yaxis %]");
    });
  </script>

[% END;


BLOCK renderMachineName;
machine ? stripSSHUser(machine).match('^(([^\.]|\.[0-9])*)').0 : "localhost";
END;


%]
