Merge pull request #677 from twhitehead/javascripts-update

Javascript libraries update
This commit is contained in:
Graham Christensen 2021-04-09 14:05:47 +00:00 committed by GitHub
commit 258b39f1e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
36 changed files with 598 additions and 611 deletions

1
.gitignore vendored
View file

@ -40,3 +40,4 @@ config
stamp-h1 stamp-h1
src/hydra-evaluator/hydra-evaluator src/hydra-evaluator/hydra-evaluator
src/hydra-queue-runner/hydra-queue-runner src/hydra-queue-runner/hydra-queue-runner
src/root/static/fontawesome/

View file

@ -3,14 +3,16 @@ STATIC = \
$(wildcard static/images/*) \ $(wildcard static/images/*) \
$(wildcard static/css/*) \ $(wildcard static/css/*) \
static/js/bootbox.min.js \ static/js/bootbox.min.js \
static/js/popper.min.js \
static/js/common.js \ static/js/common.js \
static/js/jquery/jquery-1.12.3.min.js \ static/js/jquery/jquery-3.4.1.min.js \
static/js/jquery/jquery-ui-1.10.4.min.js static/js/jquery/jquery-ui-1.10.4.min.js
FLOT = flot-0.8.3.zip FLOT = flot-0.8.3.zip
BOOTSTRAP = bootstrap-2.3.1.zip BOOTSTRAP = bootstrap-4.3.1-dist.zip
FONTAWESOME = fontawesome-free-5.10.2-web.zip
ZIPS = $(FLOT) $(BOOTSTRAP) ZIPS = $(FLOT) $(BOOTSTRAP) $(FONTAWESOME)
EXTRA_DIST = $(TEMPLATES) $(STATIC) $(ZIPS) EXTRA_DIST = $(TEMPLATES) $(STATIC) $(ZIPS)
@ -20,10 +22,16 @@ nobase_hydra_DATA = $(EXTRA_DIST)
all: all:
mkdir -p $(srcdir)/static/js mkdir -p $(srcdir)/static/js
unzip -u -d $(srcdir)/static $(BOOTSTRAP) unzip -u -d $(srcdir)/static $(BOOTSTRAP)
mv $(srcdir)/static/$(basename $(BOOTSTRAP)) $(srcdir)/static/bootstrap
unzip -u -d $(srcdir)/static/js $(FLOT) unzip -u -d $(srcdir)/static/js $(FLOT)
unzip -u -d $(srcdir)/static $(FONTAWESOME)
mv $(srcdir)/static/$(basename $(FONTAWESOME)) $(srcdir)/static/fontawesome
install-data-local: $(ZIPS) install-data-local: $(ZIPS)
mkdir -p $(hydradir)/static/js mkdir -p $(hydradir)/static/js
cp -prvd $(srcdir)/static/js/* $(hydradir)/static/js cp -prvd $(srcdir)/static/js/* $(hydradir)/static/js
mkdir -p $(hydradir)/static/bootstrap mkdir -p $(hydradir)/static/bootstrap
cp -prvd $(srcdir)/static/bootstrap/* $(hydradir)/static/bootstrap cp -prvd $(srcdir)/static/bootstrap/* $(hydradir)/static/bootstrap
mkdir -p $(hydradir)/static/fontawesome/{css,webfonts}
cp -prvd $(srcdir)/static/fontawesome/css/* $(hydradir)/static/fontawesome/css
cp -prvd $(srcdir)/static/fontawesome/webfonts/* $(hydradir)/static/fontawesome/webfonts

View file

@ -31,26 +31,26 @@
[% ELSE %] [% ELSE %]
<div id="hydra-signin" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true"> <div id="hydra-signin" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true">
<form class="form-horizontal"> <div class="modal-dialog" role="document">
<div class="modal-body"> <div class="modal-content">
<div class="control-group"> <form>
<label class="control-label">User name</label> <div class="modal-body">
<div class="controls"> <div class="form-group">
<input type="text" class="span3" name="username" value=""/> <label for="username" class="col-form-label">User name</label>
<input type="text" class="form-control" name="username"/>
</div>
<div class="form-group">
<label for="password" class="col-form-label">Password</label>
<input type="password" class="form-control" name="password"/>
</div>
</div> </div>
</div> <div class="modal-footer">
<div class="control-group"> <button id="do-signin" type="button" class="btn btn-primary">Sign in</button>
<label class="control-label">Password</label> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<div class="controls">
<input type="password" class="span3" name="password" value=""/>
</div> </div>
</div> </form>
</div> </div>
<div class="modal-footer"> </div>
<button id="do-signin" class="btn btn-primary">Sign in</button>
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
</div>
</form>
</div> </div>
<script> <script>

Binary file not shown.

Binary file not shown.

View file

@ -114,41 +114,38 @@ END;
[% END %] [% END %]
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="dropdown"> <li class="nav-item dropdown">
<a class="dropdown-toggle actions" data-toggle="dropdown" href="#"> <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" area-haspopup="true" aria-expanded="false">Actions</a>
Actions <div class="dropdown-menu">
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
[% IF eval.nixexprinput || eval.flake %] [% IF eval.nixexprinput || eval.flake %]
<li><a href="#reproduce" data-toggle="modal">Reproduce locally</a></li> <a class="dropdown-item" href="#reproduce" data-toggle="modal">Reproduce locally</a>
[% END %] [% END %]
[% IF c.user_exists %] [% IF c.user_exists %]
[% IF available %] [% IF available %]
[% IF build.keep %] [% IF build.keep %]
<li><a href="[% c.uri_for('/build' build.id 'keep' 0) %]">Unkeep</a></li> <a class="dropdown-item" href="[% c.uri_for('/build' build.id 'keep' 0) %]">Unkeep</a>
[% ELSE %] [% ELSE %]
<li><a href="[% c.uri_for('/build' build.id 'keep' 1) %]">Keep</a></li> <a class="dropdown-item" href="[% c.uri_for('/build' build.id 'keep' 1) %]">Keep</a>
[% END %] [% END %]
[% END %] [% END %]
[% IF build.finished %] [% IF build.finished %]
<li><a href="[% c.uri_for('/build' build.id 'restart') %]">Restart</a></li> <a class="dropdown-item" href="[% c.uri_for('/build' build.id 'restart') %]">Restart</a>
[% ELSE %] [% ELSE %]
<li><a href="[% c.uri_for('/build' build.id 'cancel') %]">Cancel</a></li> <a class="dropdown-item" href="[% c.uri_for('/build' build.id 'cancel') %]">Cancel</a>
<li><a href="[% c.uri_for('/build' build.id 'bump') %]">Bump up</a></li> <a class="dropdown-item" href="[% c.uri_for('/build' build.id 'bump') %]">Bump up</a>
[% END %] [% END %]
[% END %] [% END %]
</ul> </div>
</li> </li>
<li class="active"><a href="#tabs-summary" data-toggle="tab">Summary</a></li> <li class="nav-item"><a class="nav-link active" href="#tabs-summary" data-toggle="tab">Summary</a></li>
[% IF isAggregate %]<li><a href="#tabs-constituents" data-toggle="tab">Constituents</a></li>[% END %] [% IF isAggregate %]<li class="nav-item"><a class="nav-link" href="#tabs-constituents" data-toggle="tab">Constituents</a></li>[% END %]
<li><a href="#tabs-details" data-toggle="tab">Details</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-details" data-toggle="tab">Details</a></li>
<li><a href="#tabs-buildinputs" data-toggle="tab">Inputs</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-buildinputs" data-toggle="tab">Inputs</a></li>
[% IF steps.size() > 0 %]<li><a href="#tabs-buildsteps" data-toggle="tab">Build steps</a></li>[% END %] [% IF steps.size() > 0 %]<li class="nav-item"><a class="nav-link" href="#tabs-buildsteps" data-toggle="tab">Build steps</a></li>[% END %]
[% IF build.dependents %]<li><a href="#tabs-usedby" data-toggle="tab">Used by</a></li>[% END%] [% IF build.dependents %]<li class="nav-item"><a class="nav-link" href="#tabs-usedby" data-toggle="tab">Used by</a></li>[% END%]
[% IF drvAvailable %]<li><a href="#tabs-build-deps" data-toggle="tab">Build dependencies</a></li>[% END %] [% IF drvAvailable %]<li class="nav-item"><a class="nav-link" href="#tabs-build-deps" data-toggle="tab">Build dependencies</a></li>[% END %]
[% IF localStore && available %]<li><a href="#tabs-runtime-deps" data-toggle="tab">Runtime dependencies</a></li>[% END %] [% IF localStore && available %]<li class="nav-item"><a class="nav-link" href="#tabs-runtime-deps" data-toggle="tab">Runtime dependencies</a></li>[% END %]
</ul> </ul>
<div id="generic-tabs" class="tab-content"> <div id="generic-tabs" class="tab-content">
@ -239,9 +236,9 @@ END;
<th>Logfile:</th> <th>Logfile:</th>
<td> <td>
[% actualLog = cachedBuildStep ? c.uri_for('/build' cachedBuild.id 'nixlog' cachedBuildStep.stepnr) : c.uri_for('/build' build.id 'log') %] [% actualLog = cachedBuildStep ? c.uri_for('/build' cachedBuild.id 'nixlog' cachedBuildStep.stepnr) : c.uri_for('/build' build.id 'log') %]
<a class="btn btn-mini" href="[%actualLog%]">pretty</a> <a class="btn btn-secondary btn-sm" href="[%actualLog%]">pretty</a>
<a class="btn btn-mini" href="[%actualLog%]/raw">raw</a> <a class="btn btn-secondary btn-sm" href="[%actualLog%]/raw">raw</a>
<a class="btn btn-mini" href="[%actualLog%]/tail">tail</a> <a class="btn btn-secondary btn-sm" href="[%actualLog%]/tail">tail</a>
</td> </td>
</tr> </tr>
[% END %] [% END %]
@ -489,48 +486,51 @@ END;
</div> </div>
<div id="reproduce" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true"> <div id="reproduce" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true">
[% url = c.uri_for('/build' build.id 'reproduce') %] <div class="modal-dialog" role="document">
<div class="modal-content">
[% url = c.uri_for('/build' build.id 'reproduce') %]
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button> <h3>Reproduce this build</h3>
<h3>Reproduce this build</h3> <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
</div> </div>
<div class="modal-body"> <div class="modal-body">
[% IF eval.flake %] [% IF eval.flake %]
<p>If you have <a href='https://nixos.org/nix/download.html'>Nix <p>If you have <a href='https://nixos.org/nix/download.html'>Nix
installed</a>, you can reproduce this build on your own machine by installed</a>, you can reproduce this build on your own machine by
running the following command:</p> running the following command:</p>
<pre> <div class="card bg-light"><div class="card-body p-2"><code>
<span class="shell-prompt"># </span>nix build [% HTML.escape(eval.flake) %]#hydraJobs.[% HTML.escape(job) %] <span class="shell-prompt"># </span>nix build [% HTML.escape(eval.flake) %]#hydraJobs.[% HTML.escape(job) %]
</pre> </code></div></div>
[% ELSE %] [% ELSE %]
<p>If you have <a href='https://nixos.org/nix/download.html'>Nix <p>If you have <a href='https://nixos.org/nix/download.html'>Nix
installed</a>, you can reproduce this build on your own machine by installed</a>, you can reproduce this build on your own machine by
downloading <a [% HTML.attributes(href => url) %]>a script</a> downloading <a [% HTML.attributes(href => url) %]>a script</a>
that checks out all inputs of the build and then invokes Nix to that checks out all inputs of the build and then invokes Nix to
perform the build.</p> perform the build.</p>
<p>To download and execute the script from the command line, run the <p>To download and execute the script from the command line, run the
following command:</p> following command:</p>
<pre> <div class="card bg-light"><div class="card-body p-2"><code>
<span class="shell-prompt"># </span>curl <a [% HTML.attributes(href => url) %]>[% HTML.escape(url) %]</a> | bash <span class="shell-prompt"># </span>curl <a [% HTML.attributes(href => url) %]>[% HTML.escape(url) %]</a> | bash
</pre> </code></div></div>
[% END %] [% END %]
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<a href="#" class="btn btn-primary" data-dismiss="modal">Close</a> <a href="#" class="btn btn-primary" data-dismiss="modal">Close</a>
</div>
</div>
</div> </div>
</div> </div>

View file

@ -6,21 +6,24 @@
href="http://nixos.org/">Nix package manager</a>. If you have Nix href="http://nixos.org/">Nix package manager</a>. If you have Nix
installed, you can subscribe to this channel by once executing</p> installed, you can subscribe to this channel by once executing</p>
<pre> <div class="card bg-light"><div class="card-body"><pre>
$ nix-channel --add [% curUri +%] <span class="shell-prompt">$ </span>nix-channel --add [% curUri +%]
$ nix-channel --update</pre> <span class="shell-prompt">$ </span>nix-channel --update
</pre></div></div>
<p>You can then query and install packages in the normal way, e.g.,</p> <p>You can then query and install packages in the normal way, e.g.,</p>
<pre> <div class="card bg-light"><div class="card-body"><pre>
$ nix-env -qa '*' <span class="shell-prompt">$ </span>nix-env -qa '*'
$ nix-env -i foo</pre> <span class="shell-prompt">$ </span>nix-env -i foo
</pre></pre></div>
<p>You can update to the latest versions of the packages in this channel by executing</p> <p>You can update to the latest versions of the packages in this channel by executing</p>
<pre> <div class="card bg-light"><div class="card-body"><pre>
$ nix-channel --update <span class="shell-prompt">$ </span>nix-channel --update
$ nix-env -u '*'</pre> <span class="shell-prompt">$ </span>nix-env -u '*'
</pre></div></div>
[% IF genericChannel %] [% IF genericChannel %]

View file

@ -127,7 +127,7 @@ BLOCK renderBuildListBody;
</td> </td>
[% END %] [% END %]
[% IF showSchedulingInfo %] [% IF showSchedulingInfo %]
<td>[% IF busy %]<span class="label label-success">Started</span>[% ELSE %]<span class="label">Queued</span>[% END %]</td> <td>[% IF busy %]<span class="badge badge-success">Started</span>[% ELSE %]<span class="badge badge-secondary">Queued</span>[% END %]</td>
[% END %] [% END %]
<td><a class="row-link" href="[% link %]">[% build.id %]</a></td> <td><a class="row-link" href="[% link %]">[% build.id %]</a></td>
[% IF !hideJobName %] [% IF !hideJobName %]
@ -182,7 +182,7 @@ BLOCK renderSelection;
[% END %] [% END %]
</div> </div>
[% ELSE %] [% ELSE %]
<select style='width: 15em;' [% HTML.attributes(id => param, name => param) %]> <select class="custom-select" [% HTML.attributes(id => param, name => param) %]>
[% FOREACH name IN options.keys.sort %] [% FOREACH name IN options.keys.sort %]
<option [% IF name == curValue; "selected='selected'"; END; " "; HTML.attributes(value => name) %]>[% options.$name %]</option> <option [% IF name == curValue; "selected='selected'"; END; " "; HTML.attributes(value => name) %]>[% options.$name %]</option>
[% END %] [% END %]
@ -405,11 +405,11 @@ BLOCK renderInputDiff; %]
BLOCK renderPager %] BLOCK renderPager %]
<ul class="pager"> <ul class="pagination">
<li [% IF page == 1 %]class="disabled"[% END %]><a href="[% "$baseUri?page=1" %]">« First</a></li> <li class="page-item[% IF page == 1 %] disabled[% END %]"><a class="page-link" href="[% "$baseUri?page=1" %]">&laquo; First</a></li>
<li [% IF page == 1 %]class="disabled"[% END %]><a href="[% "$baseUri?page="; (page - 1) %]"> Previous</a></li> <li class="page-item[% IF page == 1 %] disabled[% END %]"><a class="page-link" href="[% "$baseUri?page="; (page - 1) %]">&lsaquo; Previous</a></li>
<li [% IF page * resultsPerPage >= total %]class="disabled"[% END %]><a href="[% "$baseUri?page="; (page + 1) %]">Next </a></li> <li class="page-item[% IF page * resultsPerPage >= total %] disabled[% END %]"><a class="page-link" href="[% "$baseUri?page="; (page + 1) %]">Next &rsaquo;</a></li>
<li [% IF page * resultsPerPage >= total %]class="disabled"[% END %]><a href="[% "$baseUri?page="; (total - 1) div resultsPerPage + 1 %]">Last »</a></li> <li class="page-item[% IF page * resultsPerPage >= total %] disabled[% END %]"><a class="page-link" href="[% "$baseUri?page="; (total - 1) div resultsPerPage + 1 %]">Last &raquo;</a></li>
</ul> </ul>
[% END; [% END;
@ -439,10 +439,7 @@ BLOCK renderEvals %]
[% END %] [% END %]
<th rowspan="2" style="width: 10em">Date</th> <th rowspan="2" style="width: 10em">Date</th>
<th rowspan="2">Input changes</th> <th rowspan="2">Input changes</th>
<th colspan="3">Jobs</th> <th colspan="4">Jobs</th>
<th rowspan="2">
<img src="[% c.uri_for("/static/images/delta.svg") %]" height="12" width="12" title="Delta" alt="Delta" class="build-status" />
</th>
</tr> </tr>
<tr> <tr>
<th style="width: 2em"> <th style="width: 2em">
@ -454,6 +451,9 @@ BLOCK renderEvals %]
<th style="width: 2em"> <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" /> <img src="[% c.uri_for("/static/images/emojione-question-2754.svg") %]" height="12" width="12" title="Queued" alt="Queued" class="build-status" />
</th> </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> </tr>
</thead> </thead>
<tbody> <tbody>
@ -477,33 +477,33 @@ BLOCK renderEvals %]
- -
[% END %] [% END %]
[% IF eval.evaluationerror.errormsg %] [% IF eval.evaluationerror.errormsg %]
<span class="label label-warning">Eval Errors</span> <span class="badge badge-warning">Eval Errors</span>
[% END %] [% END %]
</td> </td>
<td align='right' class="nowrap"> <td align='right' class="nowrap">
<span class="label label-success">[% e.nrSucceeded %]</span> <span class="badge badge-success">[% e.nrSucceeded %]</span>
</td> </td>
<td align="right" class="nowrap"> <td align="right" class="nowrap">
[% IF e.nrFailed > 0 %] [% IF e.nrFailed > 0 %]
<span class="label label-important">[% e.nrFailed %]</span> <span class="badge badge-danger">[% e.nrFailed %]</span>
[% END %] [% END %]
</td> </td>
<td align="right" class="nowrap"> <td align="right" class="nowrap">
[% IF e.nrScheduled > 0 %] [% IF e.nrScheduled > 0 %]
<span class="label">[% e.nrScheduled %]</span> <span class="badge badge-secondary">[% e.nrScheduled %]</span>
[% END %] [% END %]
</td> </td>
<td align='right' class="nowrap"> <td align='right' class="nowrap">
[% IF e.diff > 0 %] [% IF e.diff > 0 %]
<span class='label label-success'><strong>+[% e.diff %]</strong></span> <span class='badge badge-success'><strong>+[% e.diff %]</strong></span>
[% ELSIF e.diff < 0 && e.nrScheduled == 0 %] [% ELSIF e.diff < 0 && e.nrScheduled == 0 %]
<span class='label label-important'><strong>[% e.diff %]</strong></span> <span class='badge badge-danger'><strong>[% e.diff %]</strong></span>
[% END %] [% END %]
</td> </td>
</tr> </tr>
[% END; [% END;
IF linkToAll %] IF linkToAll %]
<tr><td class="centered" colspan="5"><a href="[% linkToAll %]"><em>More...</em></a></td></tr> <tr><td class="centered" colspan="7"><a href="[% linkToAll %]"><em>More...</em></a></td></tr>
[% END %] [% END %]
</tbody> </tbody>
</table> </table>
@ -517,7 +517,7 @@ BLOCK renderLogLinks %]
BLOCK makeLazyTab %] BLOCK makeLazyTab %]
<div id="[% tabName %]" class="tab-pane"> <div id="[% tabName %]" class="tab-pane">
<center><img src="[% c.uri_for("/static/images/ajax-loader.gif") %]" alt="Loading..." /></center> <center><span class="spinner-border spinner-border-sm"/></center>
</div> </div>
<script> <script>
$(function() { makeLazyTab("[% tabName %]", "[% uri %]"); }); $(function() { makeLazyTab("[% tabName %]", "[% uri %]"); });
@ -526,16 +526,26 @@ BLOCK makeLazyTab %]
BLOCK makePopover %] BLOCK makePopover %]
<div class="btn hydra-popover [% classes %]" data-toggle="popover" data-html="true" [% HTML.attributes('data-content' => content, 'data-placement' => placement || 'bottom') %]> <button type="button" class="btn hydra-popover [% classes %]" data-toggle="popover" data-html="true" [% HTML.attributes('data-content' => content, 'data-placement' => placement || 'bottom') %]>
[% title %] [% title %]
</div> </button>
[% END; [% END;
BLOCK menuItem %] BLOCK menuItem %]
<li class="[% IF "${root}${curUri}" == uri %]active[% END %]" [% IF confirmmsg %]onclick="javascript:return confirm('[% confirmmsg %]')"[% END %]> <a class="dropdown-item[% IF "${root}${curUri}" == uri %] active[% END %]"
<a [% HTML.attributes(href => uri) %] [%+ IF modal %]data-toggle="modal"[% END %]> [% HTML.attributes(href => uri) %] [%+ IF modal %]data-toggle="modal"[% END %]
[% IF icon %]<i class="[% icon %] icon-black"></i> [%+ 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) %]>
[% title %] [% title %]
</a> </a>
</li> </li>
@ -588,35 +598,35 @@ BLOCK renderJobsetOverview %]
<td>[% HTML.escape(j.description) %]</td> <td>[% HTML.escape(j.description) %]</td>
<td>[% IF j.lastcheckedtime; <td>[% IF j.lastcheckedtime;
INCLUDE renderDateTime timestamp = j.lastcheckedtime; INCLUDE renderDateTime timestamp = j.lastcheckedtime;
IF j.errormsg || j.fetcherrormsg; %]&nbsp;<span class = 'label label-warning'>Error</span>[% END; IF j.errormsg || j.fetcherrormsg; %]&nbsp;<span class = 'badge badge-warning'>Error</span>[% END;
ELSE; "-"; ELSE; "-";
END %]</td> END %]</td>
[% IF j.get_column('nrtotal') > 0 %] [% IF j.get_column('nrtotal') > 0 %]
[% successrate = ( j.get_column('nrsucceeded') / j.get_column('nrtotal') )*100 %] [% successrate = ( j.get_column('nrsucceeded') / j.get_column('nrtotal') )*100 %]
[% IF j.get_column('nrscheduled') > 0 %] [% IF j.get_column('nrscheduled') > 0 %]
[% class = 'label' %] [% class = 'badge badge-secondary' %]
[% ELSIF successrate < 25 %] [% ELSIF successrate < 25 %]
[% class = 'label label-important' %] [% class = 'badge badge-danger' %]
[% ELSIF successrate < 75 %] [% ELSIF successrate < 75 %]
[% class = 'label label-warning' %] [% class = 'badge badge-warning' %]
[% ELSIF successrate <= 100 %] [% ELSIF successrate <= 100 %]
[% class = 'label label-success' %] [% class = 'badge badge-success' %]
[% END %] [% END %]
[% END %] [% END %]
<td><span class="[% class %]">[% successrate FILTER format('%d') %]%</span></td> <td><span class="[% class %]">[% successrate FILTER format('%d') %]%</span></td>
<td> <td>
[% IF j.get_column('nrsucceeded') > 0 %] [% IF j.get_column('nrsucceeded') > 0 %]
<span class="label label-success">[% j.get_column('nrsucceeded') %]</span> <span class="badge badge-success">[% j.get_column('nrsucceeded') %]</span>
[% END %] [% END %]
</td> </td>
<td> <td>
[% IF j.get_column('nrfailed') > 0 %] [% IF j.get_column('nrfailed') > 0 %]
<span class="label label-important">[% j.get_column('nrfailed') %]</span> <span class="badge badge-danger">[% j.get_column('nrfailed') %]</span>
[% END %] [% END %]
</td> </td>
<td> <td>
[% IF j.get_column('nrscheduled') > 0 %] [% IF j.get_column('nrscheduled') > 0 %]
<span class="label label">[% j.get_column('nrscheduled') %]</span> <span class="badge badge-secondary">[% j.get_column('nrscheduled') %]</span>
[% END %] [% END %]
</td> </td>
</tr> </tr>

View file

@ -2,9 +2,9 @@
[% PROCESS common.tt %] [% PROCESS common.tt %]
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a href="#tabs-starred-jobs" data-toggle="tab">Starred jobs</a></li> <li class="nav-item"><a class="nav-link active" href="#tabs-starred-jobs" data-toggle="tab">Starred jobs</a></li>
<li><a href="#tabs-my-jobs" data-toggle="tab">My jobs</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-my-jobs" data-toggle="tab">My jobs</a></li>
<li><a href="#tabs-my-jobsets" data-toggle="tab">My jobsets</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-my-jobsets" data-toggle="tab">My jobsets</a></li>
</ul> </ul>
<div id="generic-tabs" class="tab-content"> <div id="generic-tabs" class="tab-content">

View file

@ -9,7 +9,7 @@
[% BLOCK renderJobsetInput %] [% BLOCK renderJobsetInput %]
<tr class="input [% extraClass %]" [% IF id %]id="[% id %]"[% END %]> <tr class="input [% extraClass %]" [% IF id %]id="[% id %]"[% END %]>
<td> <td>
<button type="button" class="btn btn-warning" onclick='$(this).parents(".input").remove()'><i class="icon-trash icon-white"></i></button> <button type="button" class="btn btn-warning" onclick='$(this).parents(".input").remove()'><i class="fas fa-trash"></i></button>
</td> </td>
<td> <td>
<input type="text" id="[% baseName %]-name" name="[% baseName %]-name" [% HTML.attributes(value => input.name) %]/> <input type="text" id="[% baseName %]-name" name="[% baseName %]-name" [% HTML.attributes(value => input.name) %]/>
@ -51,130 +51,136 @@
[% INCLUDE renderJobsetInput input=input baseName="input-$input.name" %] [% INCLUDE renderJobsetInput input=input baseName="input-$input.name" %]
[% END %] [% END %]
<tr> <tr>
<td colspan="4" style="text-align: center;"><button type="button" class="add-input btn btn-success"><i class="icon-plus icon-white"></i> Add a new input</button></td> <td colspan="4" style="text-align: center;"><button type="button" class="add-input btn btn-success"><i class="fas fa-plus"></i> Add a new input</button></td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
[% END %] [% END %]
<form class="form-horizontal"> <form>
<fieldset> <div class="form-group row">
<label class="col-sm-3" for="editjobsetenabled">State</label>
<div class="btn-group btn-group-toggle col-sm-9" data-toggle="buttons">
<label class="btn btn-secondary[% IF jobset.enabled == 1 %] active[% END %]">
<input type="radio" id="editjobsetenabled" name="enabled" value="1" [% IF jobset.enabled == 1 %]checked[% END %]>Enabled</button>
</label>
<label class="btn btn-secondary[% IF jobset.enabled == 2 %] active[% END %]">
<input type="radio" name="enabled" value="2" [% IF jobset.enabled == 2 %]checked[% END %]>One-shot</button>
</label>
<label class="btn btn-secondary[% IF jobset.enabled == 3 %] active[% END %]">
<input type="radio" name="enabled" value="3" [% IF jobset.enabled == 3 %]checked[% END %]>One-at-a-time</button>
</label>
<label class="btn btn-secondary[% IF jobset.enabled == 0 %] active[% END %]">
<input type="radio" name="enabled" value="0" [% IF jobset.enabled == 0 %]checked[% END %]>Disabled</button>
</label>
</div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">State</label> <label class="col-form-label col-sm-3" for="editjobsetvisible">Visible</label>
<div class="controls"> <div class="col-sm-9">
<div class="btn-group" data-toggle="buttons-radio"> <input type="checkbox" id="editjobsetvisible" name="visible" [% IF !jobset.hidden; 'checked="checked"'; END %]/>
<input type="hidden" name="enabled" value="[% jobset.enabled %]" /> </div>
<button type="button" class="btn" value="1">Enabled</button> </div>
<button type="button" class="btn" value="2">One-shot</button>
<button type="button" class="btn" value="3">One-at-a-time</button> <div class="form-group row">
<button type="button" class="btn" value="0">Disabled</button> <label class="col-form-label col-sm-3" for="editjobsetname">Identifier</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="editjobsetname" name="name" [% HTML.attributes(value => edit ? jobset.name : "") %]/>
</div>
</div>
<div class="form-group row">
<label class="col-form-label col-sm-3" for="editjobsettype">Type</label>
<div class="btn-group btn-group-toggle col-sm-9" data-toggle="buttons">
<label id="type-flake" class="btn btn-secondary[% IF jobset.type == 1 %] active[% END %]">
<input type="radio" id="editjobsettype" name="type" value="1" [% IF jobset.type == 1 %]checked[% END %]>Flake</button>
</label>
<label id="type-legacy" class="btn btn-secondary[% IF jobset.type == 0 %] active[% END %]">
<input type="radio" name="type" value="0" [% IF jobset.type == 0 %]checked[% END %]>Legacy</button>
</label>
</div>
</div>
<div class="form-group row">
<label class="col-form-label col-sm-3" for="editjobsetdescription">Description</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="editjobsetdescription" name="description" [% HTML.attributes(value => jobset.description) %]/>
</div>
</div>
<div class="form-group row show-on-flake">
<label class="col-form-label col-sm-3" for="editjobsetflakeref">Flake URI</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="editjobsetflakeref" name="flakeref" [% HTML.attributes(value => jobset.flake) %]/>
</div>
</div>
<div class="form-group row show-on-legacy">
<label class="col-form-label col-sm-3" for="editjobsetnixexpr">Nix expression</label>
<div class="col-sm-9">
<div class="input-group">
<input type="text" class="form-control" id="editjobsetnixexpr" name="nixexprpath" [% HTML.attributes(value => jobset.nixexprpath) %]/>
<div class="input-group-append input-group-prepend">
<span class="input-group-text">in</span>
</div>
<input type="text" class="form-control" name="nixexprinput" [% HTML.attributes(value => jobset.nixexprinput) %]/>
</div>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3" for="editjobsetcheckinterval">
Check interval
<small class="form-text text-muted">(0 to disable polling)</small>
</label>
<div class="col-sm-9">
<div class="input-group">
<input type="number" class="form-control" id="editjobsetcheckinterval" name="checkinterval" [% HTML.attributes(value => jobset.checkinterval) %]/>
<div class="input-group-append">
<span class="input-group-text">sec</span>
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<div class="controls"> <label class="col-sm-3" for="editjobsetschedulingshares">
<label class="checkbox"> Scheduling shares
<input type="checkbox" name="visible" [% IF !jobset.hidden; 'checked="checked"'; END %]/>Visible [% IF totalShares %]
</label> <small class="form-text text-muted">([% f = format("%.2f"); f(jobset.schedulingshares / totalShares * 100) %]% out of [% totalShares %] shares)</small>
</div> [% END %]
</label>
<div class="col-sm-9">
<input type="number" class="form-control" id="editjobschedulingshares" name="schedulingshares" [% HTML.attributes(value => jobset.schedulingshares) %]/>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Identifier</label> <label class="col-sm-3" for="editjobsetenableemail">Email notification</label>
<div class="controls"> <div class="col-sm-9">
<input type="text" class="span3" name="name" [% HTML.attributes(value => edit ? jobset.name : "") %]/> <input type="checkbox" id="editjobsetenableemail" name="enableemail" [% IF jobset.enableemail %]checked[% END %] [% IF !emailNotification %]disabled[% END %]/>
</div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Description</label> <label class="col-sm-3" for="editjobsetemailoverride">Email override</label>
<div class="controls"> <div class="col-sm-9">
<input type="text" class="span3" name="description" [% HTML.attributes(value => jobset.description) %]/> <input type="text" class="form-control" id="editjobsetemailoverride" name="emailoverride" [% HTML.attributes(value => jobset.emailoverride) %] [% IF !emailNotification %]disabled[% END %]/>
</div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Type</label> <label class="col-sm-3" for="editjobsetkeepnumber">Number of evaluations to keep</label>
<div class="controls"> <div class="col-sm-9">
<div class="btn-group" data-toggle="buttons-radio"> <input type="number" class="form-control" id="editjobsetkeepnumber" name="keepnr" [% HTML.attributes(value => jobset.keepnr) %]/>
<input type="hidden" id="type" name="type" value="[% jobset.type %]" />
<button type="button" class="btn" value="1" id="type-flake">Flake</button>
<button type="button" class="btn" value="0" id="type-legacy">Legacy</button>
</div>
</div>
</div> </div>
</div>
<div class="control-group show-on-flake"> [% INCLUDE renderJobsetInputs %]
<label class="control-label">Flake URI</label>
<div class="controls">
<input type="text" class="span3" name="flakeref" [% HTML.attributes(value => jobset.flake) %]/>
</div>
</div>
<div class="control-group show-on-legacy"> <button id="submit-jobset" type="submit" class="btn btn-primary"><i class="fas fa-check"></i> [%IF !edit %]Create jobset[% ELSE %]Apply changes[% END %]</button>
<label class="control-label">Nix expression</label>
<div class="controls">
<input type="text" class="span3" name="nixexprpath" [% HTML.attributes(value => jobset.nixexprpath) %]/>
in
<input type="text" class="span3" name="nixexprinput" [% HTML.attributes(value => jobset.nixexprinput) %]/>
</div>
</div>
<div class="control-group">
<label class="control-label">Check interval</label>
<div class="controls">
<div class="input-append">
<input type="number" class="span3" name="checkinterval" [% HTML.attributes(value => jobset.checkinterval) %]/>
<span class="add-on">sec</span>
</div>
<span class="help-inline">(0 to disable polling)</span>
</div>
</div>
<div class="control-group">
<label class="control-label">Scheduling shares</label>
<div class="controls">
<div class="input-append">
<input type="number" class="span3" name="schedulingshares" [% HTML.attributes(value => jobset.schedulingshares) %]/>
</div>
[% IF totalShares %]
<span class="help-inline">([% f = format("%.2f"); f(jobset.schedulingshares / totalShares * 100) %]% out of [% totalShares %] shares)</span>
[% END %]
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" name="enableemail" [% IF jobset.enableemail; 'checked="checked"'; END %] [%IF !emailNotification%]disabled=1[%END%] />Email notification
</label>
</div>
</div>
<div class="control-group">
<label class="control-label">Email override</label>
<div class="controls">
<input type="text" class="span3" name="emailoverride" [% HTML.attributes(value => jobset.emailoverride) %] [%IF !emailNotification%]disabled=1[%END%] />
</div>
</div>
<div class="control-group">
<label class="control-label">Number of evaluations to keep</label>
<div class="controls">
<input type="number" class="span3" name="keepnr" [% HTML.attributes(value => jobset.keepnr) %]/>
</div>
</div>
[% INCLUDE renderJobsetInputs %]
<div class="form-actions">
<button id="submit-jobset" type="submit" class="btn btn-primary"><i class="icon-ok icon-white"></i> [%IF !edit %]Create jobset[% ELSE %]Apply changes[% END %]</button>
</div>
</fieldset>
<table style="display: none"> <table style="display: none">
[% INCLUDE renderJobsetInput input="" extraClass="template" id="input-template" baseName="input-template" %] [% INCLUDE renderJobsetInput input="" extraClass="template" id="input-template" baseName="input-template" %]
@ -187,7 +193,7 @@
var id = 0; var id = 0;
function update() { function update() {
if ($("#type").val() == 0) { if ($("input[type='radio'][name='type']:checked").val() == 0) {
$(".show-on-legacy").show(); $(".show-on-legacy").show();
$(".show-on-flake").hide(); $(".show-on-flake").hide();
} else { } else {
@ -196,8 +202,7 @@
} }
} }
$("#type-flake").click(function() { update(); }); $("input[type='radio'][name='type']").change(function() { update(); });
$("#type-legacy").click(function() { update(); });
update(); update();

View file

@ -1,85 +1,79 @@
[% WRAPPER layout.tt title=(create ? "New project" : "Editing project $project.name") %] [% WRAPPER layout.tt title=(create ? "New project" : "Editing project $project.name") %]
[% PROCESS common.tt %] [% PROCESS common.tt %]
<form class="form-horizontal"> <form>
<fieldset> <div class="form-group row">
<label class="col-sm-3" for="editprojectenabled">Enabled</label>
<div class="control-group"> <div class="col-sm-9">
<div class="controls"> <input type="checkbox" id="editprojectenabled" name="enabled" [% IF create || project.enabled %] checked="checked" [% END %]/>
<label class="checkbox">
<input type="checkbox" name="enabled" [% IF create || project.enabled; 'checked="checked"'; END %]/>Enabled
</label>
</div>
<div class="controls">
<label class="checkbox">
<input type="checkbox" name="visible" [% IF !project.hidden; 'checked="checked"'; END %]/>Visible in the list of projects
</label>
</div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Identifier</label> <label class="col-sm-3" for="editprojectvisible">Visible in projects list</label>
<div class="controls"> <div class="col-sm-9">
<input type="text" class="span3" name="name" [% HTML.attributes(value => project.name) %]/> <input type="checkbox" id="editprojectvisible" name="visible" [% IF !project.hidden %] checked="checked" [% END %]/>
</div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Display name</label> <label class="col-sm-3" for="editprojectidentifier">Identifier</label>
<div class="controls"> <div class="col-sm-9">
<input type="text" class="span3" name="displayname" [% HTML.attributes(value => project.displayname) %]/> <input type="text" class="form-control" id="editprojectidentifier" name="name" [% HTML.attributes(value => project.name) %]/>
</div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Description</label> <label class="col-sm-3" for="editprojectdisplayname">Display name</label>
<div class="controls"> <div class="col-sm-9">
<input type="text" class="span3" name="description" [% HTML.attributes(value => project.description) %]/> <input type="text" class="form-control" id="editprojectdisplayname" name="displayname" [% HTML.attributes(value => project.displayname) %]/>
</div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Homepage</label> <label class="col-sm-3" for="editprojectdescription">Description</label>
<div class="controls"> <div class="col-sm-9">
<input type="text" class="span3" name="homepage" [% HTML.attributes(value => project.homepage) %]/> <input type="text" class="form-control" id="editprojectdescription" name="description" [% HTML.attributes(value => project.description) %]/>
</div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Owner</label> <label class="col-sm-3" for="editprojecthomepage">Homepage</label>
<div class="controls"> <div class="col-sm-9">
<input type="text" class="span3" name="owner" [% HTML.attributes(value => project.owner.username || c.user.username) %]/> <input type="text" class="form-control" id="editprojecthomepage" name="homepage" [% HTML.attributes(value => project.homepage) %]/>
</div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Declarative spec file</label> <label class="col-sm-3" for="editprojectowner">Owner</label>
<div class="controls"> <div class="col-sm-9">
<div class="input-append"> <input type="text" class="form-control" id="editprojectowner" name="owner" [% HTML.attributes(value => project.owner.username || c.user.username) %]/>
<input type="text" class="span3" name="declfile" [% HTML.attributes(value => project.declfile) %]/>
</div>
<span class="help-inline">(Leave blank for non-declarative project configuration)</span>
</div>
</div> </div>
</div>
<div class="control-group"> <div class="form-group row">
<label class="control-label">Declarative input type</label> <label class="col-sm-3" for="editprojectdeclfile">
<div class="controls"> Declarative spec file
[% INCLUDE renderSelection param="decltype" options=inputTypes edit=1 curValue=project.decltype %] <small class="form-text text-muted">(Leave blank for non-declarative project configuration)</small>
value </label>
<input style="width: 70%" type="text" [% HTML.attributes(value => project.declvalue, name => "declvalue") %]/> <div class="col-sm-9">
</div> <input type="text" class="form-control" id="editprojectdeclfile" name="declfile" [% HTML.attributes(value => project.declfile) %]/>
</div> </div>
</div>
<div class="form-actions"> <div class="form-group row">
<button id="submit-project" type="submit" class="btn btn-primary"> <label class="col-sm-3" for="editprojectdeclvalue">Declarative input type</label>
<i class="icon-ok icon-white"></i> <div class="col-sm-9">
[%IF create %]Create project[% ELSE %]Apply changes[% END %] [% INCLUDE renderSelection param="decltype" options=inputTypes edit=1 curValue=project.decltype %]
</button> <input type="text" class="form-control" id="editprojectdeclvalue" name="declvalue" [% HTML.attributes(value => project.declvalue) %]/>
</div> </div>
</div>
</fieldset> <button id="submit-project" type="submit" class="btn btn-primary">
<i class="fas fa-check"></i>
[%IF create %]Create project[% ELSE %]Apply changes[% END %]
</button>
</form> </form>

Binary file not shown.

View file

@ -15,12 +15,12 @@ removed or had an evaluation error.</div>
[% END %] [% END %]
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
<li class="active"><a href="#tabs-status" data-toggle="tab">Status</a></li> <li class="nav-item"><a class="nav-link active" href="#tabs-status" data-toggle="tab">Status</a></li>
[% IF constituentJobs.size > 0 %] [% IF constituentJobs.size > 0 %]
<li><a href="#tabs-constituents" data-toggle="tab">Constituents</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-constituents" data-toggle="tab">Constituents</a></li>
[% END %] [% END %]
<li><a href="#tabs-charts" data-toggle="tab">Charts</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-charts" data-toggle="tab">Charts</a></li>
<li><a href="#tabs-links" data-toggle="tab">Links</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-links" data-toggle="tab">Links</a></li>
</ul> </ul>
<div id="generic-tabs" class="tab-content"> <div id="generic-tabs" class="tab-content">

View file

@ -2,7 +2,7 @@
[% IF channels.size == 0 %] [% IF channels.size == 0 %]
<div class="alert">There are no channels available.</div> <div class="alert alert-warning">There are no channels available.</div>
[% ELSE %] [% ELSE %]

View file

@ -1,21 +1,21 @@
[% WRAPPER layout.tt title="Evaluation $eval.id of jobset $project.name:$jobset.name " %] [% WRAPPER layout.tt title="Evaluation $eval.id of jobset $project.name:$jobset.name " %]
[% PROCESS common.tt %] [% PROCESS common.tt %]
<div class="btn-group pull-right"> <div class="dropdown">
<a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#"><i class="icon-white icon-eye-open"></i> Compare to...</a> <button class="btn btn-primary dropdown-toggle float-right" data-toggle="dropdown"><i class="fas fa-eye"></i> Compare to...</button>
<ul class="dropdown-menu"> <div class="dropdown-menu dropdown-menu-right">
<li><a href="?">Preceding evaluation in this jobset</a></li> <a class="dropdown-item" href="?">Preceding evaluation in this jobset</a>
<li class="divider"></li> <div class="dropdown-divider"></div>
<li><a href="?compare=-[% 24 * 60 * 60 %]">This jobset <strong>one day</strong> earlier</a></li> <a class="dropdown-item" href="?compare=-[% 24 * 60 * 60 %]">This jobset <strong>one day</strong> earlier</a>
<li><a href="?compare=-[% 7 * 24 * 60 * 60 %]">This jobset <strong>one week</strong> earlier</a></li> <a class="dropdown-item" href="?compare=-[% 7 * 24 * 60 * 60 %]">This jobset <strong>one week</strong> earlier</a>
<li><a href="?compare=-[% 31 * 24 * 60 * 60 %]">This jobset <strong>one month</strong> earlier</a></li> <a class="dropdown-item" href="?compare=-[% 31 * 24 * 60 * 60 %]">This jobset <strong>one month</strong> earlier</a>
[% IF project.jobsets_rs.count > 1 %] [% IF project.jobsets_rs.count > 1 %]
<li class="divider"></li> <div class="dropdown-divider"></div>
[% FOREACH j IN project.jobsets.sort('name'); IF j.name != jobset.name %] [% FOREACH j IN project.jobsets.sort('name'); IF j.name != jobset.name %]
<li><a href="?compare=[% j.name %]">Jobset <tt>[% project.name %]:[% j.name %]</tt></a></li> <a class="dropdown-item" href="?compare=[% j.name %]">Jobset <tt>[% project.name %]:[% j.name %]</tt></a>
[% END; END %] [% END; END %]
[% END %] [% END %]
</ul> </div>
</div> </div>
<p>This evaluation was performed [% IF eval.flake %]from the flake <p>This evaluation was performed [% IF eval.flake %]from the flake
@ -29,70 +29,68 @@ project=otherEval.jobset.project.name jobset=otherEval.jobset.name %] evaluation
c.uri_for(c.controller('JobsetEval').action_for('view'), c.uri_for(c.controller('JobsetEval').action_for('view'),
[otherEval.id]) %]">[% otherEval.id %]</a>.</p> [otherEval.id]) %]">[% otherEval.id %]</a>.</p>
[% ELSE %] [% ELSE %]
<div class="alert">Couldn't find an evaluation to compare to.</div> <div class="alert alert-danger">Couldn't find an evaluation to compare to.</div>
[% END %] [% END %]
<form class="form-search"> <form>
<input name="filter" type="text" class="input-large search-query" placeholder="Search jobs by name..." [% HTML.attributes(value => filter) %]/> <div class="form-group">
<input name="compare" type="hidden" [% HTML.attributes(value => otherEval.id) %]/> <input name="filter" type="text" class="form-control" type="search" placeholder="Search jobs by name..." [% HTML.attributes(value => filter) %]/>
<input name="full" type="hidden" [% HTML.attributes(value => full) %]/> <input name="compare" type="hidden" [% HTML.attributes(value => otherEval.id) %]/>
<input name="full" type="hidden" [% HTML.attributes(value => full) %]/>
</div>
</form> </form>
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
[% IF c.user_exists %] [% IF c.user_exists %]
<li class="dropdown"> <li class="nav-item dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Actions</a>
Actions <div class="dropdown-menu">
<b class="caret"></b> <a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('create_jobset'), [eval.id]) %]">Create a jobset from this evaluation</a>
</a>
<ul class="dropdown-menu">
<li><a href="[% c.uri_for(c.controller('JobsetEval').action_for('create_jobset'), [eval.id]) %]">Create a jobset from this evaluation</a></li>
[% IF unfinished.size > 0 %] [% IF unfinished.size > 0 %]
<li><a href="[% c.uri_for(c.controller('JobsetEval').action_for('cancel'), [eval.id]) %]">Cancel all scheduled builds</a></li> <a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('cancel'), [eval.id]) %]">Cancel all scheduled builds</a>
[% END %] [% END %]
[% IF aborted.size > 0 || stillFail.size > 0 || nowFail.size > 0 %] [% IF aborted.size > 0 || stillFail.size > 0 || nowFail.size > 0 %]
<li><a href="[% c.uri_for(c.controller('JobsetEval').action_for('restart_failed'), [eval.id]) %]">Restart all failed builds</a></li> <a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('restart_failed'), [eval.id]) %]">Restart all failed builds</a>
[% END %] [% END %]
[% IF aborted.size > 0 %] [% IF aborted.size > 0 %]
<li><a href="[% c.uri_for(c.controller('JobsetEval').action_for('restart_aborted'), [eval.id]) %]">Restart all aborted builds</a></li> <a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('restart_aborted'), [eval.id]) %]">Restart all aborted builds</a>
[% END %] [% END %]
[% IF unfinished.size > 0 %] [% IF unfinished.size > 0 %]
<li><a href="[% c.uri_for(c.controller('JobsetEval').action_for('bump'), [eval.id]) %]">Bump builds to front of queue</a></li> <a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('bump'), [eval.id]) %]">Bump builds to front of queue</a>
[% END %] [% END %]
</ul> </div>
</li> </li>
[% END %] [% END %]
[% IF aborted.size > 0 %] [% IF aborted.size > 0 %]
<li><a href="#tabs-aborted" data-toggle="tab"><span class="text-warning">Aborted jobs ([% aborted.size %])</span></a></li> <li class="nav-item"><a class="nav-link" href="#tabs-aborted" data-toggle="tab"><span class="text-warning">Aborted jobs ([% aborted.size %])</span></a></li>
[% END %] [% END %]
[% IF nowFail.size > 0 %] [% IF nowFail.size > 0 %]
<li><a href="#tabs-now-fail" data-toggle="tab"><span class="text-warning">Newly failing jobs ([% nowFail.size %])</span></a></li> <li class="nav-item"><a class="nav-link" href="#tabs-now-fail" data-toggle="tab"><span class="text-warning">Newly failing jobs ([% nowFail.size %])</span></a></li>
[% END %] [% END %]
[% IF nowSucceed.size > 0 %] [% IF nowSucceed.size > 0 %]
<li><a href="#tabs-now-succeed" data-toggle="tab"><span class="text-success">Newly succeeding jobs ([% nowSucceed.size %])</span></a></li> <li class="nav-item"><a class="nav-link" href="#tabs-now-succeed" data-toggle="tab"><span class="text-success">Newly succeeding jobs ([% nowSucceed.size %])</span></a></li>
[% END %] [% END %]
[% IF new.size > 0 %] [% IF new.size > 0 %]
<li><a href="#tabs-new" data-toggle="tab">New jobs ([% new.size %])</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-new" data-toggle="tab">New jobs ([% new.size %])</a></li>
[% END %] [% END %]
[% IF removed.size > 0 %] [% IF removed.size > 0 %]
<li><a href="#tabs-removed" data-toggle="tab">Removed jobs ([% removed.size %])</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-removed" data-toggle="tab">Removed jobs ([% removed.size %])</a></li>
[% END %] [% END %]
[% IF stillFail.size > 0 %] [% IF stillFail.size > 0 %]
<li><a href="#tabs-still-fail" data-toggle="tab">Still failing jobs ([% stillFail.size %])</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-still-fail" data-toggle="tab">Still failing jobs ([% stillFail.size %])</a></li>
[% END %] [% END %]
[% IF stillSucceed.size > 0 %] [% IF stillSucceed.size > 0 %]
<li><a href="#tabs-still-succeed" data-toggle="tab">Still succeeding jobs ([% stillSucceed.size %])</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-still-succeed" data-toggle="tab">Still succeeding jobs ([% stillSucceed.size %])</a></li>
[% END %] [% END %]
[% IF unfinished.size > 0 %] [% IF unfinished.size > 0 %]
<li><a href="#tabs-unfinished" data-toggle="tab">Queued jobs ([% unfinished.size %])</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-unfinished" data-toggle="tab">Queued jobs ([% unfinished.size %])</a></li>
[% END %] [% END %]
<li><a href="#tabs-inputs" data-toggle="tab">Inputs</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-inputs" data-toggle="tab">Inputs</a></li>
[% IF eval.evaluationerror.errormsg %] [% IF eval.evaluationerror.errormsg %]
<li><a href="#tabs-errors" data-toggle="tab"><span class="text-warning">Evaluation errors</span></a></li> <li class="nav-item"><a class="nav-link" href="#tabs-errors" data-toggle="tab"><span class="text-warning">Evaluation errors</span></a></li>
[% END %] [% END %]
</ul> </ul>
[% BLOCK renderSome %] [% BLOCK renderSome %]
@ -111,7 +109,7 @@ c.uri_for(c.controller('JobsetEval').action_for('view'),
[% IF eval.evaluationerror.errormsg %] [% IF eval.evaluationerror.errormsg %]
<div id="tabs-errors" class="tab-pane"> <div id="tabs-errors" class="tab-pane">
<p>Errors occurred at [% INCLUDE renderDateTime timestamp=(eval.evaluationerror.errortime || eval.timestamp) %].</p> <p>Errors occurred at [% INCLUDE renderDateTime timestamp=(eval.evaluationerror.errortime || eval.timestamp) %].</p>
<pre class="alert alert-error">[% HTML.escape(eval.evaluationerror.errormsg) %]</pre> <div class="card bg-light"><div class="card-body"><pre>[% HTML.escape(eval.evaluationerror.errormsg) %]</pre></div></div>
</div> </div>
[% END %] [% END %]
@ -175,7 +173,7 @@ c.uri_for(c.controller('JobsetEval').action_for('view'),
[% IF eval.evaluationerror.errormsg %] [% IF eval.evaluationerror.errormsg %]
<div id="tabs-errors" class="tab-pane"> <div id="tabs-errors" class="tab-pane">
<p>Errors occurred at [% INCLUDE renderDateTime timestamp=(eval.evaluationerror.errortime || eval.timestamp) %].</p> <p>Errors occurred at [% INCLUDE renderDateTime timestamp=(eval.evaluationerror.errortime || eval.timestamp) %].</p>
<pre class="alert alert-error">[% HTML.escape(eval.evaluationerror.errormsg) %]</pre> <div class="card bg-light"><div class="card-body"><pre>[% HTML.escape(eval.evaluationerror.errormsg) %]</pre></div></div>
</div> </div>
[% END %] [% END %]
</div> </div>

View file

@ -1,12 +1,15 @@
[% PROCESS common.tt; USE Math %] [% PROCESS common.tt; USE Math %]
<form class="form-search" id="filter-jobs"> <form id="filter-jobs">
<div class="input-append"> <div class="form-group input-group">
<input name="filter" type="text" class="input-large search-query" placeholder="Search jobs by name..." [% HTML.attributes(value => filter) %]/> <input name="filter" type="search" class="form-control" placeholder="Search jobs by name..." [% HTML.attributes(value => filter) %]/>
<button type="button" class="btn btn-info [% IF showInactive %]active[% END %]" id="active-toggle">Show inactive jobs</button> <div class="input-group-append">
<button type="button" class="btn btn-info [% IF showInactive %]active[% END %]" id="active-toggle">
<span class="spinner-border spinner-border-sm" id="filter-loading" style="display:none"/>
Show inactive jobs
</button>
</div>
</div> </div>
&nbsp;
<img src="[% c.uri_for("/static/images/ajax-loader.gif") %]" alt="Loading..." style="display: none;" id="filter-loading" />
</form> </form>
<script> <script>
@ -33,12 +36,12 @@
[% IF jobs.size == 0 %] [% IF jobs.size == 0 %]
<div class="alert">There are no matching jobs.</div> <div class="alert alert-warning">There are no matching jobs.</div>
[% ELSE %] [% ELSE %]
[% IF nrJobs > jobs.size %] [% IF nrJobs > jobs.size %]
<div class="alert">Showing the first [% jobs.size %] jobs. <a href="javascript:setFilter('filter=%')">Show all [% nrJobs %] jobs...</a></div> <div class="alert alert-info">Showing the first [% jobs.size %] jobs. <a href="javascript:setFilter('filter=%')">Show all [% nrJobs %] jobs...</a></div>
[% END %] [% END %]
[% evalIds = evals.keys.nsort.reverse %] [% evalIds = evals.keys.nsort.reverse %]

View file

@ -43,12 +43,9 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
[% IF c.user_exists %] [% IF c.user_exists %]
<li class="dropdown"> <li class="nav-item dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Actions</a>
Actions <div class="dropdown-menu">
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
[% UNLESS project.declfile %] [% UNLESS project.declfile %]
[% INCLUDE menuItem title="Edit configuration" icon="icon-edit" uri=c.uri_for(c.controller('Jobset').action_for('edit'), c.req.captures) %] [% INCLUDE menuItem title="Edit configuration" icon="icon-edit" uri=c.uri_for(c.controller('Jobset').action_for('edit'), c.req.captures) %]
<!-- <!--
@ -57,18 +54,18 @@
[% INCLUDE menuItem title="Clone this jobset" uri=c.uri_for(c.controller('Jobset').action_for('edit'), c.req.captures, { cloneJobset => 1 }) %] [% INCLUDE menuItem title="Clone this jobset" uri=c.uri_for(c.controller('Jobset').action_for('edit'), c.req.captures, { cloneJobset => 1 }) %]
[% END %] [% END %]
[% INCLUDE menuItem title="Evaluate this jobset" uri="javascript:confirmEvaluateJobset()" %] [% INCLUDE menuItem title="Evaluate this jobset" uri="javascript:confirmEvaluateJobset()" %]
</ul> </div>
</li> </li>
[% END %] [% END %]
<li class="active"><a href="#tabs-evaluations" data-toggle="tab">Evaluations</a></li> <li class="nav-item"><a class="nav-link active" href="#tabs-evaluations" data-toggle="tab">Evaluations</a></li>
[% IF jobset.errormsg || jobset.fetcherrormsg %] [% IF jobset.errormsg || jobset.fetcherrormsg %]
<li><a href="#tabs-errors" data-toggle="tab"><span class="text-warning">Evaluation errors</span></a></li> <li class="nav-item"><a class="nav-link" href="#tabs-errors" data-toggle="tab"><span class="text-warning">Evaluation errors</span></a></li>
[% END %] [% END %]
<li><a href="#tabs-jobs" data-toggle="tab">Jobs</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-jobs" data-toggle="tab">Jobs</a></li>
<li><a href="#tabs-configuration" data-toggle="tab">Configuration</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-configuration" data-toggle="tab">Configuration</a></li>
<li><a href="#tabs-links" data-toggle="tab">Links</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-links" data-toggle="tab">Links</a></li>
<li><a href="#tabs-channels" data-toggle="tab">Channels</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-channels" data-toggle="tab">Channels</a></li>
</ul> </ul>
<div id="generic-tabs" class="tab-content"> <div id="generic-tabs" class="tab-content">
@ -120,7 +117,7 @@
[% IF jobset.errormsg || jobset.fetcherrormsg %] [% IF jobset.errormsg || jobset.fetcherrormsg %]
<div id="tabs-errors" class="tab-pane"> <div id="tabs-errors" class="tab-pane">
<p>Errors occurred at [% INCLUDE renderDateTime timestamp=(jobset.errortime || jobset.lastcheckedtime) %].</p> <p>Errors occurred at [% INCLUDE renderDateTime timestamp=(jobset.errortime || jobset.lastcheckedtime) %].</p>
<pre class="alert alert-error">[% HTML.escape(jobset.fetcherrormsg || jobset.errormsg) %]</pre> <div class="card bg-light"><div class="card-body"><pre>[% HTML.escape(jobset.fetcherrormsg || jobset.errormsg) %]</pre></div></div>
</div> </div>
[% END %] [% END %]

View file

@ -11,20 +11,20 @@
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<script type="text/javascript" src="[% c.uri_for("/static/js/jquery/jquery-1.12.3.min.js") %]"></script> <script type="text/javascript" src="[% c.uri_for("/static/js/jquery/jquery-3.4.1.min.js") %]"></script>
<script type="text/javascript" src="[% c.uri_for("/static/js/jquery/jquery-ui-1.10.4.min.js") %]"></script> <script type="text/javascript" src="[% c.uri_for("/static/js/jquery/jquery-ui-1.10.4.min.js") %]"></script>
<script type="text/javascript" src="[% c.uri_for("/static/js/moment/moment-2.24.0.min.js") %]"></script> <script type="text/javascript" src="[% c.uri_for("/static/js/moment/moment-2.24.0.min.js") %]"></script>
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link href="[% c.uri_for("/static/fontawesome/css/all.css") %]" rel="stylesheet" />
<script type="text/javascript" src="[% c.uri_for("/static/js/popper.min.js") %]"></script>
<script type="text/javascript" src="[% c.uri_for("/static/bootstrap/js/bootstrap.min.js") %]"></script> <script type="text/javascript" src="[% c.uri_for("/static/bootstrap/js/bootstrap.min.js") %]"></script>
<link href="[% c.uri_for("/static/bootstrap/css/bootstrap.min.css") %]" rel="stylesheet" /> <link href="[% c.uri_for("/static/bootstrap/css/bootstrap.min.css") %]" rel="stylesheet" />
<!-- hydra.css must be included before bootstrap-responsive to <!-- hydra.css may need to be moved to before boostrap to make the @media rule work. -->
make the @media rule work. -->
<link rel="stylesheet" href="[% c.uri_for("/static/css/hydra.css") %]" type="text/css" /> <link rel="stylesheet" href="[% c.uri_for("/static/css/hydra.css") %]" type="text/css" />
<link rel="stylesheet" href="[% c.uri_for("/static/css/rotated-th.css") %]" type="text/css" /> <link rel="stylesheet" href="[% c.uri_for("/static/css/rotated-th.css") %]" type="text/css" />
<link href="[% c.uri_for("/static/bootstrap/css/bootstrap-responsive.min.css") %]" rel="stylesheet" />
<style> <style>
.popover { max-width: 40%; } .popover { max-width: 40%; }
@ -46,27 +46,23 @@
<body> <body>
<div class="navbar navbar-fixed-top"> <nav class="navbar navbar-expand-md navbar-light bg-light">
<div class="navbar-inner"> <div class="container">
<div class="container"> <a class="navbar-brand" href="[% c.uri_for(c.controller('Root').action_for('index')) %]">
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> [% IF logo == "" %]
<span class="icon-bar"></span> Hydra
<span class="icon-bar"></span> [% ELSE %]
<span class="icon-bar"></span> <img src="[% c.uri_for(logo) %]" alt="Hydra Logo" class="logo" />
</button> [% END %]
<a class="brand" href="[% c.uri_for(c.controller('Root').action_for('index')) %]"> </a>
[% IF logo == "" %] <button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbarSupportedContent">
Hydra <span class="navbar-toggler-icon"></span>
[% ELSE %] </button>
<img src="[% c.uri_for(logo) %]" alt="Hydra Logo" class="logo" /> <div class="collapse navbar-collapse" id="navbarSupportedContent">
[% END %] [% PROCESS topbar.tt %]
</a>
<div class="nav-collapse collapse">
[% PROCESS topbar.tt %]
</div>
</div> </div>
</div> </div>
</div> </nav>
<div class="container"> <div class="container">
<div class="skip-topbar"></div> <div class="skip-topbar"></div>

View file

@ -18,9 +18,9 @@
[% END %] [% END %]
</p> </p>
<pre class="log" id="contents"> <div class="card bg-light"><div class="card-body"><pre class="log" id="contents">
<em>Loading...</em> <em>Loading...</em>
</pre> </pre></div></div>
<script type="text/javascript"> <script type="text/javascript">
$(document).ready(function() { $(document).ready(function() {

View file

@ -14,29 +14,25 @@
<tr> <tr>
<td>[% INCLUDE renderDateTime timestamp=i.createtime %]</td> <td>[% INCLUDE renderDateTime timestamp=i.createtime %]</td>
<td>[% contents.replace('\n','<br />\n') %]</td> <td>[% contents.replace('\n','<br />\n') %]</td>
<td>[% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('news_delete') i.id) content = "Delete" confirmmsg = "Are you sure you want to delete this news item?" class = "btn btn-mini btn-danger" %]</td> <td>[% INCLUDE maybeLink uri = c.uri_for(c.controller('Admin').action_for('news_delete') i.id) content = "Delete" confirmmsg = "Are you sure you want to delete this news item?" class = "btn btn-sm btn-danger" %]</td>
</tr> </tr>
[% END %] [% END %]
</tbody> </tbody>
</table> </table>
[% END %] [% END %]
<form class="form-horizontal" action="[% c.uri_for('/admin/news/submit') %]" method="post"> <form action="[% c.uri_for('/admin/news/submit') %]" method="post">
<fieldset> <div class="page-header">Add news item</div>
<legend>Add news item</legend>
<div class="control-group"> <div class="form-group">
<label class="control-label">News text (HTML)</label> <label for="newscontents">News text (HTML)</label>
<div class="controls"> <textarea class="form-control" id="newscontents" name="contents"></textarea>
<textarea class="span9" name="contents"></textarea>
</div>
</div>
</fieldset>
<div class="form-actions">
<button type="submit" class="btn btn-primary">
<i class="icon-ok icon-white"></i>
Post
</button>
</div> </div>
<button type="submit" class="btn btn-primary">
<i class="fas fa-check"></i>
Post
</button>
</form> </form>
[% END %] [% END %]

View file

@ -40,7 +40,7 @@
</script> </script>
<p>The following projects are hosted on this server: <p>The following projects are hosted on this server:
<label id="show-disabled" class="btn btn-small pull-right" data-toggle="button">Show disabled projects</label> <label id="show-disabled" class="btn btn-secondary btn-sm float-right" data-toggle="button">Show disabled projects</label>
</p> </p>
<table class="table table-condensed table-striped clickable-rows"> <table class="table table-condensed table-striped clickable-rows">

View file

@ -5,6 +5,6 @@
[% jobset = build.jobset %] [% jobset = build.jobset %]
[% job = build.job %] [% job = build.job %]
<pre>[% HTML.escape(contents) %]</pre> <div class="card bg-light"><div class="card-body"><pre>[% HTML.escape(contents) %]</pre></div></div>
[% END %] [% END %]

View file

@ -54,11 +54,11 @@
</a> </a>
</td> </td>
<td> <td>
[% WRAPPER makePopover title="Help" classes="btn-mini" %] [% WRAPPER makePopover title="Help" classes="btn-secondary btn-sm" %]
<p>If you have Nix installed on your machine, this failed build output and <p>If you have Nix installed on your machine, this failed build output and
all its dependencies can be unpacked into your local Nix store by doing:</p> all its dependencies can be unpacked into your local Nix store by doing:</p>
<pre><span class="shell-prompt">$ </span>curl [% uri %] | gunzip | nix-store --import</pre> <div class="card bg-light"><div class="card-body p-2"><code><span class="shell-prompt">$ </span>curl [% uri %] | gunzip | nix-store --import</code></div></div>
<p>The build output can then be found in the path <tt>[% product.path %]</tt>.</p> <p>The build output can then be found in the path <tt>[% product.path %]</tt>.</p>
[% END %] [% END %]
@ -77,14 +77,14 @@
<tt>[% HTML.escape(build.nixname) %]</tt> <tt>[% HTML.escape(build.nixname) %]</tt>
</td> </td>
<td> <td>
[% WRAPPER makePopover title="Help" classes="btn-mini" [% WRAPPER makePopover title="Help" classes="btn-secondary btn-sm"
%] <p>You can install this package using the Nix package %] <p>You can install this package using the Nix package
manager from the command-line:</p> manager from the command-line:</p>
<pre><span class="shell-prompt">$ </span>nix-env -i [%HTML.escape(product.path)%][% IF binaryCachePublicUri %] --option binary-caches [% HTML.escape(binaryCachePublicUri) %][% END %]</pre> <div class="card bg-light"><div class="card-body p-2"><code><span class="shell-prompt">$ </span>nix-env -i [%HTML.escape(product.path)%][% IF binaryCachePublicUri %] --option binary-caches [% HTML.escape(binaryCachePublicUri) %][% END %]</code></div></div>
[% END %] [% END %]
[% IF localStore %] [% IF localStore %]
<a class="btn btn-mini" href="[% contents %]">Contents</a> <a class="btn btn-secondary btn-sm" href="[% contents %]">Contents</a>
[% END %] [% END %]
</td> </td>
</tr> </tr>
@ -105,21 +105,21 @@
</a> </a>
</td> </td>
<td> <td>
[% WRAPPER makePopover title="Help" classes="btn-mini" %] [% WRAPPER makePopover title="Help" classes="btn-secondary btn-sm" %]
<p>If you have Nix installed on your machine, this build and <p>If you have Nix installed on your machine, this build and
all its dependencies can be unpacked into your local Nix all its dependencies can be unpacked into your local Nix
store by doing:</p> store by doing:</p>
<pre><span class="shell-prompt">$ </span>gunzip &lt; [% filename %] | nix-store --import</pre> <div class="card bg-light"><div class="card-body p-2"><code><span class="shell-prompt">$ </span>gunzip &lt; [% filename %] | nix-store --import</code></div></div>
<p>or to download and unpack in one command:</p> <p>or to download and unpack in one command:</p>
<pre><span class="shell-prompt">$ </span>curl [% uri %] | gunzip | nix-store --import</pre> <div class="card bg-light"><div class="card-body p-2"><code><span class="shell-prompt">$ </span>curl [% uri %] | gunzip | nix-store --import</code></div></div>
<p>The package can then be found in the path <tt>[% <p>The package can then be found in the path <tt>[%
product.path %]</tt>. Youll probably also want to do</p> product.path %]</tt>. Youll probably also want to do</p>
<pre><span class="shell-prompt">$ </span>nix-env -i [% product.path %]</pre> <div class="card bg-light"><div class="card-body p-2"><code><span class="shell-prompt">$ </span>nix-env -i [% product.path %]</code></div></div>
<p>to actually install the package in your Nix user environment.</p> <p>to actually install the package in your Nix user environment.</p>
@ -187,7 +187,7 @@
</a> </a>
</td> </td>
<td> <td>
[% WRAPPER makePopover title="Details" classes="btn-mini" %] [% WRAPPER makePopover title="Details" classes="btn-secondary btn-sm" %]
<table class="info-table"> <table class="info-table">
[% INCLUDE renderProductLinks %] [% INCLUDE renderProductLinks %]
<tr><th>File size:</th><td>[% product.filesize %] bytes ([% mibs(product.filesize / (1024 * 1024)) %] MiB)</td></tr> <tr><th>File size:</th><td>[% product.filesize %] bytes ([% mibs(product.filesize / (1024 * 1024)) %] MiB)</td></tr>
@ -196,7 +196,7 @@
</table> </table>
[% END %] [% END %]
[% IF localStore %] [% IF localStore %]
<a class="btn btn-mini" href="[% contents %]">Contents</a> <a class="btn btn-secondary btn-sm" href="[% contents %]">Contents</a>
[% END %] [% END %]
</td> </td>
</tr> </tr>
@ -254,7 +254,7 @@
</a> </a>
</td> </td>
<td> <td>
[% WRAPPER makePopover title="Details" classes="btn-mini" %] [% WRAPPER makePopover title="Details" classes="btn-secondary btn-sm" %]
<table class="info-table"> <table class="info-table">
[% INCLUDE renderProductLinks %] [% INCLUDE renderProductLinks %]
</table> </table>

View file

@ -3,23 +3,20 @@
<ul class="nav nav-tabs"> <ul class="nav nav-tabs">
[% IF c.user_exists %] [% IF c.user_exists %]
<li class="dropdown"> <li class="nav-item dropdown">
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> <a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Actions</a>
Actions <div class="dropdown-menu">
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
[% INCLUDE menuItem title="Edit configuration" icon="icon-edit" uri=c.uri_for(c.controller('Project').action_for('edit'), c.req.captures) %] [% INCLUDE menuItem title="Edit configuration" icon="icon-edit" uri=c.uri_for(c.controller('Project').action_for('edit'), c.req.captures) %]
[% INCLUDE menuItem title="Delete this project" icon="icon-trash" uri="javascript:deleteProject()" %] [% INCLUDE menuItem title="Delete this project" icon="icon-trash" uri="javascript:deleteProject()" %]
[% UNLESS project.declfile %] [% UNLESS project.declfile %]
[% INCLUDE menuItem title="Create jobset" icon="icon-plus" uri=c.uri_for(c.controller('Project').action_for('create_jobset'), c.req.captures) %] [% INCLUDE menuItem title="Create jobset" icon="icon-plus" uri=c.uri_for(c.controller('Project').action_for('create_jobset'), c.req.captures) %]
[% END %] [% END %]
</ul> </div>
</li> </li>
[% END %] [% END %]
<li class="active"><a href="#tabs-project" data-toggle="tab">Jobsets</a></li> <li class="nav-item"><a class="nav-link active" href="#tabs-project" data-toggle="tab">Jobsets</a></li>
<li><a href="#tabs-configuration" data-toggle="tab">Configuration</a></li> <li class="nav-item"><a class="nav-link" href="#tabs-configuration" data-toggle="tab">Configuration</a></li>
</ul> </ul>
<div class="tab-content"> <div class="tab-content">
@ -50,12 +47,17 @@
<div id="tabs-project" class="tab-pane active"> <div id="tabs-project" class="tab-pane active">
[% IF project.jobsets %] [% IF project.jobsets %]
<p>This project has the following jobsets: <div class="row">
<label id="show-disabled" class="btn btn-small pull-right" data-toggle="button">Show disabled jobsets</label> <div class="col">
[% IF isProjectOwner %] This project has the following jobsets:
<label id="show-hidden" class="btn btn-small pull-right" data-toggle="button">Show hidden jobsets</label> </div>
[% END %] <div class="col-auto">
</p> <label id="show-disabled" class="btn btn-secondary" data-toggle="button">Show disabled jobsets</label>
[% IF isProjectOwner %]
<label id="show-hidden" class="btn btn-secondary" data-toggle="button">Show hidden jobsets</label>
[% END %]
</div>
</div>
[% INCLUDE renderJobsetOverview %] [% INCLUDE renderJobsetOverview %]
[% ELSE %] [% ELSE %]
<p>No jobsets have been defined yet.</p> <p>No jobsets have been defined yet.</p>

View file

@ -1,8 +1,6 @@
[% WRAPPER layout.tt title="Queue runner status" %] [% WRAPPER layout.tt title="Queue runner status" %]
[% PROCESS common.tt %] [% PROCESS common.tt %]
<pre> <div class="card bg-light"><div class="card-body"><pre>[% HTML.escape(status) %]</pre></div></div>
[% HTML.escape(status) %]
</pre>
[% END %] [% END %]

View file

@ -81,7 +81,7 @@
[% IF builds.size > 0 || buildsdrv.size > 0 ; matched = 1 ; END %] [% IF builds.size > 0 || buildsdrv.size > 0 ; matched = 1 ; END %]
[% IF !matched %] [% IF !matched %]
<div class="alert alert-warn">Sorry! Nothing matches your query.</div> <div class="alert alert-warning">Sorry! Nothing matches your query.</div>
[% END %] [% END %]
[% END %] [% END %]

View file

@ -33,12 +33,6 @@ span:target > span.dep-tree-line {
font-weight: bold; font-weight: bold;
} }
:target {
padding-top: 40px;
margin-top: -40px;
display: inline-block; /* required for webkit browsers */
}
span.disabled-project, span.disabled-jobset, span.disabled-job { span.disabled-project, span.disabled-jobset, span.disabled-job {
text-decoration: line-through; text-decoration: line-through;
} }
@ -52,11 +46,6 @@ table.info-table th {
padding-bottom: 0.2em; padding-bottom: 0.2em;
} }
/* Missing in bootstrap 2.0.2 */
.text-warning {
color: #c09853;
}
table.clickable-rows > tbody > tr { table.clickable-rows > tbody > tr {
cursor: pointer; cursor: pointer;
} }
@ -152,3 +141,7 @@ td.step-status span.warn {
cursor: help; cursor: help;
border-bottom: 1px dotted #999; border-bottom: 1px dotted #999;
} }
.tab-content > .tab-pane {
padding-top: 1.5rem;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

File diff suppressed because one or more lines are too long

View file

@ -46,29 +46,30 @@ $(document).ready(function() {
window.location = link.attr("href"); window.location = link.attr("href");
}); });
bootbox.animate(false); bootbox.setDefaults({ animate: false });
/* Enable popovers (and allow table and teletype elements in them). */
$.fn.popover.Constructor.Default.whiteList.table = [];
$.fn.popover.Constructor.Default.whiteList.thead = []
$.fn.popover.Constructor.Default.whiteList.tbody = [];
$.fn.popover.Constructor.Default.whiteList.tr = [];
$.fn.popover.Constructor.Default.whiteList.th = [];
$.fn.popover.Constructor.Default.whiteList.td = [];
$.fn.popover.Constructor.Default.whiteList.tt = [];
$(".hydra-popover").popover({}); $(".hydra-popover").popover({});
$(function() { /* Activates tab according to URL anchor. */
if (window.location.hash) { if (window.location.hash) {
$(".nav-tabs a[href='" + window.location.hash + "']").tab('show'); $('.nav-tabs > .nav-item:not(.dropdown) a[href="' + window.location.hash + '"]').tab('show');
} }
/* If no tab is active, show the first one. */ $('.nav-tabs').each(function() {
$(".nav-tabs").each(function() { if ($('.nav-item:not(.dropdown) a.active',this).length == 0)
if ($("li.active", this).length > 0) return; $('.nav-item:not(.dropdown) a',this).first().tab('show');
$("a", $(this).children("li:not(.dropdown)").first()).tab('show'); });
});
/* Ensure that pressing the back button on another page $('.nav-tabs > .nav-item:not(.dropdown) a[href^="#"]').on('click', function() {
navigates back to the previously selected tab on this history.replaceState(null, null, window.location.href.split("#")[0] + $(this).attr("href"));
page. */
$('.nav-tabs').bind('show', function(e) {
var pattern = /#.+/gi;
var id = e.target.toString().match(pattern)[0];
history.replaceState(null, "", id);
});
}); });
/* Automatically set Bootstrap radio buttons from hidden form controls. */ /* Automatically set Bootstrap radio buttons from hidden form controls. */
@ -131,7 +132,7 @@ $(document).ready(function() {
var tabsLoaded = {}; var tabsLoaded = {};
function makeLazyTab(tabName, uri) { function makeLazyTab(tabName, uri) {
$('.nav-tabs').bind('show', function(e) { $('.nav-tabs').bind('show.bs.tab', function(e) {
var pattern = /#.+/gi; var pattern = /#.+/gi;
var id = e.target.toString().match(pattern)[0]; var id = e.target.toString().match(pattern)[0];
if (id == '#' + tabName && !tabsLoaded[id]) { if (id == '#' + tabName && !tabsLoaded[id]) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
src/root/static/js/popper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,18 +1,18 @@
[% BLOCK makeSubMenu %] [% BLOCK makeSubMenu %]
<li class="dropdown" [% IF id; HTML.attributes(id => id); END %] > <li class="nav-item dropdown" [% IF id; HTML.attributes(id => id); END %] >
<a class="dropdown-toggle" href="#" data-toggle="dropdown">[% title %]<b class="caret"></b></a> <a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown">[% title %]<b class="caret"></b></a>
<ul class="dropdown-menu"> <div class="dropdown-menu[% IF align == 'right' %] dropdown-menu-right[% END %]">
[% content %] [% content %]
</ul> </div>
</li> </li>
[% END %] [% END %]
[% showPrivate = (isPrivateHydra && c.user_exists) || ! isPrivateHydra %] [% showPrivate = (isPrivateHydra && c.user_exists) || ! isPrivateHydra %]
[% IF showPrivate %] [% IF showPrivate %]
<ul class="nav pull-left"> <ul class="navbar-nav mr-auto">
[% IF c.user_exists %] [% IF c.user_exists %]
[% INCLUDE menuItem uri = c.uri_for(c.controller('User').action_for('dashboard'), [c.user.username]) title = "Dashboard" %] [% INCLUDE navItem uri = c.uri_for(c.controller('User').action_for('dashboard'), [c.user.username]) title = "Dashboard" %]
[% END %] [% END %]
[% WRAPPER makeSubMenu title="Status" %] [% WRAPPER makeSubMenu title="Status" %]
@ -38,8 +38,8 @@
[% IF project %] [% IF project %]
[% WRAPPER makeSubMenu title="Project" %] [% WRAPPER makeSubMenu title="Project" %]
<li class="nav-header">[% HTML.escape(project.name) %]</li> <h6 class="dropdown-header">[% HTML.escape(project.name) %]</h6>
<li class="divider"></li> <div class="dropdown-divider"></div>
[% INCLUDE menuItem uri = c.uri_for(c.controller('Project').action_for('project'), [project.name]) title = "Overview" %] [% INCLUDE menuItem uri = c.uri_for(c.controller('Project').action_for('project'), [project.name]) title = "Overview" %]
[% INCLUDE menuItem uri = c.uri_for(c.controller('Project').action_for('all'), [project.name]) title = "Latest builds" %] [% INCLUDE menuItem uri = c.uri_for(c.controller('Project').action_for('all'), [project.name]) title = "Latest builds" %]
[% INCLUDE menuItem uri = c.uri_for('/project' project.name 'channel' 'latest') title = "Channel" %] [% INCLUDE menuItem uri = c.uri_for('/project' project.name 'channel' 'latest') title = "Channel" %]
@ -48,8 +48,8 @@
[% IF jobset %] [% IF jobset %]
[% WRAPPER makeSubMenu title="Jobset" %] [% WRAPPER makeSubMenu title="Jobset" %]
<li class="nav-header">[% HTML.escape(jobset.name) %]</li> <h6 class="dropdown-header">[% HTML.escape(jobset.name) %]</h6>
<li class="divider"></li> <div class="dropdown-divider"></div>
[% INCLUDE menuItem [% INCLUDE menuItem
uri = c.uri_for(c.controller('Jobset').action_for('jobset'), [project.name, jobset.name]) uri = c.uri_for(c.controller('Jobset').action_for('jobset'), [project.name, jobset.name])
title = "Overview" %] title = "Overview" %]
@ -65,8 +65,8 @@
[% IF job %] [% IF job %]
[% WRAPPER makeSubMenu title="Job" %] [% WRAPPER makeSubMenu title="Job" %]
<li class="nav-header">[% HTML.escape(job) %]</li> <h6 class="dropdown-header">[% HTML.escape(job) %]</h6>
<li class="divider"></li> <div class="dropdown-divider"></div>
[% INCLUDE menuItem [% INCLUDE menuItem
uri = c.uri_for(c.controller('Job').action_for('overview'), [project.name, jobset.name, job]) uri = c.uri_for(c.controller('Job').action_for('overview'), [project.name, jobset.name, job])
title = "Overview" %] title = "Overview" %]
@ -82,7 +82,7 @@
[% WRAPPER makeSubMenu title="Admin" %] [% WRAPPER makeSubMenu title="Admin" %]
[% IF c.check_user_roles('admin') || c.check_user_roles('create-projects') %] [% IF c.check_user_roles('admin') || c.check_user_roles('create-projects') %]
[% INCLUDE menuItem uri = c.uri_for(c.controller('Project').action_for('create')) title = "Create project" %] [% INCLUDE menuItem uri = c.uri_for(c.controller('Project').action_for('create')) title = "Create project" %]
<li class="divider"></li> <div class="dropdown-divider"></div>
[% END %] [% END %]
[% IF c.check_user_roles('admin') %] [% IF c.check_user_roles('admin') %]
[% INCLUDE menuItem [% INCLUDE menuItem
@ -94,7 +94,7 @@
[% INCLUDE menuItem [% INCLUDE menuItem
uri = c.uri_for(c.controller('Admin').action_for('users')) uri = c.uri_for(c.controller('Admin').action_for('users'))
title = "Manage users" %] title = "Manage users" %]
<li class="divider"></li> <div class="dropdown-divider"></div>
[% INCLUDE menuItem [% INCLUDE menuItem
uri = c.uri_for(c.controller('Admin').action_for('clear_queue_non_current')) uri = c.uri_for(c.controller('Admin').action_for('clear_queue_non_current'))
title = "Cancel queued non-current builds" title = "Cancel queued non-current builds"
@ -117,32 +117,31 @@
</ul> </ul>
[% END %] [% END %]
<ul class="nav pull-right"> [% IF showPrivate %]
<form class="form-inline" action="[% c.uri_for('/search') %]">
<input name="query" type="text" class="form-control" placeholder="Search" [% HTML.attributes(value => c.req.params.query) %]/>
</form>
[% END %]
<ul class="navbar-nav">
[% IF showPrivate %]
<form class="navbar-search" action="[% c.uri_for('/search') %]">
<input name="query" type="text" class="search-query span2" placeholder="Search" [% HTML.attributes(value => c.req.params.query) %]/>
</form>
[% END %]
[% IF c.user_exists %] [% IF c.user_exists %]
[% INCLUDE menuItem uri = c.uri_for(c.controller('User').action_for('edit'), [c.user.username]) title = "Preferences" %] [% INCLUDE navItem uri = c.uri_for(c.controller('User').action_for('edit'), [c.user.username]) title = "Preferences" %]
<li> <li class="nav-item">
<a href="#" onclick="signOut();">Sign out</a> <a class="nav-link" href="#" onclick="signOut();">Sign out</a>
</li> </li>
[% ELSE %] [% ELSE %]
[% WRAPPER makeSubMenu title="Sign in" id="sign-in-menu" %] [% WRAPPER makeSubMenu title="Sign in" id="sign-in-menu" align="right" %]
[% IF c.config.enable_google_login %] [% IF c.config.enable_google_login %]
<div style="display: none" class="g-signin2" data-onsuccess="onGoogleSignIn" data-theme="dark"></div></a> <div style="display: none" class="g-signin2" data-onsuccess="onGoogleSignIn" data-theme="dark"></div>
<li><a href="#" id="google-signin">Sign in with Google</a></li> <a class="dropdown-item" href="#" id="google-signin">Sign in with Google</a>
<li class="divider"></li> <div class="dropdown-divider"></div>
[% END %] [% END %]
[% IF c.config.github_client_id %] [% IF c.config.github_client_id %]
<li><a href="/github-redirect?after=[% c.req.path %]">Sign in with GitHub</a></li> <a class="dropdown-item" href="/github-redirect?after=[% c.req.path %]">Sign in with GitHub</a>
<li class="divider"></li> <div class="dropdown-divider"></div>
[% END %] [% END %]
<li> <a class="dropdown-item" href="#hydra-signin" data-toggle="modal">Sign in with a Hydra account</a>
<a href="#hydra-signin" data-toggle="modal">Sign in with a Hydra account</a>
</li>
[% END %] [% END %]
[% END %] [% END %]

View file

@ -14,115 +14,107 @@
>[% role %]</option> >[% role %]</option>
[% END %] [% END %]
<form class="form-horizontal"> <form>
<fieldset> [% IF create %]
<div class="form-group row">
<label class="col-sm-3" for="userusername">User name</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="userusername" name="username" [% HTML.attributes(value => username) %]/>
</div>
</div>
[% END %]
[% IF create %] <div class="form-group row">
<div class="control-group"> <label class="col-sm-3" for="userfullname">Full name</label>
<label class="control-label">User name</label> <div class="col-sm-9">
<div class="controls"> <input type="text" class="form-control" id="userfullname" name="fullname" [% HTML.attributes(value => create ? '' : user.fullname) %]/>
<input type="text" class="span3" name="username" [% HTML.attributes(value => username) %]/> </div>
</div>
[% IF create || user.type == 'hydra' %]
<div class="form-group row">
<label class="col-sm-3" for="userpassword">Password</label>
<div class="col-sm-9">
<input type="password" class="form-control" id="userpassword" name="password" value=""/>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3" for="userpassword2">Confirm password</label>
<div class="col-sm-9">
<input type="password" class="form-control" id="userpassword2" name="password2" value=""/>
</div>
</div>
[% END %]
<div class="form-group row">
<label class="col-sm-3" for="useremailaddress">Email</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="useremailaddress" name="emailaddress" [% IF !create && user.username.search('@') %]disabled="disabled"[% END %] [%+ HTML.attributes(value => user.emailaddress) %]/>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3" for="useremailonerror">Receive evaluation error notifications</label>
<div class="col-sm-9">
<input type="checkbox" name="emailonerror" [% IF !create && user.emailonerror; 'checked="checked"'; END %]/>
</div>
</div>
<div class="form-group row">
<label class="col-sm-3" for="userpublicdashboard">Public dashboard</label>
<div class="col-sm-9">
<input type="checkbox" name="publicdashboard" [% IF !create && user.publicdashboard; 'checked="checked"'; END %]/>
</div>
</div>
[% IF !create || c.check_user_roles('admin') %]
<div class="form-group row">
<label class="col-sm-3">Roles</label>
<div class="col-sm-9">
<select multiple="multiple" name="roles" class="form-control" [% IF !c.check_user_roles('admin') %]disabled="disabled"[% END %]>
[% INCLUDE roleoption role="admin" %]
[% INCLUDE roleoption role="create-projects" %]
[% INCLUDE roleoption role="restart-jobs" %]
[% INCLUDE roleoption role="bump-to-front" %]
[% INCLUDE roleoption role="cancel-build" %]
</select>
</div> </div>
</div> </div>
[% END %] [% END %]
<div class="control-group"> [% IF create && !c.check_user_roles('admin') %]
<label class="control-label">Full name</label> <div class="form-group row">
<div class="controls"> <label class="col-sm-3"></label>
<input type="text" class="span3" name="fullname" [% HTML.attributes(value => create ? '' : user.fullname) %]/> <div class="col-sm-9">
<img src="[% c.uri_for('/captcha') %]" alt="CAPTCHA">
</div> </div>
</div> </div>
<div class="form-group row">
[% IF create || user.type == 'hydra' %] <label class="col-sm-3" for="usercaptcha">Type the digits shown in the image above</label>
<div class="control-group"> <div class="col-sm-9">
<label class="control-label">Password</label> <input type="text" class="form-control" id="usercaptcha" name="captcha" value="">
<div class="controls">
<input type="password" class="span3" name="password" value=""/>
</div> </div>
</div> </div>
[% END %]
<div class="control-group"> <button id="submit-user" class="btn btn-primary">
<label class="control-label">Confirm password</label> <i class="fas fa-check"></i>
<div class="controls"> [%IF create %]Create[% ELSE %]Apply changes[% END %]
<input type="password" class="span3" name="password2" value=""/> </button>
</div> [% IF !create && c.check_user_roles('admin') && user.type == 'hydra' %]
</div> <button id="reset-password" class="btn btn-warning">
[% END %] <i class="fas fa-lock"></i>
Reset password
<div class="control-group"> </button>
<label class="control-label">Email</label> [% END %]
<div class="controls"> [% IF !create %]
<input type="text" class="span3" name="emailaddress" [% IF !create && user.username.search('@') %]disabled="disabled"[% END %] [%+ HTML.attributes(value => user.emailaddress) %]/> <button id="delete-user" class="btn btn-danger">
</div> <i class="fas fa-trash"></i>
</div> Delete this user
</button>
<div class="control-group"> [% END %]
<div class="controls">
<label class="checkbox">
<input type="checkbox" name="emailonerror" [% IF !create && user.emailonerror; 'checked="checked"'; END %]/>Receive evaluation error notifications
</label>
</div>
</div>
<div class="control-group">
<div class="controls">
<label class="checkbox">
<input type="checkbox" name="publicdashboard" [% IF !create && user.publicdashboard; 'checked="checked"'; END %]/>Public dashboard
</label>
</div>
</div>
[% IF !create || c.check_user_roles('admin') %]
<div class="control-group">
<label class="control-label">Roles</label>
<div class="controls">
<select multiple="multiple" name="roles" class="span3" [% IF !c.check_user_roles('admin') %]disabled="disabled"[% END %]>
[% INCLUDE roleoption role="admin" %]
[% INCLUDE roleoption role="create-projects" %]
[% INCLUDE roleoption role="restart-jobs" %]
[% INCLUDE roleoption role="bump-to-front" %]
[% INCLUDE roleoption role="cancel-build" %]
</select>
</div>
</div>
[% END %]
[% IF create && !c.check_user_roles('admin') %]
<div class="control-group">
<div class="controls">
<img src="[% c.uri_for('/captcha') %]" alt="CAPTCHA"/>
</div>
</div>
<div class="control-group">
<label class="control-label">Type the digits shown in the image above</label>
<div class="controls">
<input type="text" class="span3" name="captcha" value=""/>
</div>
</div>
[% END %]
<div class="form-actions">
<button id="submit-user" class="btn btn-primary">
<i class="icon-ok icon-white"></i>
[%IF create %]Create[% ELSE %]Apply changes[% END %]
</button>
[% IF !create && c.check_user_roles('admin') && user.type == 'hydra' %]
<button id="reset-password" class="btn btn-warning">
<i class="icon-trash icon-white"></i>
Reset password
</button>
[% END %]
[% IF !create %]
<button id="delete-user" class="btn btn-danger">
<i class="icon-trash icon-white"></i>
Delete this user
</button>
[% END %]
</div>
</fieldset>
</form> </form>

View file

@ -24,8 +24,8 @@
</tbody> </tbody>
</table> </table>
<p><a class="btn" href="[% c.uri_for(c.controller('Root').action_for('register')) %]"> <a class="btn btn-primary" href="[% c.uri_for(c.controller('Root').action_for('register')) %]">
<i class="icon-plus"></i> Add a new user <i class="fas fa-plus"></i> Add a new user
</a></p> </a>
[% END %] [% END %]