Merge branch 'master' into patch-1
This commit is contained in:
@@ -1,29 +0,0 @@
|
||||
TEMPLATES = $(wildcard *.tt)
|
||||
STATIC = \
|
||||
$(wildcard static/images/*) \
|
||||
$(wildcard static/css/*) \
|
||||
static/js/bootbox.min.js \
|
||||
static/js/common.js \
|
||||
static/js/jquery/jquery-1.12.3.min.js \
|
||||
static/js/jquery/jquery-ui-1.10.4.min.js
|
||||
|
||||
FLOT = flot-0.8.3.zip
|
||||
BOOTSTRAP = bootstrap-2.3.1.zip
|
||||
|
||||
ZIPS = $(FLOT) $(BOOTSTRAP)
|
||||
|
||||
EXTRA_DIST = $(TEMPLATES) $(STATIC) $(ZIPS)
|
||||
|
||||
hydradir = $(libexecdir)/hydra/root
|
||||
nobase_hydra_DATA = $(EXTRA_DIST)
|
||||
|
||||
all:
|
||||
mkdir -p $(srcdir)/static/js
|
||||
unzip -u -d $(srcdir)/static $(BOOTSTRAP)
|
||||
unzip -u -d $(srcdir)/static/js $(FLOT)
|
||||
|
||||
install-data-local: $(ZIPS)
|
||||
mkdir -p $(hydradir)/static/js
|
||||
cp -prvd $(srcdir)/static/js/* $(hydradir)/static/js
|
||||
mkdir -p $(hydradir)/static/bootstrap
|
||||
cp -prvd $(srcdir)/static/bootstrap/* $(hydradir)/static/bootstrap
|
@@ -1,7 +1,14 @@
|
||||
[% WRAPPER layout.tt title="Latest builds" _
|
||||
(job ? " for job $project.name:$jobset.name:$job" :
|
||||
jobset ? " for jobset $project.name:$jobset.name" :
|
||||
project ? " for project $project.name" : "") %]
|
||||
[% WRAPPER layout.tt
|
||||
titleHTML="Latest builds" _
|
||||
(job ? " for job " _ linkToJob(jobset, job) :
|
||||
jobset ? " for jobset " _ linkToJobset(jobset) :
|
||||
project ? " for project " _ linkToProject(project) :
|
||||
"")
|
||||
title="Latest builds" _
|
||||
(job ? " for job " _ makeNameTextForJob(jobset, job) :
|
||||
jobset ? " for jobset " _ makeNameTextForJobset(jobset) :
|
||||
project ? " for project $project.name" :
|
||||
"") %]
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
<p>Showing builds [% (page - 1) * resultsPerPage + 1 %] - [% (page - 1) * resultsPerPage + builds.size %] out of [% total %] in order of descending finish time.</p>
|
||||
|
@@ -31,36 +31,37 @@
|
||||
[% ELSE %]
|
||||
|
||||
<div id="hydra-signin" class="modal hide fade" tabindex="-1" role="dialog" aria-hidden="true">
|
||||
<form class="form-horizontal">
|
||||
<div class="modal-body">
|
||||
<div class="control-group">
|
||||
<label class="control-label">User name</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="username" value=""/>
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<form id="signin-form">
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<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 class="control-group">
|
||||
<label class="control-label">Password</label>
|
||||
<div class="controls">
|
||||
<input type="password" class="span3" name="password" value=""/>
|
||||
<div class="modal-footer">
|
||||
<button type="submit" class="btn btn-primary">Sign in</button>
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<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>
|
||||
|
||||
function finishSignOut() { }
|
||||
|
||||
$("#do-signin").click(function() {
|
||||
$("#signin-form").submit(function(e) {
|
||||
e.preventDefault();
|
||||
requestJSON({
|
||||
url: "[% c.uri_for('/login') %]",
|
||||
data: $(this).parents("form").serialize(),
|
||||
data: $(this).serialize(),
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
window.location.reload();
|
||||
@@ -82,7 +83,7 @@
|
||||
function onGoogleSignIn(googleUser) {
|
||||
requestJSON({
|
||||
url: "[% c.uri_for('/google-login') %]",
|
||||
data: "id_token=" + googleUser.getAuthResponse().id_token,
|
||||
data: "id_token=" + googleUser.credential,
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
window.location.reload();
|
||||
@@ -91,9 +92,6 @@
|
||||
return false;
|
||||
};
|
||||
|
||||
$("#google-signin").click(function() {
|
||||
$(".g-signin2:first-child > div").click();
|
||||
});
|
||||
</script>
|
||||
[% END %]
|
||||
|
||||
|
Binary file not shown.
BIN
src/root/bootstrap-4.3.1-dist.zip
Normal file
BIN
src/root/bootstrap-4.3.1-dist.zip
Normal file
Binary file not shown.
@@ -4,6 +4,6 @@
|
||||
|
||||
<div class="dep-tree">
|
||||
<ul class="tree">
|
||||
[% INCLUDE renderNode node=buildTimeGraph %]
|
||||
[% INCLUDE renderNode node=buildTimeGraph isRoot=1 %]
|
||||
</ul>
|
||||
</div>
|
||||
|
@@ -1,4 +1,7 @@
|
||||
[% WRAPPER layout.tt title="Build $id of job $project.name:$jobset.name:$job" %]
|
||||
[% WRAPPER layout.tt
|
||||
title="Build $id of job " _ makeNameTextForJob(jobset, job)
|
||||
titleHTML="Build $id of job " _ linkToJob(jobset, job)
|
||||
%]
|
||||
[% PROCESS common.tt %]
|
||||
[% PROCESS "product-list.tt" %]
|
||||
[% USE HTML %]
|
||||
@@ -58,21 +61,7 @@ END;
|
||||
<td>[% IF step.busy != 0 || ((step.machine || step.starttime) && (step.status == 0 || step.status == 1 || step.status == 3 || step.status == 4 || step.status == 7)); INCLUDE renderMachineName machine=step.machine; ELSE; "<em>n/a</em>"; END %]</td>
|
||||
<td class="step-status">
|
||||
[% IF step.busy != 0 %]
|
||||
[% 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 == 40 %]
|
||||
<strong>Receiving outputs</strong>
|
||||
[% ELSIF step.busy == 50 %]
|
||||
<strong>Post-processing</strong>
|
||||
[% ELSE %]
|
||||
<strong>Unknown state</strong>
|
||||
[% END %]
|
||||
[% INCLUDE renderBusyStatus %]
|
||||
[% ELSIF step.status == 0 %]
|
||||
[% IF step.isnondeterministic %]
|
||||
<span class="warn">Succeeded with non-determistic result</span>
|
||||
@@ -114,41 +103,39 @@ END;
|
||||
[% END %]
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle actions" data-toggle="dropdown" href="#">
|
||||
Actions
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" area-haspopup="true" aria-expanded="false">Actions</a>
|
||||
<div class="dropdown-menu">
|
||||
[% 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 %]
|
||||
[% IF c.user_exists %]
|
||||
[% IF available %]
|
||||
[% 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 %]
|
||||
<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 %]
|
||||
[% 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 %]
|
||||
<li><a href="[% c.uri_for('/build' build.id 'cancel') %]">Cancel</a></li>
|
||||
<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 'cancel') %]">Cancel</a>
|
||||
<a class="dropdown-item" href="[% c.uri_for('/build' build.id 'bump') %]">Bump up</a>
|
||||
[% END %]
|
||||
[% END %]
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li class="active"><a href="#tabs-summary" data-toggle="tab">Summary</a></li>
|
||||
[% IF isAggregate %]<li><a href="#tabs-constituents" data-toggle="tab">Constituents</a></li>[% END %]
|
||||
<li><a href="#tabs-details" data-toggle="tab">Details</a></li>
|
||||
<li><a 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 build.dependents %]<li><a 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 localStore && available %]<li><a href="#tabs-runtime-deps" data-toggle="tab">Runtime dependencies</a></li>[% END %]
|
||||
<li class="nav-item"><a class="nav-link active" href="#tabs-summary" data-toggle="tab">Summary</a></li>
|
||||
[% IF isAggregate %]<li class="nav-item"><a class="nav-link" href="#tabs-constituents" data-toggle="tab">Constituents</a></li>[% END %]
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-details" data-toggle="tab">Details</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-buildinputs" data-toggle="tab">Inputs</a></li>
|
||||
[% 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 class="nav-item"><a class="nav-link" href="#tabs-usedby" data-toggle="tab">Used By</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 class="nav-item"><a class="nav-link" href="#tabs-runtime-deps" data-toggle="tab">Runtime Dependencies</a></li>[% END %]
|
||||
[% IF runcommandlogProblem || runcommandlogs.size() > 0 %]<li class="nav-item"><a class="nav-link" href="#tabs-runcommandlogs" data-toggle="tab">RunCommand Logs[% IF runcommandlogProblem %] <span class="badge badge-warning">Disabled</span>[% END %]</a></li>[% END %]
|
||||
</ul>
|
||||
|
||||
<div id="generic-tabs" class="tab-content">
|
||||
@@ -239,9 +226,9 @@ END;
|
||||
<th>Logfile:</th>
|
||||
<td>
|
||||
[% 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-mini" href="[%actualLog%]/raw">raw</a>
|
||||
<a class="btn btn-mini" href="[%actualLog%]/tail">tail</a>
|
||||
<a class="btn btn-secondary btn-sm" href="[%actualLog%]">pretty</a>
|
||||
<a class="btn btn-secondary btn-sm" href="[%actualLog%]/raw">raw</a>
|
||||
<a class="btn btn-secondary btn-sm" href="[%actualLog%]/tail">tail</a>
|
||||
</td>
|
||||
</tr>
|
||||
[% END %]
|
||||
@@ -477,60 +464,136 @@ END;
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% IF drvAvailable %]
|
||||
[% INCLUDE makeLazyTab tabName="tabs-build-deps" uri=c.uri_for('/build' build.id 'build-deps') %]
|
||||
[% INCLUDE makeLazyTab tabName="tabs-build-deps" uri=c.uri_for('/build' build.id 'build-deps') callback="makeTreeCollapsible" %]
|
||||
[% END %]
|
||||
|
||||
[% IF available %]
|
||||
[% INCLUDE makeLazyTab tabName="tabs-runtime-deps" uri=c.uri_for('/build' build.id 'runtime-deps') %]
|
||||
[% INCLUDE makeLazyTab tabName="tabs-runtime-deps" uri=c.uri_for('/build' build.id 'runtime-deps') callback="makeTreeCollapsible" %]
|
||||
[% END %]
|
||||
|
||||
<div id="tabs-runcommandlogs" class="tab-pane">
|
||||
[% IF runcommandlogProblem %]
|
||||
<div class="alert alert-warning" role="alert">
|
||||
[% IF runcommandlogProblem == "disabled-server" %]
|
||||
This server does not enable Dynamic RunCommand support.
|
||||
[% ELSIF runcommandlogProblem == "disabled-project" %]
|
||||
This project does not enable Dynamic RunCommand support.
|
||||
[% ELSIF runcommandlogProblem == "disabled-jobset" %]
|
||||
This jobset does not enable Dynamic RunCommand support.
|
||||
[% ELSE %]
|
||||
Dynamic RunCommand is not enabled: [% runcommandlogProblem %].
|
||||
[% END %]
|
||||
</div>
|
||||
[% END %]
|
||||
<div class="d-flex flex-column">
|
||||
[% FOREACH runcommandlog IN runcommandlogs %]
|
||||
<div class="p-2 border-bottom">
|
||||
<div class="d-flex flex-row">
|
||||
<div class="d-flex flex-column" style="padding: 10px; width: 50px;">
|
||||
[% IF runcommandlog.did_succeed() %]
|
||||
<img src="[% c.uri_for("/static/images/emojione-check-2714.svg") %]" height="30" width="30" title="Succeeded" alt="Succeeded" class="build-status" />
|
||||
[% ELSIF runcommandlog.is_running() %]
|
||||
|
||||
[% ELSE %]
|
||||
<img src="[% c.uri_for("/static/images/emojione-red-x-274c.svg") %]" height="30" width="30" title="Failed" alt="Failed" class="build-status" />
|
||||
[% END %]
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column mr-auto align-self-center">
|
||||
<div><tt>[% runcommandlog.command | html%]</tt></div>
|
||||
<div>
|
||||
[% IF not runcommandlog.is_running() %]
|
||||
[% IF runcommandlog.did_fail_with_signal() %]
|
||||
Exit signal: [% runcommandlog.signal %]
|
||||
[% IF runcommandlog.core_dumped %]
|
||||
(Core Dumped)
|
||||
[% END %]
|
||||
[% ELSIF runcommandlog.did_fail_with_exec_error() %]
|
||||
Exec error: [% runcommandlog.error_number %]
|
||||
[% ELSIF not runcommandlog.did_succeed() %]
|
||||
Exit code: [% runcommandlog.exit_code %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex flex-column align-items-end">
|
||||
[% IF runcommandlog.start_time != undef %]
|
||||
<div>Started at [% INCLUDE renderDateTime timestamp = runcommandlog.start_time; %]</div>
|
||||
<div class="d-flex flex-column align-items-end">
|
||||
[% IF runcommandlog.end_time != undef %]
|
||||
Ran for [% INCLUDE renderDuration duration = runcommandlog.end_time - runcommandlog.start_time %]
|
||||
[% ELSE %]
|
||||
Running for [% INCLUDE renderDuration duration = curTime - runcommandlog.start_time %]
|
||||
[% END %]
|
||||
[% IF runcommandlog.uuid != undef %]
|
||||
[% runLog = c.uri_for('/build', build.id, 'runcommandlog', runcommandlog.uuid) %]
|
||||
<div>
|
||||
<a class="btn btn-secondary btn-sm" href="[% runLog %]">pretty</a>
|
||||
<a class="btn btn-secondary btn-sm" href="[% runLog %]/raw">raw</a>
|
||||
<a class="btn btn-secondary btn-sm" href="[% runLog %]/tail">tail</a>
|
||||
</div>
|
||||
[% END %]
|
||||
</div>
|
||||
[% ELSE %]
|
||||
<div>Pending</div>
|
||||
[% END %]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
[% END %]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<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">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h3>Reproduce this build</h3>
|
||||
</div>
|
||||
<div class="modal-header">
|
||||
<h3>Reproduce this build</h3>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
</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
|
||||
installed</a>, you can reproduce this build on your own machine by
|
||||
running the following command:</p>
|
||||
<p>If you have <a href='https://nixos.org/download/'>Nix
|
||||
installed</a>, you can reproduce this build on your own machine by
|
||||
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) %]
|
||||
</pre>
|
||||
</code></div></div>
|
||||
|
||||
[% ELSE %]
|
||||
[% ELSE %]
|
||||
|
||||
<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
|
||||
downloading <a [% HTML.attributes(href => url) %]>a script</a>
|
||||
that checks out all inputs of the build and then invokes Nix to
|
||||
perform the build.</p>
|
||||
<p>If you have <a href='https://nixos.org/download/'>Nix
|
||||
installed</a>, you can reproduce this build on your own machine by
|
||||
downloading <a [% HTML.attributes(href => url) %]>a script</a>
|
||||
that checks out all inputs of the build and then invokes Nix to
|
||||
perform the build.</p>
|
||||
|
||||
<p>To download and execute the script from the command line, run the
|
||||
following command:</p>
|
||||
<p>To download and execute the script from the command line, run the
|
||||
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
|
||||
</pre>
|
||||
</code></div></div>
|
||||
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="btn btn-primary" data-dismiss="modal">Close</a>
|
||||
<div class="modal-footer">
|
||||
<a href="#" class="btn btn-primary" data-dismiss="modal">Close</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@@ -6,21 +6,24 @@
|
||||
href="http://nixos.org/">Nix package manager</a>. If you have Nix
|
||||
installed, you can subscribe to this channel by once executing</p>
|
||||
|
||||
<pre>
|
||||
$ nix-channel --add [% curUri +%]
|
||||
$ nix-channel --update</pre>
|
||||
<div class="card bg-light"><div class="card-body"><pre>
|
||||
<span class="shell-prompt">$ </span>nix-channel --add [% curUri +%]
|
||||
<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>
|
||||
|
||||
<pre>
|
||||
$ nix-env -qa '*'
|
||||
$ nix-env -i foo</pre>
|
||||
<div class="card bg-light"><div class="card-body"><pre>
|
||||
<span class="shell-prompt">$ </span>nix-env -qa '*'
|
||||
<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>
|
||||
|
||||
<pre>
|
||||
$ nix-channel --update
|
||||
$ nix-env -u '*'</pre>
|
||||
<div class="card bg-light"><div class="card-body"><pre>
|
||||
<span class="shell-prompt">$ </span>nix-channel --update
|
||||
<span class="shell-prompt">$ </span>nix-env -u '*'
|
||||
</pre></div></div>
|
||||
|
||||
[% IF genericChannel %]
|
||||
|
||||
|
@@ -80,7 +80,7 @@ BLOCK renderFullJobName %]
|
||||
|
||||
|
||||
BLOCK renderFullJobNameOfBuild;
|
||||
INCLUDE renderFullJobName project=build.get_column("project") jobset = build.get_column("jobset") job = build.get_column("job");
|
||||
INCLUDE renderFullJobName project=build.jobset.get_column("project") jobset = build.jobset.get_column("name") job = build.get_column("job");
|
||||
END;
|
||||
|
||||
|
||||
@@ -91,6 +91,17 @@ BLOCK renderDuration;
|
||||
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> ([% action %] of [% drvname %])</em>[% END;
|
||||
END;
|
||||
END;
|
||||
|
||||
|
||||
BLOCK renderBuildListHeader %]
|
||||
<table class="table table-striped table-condensed clickable-rows">
|
||||
@@ -127,11 +138,16 @@ BLOCK renderBuildListBody;
|
||||
</td>
|
||||
[% END %]
|
||||
[% 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 %]
|
||||
<td><a class="row-link" href="[% link %]">[% build.id %]</a></td>
|
||||
[% IF !hideJobName %]
|
||||
<td><a href="[%link%]">[% IF !hideJobsetName %][%build.get_column("project")%]:[%build.get_column("jobset")%]:[% END %][%build.get_column("job")%]</td>
|
||||
<td>
|
||||
<a href="[%link%]">[% IF !hideJobsetName %][%build.jobset.get_column("project")%]:[%build.jobset.get_column("name")%]:[% END %][%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') ? build.get_column('releasename') : build.nixname %]</td>
|
||||
@@ -182,7 +198,7 @@ BLOCK renderSelection;
|
||||
[% END %]
|
||||
</div>
|
||||
[% 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 %]
|
||||
<option [% IF name == curValue; "selected='selected'"; END; " "; HTML.attributes(value => name) %]>[% options.$name %]</option>
|
||||
[% END %]
|
||||
@@ -245,6 +261,27 @@ BLOCK renderBuildStatusIcon;
|
||||
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;
|
||||
@@ -374,7 +411,7 @@ BLOCK renderInputDiff; %]
|
||||
[% ELSIF bi1.uri == bi2.uri && bi1.revision != bi2.revision %]
|
||||
[% IF bi1.type == "git" %]
|
||||
<tr><td>
|
||||
<b>[% bi1.name %]</b></td><td><tt>[% INCLUDE renderDiffUri contents=(bi1.revision.substr(0, 6) _ ' to ' _ bi2.revision.substr(0, 6)) %]</tt>
|
||||
<b>[% bi1.name %]</b></td><td><tt>[% INCLUDE renderDiffUri contents=(bi1.revision.substr(0, 12) _ ' to ' _ bi2.revision.substr(0, 12)) %]</tt>
|
||||
</td></tr>
|
||||
[% ELSE %]
|
||||
<tr><td>
|
||||
@@ -405,11 +442,11 @@ BLOCK renderInputDiff; %]
|
||||
|
||||
|
||||
BLOCK renderPager %]
|
||||
<ul class="pager">
|
||||
<li [% IF page == 1 %]class="disabled"[% END %]><a href="[% "$baseUri?page=1" %]">« First</a></li>
|
||||
<li [% IF page == 1 %]class="disabled"[% END %]><a href="[% "$baseUri?page="; (page - 1) %]">‹ Previous</a></li>
|
||||
<li [% IF page * resultsPerPage >= total %]class="disabled"[% END %]><a href="[% "$baseUri?page="; (page + 1) %]">Next ›</a></li>
|
||||
<li [% IF page * resultsPerPage >= total %]class="disabled"[% END %]><a href="[% "$baseUri?page="; (total - 1) div resultsPerPage + 1 %]">Last »</a></li>
|
||||
<ul class="pagination">
|
||||
<li class="page-item[% IF page == 1 %] disabled[% END %]"><a class="page-link" href="[% "$baseUri?page=1" %]">« First</a></li>
|
||||
<li class="page-item[% IF page == 1 %] disabled[% END %]"><a class="page-link" href="[% "$baseUri?page="; (page - 1) %]">‹ Previous</a></li>
|
||||
<li class="page-item[% IF page * resultsPerPage >= total %] disabled[% END %]"><a class="page-link" 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="; (total - 1) div resultsPerPage + 1 %]">Last »</a></li>
|
||||
</ul>
|
||||
[% END;
|
||||
|
||||
@@ -439,10 +476,7 @@ BLOCK renderEvals %]
|
||||
[% END %]
|
||||
<th rowspan="2" style="width: 10em">Date</th>
|
||||
<th rowspan="2">Input changes</th>
|
||||
<th colspan="3">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>
|
||||
<th colspan="4">Jobs</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th style="width: 2em">
|
||||
@@ -454,6 +488,9 @@ BLOCK renderEvals %]
|
||||
<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>
|
||||
@@ -476,34 +513,34 @@ BLOCK renderEvals %]
|
||||
ELSE %]
|
||||
-
|
||||
[% END %]
|
||||
[% IF eval.evaluationerror.errormsg %]
|
||||
<span class="label label-warning">Eval Errors</span>
|
||||
[% IF eval.evaluationerror.has_error %]
|
||||
<span class="badge badge-warning">Eval Errors</span>
|
||||
[% END %]
|
||||
</td>
|
||||
<td align='right' class="nowrap">
|
||||
<span class="label label-success">[% e.nrSucceeded %]</span>
|
||||
<span class="badge badge-success">[% e.nrSucceeded %]</span>
|
||||
</td>
|
||||
<td align="right" class="nowrap">
|
||||
[% IF e.nrFailed > 0 %]
|
||||
<span class="label label-important">[% e.nrFailed %]</span>
|
||||
<span class="badge badge-danger">[% e.nrFailed %]</span>
|
||||
[% END %]
|
||||
</td>
|
||||
<td align="right" class="nowrap">
|
||||
[% IF e.nrScheduled > 0 %]
|
||||
<span class="label">[% e.nrScheduled %]</span>
|
||||
<span class="badge badge-secondary">[% e.nrScheduled %]</span>
|
||||
[% END %]
|
||||
</td>
|
||||
<td align='right' class="nowrap">
|
||||
[% 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 %]
|
||||
<span class='label label-important'><strong>[% e.diff %]</strong></span>
|
||||
<span class='badge badge-danger'><strong>[% e.diff %]</strong></span>
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
[% END;
|
||||
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 %]
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -517,25 +554,39 @@ BLOCK renderLogLinks %]
|
||||
|
||||
BLOCK makeLazyTab %]
|
||||
<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>
|
||||
<script>
|
||||
$(function() { makeLazyTab("[% tabName %]", "[% uri %]"); });
|
||||
[% IF callback.defined %]
|
||||
$(function() { makeLazyTab("[% tabName %]", "[% uri %]", [% callback %] ); });
|
||||
[% ELSE %]
|
||||
$(function() { makeLazyTab("[% tabName %]", "[% uri %]", null ); });
|
||||
[% END %]
|
||||
</script>
|
||||
[% END;
|
||||
|
||||
|
||||
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 %]
|
||||
</div>
|
||||
</button>
|
||||
[% END;
|
||||
|
||||
|
||||
BLOCK menuItem %]
|
||||
<li class="[% IF "${root}${curUri}" == uri %]active[% END %]" [% IF confirmmsg %]onclick="javascript:return confirm('[% confirmmsg %]')"[% END %]>
|
||||
<a [% HTML.attributes(href => uri) %] [%+ IF modal %]data-toggle="modal"[% END %]>
|
||||
[% IF icon %]<i class="[% icon %] icon-black"></i> [%+ END %]
|
||||
<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) %]>
|
||||
[% title %]
|
||||
</a>
|
||||
</li>
|
||||
@@ -588,35 +639,35 @@ BLOCK renderJobsetOverview %]
|
||||
<td>[% HTML.escape(j.description) %]</td>
|
||||
<td>[% IF j.lastcheckedtime;
|
||||
INCLUDE renderDateTime timestamp = j.lastcheckedtime;
|
||||
IF j.errormsg || j.fetcherrormsg; %] <span class = 'label label-warning'>Error</span>[% END;
|
||||
IF j.has_error || j.fetcherrormsg; %] <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 = 'label' %]
|
||||
[% class = 'badge badge-secondary' %]
|
||||
[% ELSIF successrate < 25 %]
|
||||
[% class = 'label label-important' %]
|
||||
[% class = 'badge badge-danger' %]
|
||||
[% ELSIF successrate < 75 %]
|
||||
[% class = 'label label-warning' %]
|
||||
[% class = 'badge badge-warning' %]
|
||||
[% ELSIF successrate <= 100 %]
|
||||
[% class = 'label label-success' %]
|
||||
[% 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="label label-success">[% j.get_column('nrsucceeded') %]</span>
|
||||
<span class="badge badge-success">[% j.get_column('nrsucceeded') %]</span>
|
||||
[% END %]
|
||||
</td>
|
||||
<td>
|
||||
[% 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 %]
|
||||
</td>
|
||||
<td>
|
||||
[% 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 %]
|
||||
</td>
|
||||
</tr>
|
||||
|
@@ -2,9 +2,9 @@
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="active"><a 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><a href="#tabs-my-jobsets" data-toggle="tab">My jobsets</a></li>
|
||||
<li class="nav-item"><a class="nav-link active" href="#tabs-starred-jobs" data-toggle="tab">Starred Jobs</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-my-jobs" data-toggle="tab">My Jobs</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-my-jobsets" data-toggle="tab">My Jobsets</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="generic-tabs" class="tab-content">
|
||||
|
@@ -19,9 +19,16 @@
|
||||
<tt>[% node.name %]</tt> (<em>no info</em>)
|
||||
[% END %]
|
||||
</span></span>
|
||||
[% IF isRoot %]
|
||||
<span class="dep-tree-buttons">
|
||||
(<a href="#" class="tree-collapse-all">collapse all</a>
|
||||
–
|
||||
<a href="#" class="tree-expand-all">expand all</a>)
|
||||
</span>
|
||||
[% END %]
|
||||
[% IF node.refs.size > 0 %]
|
||||
<ul class="subtree">
|
||||
[% FOREACH ref IN node.refs; INCLUDE renderNode node=ref; END %]
|
||||
[% FOREACH ref IN node.refs; INCLUDE renderNode node=ref isRoot=0; END %]
|
||||
</ul>
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
@@ -1,15 +1,15 @@
|
||||
[% WRAPPER layout.tt title=
|
||||
(create ? "Creating jobset in project $project.name" :
|
||||
createFromEval ? "Creating jobset from evaluation $eval.id of $project.name:$jobset.name" :
|
||||
cloneJobset ? "Cloning jobset $project.name:$jobset.name" :
|
||||
"Editing jobset $project.name:$jobset.name") %]
|
||||
createFromEval ? "Creating jobset from evaluation $eval.id of " _ makeNameTextForJobset(jobset) :
|
||||
cloneJobset ? "Cloning jobset " _ makeNameTextForJobset(jobset) :
|
||||
"Editing jobset " _ makeNameTextForJobset(jobset)) %]
|
||||
[% PROCESS common.tt %]
|
||||
[% USE format %]
|
||||
|
||||
[% BLOCK renderJobsetInput %]
|
||||
<tr class="input [% extraClass %]" [% IF id %]id="[% id %]"[% END %]>
|
||||
<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>
|
||||
<input type="text" id="[% baseName %]-name" name="[% baseName %]-name" [% HTML.attributes(value => input.name) %]/>
|
||||
@@ -51,130 +51,151 @@
|
||||
[% INCLUDE renderJobsetInput input=input baseName="input-$input.name" %]
|
||||
[% END %]
|
||||
<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="5" 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>
|
||||
</tbody>
|
||||
</table>
|
||||
[% 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 or jobset.enabled == undef %] active[% END %]">
|
||||
<input type="radio" id="editjobsetenabled" name="enabled" value="1" [% IF jobset.enabled == 1 or jobset.enabled == undef %]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">
|
||||
<label class="control-label">State</label>
|
||||
<div class="controls">
|
||||
<div class="btn-group" data-toggle="buttons-radio">
|
||||
<input type="hidden" name="enabled" value="[% jobset.enabled %]" />
|
||||
<button type="button" class="btn" value="1">Enabled</button>
|
||||
<button type="button" class="btn" value="2">One-shot</button>
|
||||
<button type="button" class="btn" value="3">One-at-a-time</button>
|
||||
<button type="button" class="btn" value="0">Disabled</button>
|
||||
<div class="form-group row">
|
||||
<label class="col-form-label col-sm-3" for="editjobsetvisible">Visible</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="checkbox" id="editjobsetvisible" name="visible" [% IF !jobset.hidden; 'checked="checked"'; END %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<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="editjobsetflake">Flake URI</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="editjobsetflake" name="flake" [% 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 class="control-group">
|
||||
<div class="controls">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="visible" [% IF !jobset.hidden; 'checked="checked"'; END %]/>Visible
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editjobsetschedulingshares">
|
||||
Scheduling shares
|
||||
[% IF totalShares %]
|
||||
<small class="form-text text-muted">([% f = format("%.2f"); f(jobset.schedulingshares / totalShares * 100) %]% out of [% totalShares %] shares)</small>
|
||||
[% 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 class="control-group">
|
||||
<label class="control-label">Identifier</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="name" [% HTML.attributes(value => edit ? jobset.name : "") %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Description</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="description" [% HTML.attributes(value => jobset.description) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Type</label>
|
||||
<div class="controls">
|
||||
<div class="btn-group" data-toggle="buttons-radio">
|
||||
<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 class="control-group show-on-flake">
|
||||
<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">
|
||||
<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>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editjobsetenable_dynamic_run_command">Enable Dynamic RunCommand Hooks</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="checkbox" id="editjobsetenable_dynamic_run_command" name="enable_dynamic_run_command"
|
||||
[% IF !c.config.dynamicruncommand.enable %]
|
||||
title="The server has not enabled dynamic RunCommands" disabled
|
||||
[% ELSIF !project.enable_dynamic_run_command %]
|
||||
title="The parent project has not enabled dynamic RunCommands" disabled
|
||||
[% ELSIF jobset.enable_dynamic_run_command %]
|
||||
checked
|
||||
[% END %]
|
||||
</div>
|
||||
/>
|
||||
</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 class="form-group row">
|
||||
<label class="col-sm-3" for="editjobsetenableemail">Email notification</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="checkbox" id="editjobsetenableemail" name="enableemail" [% IF jobset.enableemail %]checked[% END %] [% IF !emailNotification %]disabled[% END %]/>
|
||||
</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 class="form-group row">
|
||||
<label class="col-sm-3" for="editjobsetemailoverride">Email override</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="editjobsetemailoverride" name="emailoverride" [% HTML.attributes(value => jobset.emailoverride) %] [% IF !emailNotification %]disabled[% 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 class="form-group row">
|
||||
<label class="col-sm-3" for="editjobsetkeepnumber">Number of evaluations to keep</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="number" class="form-control" id="editjobsetkeepnumber" name="keepnr" [% HTML.attributes(value => jobset.keepnr) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
[% INCLUDE renderJobsetInputs %]
|
||||
[% 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>
|
||||
<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>
|
||||
|
||||
<table style="display: none">
|
||||
[% INCLUDE renderJobsetInput input="" extraClass="template" id="input-template" baseName="input-template" %]
|
||||
@@ -187,7 +208,7 @@
|
||||
var id = 0;
|
||||
|
||||
function update() {
|
||||
if ($("#type").val() == 0) {
|
||||
if ($("input[type='radio'][name='type']:checked").val() == 0) {
|
||||
$(".show-on-legacy").show();
|
||||
$(".show-on-flake").hide();
|
||||
} else {
|
||||
@@ -196,8 +217,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
$("#type-flake").click(function() { update(); });
|
||||
$("#type-legacy").click(function() { update(); });
|
||||
$("input[type='radio'][name='type']").change(function() { update(); });
|
||||
|
||||
update();
|
||||
|
||||
|
@@ -1,97 +1,120 @@
|
||||
[% WRAPPER layout.tt title=(create ? "New project" : "Editing project $project.name") %]
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
<form class="form-horizontal">
|
||||
<form>
|
||||
|
||||
<fieldset>
|
||||
|
||||
<div class="control-group">
|
||||
<div class="controls">
|
||||
<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 class="form-group row">
|
||||
<label class="col-sm-3" for="editprojectenabled">Enabled</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="checkbox" id="editprojectenabled" name="enabled" [% IF create || project.enabled %] checked="checked" [% END %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Identifier</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="name" [% HTML.attributes(value => project.name) %]/>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editprojectvisible">Visible in projects list</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="checkbox" id="editprojectvisible" name="visible" [% IF !project.hidden %] checked="checked" [% END %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Display name</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="displayname" [% HTML.attributes(value => project.displayname) %]/>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editprojectidentifier">Identifier</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="editprojectidentifier" name="name" [% HTML.attributes(value => project.name) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Description</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="description" [% HTML.attributes(value => project.description) %]/>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editprojectdisplayname">Display name</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="editprojectdisplayname" name="displayname" [% HTML.attributes(value => project.displayname) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Homepage</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="homepage" [% HTML.attributes(value => project.homepage) %]/>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editprojectdescription">Description</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="editprojectdescription" name="description" [% HTML.attributes(value => project.description) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Owner</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="owner" [% HTML.attributes(value => project.owner.username || c.user.username) %]/>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editprojecthomepage">Homepage</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="editprojecthomepage" name="homepage" [% HTML.attributes(value => project.homepage) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Declarative spec file</label>
|
||||
<div class="controls">
|
||||
<div class="input-append">
|
||||
<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 class="form-group row">
|
||||
<label class="col-sm-3" for="editprojectowner">Owner</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="editprojectowner" name="owner" [% HTML.attributes(value => project.owner.username || c.user.username) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Declarative input type</label>
|
||||
<div class="controls">
|
||||
[% INCLUDE renderSelection param="decltype" options=inputTypes edit=1 curValue=project.decltype %]
|
||||
value
|
||||
<input style="width: 70%" type="text" [% HTML.attributes(value => project.declvalue, name => "declvalue") %]/>
|
||||
</div>
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editprojectenable_dynamic_run_command">Enable Dynamic RunCommand Hooks for Jobsets</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="checkbox" id="editprojectenable_dynamic_run_command" name="enable_dynamic_run_command"
|
||||
[% IF !c.config.dynamicruncommand.enable %]
|
||||
title="The server has not enabled dynamic RunCommands" disabled
|
||||
[% ELSIF project.enable_dynamic_run_command %]
|
||||
checked
|
||||
[% END %]
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-actions">
|
||||
<button id="submit-project" type="submit" class="btn btn-primary">
|
||||
<i class="icon-ok icon-white"></i>
|
||||
[%IF create %]Create project[% ELSE %]Apply changes[% END %]
|
||||
</button>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editprojectdeclfile">
|
||||
Declarative spec file
|
||||
<small class="form-text text-muted">(Leave blank for non-declarative project configuration)</small>
|
||||
</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="editprojectdeclfile" name="declfile" [% HTML.attributes(value => project.declfile) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</fieldset>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="editprojectdeclvalue">Declarative input type</label>
|
||||
<div class="col-sm-9">
|
||||
[% INCLUDE renderSelection param="decltype" options=inputTypes edit=1 curValue=project.decltype %]
|
||||
<input type="text" class="form-control" id="editprojectdeclvalue" name="declvalue" [% HTML.attributes(value => project.declvalue) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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>
|
||||
|
||||
<script type="text/javascript">
|
||||
$("#submit-project").click(function() {
|
||||
var formElements = $(this).parents("form").serializeArray();
|
||||
var data = { 'declarative': {} };
|
||||
var decl = {};
|
||||
for (var i = 0; formElements.length > i; i++) {
|
||||
var elem = formElements[i];
|
||||
var match = elem.name.match(/^decl(file|type|value)$/);
|
||||
if (match === null) {
|
||||
data[elem.name] = elem.value;
|
||||
} else {
|
||||
var param = match[1];
|
||||
decl[param] = elem.value;
|
||||
}
|
||||
}
|
||||
data.declarative = decl;
|
||||
redirectJSON({
|
||||
[% IF create %]
|
||||
url: "[% c.uri_for('/project' '.new') %]",
|
||||
[% ELSE %]
|
||||
url: "[% c.uri_for('/project' project.name) %]",
|
||||
[% END %]
|
||||
data: $(this).parents("form").serialize(),
|
||||
data: JSON.stringify(data),
|
||||
contentType: 'application/json',
|
||||
type: 'PUT'
|
||||
});
|
||||
return false;
|
||||
|
26
src/root/eval-error.tt
Normal file
26
src/root/eval-error.tt
Normal file
@@ -0,0 +1,26 @@
|
||||
[% PROCESS common.tt %]
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
|
||||
[% INCLUDE style.tt %]
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<div class="tab-content tab-pane">
|
||||
<div id="tabs-errors" class="">
|
||||
[% IF eval %]
|
||||
<p>Errors occurred at [% INCLUDE renderDateTime timestamp=(eval.evaluationerror.errortime || eval.timestamp) %].</p>
|
||||
<div class="card bg-light"><div class="card-body"><pre>[% HTML.escape(eval.evaluationerror.errormsg) %]</pre></div></div>
|
||||
[% ELSIF jobset %]
|
||||
<p>Errors occurred at [% INCLUDE renderDateTime timestamp=(jobset.errortime || jobset.lastcheckedtime) %].</p>
|
||||
<div class="card bg-light"><div class="card-body"><pre>[% HTML.escape(jobset.fetcherrormsg || jobset.errormsg) %]</pre></div></div>
|
||||
[% END %]
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@@ -1,6 +1,11 @@
|
||||
[% WRAPPER layout.tt title=
|
||||
[% WRAPPER layout.tt
|
||||
title=
|
||||
(build ? "Evaluations containing build $build.id" :
|
||||
jobset ? "Evaluations of jobset $project.name:$jobset.name" :
|
||||
jobset ? "Evaluations of jobset " _ makeNameTextForJobset(jobset) :
|
||||
"Latest evaluations")
|
||||
titleHTML =
|
||||
(build ? "Evaluations containing build $build.id" :
|
||||
jobset ? "Evaluations of jobset " _ linkToJobset(jobset) :
|
||||
"Latest evaluations") %]
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
|
BIN
src/root/fontawesome-free-5.10.2-web.zip
Normal file
BIN
src/root/fontawesome-free-5.10.2-web.zip
Normal file
Binary file not shown.
@@ -18,8 +18,7 @@
|
||||
|
||||
<h3>Metric: <a [% HTML.attributes(href => c.uri_for('/job' project.name jobset.name job 'metric' metric.name)) %]><tt>[%HTML.escape(metric.name)%]</tt></a></h3>
|
||||
|
||||
[% id = "metric-" _ metric.name;
|
||||
id = id.replace('\.', '_');
|
||||
[% id = metricDivId(metric.name);
|
||||
INCLUDE createChart dataUrl=c.uri_for('/job' project.name jobset.name job 'metric' metric.name); %]
|
||||
|
||||
[% END %]
|
||||
|
@@ -1,5 +1,6 @@
|
||||
[% WRAPPER layout.tt
|
||||
title="Job $project.name:$jobset.name:$job"
|
||||
title=makeNameTextForJob(jobset, job)
|
||||
titleHTML=makeNameLinksForJob(jobset, job)
|
||||
starUri=c.uri_for(c.controller('Job').action_for('star'), c.req.captures)
|
||||
%]
|
||||
[% PROCESS common.tt %]
|
||||
@@ -15,12 +16,12 @@ removed or had an evaluation error.</div>
|
||||
[% END %]
|
||||
|
||||
<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 %]
|
||||
<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 %]
|
||||
<li><a 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-charts" data-toggle="tab">Charts</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-links" data-toggle="tab">Links</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="generic-tabs" class="tab-content">
|
||||
@@ -84,7 +85,7 @@ removed or had an evaluation error.</div>
|
||||
|
||||
[% END %]
|
||||
|
||||
[% INCLUDE makeLazyTab tabName="tabs-charts" uri=c.uri_for('/job' project.name jobset.name job 'metrics-tab') %]
|
||||
[% INCLUDE makeLazyTab tabName="tabs-charts" uri=c.uri_for('/job' project.name jobset.name job 'metric-tab') %]
|
||||
|
||||
<div id="tabs-links" class="tab-pane">
|
||||
<ul>
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
[% 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 %]
|
||||
|
||||
|
@@ -1,21 +1,23 @@
|
||||
[% WRAPPER layout.tt title="Evaluation $eval.id of jobset $project.name:$jobset.name " %]
|
||||
[% WRAPPER layout.tt
|
||||
title="Evaluation $eval.id of jobset " _ makeNameTextForJobset(jobset)
|
||||
titleHTML="Evaluation $eval.id of jobset " _ linkToJobset(jobset) %]
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
<div class="btn-group pull-right">
|
||||
<a class="btn btn-primary dropdown-toggle" data-toggle="dropdown" href="#"><i class="icon-white icon-eye-open"></i> Compare to...</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="?">Preceding evaluation in this jobset</a></li>
|
||||
<li class="divider"></li>
|
||||
<li><a href="?compare=-[% 24 * 60 * 60 %]">This jobset <strong>one day</strong> earlier</a></li>
|
||||
<li><a href="?compare=-[% 7 * 24 * 60 * 60 %]">This jobset <strong>one week</strong> earlier</a></li>
|
||||
<li><a href="?compare=-[% 31 * 24 * 60 * 60 %]">This jobset <strong>one month</strong> earlier</a></li>
|
||||
<div class="dropdown">
|
||||
<button class="btn btn-primary dropdown-toggle float-right" data-toggle="dropdown"><i class="fas fa-eye"></i> Compare to...</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item" href="?">Preceding evaluation in this jobset</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" href="?compare=-[% 24 * 60 * 60 %]&full=[% full ? 1 : 0 %]">This jobset <strong>one day</strong> earlier</a>
|
||||
<a class="dropdown-item" href="?compare=-[% 7 * 24 * 60 * 60 %]&full=[% full ? 1 : 0 %]">This jobset <strong>one week</strong> earlier</a>
|
||||
<a class="dropdown-item" href="?compare=-[% 31 * 24 * 60 * 60 %]&full=[% full ? 1 : 0 %]">This jobset <strong>one month</strong> earlier</a>
|
||||
[% 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 %]
|
||||
<li><a href="?compare=[% j.name %]">Jobset <tt>[% project.name %]:[% j.name %]</tt></a></li>
|
||||
<a class="dropdown-item" href="?compare=[% j.name %]&full=[% full ? 1 : 0 %]">Jobset <tt>[% project.name %]:[% j.name %]</tt></a>
|
||||
[% END; END %]
|
||||
[% END %]
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>This evaluation was performed [% IF eval.flake %]from the flake
|
||||
@@ -29,70 +31,68 @@ project=otherEval.jobset.project.name jobset=otherEval.jobset.name %] evaluation
|
||||
c.uri_for(c.controller('JobsetEval').action_for('view'),
|
||||
[otherEval.id]) %]">[% otherEval.id %]</a>.</p>
|
||||
[% 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 %]
|
||||
|
||||
<form class="form-search">
|
||||
<input name="filter" type="text" class="input-large search-query" placeholder="Search jobs by name..." [% HTML.attributes(value => filter) %]/>
|
||||
<input name="compare" type="hidden" [% HTML.attributes(value => otherEval.id) %]/>
|
||||
<input name="full" type="hidden" [% HTML.attributes(value => full) %]/>
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<input name="filter" type="text" class="form-control" type="search" placeholder="Search jobs by name..." [% HTML.attributes(value => filter) %]/>
|
||||
<input name="compare" type="hidden" [% HTML.attributes(value => otherEval.id) %]/>
|
||||
<input name="full" type="hidden" [% HTML.attributes(value => full) %]/>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
[% IF c.user_exists %]
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
Actions
|
||||
<b class="caret"></b>
|
||||
</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 %]
|
||||
<li><a href="[% c.uri_for(c.controller('JobsetEval').action_for('cancel'), [eval.id]) %]">Cancel all scheduled builds</a></li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Actions</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('create_jobset'), [eval.id]) %]">Create a jobset from this evaluation</a>
|
||||
[% IF totalQueued > 0 %]
|
||||
<a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('cancel'), [eval.id]) %]">Cancel all scheduled builds</a>
|
||||
[% END %]
|
||||
[% 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>
|
||||
[% IF totalFailed > 0 %]
|
||||
<a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('restart_failed'), [eval.id]) %]">Restart all failed builds</a>
|
||||
[% END %]
|
||||
[% 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>
|
||||
[% IF totalAborted > 0 %]
|
||||
<a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('restart_aborted'), [eval.id]) %]">Restart all aborted builds</a>
|
||||
[% END %]
|
||||
[% 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>
|
||||
[% IF totalQueued > 0 %]
|
||||
<a class="dropdown-item" href="[% c.uri_for(c.controller('JobsetEval').action_for('bump'), [eval.id]) %]">Bump builds to front of queue</a>
|
||||
[% END %]
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
[% END %]
|
||||
|
||||
[% 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 / Timed out Jobs ([% aborted.size %])</span></a></li>
|
||||
[% END %]
|
||||
[% 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 %]
|
||||
[% 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 %]
|
||||
[% 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 %]
|
||||
[% 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 %]
|
||||
[% 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 %]
|
||||
[% 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 %]
|
||||
[% 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 %]
|
||||
<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 %]
|
||||
<li><a href="#tabs-errors" data-toggle="tab"><span class="text-warning">Evaluation errors</span></a></li>
|
||||
[% IF eval.evaluationerror.has_error %]
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-errors" data-toggle="tab"><span class="text-warning">Evaluation Errors</span></a></li>
|
||||
[% END %]
|
||||
|
||||
</ul>
|
||||
|
||||
[% BLOCK renderSome %]
|
||||
@@ -108,13 +108,6 @@ c.uri_for(c.controller('JobsetEval').action_for('view'),
|
||||
|
||||
<div class="tab-content">
|
||||
|
||||
[% IF eval.evaluationerror.errormsg %]
|
||||
<div id="tabs-errors" class="tab-pane">
|
||||
<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>
|
||||
[% END %]
|
||||
|
||||
<div id="tabs-aborted" class="tab-pane">
|
||||
[% INCLUDE renderSome builds=aborted tabname="#tabs-aborted" %]
|
||||
</div>
|
||||
@@ -172,10 +165,9 @@ c.uri_for(c.controller('JobsetEval').action_for('view'),
|
||||
[% END %]
|
||||
</div>
|
||||
|
||||
[% IF eval.evaluationerror.errormsg %]
|
||||
[% IF eval.evaluationerror.has_error %]
|
||||
<div id="tabs-errors" class="tab-pane">
|
||||
<p>Errors occurred at [% INCLUDE renderDateTime timestamp=(eval.evaluationerror.errortime || eval.timestamp) %].</p>
|
||||
<pre class="alert alert-error">[% HTML.escape(eval.evaluationerror.errormsg) %]</pre>
|
||||
<iframe src="[% c.uri_for(c.controller('JobsetEval').action_for('errors'), [eval.id], params) %]" loading="lazy" frameBorder="0" width="100%"></iframe>
|
||||
</div>
|
||||
[% END %]
|
||||
</div>
|
||||
|
@@ -1,12 +1,15 @@
|
||||
[% PROCESS common.tt; USE Math %]
|
||||
|
||||
<form class="form-search" id="filter-jobs">
|
||||
<div class="input-append">
|
||||
<input name="filter" type="text" class="input-large search-query" 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>
|
||||
<form id="filter-jobs">
|
||||
<div class="form-group input-group">
|
||||
<input name="filter" type="search" class="form-control" placeholder="Search jobs by name..." [% HTML.attributes(value => filter) %]/>
|
||||
<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>
|
||||
|
||||
<img src="[% c.uri_for("/static/images/ajax-loader.gif") %]" alt="Loading..." style="display: none;" id="filter-loading" />
|
||||
</form>
|
||||
|
||||
<script>
|
||||
@@ -33,12 +36,12 @@
|
||||
|
||||
[% 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 %]
|
||||
|
||||
[% 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 %]
|
||||
|
||||
[% evalIds = evals.keys.nsort.reverse %]
|
||||
|
@@ -1,4 +1,6 @@
|
||||
[% WRAPPER layout.tt title="Jobset $project.name:$jobset.name" %]
|
||||
[% WRAPPER layout.tt
|
||||
titleHTML=makeNameLinksForJobset(jobset)
|
||||
title=makeNameTextForJobset(jobset) %]
|
||||
[% PROCESS common.tt %]
|
||||
[% USE format %]
|
||||
|
||||
@@ -43,12 +45,9 @@
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
[% IF c.user_exists %]
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
Actions
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Actions</a>
|
||||
<div class="dropdown-menu">
|
||||
[% UNLESS project.declfile %]
|
||||
[% INCLUDE menuItem title="Edit configuration" icon="icon-edit" uri=c.uri_for(c.controller('Jobset').action_for('edit'), c.req.captures) %]
|
||||
<!--
|
||||
@@ -57,18 +56,18 @@
|
||||
[% INCLUDE menuItem title="Clone this jobset" uri=c.uri_for(c.controller('Jobset').action_for('edit'), c.req.captures, { cloneJobset => 1 }) %]
|
||||
[% END %]
|
||||
[% INCLUDE menuItem title="Evaluate this jobset" uri="javascript:confirmEvaluateJobset()" %]
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
[% END %]
|
||||
|
||||
<li class="active"><a href="#tabs-evaluations" data-toggle="tab">Evaluations</a></li>
|
||||
[% 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 active" href="#tabs-evaluations" data-toggle="tab">Evaluations</a></li>
|
||||
[% IF jobset.has_error || jobset.fetcherrormsg %]
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-errors" data-toggle="tab"><span class="text-warning">Evaluation Errors</span></a></li>
|
||||
[% END %]
|
||||
<li><a href="#tabs-jobs" data-toggle="tab">Jobs</a></li>
|
||||
<li><a href="#tabs-configuration" data-toggle="tab">Configuration</a></li>
|
||||
<li><a 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-jobs" data-toggle="tab">Jobs</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-configuration" data-toggle="tab">Configuration</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-links" data-toggle="tab">Links</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-channels" data-toggle="tab">Channels</a></li>
|
||||
</ul>
|
||||
|
||||
<div id="generic-tabs" class="tab-content">
|
||||
@@ -80,7 +79,7 @@
|
||||
<th>Last checked:</th>
|
||||
<td>
|
||||
[% IF jobset.lastcheckedtime %]
|
||||
[% INCLUDE renderDateTime timestamp = jobset.lastcheckedtime %], [% IF jobset.errormsg || jobset.fetcherrormsg %]<em class="text-warning">with errors!</em>[% ELSE %]<em>no errors</em>[% END %]
|
||||
[% INCLUDE renderDateTime timestamp = jobset.lastcheckedtime %], [% IF jobset.has_error || jobset.fetcherrormsg %]<em class="text-warning">with errors!</em>[% ELSE %]<em>no errors</em>[% END %]
|
||||
[% ELSE %]
|
||||
<em>never</em>
|
||||
[% END %]
|
||||
@@ -91,6 +90,7 @@
|
||||
<td>
|
||||
[% IF latestEval %]
|
||||
[% INCLUDE renderDateTime timestamp = latestEval.timestamp %]
|
||||
(took [% relativeDuration (latestEval.checkouttime + latestEval.evaltime) %])
|
||||
[% ELSE %]
|
||||
<em>never</em>
|
||||
[% END %]
|
||||
@@ -117,10 +117,9 @@
|
||||
|
||||
</div>
|
||||
|
||||
[% IF jobset.errormsg || jobset.fetcherrormsg %]
|
||||
[% IF jobset.has_error || jobset.fetcherrormsg %]
|
||||
<div id="tabs-errors" class="tab-pane">
|
||||
<p>Errors occurred at [% INCLUDE renderDateTime timestamp=(jobset.errortime || jobset.lastcheckedtime) %].</p>
|
||||
<pre class="alert alert-error">[% HTML.escape(jobset.fetcherrormsg || jobset.errormsg) %]</pre>
|
||||
<iframe src="[% c.uri_for('/jobset' project.name jobset.name "errors") %]" loading="lazy" frameBorder="0" width="100%"></iframe>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
@@ -160,6 +159,10 @@
|
||||
<th>Scheduling shares:</th>
|
||||
<td>[% jobset.schedulingshares %] [% IF totalShares %] ([% f = format("%.2f"); f(jobset.schedulingshares / totalShares * 100) %]% out of [% totalShares %] shares)[% END %]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Enable Dynamic RunCommand Hooks:</th>
|
||||
<td>[% c.config.dynamicruncommand.enable ? project.enable_dynamic_run_command ? jobset.enable_dynamic_run_command ? "Yes" : "No (not enabled by jobset)" : "No (not enabled by project)" : "No (not enabled by server)" %]</td>
|
||||
</tr>
|
||||
[% IF emailNotification %]
|
||||
<tr>
|
||||
<th>Enable email notification:</th>
|
||||
@@ -201,6 +204,7 @@
|
||||
if (!c) return;
|
||||
requestJSON({
|
||||
url: "[% HTML.escape(c.uri_for('/api/push', { jobsets = project.name _ ':' _ jobset.name, force = "1" })) %]",
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
bootbox.alert("The jobset has been scheduled for evaluation.");
|
||||
}
|
||||
|
@@ -10,31 +10,7 @@
|
||||
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<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-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>
|
||||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
|
||||
<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" />
|
||||
|
||||
<!-- hydra.css must be included before bootstrap-responsive to
|
||||
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/rotated-th.css") %]" type="text/css" />
|
||||
<link href="[% c.uri_for("/static/bootstrap/css/bootstrap-responsive.min.css") %]" rel="stylesheet" />
|
||||
|
||||
<style>
|
||||
.popover { max-width: 40%; }
|
||||
</style>
|
||||
|
||||
<script type="text/javascript" src="[% c.uri_for("/static/js/bootbox.min.js") %]"></script>
|
||||
|
||||
<link rel="stylesheet" href="[% c.uri_for("/static/css/tree.css") %]" type="text/css" />
|
||||
|
||||
<script type="text/javascript" src="[% c.uri_for("/static/js/common.js") %]"></script>
|
||||
[% INCLUDE style.tt %]
|
||||
|
||||
[% IF c.config.enable_google_login %]
|
||||
<meta name="google-signin-client_id" content="[% c.config.google_client_id %]">
|
||||
@@ -46,27 +22,23 @@
|
||||
|
||||
<body>
|
||||
|
||||
<div class="navbar navbar-fixed-top">
|
||||
<div class="navbar-inner">
|
||||
<div class="container">
|
||||
<button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="brand" href="[% c.uri_for(c.controller('Root').action_for('index')) %]">
|
||||
[% IF logo == "" %]
|
||||
Hydra
|
||||
[% ELSE %]
|
||||
<img src="[% c.uri_for(logo) %]" alt="Hydra Logo" class="logo" />
|
||||
[% END %]
|
||||
</a>
|
||||
<div class="nav-collapse collapse">
|
||||
[% PROCESS topbar.tt %]
|
||||
</div>
|
||||
<nav class="navbar navbar-expand-md navbar-light bg-light">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="[% c.uri_for(c.controller('Root').action_for('index')) %]">
|
||||
[% IF logo == "" %]
|
||||
Hydra
|
||||
[% ELSE %]
|
||||
<img src="[% c.uri_for(logo) %]" alt="Hydra Logo" class="logo" />
|
||||
[% END %]
|
||||
</a>
|
||||
<button type="button" class="navbar-toggler" data-toggle="collapse" data-target="#navbarSupportedContent">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
[% PROCESS topbar.tt %]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div class="container">
|
||||
<div class="skip-topbar"></div>
|
||||
@@ -85,7 +57,8 @@
|
||||
|
||||
[% IF !hideHeader %]
|
||||
<div class="page-header">
|
||||
[% IF c.user_exists && starUri; INCLUDE makeStar; " "; END; HTML.escape(title) %]
|
||||
[% IF c.user_exists && starUri; INCLUDE makeStar; " "; END %]
|
||||
[% IF titleHTML != ""; titleHTML; ELSE; HTML.escape(title); END %]
|
||||
</div>
|
||||
[% ELSE %]
|
||||
[% IF first %]<br />[% first = 0; END; %]
|
||||
@@ -96,7 +69,7 @@
|
||||
<footer class="navbar">
|
||||
<hr />
|
||||
<small>
|
||||
<em><a href="http://nixos.org/hydra" target="_blank">Hydra</a> [% HTML.escape(version) %] (using [% HTML.escape(nixVersion) %]).</em>
|
||||
<em><a href="http://nixos.org/hydra" target="_blank" class="squiggle">Hydra</a> [% HTML.escape(version) %] (using [% HTML.escape(nixVersion) %] and [% HTML.escape(nixEvalJobsVersion) %]).</em>
|
||||
[% IF c.user_exists %]
|
||||
You are signed in as <tt>[% HTML.escape(c.user.username) %]</tt>
|
||||
[%- IF c.user.type == 'google' %] via Google[% END %].
|
||||
|
@@ -1,4 +1,7 @@
|
||||
[% WRAPPER layout.tt title="Log of " _ (step ? " step $step.stepnr of " : "") _ "build ${build.id} of job $build.project.name:$build.jobset.name:$build.job.name" %]
|
||||
[% WRAPPER layout.tt
|
||||
titleHTML="Log of " _ (step ? " step $step.stepnr of " : "") _ "build ${build.id} of job " _ linkToJob(build.jobset, job)
|
||||
title="Log of " _ (step ? " step $step.stepnr of " : "") _ "build ${build.id} of job " _ makeNameTextForJob(build.jobset, job)
|
||||
%]
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
<p>
|
||||
@@ -8,7 +11,8 @@
|
||||
[% ELSE %]
|
||||
is
|
||||
[% END %]
|
||||
the build log of derivation <tt>[% IF step; step.drvpath; ELSE; build.drvpath; END %]</tt>.
|
||||
the build log (<a href="[% step ? c.uri_for('/build' build.id 'nixlog' step.stepnr, 'raw')
|
||||
: c.uri_for('/build' build.id 'log', 'raw') %]">raw</a>) of derivation <tt>[% IF step; step.drvpath; ELSE; build.drvpath; END %]</tt>.
|
||||
[% IF step && step.machine %]
|
||||
It was built on <tt>[% step.machine %]</tt>.
|
||||
[% END %]
|
||||
@@ -18,9 +22,9 @@
|
||||
[% END %]
|
||||
</p>
|
||||
|
||||
<pre class="log" id="contents">
|
||||
<div class="card bg-light"><div class="card-body"><pre class="log" id="contents">
|
||||
<em>Loading...</em>
|
||||
</pre>
|
||||
</pre></div></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
|
@@ -6,10 +6,10 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Job</th>
|
||||
<th>System</th>
|
||||
<th>Build</th>
|
||||
<th>Step</th>
|
||||
<th>What</th>
|
||||
<th>Status</th>
|
||||
<th>Since</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -17,7 +17,7 @@
|
||||
[% name = m.key ? stripSSHUser(m.key) : "localhost" %]
|
||||
<thead>
|
||||
<tr>
|
||||
<th colspan="6">
|
||||
<th colspan="7">
|
||||
<tt [% IF m.value.disabled %]style="text-decoration: line-through;"[% END %]>[% INCLUDE renderMachineName machine=m.key %]</tt>
|
||||
[% IF m.value.systemTypes %]
|
||||
<span class="muted" style="font-weight: normal;">
|
||||
@@ -40,10 +40,10 @@
|
||||
[% idle = 0 %]
|
||||
<tr>
|
||||
<td><tt>[% INCLUDE renderFullJobName project=step.project jobset=step.jobset job=step.job %]</tt></td>
|
||||
<td><tt>[% step.system %]</tt></td>
|
||||
<td><a href="[% c.uri_for('/build' step.build) %]">[% step.build %]</a></td>
|
||||
<td>[% IF step.busy >= 30 %]<a class="row-link" href="[% c.uri_for('/build' step.build 'nixlog' step.stepnr 'tail') %]">[% step.stepnr %]</a>[% ELSE; step.stepnr; END %]</td>
|
||||
<td><tt>[% step.drvpath.match('-(.*)').0 %]</tt></td>
|
||||
<td>[% INCLUDE renderBusyStatus %]</td>
|
||||
<td style="width: 10em">[% INCLUDE renderDuration duration = curTime - step.starttime %] </td>
|
||||
</tr>
|
||||
[% END %]
|
||||
|
@@ -14,29 +14,25 @@
|
||||
<tr>
|
||||
<td>[% INCLUDE renderDateTime timestamp=i.createtime %]</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>
|
||||
[% END %]
|
||||
</tbody>
|
||||
</table>
|
||||
[% END %]
|
||||
|
||||
<form class="form-horizontal" action="[% c.uri_for('/admin/news/submit') %]" method="post">
|
||||
<fieldset>
|
||||
<legend>Add news item</legend>
|
||||
<div class="control-group">
|
||||
<label class="control-label">News text (HTML)</label>
|
||||
<div class="controls">
|
||||
<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>
|
||||
<form action="[% c.uri_for('/admin/news/submit') %]" method="post">
|
||||
<div class="page-header">Add news item</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="newscontents">News text (HTML)</label>
|
||||
<textarea class="form-control" id="newscontents" name="contents"></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<i class="fas fa-check"></i>
|
||||
Post
|
||||
</button>
|
||||
</form>
|
||||
|
||||
[% END %]
|
||||
|
@@ -40,7 +40,7 @@
|
||||
</script>
|
||||
|
||||
<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>
|
||||
|
||||
<table class="table table-condensed table-striped clickable-rows">
|
||||
|
@@ -5,6 +5,6 @@
|
||||
[% jobset = build.jobset %]
|
||||
[% 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 %]
|
||||
|
@@ -54,11 +54,11 @@
|
||||
</a>
|
||||
</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
|
||||
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>
|
||||
[% END %]
|
||||
@@ -77,14 +77,14 @@
|
||||
<tt>[% HTML.escape(build.nixname) %]</tt>
|
||||
</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
|
||||
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 %]
|
||||
[% IF localStore %]
|
||||
<a class="btn btn-mini" href="[% contents %]">Contents</a>
|
||||
<a class="btn btn-secondary btn-sm" href="[% contents %]">Contents</a>
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
@@ -105,21 +105,21 @@
|
||||
</a>
|
||||
</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
|
||||
all its dependencies can be unpacked into your local Nix
|
||||
store by doing:</p>
|
||||
|
||||
<pre><span class="shell-prompt">$ </span>gunzip < [% filename %] | nix-store --import</pre>
|
||||
<div class="card bg-light"><div class="card-body p-2"><code><span class="shell-prompt">$ </span>gunzip < [% filename %] | nix-store --import</code></div></div>
|
||||
|
||||
<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>[%
|
||||
product.path %]</tt>. You’ll 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>
|
||||
|
||||
@@ -187,7 +187,7 @@
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
[% WRAPPER makePopover title="Details" classes="btn-mini" %]
|
||||
[% WRAPPER makePopover title="Details" classes="btn-secondary btn-sm" %]
|
||||
<table class="info-table">
|
||||
[% INCLUDE renderProductLinks %]
|
||||
<tr><th>File size:</th><td>[% product.filesize %] bytes ([% mibs(product.filesize / (1024 * 1024)) %] MiB)</td></tr>
|
||||
@@ -196,7 +196,7 @@
|
||||
</table>
|
||||
[% END %]
|
||||
[% IF localStore %]
|
||||
<a class="btn btn-mini" href="[% contents %]">Contents</a>
|
||||
<a class="btn btn-secondary btn-sm" href="[% contents %]">Contents</a>
|
||||
[% END %]
|
||||
</td>
|
||||
</tr>
|
||||
@@ -254,7 +254,7 @@
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
[% WRAPPER makePopover title="Details" classes="btn-mini" %]
|
||||
[% WRAPPER makePopover title="Details" classes="btn-secondary btn-sm" %]
|
||||
<table class="info-table">
|
||||
[% INCLUDE renderProductLinks %]
|
||||
</table>
|
||||
|
@@ -3,23 +3,20 @@
|
||||
|
||||
<ul class="nav nav-tabs">
|
||||
[% IF c.user_exists %]
|
||||
<li class="dropdown">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
Actions
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#">Actions</a>
|
||||
<div 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="Delete this project" icon="icon-trash" uri="javascript:deleteProject()" %]
|
||||
[% 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 %]
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
[% END %]
|
||||
|
||||
<li class="active"><a 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 active" href="#tabs-project" data-toggle="tab">Jobsets</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="#tabs-configuration" data-toggle="tab">Configuration</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="tab-content">
|
||||
@@ -50,12 +47,17 @@
|
||||
|
||||
<div id="tabs-project" class="tab-pane active">
|
||||
[% IF project.jobsets %]
|
||||
<p>This project has the following jobsets:
|
||||
<label id="show-disabled" class="btn btn-small pull-right" data-toggle="button">Show disabled jobsets</label>
|
||||
[% IF isProjectOwner %]
|
||||
<label id="show-hidden" class="btn btn-small pull-right" data-toggle="button">Show hidden jobsets</label>
|
||||
[% END %]
|
||||
</p>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
This project has the following jobsets:
|
||||
</div>
|
||||
<div class="col-auto">
|
||||
<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 %]
|
||||
[% ELSE %]
|
||||
<p>No jobsets have been defined yet.</p>
|
||||
@@ -90,6 +92,10 @@
|
||||
<th>Enabled:</th>
|
||||
<td>[% project.enabled ? "Yes" : "No" %]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Enable Dynamic RunCommand Hooks:</th>
|
||||
<td>[% c.config.dynamicruncommand.enable ? project.enable_dynamic_run_command ? "Yes" : "No (not enabled by project)" : "No (not enabled by server)" %]</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
|
@@ -1,8 +1,6 @@
|
||||
[% WRAPPER layout.tt title="Queue runner status" %]
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
<pre>
|
||||
[% HTML.escape(status) %]
|
||||
</pre>
|
||||
<div class="card bg-light"><div class="card-body"><pre>[% HTML.escape(status) %]</pre></div></div>
|
||||
|
||||
[% END %]
|
||||
|
@@ -7,7 +7,7 @@ main() {
|
||||
|
||||
set -e
|
||||
|
||||
tmpDir=${TMPDIR:-/tmp}/build-[% build.id +%]
|
||||
tmpDir=$(realpath "${TMPDIR:-/tmp}")/build-[% build.id +%]
|
||||
declare -a args extraArgs
|
||||
|
||||
|
||||
@@ -210,10 +210,9 @@ if [ -n "$printFlags" ]; then
|
||||
fi
|
||||
|
||||
info "running nix-build..."
|
||||
echo "using these flags: ${args[@]}" >&2
|
||||
|
||||
exec nix-build "${args[@]}" "${extraArgs[@]}"
|
||||
|
||||
echo "using the following invocation:" >&2
|
||||
set -x
|
||||
nix-build "${args[@]}" "${extraArgs[@]}"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
|
49
src/root/runcommand-log.tt
Normal file
49
src/root/runcommand-log.tt
Normal file
@@ -0,0 +1,49 @@
|
||||
[% WRAPPER layout.tt
|
||||
titleHTML="RunCommand log of " _ (step ? " step $step.stepnr of " : "") _ "build ${build.id} of job " _ linkToJob(build.jobset, job)
|
||||
title="RunCommand log of " _ (step ? " step $step.stepnr of " : "") _ "build ${build.id} of job " _ makeNameTextForJob(build.jobset, job)
|
||||
%]
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
<p>
|
||||
Below
|
||||
[% IF tail %]
|
||||
are the last lines of
|
||||
[% ELSE %]
|
||||
is
|
||||
[% END %]
|
||||
the output of a RunCommand execution of the command <tt>[% HTML.escape(runcommandlog.command) %]</tt>
|
||||
on <a href="[% c.uri_for('/build', build.id) %]">Build [% build.id %]</a>.
|
||||
[% IF tail %]
|
||||
The <a href="[% c.uri_for('/build', build.id, 'runcommandlog', runcommandlog.uuid) %]">full log</a> is also available.
|
||||
[% END %]
|
||||
</p>
|
||||
|
||||
<div class="card bg-light"><div class="card-body"><pre class="log" id="contents">
|
||||
<em>Loading...</em>
|
||||
</pre></div></div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function() {
|
||||
requestPlainFile({
|
||||
url: "[% HTML.escape(log_uri) %]",
|
||||
dataType: "text",
|
||||
type: 'GET',
|
||||
success: function (log_data) {
|
||||
|
||||
[% IF tail %]
|
||||
/* The server may give us a full log (e.g. if the log is in
|
||||
S3). So extract the last lines. */
|
||||
log_data = log_data.split("\n").slice(-[%tail%]).join("\n");
|
||||
[% END %]
|
||||
|
||||
$("#contents").text(log_data);
|
||||
},
|
||||
error: function () {
|
||||
bootbox.alert("The RunCommand log file is not available.");
|
||||
$("#contents").text("(Unavailable)");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
[% END %]
|
@@ -67,7 +67,7 @@
|
||||
<tbody>
|
||||
[% FOREACH j IN jobs %]
|
||||
<tr>
|
||||
<td><span>[% INCLUDE renderFullJobName project=j.get_column('project') jobset=j.get_column('jobset') job=j.job inRow=1 %]</span></td>
|
||||
<td><span>[% INCLUDE renderFullJobName project=j.jobset.get_column('project') jobset=j.jobset.get_column('name') job=j.job inRow=1 %]</span></td>
|
||||
</tr>
|
||||
[% END %]
|
||||
</tbody>
|
||||
@@ -81,7 +81,7 @@
|
||||
[% IF builds.size > 0 || buildsdrv.size > 0 ; matched = 1 ; END %]
|
||||
|
||||
[% 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 %]
|
||||
|
@@ -1,5 +1,5 @@
|
||||
div.skip-topbar {
|
||||
padding-top: 40px;
|
||||
padding-top: 20px;
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
@@ -33,10 +33,9 @@ span:target > span.dep-tree-line {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
:target {
|
||||
padding-top: 40px;
|
||||
margin-top: -40px;
|
||||
display: inline-block; /* required for webkit browsers */
|
||||
span.dep-tree-buttons {
|
||||
font-style: italic;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
span.disabled-project, span.disabled-jobset, span.disabled-job {
|
||||
@@ -52,11 +51,6 @@ table.info-table th {
|
||||
padding-bottom: 0.2em;
|
||||
}
|
||||
|
||||
/* Missing in bootstrap 2.0.2 */
|
||||
.text-warning {
|
||||
color: #c09853;
|
||||
}
|
||||
|
||||
table.clickable-rows > tbody > tr {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -149,6 +143,270 @@ td.step-status span.warn {
|
||||
}
|
||||
|
||||
.date {
|
||||
cursor: help;
|
||||
border-bottom: 1px dotted #999;
|
||||
cursor: help;
|
||||
border-bottom: 1px dotted #999;
|
||||
}
|
||||
|
||||
.tab-content > .tab-pane {
|
||||
padding-top: 1.5rem;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 80%;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
margin-right: 0 !important;
|
||||
}
|
||||
|
||||
body {
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
a.squiggle:hover {
|
||||
background-image: url("data:image/svg+xml;charset=utf8,%3Csvg id='squiggle-link' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' xmlns:ev='http://www.w3.org/2001/xml-events' viewBox='0 0 10 18'%3E%3Cstyle type='text/css'%3E.squiggle{animation:shift .5s linear infinite;}@keyframes shift {from {transform:translateX(-10px);}to {transform:translateX(0);}}%3C/style%3E%3Cpath fill='none' stroke='%230056b3' stroke-width='0.65' class='squiggle' d='M0,17.5 c 2.5,0,2.5,-1.5,5,-1.5 s 2.5,1.5,5,1.5 c 2.5,0,2.5,-1.5,5,-1.5 s 2.5,1.5,5,1.5' /%3E%3C/svg%3E");
|
||||
background-position: 0 100%;
|
||||
background-size: auto 24px;
|
||||
background-repeat: repeat;
|
||||
text-decoration: none;
|
||||
border-bottom: none;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
/* Prevent some flickering */
|
||||
html {
|
||||
background-color: #1f1f1f;
|
||||
}
|
||||
body, div.popover, div.popover-body {
|
||||
background-color: #1f1f1f;
|
||||
color: #fafafa !important;
|
||||
}
|
||||
|
||||
/*
|
||||
Navbar
|
||||
*/
|
||||
nav.navbar {
|
||||
background-color: #303030 !important;
|
||||
border-bottom: solid 1px #404040;
|
||||
}
|
||||
|
||||
nav.navbar a {
|
||||
color: #fafafa !important;
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
background-color: #1f1f1f;
|
||||
}
|
||||
|
||||
.dropdown-header {
|
||||
color: #999999;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.dropdown-menu .dropdown-item:hover,
|
||||
.dropdown-menu .dropdown-item.active {
|
||||
background-color: #2f2f30;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.dropdown-menu .dropdown-item.active {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
/*
|
||||
UI Elements
|
||||
*/
|
||||
label.btn-secondary,
|
||||
button.btn,
|
||||
a.btn-secondary {
|
||||
background-color: #333;
|
||||
border: none;
|
||||
box-shadow: inset 0 0 0 1px #525252;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input,
|
||||
select,
|
||||
textarea {
|
||||
color: white !important;
|
||||
background-color: #404040 !important;
|
||||
border-color: #c4c4c4;
|
||||
box-shadow: inset 0 0 0 1px #4f4f4f;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
div.card.bg-light,
|
||||
div.card,
|
||||
pre {
|
||||
background-color: #333333 !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
div.page-header {
|
||||
color: white;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
div.dropdown.show > div.dropdown-menu a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
span.muted {
|
||||
color: #666666;
|
||||
}
|
||||
|
||||
/*
|
||||
Tables
|
||||
*/
|
||||
table {
|
||||
border: 1px solid #404040;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
table.info-table, #tabs-summary table:nth-of-type(1) {
|
||||
border: none;
|
||||
}
|
||||
/* Weird fix */
|
||||
#tabs-summary table:nth-of-type(1) tr:hover a,
|
||||
div.popover td:hover a, div.popover td:hover a tt {
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
color: white;
|
||||
}
|
||||
|
||||
thead tr th, table:not(.info-table) > tbody > tr > th {
|
||||
background-color: #303030;
|
||||
border-bottom: 1px solid #333 !important;
|
||||
border-top: 1px solid #333;
|
||||
}
|
||||
|
||||
table.clickable-rows tbody tr:hover {
|
||||
background-color: #033464 !important;
|
||||
border-top: 1px solid #0b5cad;
|
||||
border-bottom: 1px solid #0b5cad;
|
||||
}
|
||||
|
||||
tbody tr:hover a:not(.btn-secondary),
|
||||
tbody tr:hover a > tt {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
tbody td {
|
||||
border-color: #404040 !important;
|
||||
}
|
||||
|
||||
.table-striped tbody tr:nth-of-type(2n+1) {
|
||||
background-color: initial;
|
||||
}
|
||||
|
||||
/*
|
||||
Tabs
|
||||
*/
|
||||
ul.nav-tabs {
|
||||
border-bottom: 1px solid #404040;
|
||||
}
|
||||
|
||||
ul.nav-tabs > li.nav-item a {
|
||||
padding: 8px;
|
||||
font-size: 14px;
|
||||
line-height: 28px;
|
||||
color: #999;
|
||||
}
|
||||
|
||||
ul.nav-tabs > li.nav-item a.active {
|
||||
color: #fff !important;
|
||||
border: none;
|
||||
border-bottom: 2px solid #868686 !important;
|
||||
background: transparent;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
ul.nav-tabs a {
|
||||
border: none !important;
|
||||
transition: background-color 100ms linear, color 100ms linear, border 100ms linear;
|
||||
border-bottom: 2px solid transparent !important;
|
||||
}
|
||||
|
||||
ul.nav-tabs li:not(.dropdown.show) a:hover {
|
||||
color: #fff !important;
|
||||
border-bottom: 2px solid #c4c4c4 !important;
|
||||
}
|
||||
|
||||
ul.nav-tabs a.dropdown-item {
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
/*
|
||||
Pagination
|
||||
*/
|
||||
ul.pagination {
|
||||
border: none;
|
||||
}
|
||||
|
||||
ul.pagination li.disabled a {
|
||||
background-color: #1f1f1f;
|
||||
border-color: #525252 !important;
|
||||
color: #868686;
|
||||
}
|
||||
|
||||
ul.pagination li.disabled:hover a {
|
||||
background-color: initial !important;
|
||||
}
|
||||
|
||||
ul.pagination li a {
|
||||
color: rgb(250, 250, 250);
|
||||
background-color: #1d1d1d !important;
|
||||
border-color: #525252;
|
||||
line-height: 1rem;
|
||||
padding-left: 0.75rem;
|
||||
padding-right: 0.75rem;
|
||||
padding-top: 0.5rem;
|
||||
padding-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
ul.pagination li:hover:not(.disabled) a {
|
||||
background: #303030 !important;
|
||||
box-shadow: inset 0 0 0 2px #868686,0 2px 2px 0 rgba(0,0,0,0.08);
|
||||
border-color: #525252 !important;
|
||||
color: rgb(250,250, 250);
|
||||
}
|
||||
|
||||
/*
|
||||
Popover
|
||||
*/
|
||||
div.popover {
|
||||
border: solid 1px white;
|
||||
}
|
||||
|
||||
/*
|
||||
Modal Dialogs
|
||||
*/
|
||||
div.modal-content {
|
||||
background-color: #1f1f1f;
|
||||
}
|
||||
|
||||
/*
|
||||
Graphs
|
||||
*/
|
||||
div.flot-tooltip {
|
||||
border: solid 1px white;
|
||||
background-color: #1f1f1f;
|
||||
color: #fafafa !important;
|
||||
}
|
||||
|
||||
div.flot-text {
|
||||
color: #fafafa !important;
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,7 @@ ul.tree, ul.subtree {
|
||||
ul.subtree > li {
|
||||
position: relative;
|
||||
padding-left: 2.0em;
|
||||
line-height: 140%;
|
||||
border-left: 0.1em solid #6185a0;
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 3.1 KiB |
22
src/root/static/js/bootbox.min.js
vendored
22
src/root/static/js/bootbox.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -1,10 +1,9 @@
|
||||
$(document).ready(function() {
|
||||
|
||||
function makeTreeCollapsible(tab) {
|
||||
/*** Tree toggles in logfiles. ***/
|
||||
|
||||
/* Set the appearance of the toggle depending on whether the
|
||||
corresponding subtree is initially shown or hidden. */
|
||||
$(".tree-toggle").map(function() {
|
||||
tab.find(".tree-toggle").map(function() {
|
||||
if ($(this).siblings("ul:hidden").length == 0) {
|
||||
$(this).text("-");
|
||||
} else {
|
||||
@@ -13,7 +12,7 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
/* When a toggle is clicked, show or hide the subtree. */
|
||||
$(".tree-toggle").click(function() {
|
||||
tab.find(".tree-toggle").click(function() {
|
||||
if ($(this).siblings("ul:hidden").length != 0) {
|
||||
$(this).siblings("ul").show();
|
||||
$(this).text("-");
|
||||
@@ -24,21 +23,23 @@ $(document).ready(function() {
|
||||
});
|
||||
|
||||
/* Implementation of the expand all link. */
|
||||
$(".tree-expand-all").click(function() {
|
||||
$(".tree-toggle", $(this).parent().siblings(".tree")).map(function() {
|
||||
tab.find(".tree-expand-all").click(function() {
|
||||
tab.find(".tree-toggle", $(this).parent().siblings(".tree")).map(function() {
|
||||
$(this).siblings("ul").show();
|
||||
$(this).text("-");
|
||||
});
|
||||
});
|
||||
|
||||
/* Implementation of the collapse all link. */
|
||||
$(".tree-collapse-all").click(function() {
|
||||
$(".tree-toggle", $(this).parent().siblings(".tree")).map(function() {
|
||||
tab.find(".tree-collapse-all").click(function() {
|
||||
tab.find(".tree-toggle", $(this).parent().siblings(".tree")).map(function() {
|
||||
$(this).siblings("ul").hide();
|
||||
$(this).text("+");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function() {
|
||||
$("table.clickable-rows").click(function(event) {
|
||||
if ($(event.target).closest("a").length) return;
|
||||
link = $(event.target).parents("tr").find("a.row-link");
|
||||
@@ -46,29 +47,31 @@ $(document).ready(function() {
|
||||
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({});
|
||||
|
||||
$(function() {
|
||||
if (window.location.hash) {
|
||||
$(".nav-tabs a[href='" + window.location.hash + "']").tab('show');
|
||||
}
|
||||
/* Activates tab according to URL anchor. */
|
||||
if (window.location.hash) {
|
||||
setTimeout(function () { $('.nav-tabs > .nav-item:not(.dropdown) a[href="' + window.location.hash + '"]').trigger('show.bs.tab'); }, 0);
|
||||
$('.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() {
|
||||
if ($("li.active", this).length > 0) return;
|
||||
$("a", $(this).children("li:not(.dropdown)").first()).tab('show');
|
||||
});
|
||||
$('.nav-tabs').each(function() {
|
||||
if ($('.nav-item:not(.dropdown) a.active',this).length == 0)
|
||||
$('.nav-item:not(.dropdown) a',this).first().tab('show');
|
||||
});
|
||||
|
||||
/* Ensure that pressing the back button on another page
|
||||
navigates back to the previously selected tab on this
|
||||
page. */
|
||||
$('.nav-tabs').bind('show', function(e) {
|
||||
var pattern = /#.+/gi;
|
||||
var id = e.target.toString().match(pattern)[0];
|
||||
history.replaceState(null, "", id);
|
||||
});
|
||||
$('.nav-tabs > .nav-item:not(.dropdown) a[href^="#"]').on('click', function() {
|
||||
history.replaceState(null, null, window.location.href.split("#")[0] + $(this).attr("href"));
|
||||
});
|
||||
|
||||
/* Automatically set Bootstrap radio buttons from hidden form controls. */
|
||||
@@ -126,23 +129,33 @@ $(document).ready(function() {
|
||||
el.addClass("is-local");
|
||||
}
|
||||
});
|
||||
|
||||
[...document.getElementsByTagName("iframe")].forEach((element) => {
|
||||
element.contentWindow.addEventListener("DOMContentLoaded", (_) => {
|
||||
element.style.height = element.contentWindow.document.body.scrollHeight + 'px';
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
var tabsLoaded = {};
|
||||
|
||||
function makeLazyTab(tabName, uri) {
|
||||
$('.nav-tabs').bind('show', function(e) {
|
||||
function makeLazyTab(tabName, uri, callback) {
|
||||
$('.nav-tabs').bind('show.bs.tab', function(e) {
|
||||
var pattern = /#.+/gi;
|
||||
var id = e.target.toString().match(pattern)[0];
|
||||
if (id == '#' + tabName && !tabsLoaded[id]) {
|
||||
tabsLoaded[id] = 1;
|
||||
$('#' + tabName).load(uri, function(response, status, xhr) {
|
||||
var lazy = xhr.getResponseHeader("X-Hydra-Lazy") === "Yes";
|
||||
var tab = $('#' + tabName);
|
||||
if (status == "error" && !lazy) {
|
||||
$('#' + tabName).html("<div class='alert alert-error'>Error loading tab: " + xhr.status + " " + xhr.statusText + "</div>");
|
||||
tab.html("<div class='alert alert-error'>Error loading tab: " + xhr.status + " " + xhr.statusText + "</div>");
|
||||
}
|
||||
else {
|
||||
$('#' + tabName).html(response);
|
||||
tab.html(response);
|
||||
if (callback) {
|
||||
callback(tab);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
2
src/root/static/js/jquery/jquery-3.4.1.min.js
vendored
Normal file
2
src/root/static/js/jquery/jquery-3.4.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
src/root/static/js/popper.min.js
vendored
Normal file
4
src/root/static/js/popper.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -7,7 +7,7 @@
|
||||
|
||||
[% ELSE %]
|
||||
|
||||
[% INCLUDE renderBuildList builds=resource showSchedulingInfo=1 hideResultInfo=1 busy=1 %]
|
||||
[% INCLUDE renderBuildList builds=resource showSchedulingInfo=1 hideResultInfo=1 busy=1 showStepName=1 %]
|
||||
|
||||
[% END %]
|
||||
|
||||
|
24
src/root/style.tt
Normal file
24
src/root/style.tt
Normal file
@@ -0,0 +1,24 @@
|
||||
<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/moment/moment-2.24.0.min.js") %]"></script>
|
||||
|
||||
<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>
|
||||
<link href="[% c.uri_for("/static/bootstrap/css/bootstrap.min.css") %]" rel="stylesheet" />
|
||||
|
||||
<!-- hydra.css may need to be moved to before boostrap to 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/rotated-th.css") %]" type="text/css" />
|
||||
|
||||
<style>
|
||||
.popover { max-width: 40%; }
|
||||
</style>
|
||||
|
||||
<script type="text/javascript" src="[% c.uri_for("/static/js/bootbox.min.js") %]"></script>
|
||||
|
||||
<link rel="stylesheet" href="[% c.uri_for("/static/css/tree.css") %]" type="text/css" />
|
||||
|
||||
<script type="text/javascript" src="[% c.uri_for("/static/js/common.js") %]"></script>
|
@@ -1,18 +1,18 @@
|
||||
[% BLOCK makeSubMenu %]
|
||||
<li class="dropdown" [% IF id; HTML.attributes(id => id); END %] >
|
||||
<a class="dropdown-toggle" href="#" data-toggle="dropdown">[% title %]<b class="caret"></b></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li class="nav-item dropdown" [% IF id; HTML.attributes(id => id); END %] >
|
||||
<a class="nav-link dropdown-toggle" href="#" data-toggle="dropdown">[% title %]<b class="caret"></b></a>
|
||||
<div class="dropdown-menu[% IF align == 'right' %] dropdown-menu-right[% END %]">
|
||||
[% content %]
|
||||
</ul>
|
||||
</div>
|
||||
</li>
|
||||
[% END %]
|
||||
[% showPrivate = (isPrivateHydra && c.user_exists) || ! isPrivateHydra %]
|
||||
|
||||
[% IF showPrivate %]
|
||||
<ul class="nav pull-left">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
|
||||
[% 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 %]
|
||||
|
||||
[% WRAPPER makeSubMenu title="Status" %]
|
||||
@@ -41,18 +41,18 @@
|
||||
|
||||
[% IF project %]
|
||||
[% WRAPPER makeSubMenu title="Project" %]
|
||||
<li class="nav-header">[% HTML.escape(project.name) %]</li>
|
||||
<li class="divider"></li>
|
||||
<h6 class="dropdown-header">[% HTML.escape(project.name) %]</h6>
|
||||
<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('all'), [project.name]) title = "Latest builds" %]
|
||||
[% INCLUDE menuItem uri = c.uri_for('/project' project.name 'channel' 'latest') title = "Channel" %]
|
||||
[% IF localStore %][% INCLUDE menuItem uri = c.uri_for('/project' project.name 'channel' 'latest') title = "Channel" %][% END %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% IF jobset %]
|
||||
[% WRAPPER makeSubMenu title="Jobset" %]
|
||||
<li class="nav-header">[% HTML.escape(jobset.name) %]</li>
|
||||
<li class="divider"></li>
|
||||
<h6 class="dropdown-header">[% HTML.escape(jobset.name) %]</h6>
|
||||
<div class="dropdown-divider"></div>
|
||||
[% INCLUDE menuItem
|
||||
uri = c.uri_for(c.controller('Jobset').action_for('jobset'), [project.name, jobset.name])
|
||||
title = "Overview" %]
|
||||
@@ -62,21 +62,21 @@
|
||||
[% INCLUDE menuItem
|
||||
uri = c.uri_for(c.controller('Jobset').action_for('all'), [project.name, jobset.name])
|
||||
title = "Latest builds" %]
|
||||
[% INCLUDE menuItem uri = c.uri_for('/jobset' project.name jobset.name 'channel' 'latest') title = "Channel" %]
|
||||
[% IF localStore %][% INCLUDE menuItem uri = c.uri_for('/jobset' project.name jobset.name 'channel' 'latest') title = "Channel" %][% END %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
[% IF job %]
|
||||
[% WRAPPER makeSubMenu title="Job" %]
|
||||
<li class="nav-header">[% HTML.escape(job) %]</li>
|
||||
<li class="divider"></li>
|
||||
<h6 class="dropdown-header">[% HTML.escape(job) %]</h6>
|
||||
<div class="dropdown-divider"></div>
|
||||
[% INCLUDE menuItem
|
||||
uri = c.uri_for(c.controller('Job').action_for('overview'), [project.name, jobset.name, job])
|
||||
title = "Overview" %]
|
||||
[% INCLUDE menuItem
|
||||
uri = c.uri_for(c.controller('Job').action_for('all'), [project.name, jobset.name, job])
|
||||
title = "Latest builds" %]
|
||||
[% INCLUDE menuItem uri = c.uri_for('/job' project.name jobset.name job 'channel' 'latest') title = "Channel" %]
|
||||
[% IF localStore %][% INCLUDE menuItem uri = c.uri_for('/job' project.name jobset.name job 'channel' 'latest') title = "Channel" %][% END %]
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
[% WRAPPER makeSubMenu title="Admin" %]
|
||||
[% 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" %]
|
||||
<li class="divider"></li>
|
||||
<div class="dropdown-divider"></div>
|
||||
[% END %]
|
||||
[% IF c.check_user_roles('admin') %]
|
||||
[% INCLUDE menuItem
|
||||
@@ -97,7 +97,7 @@
|
||||
[% INCLUDE menuItem
|
||||
uri = c.uri_for(c.controller('Admin').action_for('users'))
|
||||
title = "Manage users" %]
|
||||
<li class="divider"></li>
|
||||
<div class="dropdown-divider"></div>
|
||||
[% INCLUDE menuItem
|
||||
uri = c.uri_for(c.controller('Admin').action_for('clear_queue_non_current'))
|
||||
title = "Cancel queued non-current builds"
|
||||
@@ -120,32 +120,33 @@
|
||||
</ul>
|
||||
[% 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 %]
|
||||
[% INCLUDE menuItem uri = c.uri_for(c.controller('User').action_for('edit'), [c.user.username]) title = "Preferences" %]
|
||||
<li>
|
||||
<a href="#" onclick="signOut();">Sign out</a>
|
||||
[% INCLUDE navItem uri = c.uri_for(c.controller('User').action_for('edit'), [c.user.username]) title = "Preferences" %]
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#" onclick="signOut();">Sign out</a>
|
||||
</li>
|
||||
[% 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 %]
|
||||
<div style="display: none" class="g-signin2" data-onsuccess="onGoogleSignIn" data-theme="dark"></div></a>
|
||||
<li><a href="#" id="google-signin">Sign in with Google</a></li>
|
||||
<li class="divider"></li>
|
||||
<script src="https://accounts.google.com/gsi/client" async defer></script>
|
||||
<div id="g_id_onload" data-client_id="[% c.config.google_client_id %]" data-auto_prompt="false" data-callback="onGoogleSignIn">
|
||||
</div>
|
||||
<div class="g_id_signin" data-type="standard"></div>
|
||||
<div class="dropdown-divider"></div>
|
||||
[% END %]
|
||||
[% IF c.config.github_client_id %]
|
||||
<li><a href="/github-redirect?after=[% c.req.path %]">Sign in with GitHub</a></li>
|
||||
<li class="divider"></li>
|
||||
<a class="dropdown-item" href="/github-redirect?after=[% c.req.path %]">Sign in with GitHub</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
[% END %]
|
||||
<li>
|
||||
<a href="#hydra-signin" data-toggle="modal">Sign in with a Hydra account</a>
|
||||
</li>
|
||||
<a class="dropdown-item" href="#hydra-signin" data-toggle="modal">Sign in with a Hydra account</a>
|
||||
[% END %]
|
||||
[% END %]
|
||||
|
||||
|
224
src/root/user.tt
224
src/root/user.tt
@@ -2,128 +2,132 @@
|
||||
[% PROCESS common.tt %]
|
||||
|
||||
[% BLOCK roleoption %]
|
||||
<option value="[% role %]"
|
||||
[% checked = false %]
|
||||
[% FOREACH r IN user.userroles %]
|
||||
[% checked = r.role == role %]
|
||||
[% BREAK IF checked %]
|
||||
[% END %]
|
||||
[% checked = false %]
|
||||
[% FOREACH r IN user.userroles %]
|
||||
[% checked = r.role == role %]
|
||||
[% BREAK IF checked %]
|
||||
[% END %]
|
||||
<input
|
||||
type="checkbox"
|
||||
name="roles"
|
||||
[% IF checked %]
|
||||
selected="selected"
|
||||
checked="checked"
|
||||
[% END %]
|
||||
>[% role %]</option>
|
||||
[% END %]
|
||||
|
||||
<form class="form-horizontal">
|
||||
|
||||
<fieldset>
|
||||
|
||||
[% IF create %]
|
||||
<div class="control-group">
|
||||
<label class="control-label">User name</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="username" [% HTML.attributes(value => username) %]/>
|
||||
</div>
|
||||
</div>
|
||||
[% IF !mutable %]
|
||||
disabled="disabled"
|
||||
[% END %]
|
||||
[% HTML.attributes(id => "role-${role}", value => role) %] />
|
||||
<label [% HTML.attributes(for => "role-${role}") %]> [% role %]</label><br />
|
||||
[% END %]
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Full name</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="fullname" [% HTML.attributes(value => create ? '' : user.fullname) %]/>
|
||||
<form>
|
||||
|
||||
[% 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 %]
|
||||
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="userfullname">Full name</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="userfullname" name="fullname" [% HTML.attributes(value => create ? '' : user.fullname) %]/>
|
||||
</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') %]
|
||||
[% mutable = c.check_user_roles('admin') %]
|
||||
<div class="form-group row card [% mutable ? "border-danger" : "border-light" %]">
|
||||
<div class="card-header">User Roles</div>
|
||||
<div class="card-body [% mutable ? "text-danger" : "" %]">
|
||||
[% IF mutable %]
|
||||
<h5 class="card-title">Take care, you're allowed to change [% HTML.escape(user.fullname || user.emailaddress || "this user") %]'s roles.</h5>
|
||||
[% ELSE %]
|
||||
<h5 class="card-title">[% HTML.escape(user.fullname || user.emailaddress || "this user") %]'s roles.</h5>
|
||||
[% END %]
|
||||
<p class="card-text">
|
||||
[% INCLUDE roleoption mutable=mutable role="admin" %]
|
||||
[% INCLUDE roleoption mutable=mutable role="create-projects" %]
|
||||
[% INCLUDE roleoption mutable=mutable role="restart-jobs" %]
|
||||
[% INCLUDE roleoption mutable=mutable role="bump-to-front" %]
|
||||
[% INCLUDE roleoption mutable=mutable role="cancel-build" %]
|
||||
[% INCLUDE roleoption mutable=mutable role="eval-jobset" %]
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
[% IF create || user.type == 'hydra' %]
|
||||
<div class="control-group">
|
||||
<label class="control-label">Password</label>
|
||||
<div class="controls">
|
||||
<input type="password" class="span3" name="password" value=""/>
|
||||
[% IF create && !c.check_user_roles('admin') %]
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3"></label>
|
||||
<div class="col-sm-9">
|
||||
<img src="[% c.uri_for('/captcha') %]" alt="CAPTCHA">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Confirm password</label>
|
||||
<div class="controls">
|
||||
<input type="password" class="span3" name="password2" value=""/>
|
||||
<div class="form-group row">
|
||||
<label class="col-sm-3" for="usercaptcha">Type the digits shown in the image above</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="text" class="form-control" id="usercaptcha" name="captcha" value="">
|
||||
</div>
|
||||
</div>
|
||||
[% END %]
|
||||
|
||||
<div class="control-group">
|
||||
<label class="control-label">Email</label>
|
||||
<div class="controls">
|
||||
<input type="text" class="span3" name="emailaddress" [% IF !create && user.username.search('@') %]disabled="disabled"[% END %] [%+ HTML.attributes(value => user.emailaddress) %]/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-group">
|
||||
<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>
|
||||
[% END %]
|
||||
|
||||
<button id="submit-user" class="btn btn-primary">
|
||||
<i class="fas fa-check"></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="fas fa-lock"></i>
|
||||
Reset password
|
||||
</button>
|
||||
[% END %]
|
||||
[% IF !create %]
|
||||
<button id="delete-user" class="btn btn-danger">
|
||||
<i class="fas fa-trash"></i>
|
||||
Delete this user
|
||||
</button>
|
||||
[% END %]
|
||||
</form>
|
||||
|
||||
<script>
|
||||
|
@@ -24,8 +24,8 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><a class="btn" href="[% c.uri_for(c.controller('Root').action_for('register')) %]">
|
||||
<i class="icon-plus"></i> Add a new user
|
||||
</a></p>
|
||||
<a class="btn btn-primary" href="[% c.uri_for(c.controller('Root').action_for('register')) %]">
|
||||
<i class="fas fa-plus"></i> Add a new user
|
||||
</a>
|
||||
|
||||
[% END %]
|
||||
|
Reference in New Issue
Block a user