diff --git a/src/HydraFrontend/lib/HydraFrontend/Controller/Root.pm b/src/HydraFrontend/lib/HydraFrontend/Controller/Root.pm index 925637f5..14356877 100644 --- a/src/HydraFrontend/lib/HydraFrontend/Controller/Root.pm +++ b/src/HydraFrontend/lib/HydraFrontend/Controller/Root.pm @@ -49,13 +49,51 @@ sub index :Path :Args(0) { } +sub updateProject { + my ($c, $project) = @_; + + my $projectName = $c->request->params->{name}; + die "Invalid project name: $projectName" unless $projectName =~ /^[[:alpha:]]\w*$/; + + my $displayName = $c->request->params->{displayname}; + die "Invalid display name: $displayName" unless $displayName =~ /^\w.*\w$/; + + $project->name($projectName); + $project->displayname($displayName); + $project->description($c->request->params->{description}); + + $project->update; +} + + sub project :Local { - my ( $self, $c, $projectName ) = @_; + my ( $self, $c, $projectName, $subcommand ) = @_; $c->stash->{template} = 'project.tt'; (my $project) = $c->model('DB::Projects')->search({ name => $projectName }); return error($c, "Project $projectName doesn't exist.") if !defined $project; - + + my $isPosted = $c->request->method eq "POST"; + + $subcommand = "" unless defined $subcommand; + + if ($subcommand eq "edit") { + $c->stash->{edit} = 1; + } elsif ($subcommand eq "submit" && $isPosted) { + $c->model('DB')->schema->txn_do(sub { + updateProject($c, $project); + }); + return $c->res->redirect($c->uri_for("/project", $projectName)); + } elsif ($subcommand eq "delete" && $isPosted) { + $c->model('DB')->schema->txn_do(sub { + $project->delete; + }); + return $c->res->redirect($c->uri_for("/")); + } elsif ($subcommand eq "") { + } else { + return error($c, "Unknown subcommand $subcommand."); + } + $c->stash->{curProject} = $project; $c->stash->{finishedBuilds} = $c->model('DB::Builds')->search( @@ -83,13 +121,43 @@ sub project :Local { } +sub createproject :Local { + my ( $self, $c, $subcommand ) = @_; + + if (defined $subcommand && $subcommand eq "submit") { + eval { + my $projectName = $c->request->params->{name}; + $c->model('DB')->schema->txn_do(sub { + # Note: $projectName is validated in updateProject, + # which will abort the transaction if the name isn't + # valid. + my $project = $c->model('DB::Projects')->create({name => $projectName, displayname => ""}); + updateProject($c, $project); + }); + return $c->res->redirect($c->uri_for("/project", $projectName)); + }; + if ($@) { + return error($c, $@); + } + } + + $c->stash->{template} = 'project.tt'; + $c->stash->{create} = 1; + $c->stash->{edit} = 1; +} + + sub job :Local { - my ( $self, $c, $project, $jobName ) = @_; + my ( $self, $c, $projectName, $jobName ) = @_; $c->stash->{template} = 'job.tt'; - $c->stash->{projectName} = $project; + + (my $project) = $c->model('DB::Projects')->search({ name => $projectName }); + return error($c, "Project $projectName doesn't exist.") if !defined $project; + $c->stash->{curProject} = $project; + $c->stash->{jobName} = $jobName; $c->stash->{builds} = [$c->model('DB::Builds')->search( - {finished => 1, project => $project, attrName => $jobName}, + {finished => 1, project => $projectName, attrName => $jobName}, {order_by => "timestamp DESC"})]; } diff --git a/src/HydraFrontend/root/error.tt b/src/HydraFrontend/root/error.tt index 2d8e61ab..01f7ac95 100644 --- a/src/HydraFrontend/root/error.tt +++ b/src/HydraFrontend/root/error.tt @@ -1,7 +1,8 @@ [% WRAPPER layout.tt title="Hydra Overview" %] +[% USE HTML %]

Error

-

I'm very sorry, but an error occurred: [% error %]

+

I'm very sorry, but an error occurred: [% HTML.escape(error) %]

[% END %] diff --git a/src/HydraFrontend/root/hydra.css b/src/HydraFrontend/root/hydra.css index 5059109b..2f3f5d89 100644 --- a/src/HydraFrontend/root/hydra.css +++ b/src/HydraFrontend/root/hydra.css @@ -38,6 +38,10 @@ td, th { border: solid black 1px; } +td { + vertical-align: top; +} + th { background: #ffffc0; } @@ -145,6 +149,7 @@ td.buildfarmMainColumn { .error-msg { color: red; + white-space: pre; } pre.buildlog { @@ -321,3 +326,13 @@ h1 { #footer { font-size: 80%; } + + +/* Editing */ + +input.string { + font-family: sans-serif; + font-size: 100%; + background-color: #fffff0; + width: 30em; +} diff --git a/src/HydraFrontend/root/job.tt b/src/HydraFrontend/root/job.tt index 62d6aa8b..293b5442 100644 --- a/src/HydraFrontend/root/job.tt +++ b/src/HydraFrontend/root/job.tt @@ -1,6 +1,6 @@ [% WRAPPER layout.tt title="Hydra Overview" %] -

All builds for job [% projectName %]:[% jobName %]

+

All builds for job [% curProject.name %]:[% jobName %]

diff --git a/src/HydraFrontend/root/layout.tt b/src/HydraFrontend/root/layout.tt index 064551fa..ace946b0 100644 --- a/src/HydraFrontend/root/layout.tt +++ b/src/HydraFrontend/root/layout.tt @@ -50,6 +50,7 @@
[% project.displayname %]
[% IF curProject.name == project.name %] @@ -63,7 +64,7 @@
Admin
diff --git a/src/HydraFrontend/root/project.tt b/src/HydraFrontend/root/project.tt index 227c28ad..38b4b3c5 100644 --- a/src/HydraFrontend/root/project.tt +++ b/src/HydraFrontend/root/project.tt @@ -1,9 +1,46 @@ [% WRAPPER layout.tt title="Hydra Overview" %] - -

Project [% curProject.name %]

+[% USE HTML %] -

Description: [% curProject.description %]

+[% BLOCK maybeEditString %] + [% IF edit %] + param, value => value) %] /> + [% ELSE %] + [% HTML.escape(value) %] + [% END %] +[% END %] + + +[% IF edit %] + +[% END %] + + +[% IF create %] +

New Project

+[% ELSE %] +

Project [% curProject.name %]

+[% END %] + + +

General information

+ +
+ [% IF edit %] + + + + + [% END %] + + + + + + + + +
Identifier:[% INCLUDE maybeEditString param="name" value=curProject.name %]
Display name:[% INCLUDE maybeEditString param="displayname" value=curProject.displayname %]
Description:[% INCLUDE maybeEditString param="description" value=curProject.description %]

Definition

@@ -17,13 +54,19 @@

Information

+ [% IF edit %] + + + + + [% END %] - + - +
Identifier:[% INCLUDE maybeEditString value=jobset.name %]
Description:[% jobset.description %][% INCLUDE maybeEditString value=jobset.description %]
Nix expression:[% jobset.nixexprpath %] in input [% jobset.nixexprinput %][% INCLUDE maybeEditString value=jobset.nixexprpath %] in input [% INCLUDE maybeEditString value=jobset.nixexprinput %]
@@ -36,14 +79,33 @@ [% FOREACH input IN jobset.jobsetinputs -%] - [% input.name %] - [% input.type %] + [% INCLUDE maybeEditString value=input.name %] + + [% IF edit %] + + [% ELSE %] + [% input.type %] + [% END %] + [% FOREACH alt IN input.jobsetinputalts -%] [% IF input.type == "string" %] - "[% alt.value %]" + + [% IF edit %] + +
+ [% ELSE %] + "[% alt.value %]" + [% END %] +
[% ELSE %] - [% alt.uri %] + [% INCLUDE maybeEditString value=alt.uri %] [% END %] [% END %] @@ -61,6 +123,9 @@ [% END %] +[% IF !edit %] + +

Jobs

[% IF jobNames.size > 0 %] @@ -108,4 +173,20 @@ +[% END %] + + +[% IF edit %] + +

+ + + +
+

+
+ +[% END %] + + [% END %] diff --git a/src/hydra.sql b/src/hydra.sql index 8ddd8725..ff0f14a7 100644 --- a/src/hydra.sql +++ b/src/hydra.sql @@ -174,7 +174,7 @@ create table JobsetInputs ( project text not null, jobset text not null, name text not null, - type text not null, -- "svn", "cvs", "path", "file", "string" + type text not null, -- "svn", "cvs", "path", "uri", "string" primary key (project, jobset, name), foreign key (project, jobset) references Jobsets(project, name) on delete cascade -- ignored by sqlite ); diff --git a/src/test.sql b/src/test.sql index ebf4f31f..8c7ad093 100644 --- a/src/test.sql +++ b/src/test.sql @@ -1,5 +1,5 @@ insert into projects(name, displayName, description) values('patchelf', 'PatchELF', 'A tool for modifying ELF binaries'); -insert into jobSets(project, name, description, nixExprInput, nixExprPath) values('patchelf', 'trunk', 'PatchELF', 'patchelfSrc', 'release.nix'); +insert into jobSets(project, name, description, nixExprInput, nixExprPath) values('patchelf', 'trunk', 'PatchELF trunk', 'patchelfSrc', 'release.nix'); insert into jobSetInputs(project, jobset, name, type) values('patchelf', 'trunk', 'patchelfSrc', 'path'); insert into jobSetInputAlts(project, jobset, input, altnr, uri) values('patchelf', 'trunk', 'patchelfSrc', 0, '/home/eelco/Dev/patchelf-wc'); insert into jobSetInputs(project, jobset, name, type) values('patchelf', 'trunk', 'nixpkgs', 'path');