[Bps-public-commit] r14338 - in Pushmi/trunk: . Pushmi-Admin/bin Pushmi-Admin/etc Pushmi-Admin/lib/Pushmi/Admin/Action Pushmi-Admin/lib/Pushmi/Admin/Model Pushmi-Admin/share/web/static/css Pushmi-Admin/share/web/static/images Pushmi-Admin/share/web/static/images/silk Pushmi-Admin/share/web/static/images/status Pushmi-Admin/var/svn_root
alexmv at bestpractical.com
alexmv at bestpractical.com
Mon Jul 21 15:41:37 EDT 2008
Author: alexmv
Date: Mon Jul 21 15:41:34 2008
New Revision: 14338
Added:
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/CheckURL.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/CreateReplica.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/Remirror.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/Sync.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Dispatcher.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/HttpRoot.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/Replica.pm
Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/View.pm
Pushmi/trunk/Pushmi-Admin/share/web/static/css/
Pushmi/trunk/Pushmi-Admin/share/web/static/css/app.css
Pushmi/trunk/Pushmi-Admin/share/web/static/images/
Pushmi/trunk/Pushmi-Admin/share/web/static/images/silk/
Pushmi/trunk/Pushmi-Admin/share/web/static/images/silk/database_delete.png (contents, props changed)
Pushmi/trunk/Pushmi-Admin/share/web/static/images/silk/database_refresh.png (contents, props changed)
Pushmi/trunk/Pushmi-Admin/share/web/static/images/status/
Pushmi/trunk/Pushmi-Admin/share/web/static/images/status/blue.png (contents, props changed)
Pushmi/trunk/Pushmi-Admin/share/web/static/images/status/green.png (contents, props changed)
Pushmi/trunk/Pushmi-Admin/share/web/static/images/status/orange.png (contents, props changed)
Pushmi/trunk/Pushmi-Admin/share/web/static/images/status/red.png (contents, props changed)
Pushmi/trunk/Pushmi-Admin/var/svn_root/
Modified:
Pushmi/trunk/ (props changed)
Pushmi/trunk/Pushmi-Admin/bin/jifty
Pushmi/trunk/Pushmi-Admin/etc/config.yml
Log:
r34426 at kohr-ah: chmrr | 2008-07-21 15:39:41 -0400
* Checkpoint of simple pushmi admin UI; no server integration yet
r34427 at kohr-ah: chmrr | 2008-07-21 15:41:07 -0400
* Fix an overzealous commit
Modified: Pushmi/trunk/Pushmi-Admin/bin/jifty
==============================================================================
--- Pushmi/trunk/Pushmi-Admin/bin/jifty (original)
+++ Pushmi/trunk/Pushmi-Admin/bin/jifty Mon Jul 21 15:41:34 2008
@@ -3,6 +3,12 @@
use strict;
use UNIVERSAL::require;
+BEGIN {
+ Jifty::Util->require or die $UNIVERSAL::require::ERROR;
+ my $root = Jifty::Util->app_root;
+ unshift @INC, "$root/lib" if ($root);
+}
+
use Jifty;
use Jifty::Script;
Modified: Pushmi/trunk/Pushmi-Admin/etc/config.yml
==============================================================================
--- Pushmi/trunk/Pushmi-Admin/etc/config.yml (original)
+++ Pushmi/trunk/Pushmi-Admin/etc/config.yml Mon Jul 21 15:41:34 2008
@@ -1,6 +1,6 @@
---
framework:
- AdminMode: 1
+ AdminMode: 0
ApplicationClass: Pushmi::Admin
ApplicationName: Pushmi-Admin
ApplicationUUID: 6C36B9BA-51D6-11DD-AF68-1158ADF94B82
@@ -21,32 +21,14 @@
LogLevel: INFO
Mailer: Sendmail
MailerArgs: []
-
Plugins:
- -
- LetMe: {}
-
- -
- SkeletonApp: {}
-
- -
- REST: {}
-
- -
- Halo: {}
-
- -
- ErrorTemplates: {}
-
- -
- OnlineDocs: {}
-
- -
- CompressedCSSandJS: {}
-
- -
- AdminUI: {}
-
+ - LetMe: {}
+ - SkeletonApp: {}
+ - REST: {}
+ - ErrorTemplates: {}
+ - OnlineDocs: {}
+ - CompressedCSSandJS: {}
+ - AdminUI: {}
PubSub:
Backend: Memcached
Enable: ~
@@ -62,7 +44,6 @@
BaseURL: http://localhost
DataDir: var/mason
Globals: []
-
MasonConfig:
autoflush: 0
default_escape_flags: h
@@ -72,3 +53,7 @@
ServeStaticFiles: 1
StaticRoot: share/web/static
TemplateRoot: share/web/templates
+application:
+ svn_root: %var/svn_root%
+ http_root: http://localhost:8888/
+ pushmi_bin: /usr/bin/pushmi
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/CheckURL.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/CheckURL.pm Mon Jul 21 15:41:34 2008
@@ -0,0 +1,75 @@
+use strict;
+use warnings;
+
+=head1 NAME
+
+Pushmi::Admin::Action::CheckURL
+
+=cut
+
+package Pushmi::Admin::Action::CheckURL;
+use base qw/Pushmi::Admin::Action Jifty::Action/;
+
+use Jifty::Param::Schema;
+use Jifty::Action schema {
+
+ param name =>
+ type is 'text',
+ label is "Name";
+
+ param url =>
+ type is 'text',
+ label is "URL";
+
+};
+
+use SVN::Client;
+
+sub validate_url {
+ my $self = shift;
+ my ($url) = @_;
+ warn "Validating $url\n";
+ return $self->validation_error( url => "We can only deal with http:// urls" )
+ unless $url =~ m{^http://};
+
+ $url =~ s{/+$}{};
+
+ my $client = new SVN::Client(
+ auth => [
+ SVN::Client::get_simple_provider(),
+ SVN::Client::get_username_provider(),
+ ]
+ );
+
+ my $props = {};
+ eval {
+ $client->info(
+ $url, undef, "HEAD",
+ sub {
+ $props->{$_} = $_[1]->$_
+ for qw/rev repos_UUID repos_root_URL last_changed_date/;
+ },
+ 0
+ );
+ };
+ my $err = $@;
+ if ( not keys %{$props} or $err) {
+ $self->validation_error( url => "Read of $url failed\n" );
+ }
+
+ $self->result->content(repository => $props);
+ return $self->validation_ok( "url" );
+}
+
+sub validate {
+ my $self = shift;
+ $self->SUPER::validate;
+ if ($self->result->failure) {
+ Jifty->web->next_page("/check");
+ } else {
+ Jifty->web->next_page("/create");
+ }
+}
+
+1;
+
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/CreateReplica.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/CreateReplica.pm Mon Jul 21 15:41:34 2008
@@ -0,0 +1,17 @@
+use strict;
+use warnings;
+
+package Pushmi::Admin::Action::CreateReplica;
+use base qw/Jifty::Action::Record::Create/;
+
+sub arguments {
+ my $self = shift;
+ my $args = $self->SUPER::arguments;
+ $args->{name}{ajax_validates} = 1;
+ $args->{mirror} = {};
+ return $args;
+}
+
+sub record_class { 'Pushmi::Admin::Model::Replica' }
+
+1;
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/Remirror.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/Remirror.pm Mon Jul 21 15:41:34 2008
@@ -0,0 +1,31 @@
+use strict;
+use warnings;
+
+=head1 NAME
+
+Pushmi::Admin::Action::Remirror
+
+=cut
+
+package Pushmi::Admin::Action::Remirror;
+use base qw/Pushmi::Admin::Action Jifty::Action/;
+
+use Jifty::Param::Schema;
+use Jifty::Action schema {
+
+ param replica =>
+ type is 'integer',
+ render as 'hidden',
+ is mandatory;
+
+};
+
+sub take_action {
+ my $self = shift;
+
+ my $replica = Pushmi::Admin::Model::Replica->load($self->argument_value("replica"));
+ $replica->remirror;
+}
+
+1;
+
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/Sync.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Action/Sync.pm Mon Jul 21 15:41:34 2008
@@ -0,0 +1,38 @@
+use strict;
+use warnings;
+
+=head1 NAME
+
+Pushmi::Admin::Action::Sync
+
+=cut
+
+package Pushmi::Admin::Action::Sync;
+use base qw/Pushmi::Admin::Action Jifty::Action/;
+
+use Jifty::Param::Schema;
+use Jifty::Action schema {
+
+ param bootstrap =>
+ type is 'file',
+ label is "Bootstrap file";
+
+ param replica =>
+ type is 'integer',
+ render as 'hidden',
+ is mandatory;
+
+};
+
+sub take_action {
+ my $self = shift;
+
+ my $replica = Pushmi::Admin::Model::Replica->load($self->argument_value("replica"));
+ $replica->sync;
+ if ($replica->status eq "behind") {
+ $self->result->message( "Synchronization started" );
+ }
+}
+
+1;
+
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Dispatcher.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Dispatcher.pm Mon Jul 21 15:41:34 2008
@@ -0,0 +1,38 @@
+use strict;
+use warnings;
+
+package Pushmi::Admin::Dispatcher;
+use Jifty::Dispatcher -base;
+
+on '/create' => run {
+ warn YAML::Dump(Jifty->web->response);
+ if (Jifty->web->response->result("create") and Jifty->web->response->result("create")->success) {
+ my $replica = Pushmi::Admin::Model::Replica->load(Jifty->web->response->result("create")->content("id"));
+ redirect("/replica/" . $replica->clean_name);
+ } else {
+ show "/create";
+ }
+};
+
+under '/replica/*' => run {
+ my $replica = Pushmi::Admin::Model::Replica->new;
+ $replica->load_by_cols( clean_name => $1 );
+ show '/errors/404' unless $replica->id;
+ set replica => $replica;
+ show '/replica';
+};
+
+under '/advanced/*' => run {
+ my $replica = Pushmi::Admin::Model::Replica->new;
+ $replica->load_by_cols( clean_name => $1 );
+ show '/errors/404' unless $replica->id;
+ set replica => $replica;
+ show '/advanced';
+};
+
+after '*' => run {
+ return if already_run;
+ Pushmi::Admin::Model::Replica->clear_cache;
+};
+
+1;
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/HttpRoot.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/HttpRoot.pm Mon Jul 21 15:41:34 2008
@@ -0,0 +1,25 @@
+use strict;
+use warnings;
+
+package Pushmi::Admin::Model::HttpRoot;
+use Jifty::DBI::Schema;
+use Pushmi::Admin::Model::Replica;
+
+use Pushmi::Admin::Record schema {
+
+ column path =>
+ type is 'text',
+ is mandatory,
+ is unique;
+
+ column replica_id =>
+ refers_to Pushmi::Admin::Model::Replica;
+
+};
+
+sub current_user_can {
+ return 1;
+}
+
+1;
+
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/Replica.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/Model/Replica.pm Mon Jul 21 15:41:34 2008
@@ -0,0 +1,237 @@
+use strict;
+use warnings;
+
+package Pushmi::Admin::Model::Replica;
+use Jifty::DBI::Schema;
+
+use File::Path;
+use File::Spec;
+use Pushmi::Mirror;
+use Pushmi::Command::Mirror;
+use Pushmi::Command::Sync;
+
+use Time::Duration qw//;
+
+my %CACHE;
+
+use Pushmi::Admin::Record schema {
+
+ column name =>
+ type is 'text',
+ is mandatory,
+ is unique;
+
+ column clean_name =>
+ type is 'text',
+ is protected;
+
+ column url =>
+ type is 'text',
+ is mandatory;
+
+ column status =>
+ type is 'text',
+ is protected,
+ valid_values are [qw/loading ok behind offline failed/];
+
+};
+
+sub validate_name {
+ my $self = shift;
+ my $name = shift;
+
+ my $dups = Pushmi::Admin::Model::ReplicaCollection->new;
+ $dups->limit( column => 'clean_name', value => $self->_clean_name($name));
+ $dups->limit( column => 'id', operator => '!=', value => $self->id)
+ if $self->id;
+ return (undef, "Duplicate name") if $dups->count;
+ return 1;
+}
+
+sub _clean_name {
+ my $self = shift;
+ my $name = shift || $self->name;
+
+ $name = lc $name;
+ $name =~ s/\s+/-/g;
+ $name =~ s/[^\w_-]//g;
+ return $name;
+}
+
+sub after_set_name {
+ my $self = shift;
+ $self->set_clean_name($self->_clean_name);
+}
+
+sub create {
+ my $self = shift;
+ my %args = (@_, status => "failed");
+
+ my $mirror = delete $args{mirror};
+
+ my ($id, $msg) = $self->SUPER::create(%args);
+ if ($id) {
+ if ($mirror) {
+ my $http = Pushmi::Admin::Model::HttpRoot->new;
+ $http->create( path => $mirror, replica_id => $id );
+ }
+
+ $self->set_clean_name($self->_clean_name);
+
+ eval { Pushmi::Command::Mirror->new->run( $self->svn_root, $self->url ); };
+ my $err = $@;
+
+ warn $err if $err;
+ }
+
+ return ($id, $msg);
+}
+
+sub pushmi {
+ my $self = shift;
+ return Pushmi::Mirror->new( path => $self->svn_root );
+}
+
+sub delete {
+ my $self = shift;
+ my $http = Pushmi::Admin::Model::HttpRootCollection->new;
+ $http->limit( column => "replica_id", value => $self->id );
+ $_->delete while $_ = $http->next;
+ rmtree( $self->svn_root );
+ return $self->SUPER::delete;
+}
+
+sub remirror {
+ my $self = shift;
+ rmtree( $self->svn_root );
+ eval { Pushmi::Command::Mirror->new->run( $self->svn_root, $self->url ); };
+ return if $@;
+ $self->sync;
+}
+
+sub sync {
+ my $self = shift;
+ return if $self->pushmi->locked;
+
+ unless (fork) {
+ exec($^X, Jifty->config->app("pushmi_bin"), "sync", $self->svn_root);
+ }
+}
+
+sub svn_info_for {
+ my $self = shift;
+ my ($url) = @_;
+
+ my $client = SVN::Client->new(
+ auth => [
+ SVN::Client::get_simple_provider(),
+ SVN::Client::get_username_provider(),
+ ]
+ );
+
+ my $start = Time::HiRes::time;
+ my $props;
+ local $SIG{ALRM} = sub {die "Timeout!"};
+ alarm 10;
+ eval {
+ $client->info( $url, undef, "HEAD", sub { $props->{rev} = $_[1]->rev; $props->{date} = $_[1]->last_changed_date },
+ 0 );
+ };
+ warn "$@" if $@;
+ alarm 0;
+ $props->{latency} = Time::HiRes::time - $start if $props;
+ return $props;
+}
+
+sub remote_revision {
+ my $self = shift;
+ $self->status;
+ return $CACHE{$self->id}{remote_revision};
+}
+
+sub latency {
+ my $self = shift;
+ $self->status;
+ return sprintf("%.2f seconds",$CACHE{$self->id}{latency});
+}
+
+sub last_remote {
+ my $self = shift;
+ $self->status;
+ return Time::Duration::duration(time - $CACHE{$self->id}{remote_date}/1e6) . " ago";
+}
+
+sub local_revision {
+ my $self = shift;
+ $self->status;
+ return $CACHE{$self->id}{local_revision};
+}
+
+sub last_local {
+ my $self = shift;
+ $self->status;
+ return Time::Duration::duration(time - $CACHE{$self->id}{local_date}/1e6) . " ago";
+}
+
+sub svn_root {
+ my $self = shift;
+ my @parts = File::Spec->splitpath(Jifty->config->app('svn_root'));
+ return File::Spec->catfile(@parts,$self->clean_name);
+}
+
+sub status {
+ my $self = shift;
+ if ($self->id and not $CACHE{$self->id}) {
+ my $c = $CACHE{$self->id} = {};
+ my $local = $self->svn_info_for( "file://" . $self->svn_root );
+ my $remote = $self->svn_info_for( $self->url );
+ if (not $local) {
+ $self->set_status("failed");
+ } elsif (not $remote) {
+ $c->{local_revision} = $local->{rev};
+ $c->{local_date} = $local->{date};
+ $self->set_status("offline");
+ } else {
+ $c->{remote_revision} = $remote->{rev};
+ $c->{remote_date} = $remote->{date};
+ $c->{latency} = $remote->{latency};
+ $c->{local_revision} = $local->{rev};
+ $c->{local_date} = $local->{date};
+ if ($self->pushmi->locked) {
+ $self->set_status("loading");
+ } elsif ($local->{rev} < $remote->{rev}) {
+ $self->set_status("behind");
+ } else {
+ $self->set_status("ok");
+ }
+ }
+ }
+ return $self->_value("status");
+}
+
+sub long_status {
+ my $self = shift;
+ my $status = $self->status;
+ if ($status eq "ok") {
+ return "Up to date; mirrored ". $self->local_revision . " of ". $self->remote_revision . " revisions.";
+ } elsif ($status eq "behind") {
+ return "Lagging behind master; mirrored ". $self->local_revision . " of ". $self->remote_revision . " revisions.";
+ } elsif ($status eq "loading") {
+ return "Actively updating; mirrored ". $self->local_revision . " of ". $self->remote_revision . " revisions.";
+ } elsif ($status eq "offline") {
+ return "Remote master offline! Mirrored " . $self->local_revision . " revisions locally, last is " . $self->last_local;
+ } elsif ($status eq "failed") {
+ return "Local repository error!";
+ }
+}
+
+sub current_user_can {
+ return 1;
+}
+
+sub clear_cache {
+ %CACHE = ();
+};
+
+1;
+
Added: Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/View.pm
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/lib/Pushmi/Admin/View.pm Mon Jul 21 15:41:34 2008
@@ -0,0 +1,185 @@
+package Pushmi::Admin::View;
+
+use Jifty::View::Declare -base;
+
+use YAML;
+use DateTime;
+use SVN::Client;
+
+template 'index.html' => page { title => "Pushmi Administration" } content {
+ my $replicas = Pushmi::Admin::Model::ReplicaCollection->new;
+ $replicas->unlimit;
+ div {
+ { id is 'replica_list', class is 'roundbox' };
+ h2 { "Current replicas" };
+ while (my $replica = $replicas->next) {
+ div {
+ { class is 'replica status-light '.$replica->status };
+ h3 { hyperlink( url => "/replica/" . $replica->clean_name, label => $replica->name ) };
+ hyperlink( url => $replica->url, label => $replica->url );
+ div { { class is 'status' } $replica->long_status }
+ }
+ }
+ };
+
+ add_replica();
+};
+
+
+template 'create' => page { title => "Create a new replica" } content {
+ my $result = Jifty->web->response->result("check");
+ my $data = $result ? $result->content("repository") : {};
+ my $changed = DateTime->from_epoch( epoch => $data->{last_changed_date}/1e6 );
+ $changed->set_time_zone("EST");
+ div {
+ { id is 'new_replica', class is 'roundbox' };
+ h2 { "Add a new replica" };
+ div {
+ {id is 'replica_status', class is 'roundbox'};
+ h3 { $data->{repos_root_URL} }
+ p { $data->{rev} . " revisions" }
+ p { "Last modified on " . $changed->ymd . ", at " . $changed->hms }
+ };
+
+ form {
+ my $new = Jifty->web->new_action(
+ class => "CreateReplica",
+ moniker => "create",
+ );
+ if (my $prev = Jifty->web->request->action("check")) {
+ $new->argument_value( name => $prev->argument("name") );
+ $new->argument_value( mirror => Pushmi::Admin::Model::Replica->_clean_name($prev->argument("name")));
+ $new->argument_value( url => $data->{repos_root_URL} );
+ }
+
+ render_param( $new => "name" );
+ outs_raw( $new->form_value( "url" ) );
+ render_param( $new => "url", render_as => "hidden" );
+ render_param( $new => "mirror" );
+ form_submit( label => "Create" );
+ };
+ }
+};
+
+template 'check' => page { title => "Create a new replica" } content {
+ add_replica();
+};
+
+sub add_replica {
+ div {
+ { id is 'new_replica', class is 'roundbox' };
+ h2 { "Add a new replica" };
+ form {
+ my $check = Jifty->web->new_action(
+ class => "CheckURL",
+ moniker => "check",
+ sticky_on_failure => 1,
+ sticky_on_success => 1,
+ );
+ render_param( $check => "name" );
+ render_param( $check => "url" );
+ form_submit( label => "Create" );
+ }
+ }
+}
+
+template 'replica' => page { title => "About " . get("replica")->name } content {
+ my $replica = get 'replica';
+ div {
+ { class is 'roundbox' };
+ h2 { "Replica status" }
+ div {
+ { class is 'replica status-light '.$replica->status };
+ h3 { hyperlink( url => "/replica/" . $replica->clean_name, label => $replica->name ) };
+ hyperlink( url => $replica->url, label => $replica->url );
+ div { { class is 'status' } $replica->long_status }
+ }
+ };
+
+ div {
+ { class is 'roundbox' };
+
+ if ($replica->status eq "behind" and $replica->local_revision == 0) {
+ h2 { "Next step: mirroring" }
+ p {
+ "The next step is to mirror all "
+ . $replica->remote_revision
+ . " revisions from the remote mirror. This may take some time!"
+ };
+# p {
+# "If you have a bootstrap file for this mirror, you can upload it below."
+# };
+ form {
+ my $sync = Jifty->web->new_action(
+ class => "Sync",
+ );
+ render_param( $sync => "replica" => default_value => $replica->id );
+ form_submit( label => "Start mirroring" );
+ }
+ } elsif ($replica->status ne "failed") {
+ h2 { "Replica health" };
+ p { "Last local commit: r" . $replica->local_revision ." - " . $replica->last_local };
+ if ($replica->latency) {
+ p { "Last master commit: r" . $replica->remote_revision ." - " . $replica->last_remote }
+ p { "Latency to master: " . $replica->latency }
+ }
+ form {
+ my $sync = Jifty->web->new_action(
+ class => "Sync",
+ );
+ render_param( $sync => "replica" => default_value => $replica->id );
+ form_submit( label => "Force an update now" );
+ }
+ } else {
+ h2 { "Local replica failure" };
+ }
+ };
+ div {
+ { id is 'advanced' }
+ hyperlink( url => "/advanced/" . $replica->clean_name, label => "Advanced.." );
+ }
+}
+
+template 'advanced' => page { title => "Advanced configuration for ". get("replica")->name } content {
+ my $replica = get 'replica';
+
+ div {
+ { class is 'roundbox' };
+ h2 { "Advanced options for ". $replica->name ." replica" };
+
+ form {
+ div {
+ { class is "delete_replica" };
+ my $delete = $replica->as_delete_action;
+ outs_raw(
+ $delete->button(
+ label => "Delete replica",
+ url => "/",
+ onclick => {
+ confirm => 'Really delete this replica?',
+ }
+ )
+ );
+ p { "This will permanently remove the replica from this Pushmi server." };
+ }
+
+ div {
+ { class is "remirror_replica" };
+ my $remirror = Jifty->web->new_action( class => "Remirror" );
+ outs_raw(
+ $remirror->button(
+ label => "Delete and remirror",
+ arguments => { replica => $replica->id },
+ url => "/replica/" . $replica->clean_name,
+ onclick => {
+ confirm =>
+ 'Really delete and re-mirror this replica?',
+ }
+ )
+ );
+ p { "This will remove the replica, and immediately re-create it," .
+ " remirroring all remote revisions. This is likely to take a while!" };
+ }
+ };
+ }
+}
Added: Pushmi/trunk/Pushmi-Admin/share/web/static/css/app.css
==============================================================================
--- (empty file)
+++ Pushmi/trunk/Pushmi-Admin/share/web/static/css/app.css Mon Jul 21 15:41:34 2008
@@ -0,0 +1,167 @@
+body {
+ margin: 0;
+ padding: 0;
+ background: #112;
+ color: #000;
+}
+
+#content {
+ margin-left: auto;
+ margin-right: auto;
+ background: #112;
+ color: #ddd;
+ max-width: 500px;
+}
+
+#salutation, #navigation {
+ display: none;
+}
+
+h1 {
+ margin: 0;
+ padding: 0;
+}
+
+div#jifty-wait-message {
+ background:#223;
+ border: 1px solid #334;
+ color: #ddd;
+ font-size: 1em;
+ font-weight: bold;
+ padding: 5px;
+ position: fixed;
+ right: 20px;
+ top: 5px;
+}
+
+#jifty-result-popup {
+ position: fixed;
+ bottom: 20px;
+ right: 20px;
+ width: 180px;
+}
+
+#jifty-result-popup .popup_notification {
+ margin: 5px;
+ padding: 0.5em 0.5em 0.5em 27px;
+ border: 1px solid #334;
+ background: #336 url(/static/images/silk/information.png) no-repeat 5px center;
+ overflow: hidden;
+}
+
+#jifty-result-popup .result-error {
+ background: #633 url(/static/images/silk/error.png) no-repeat 5px center;
+ border: 1px solid #600;
+}
+
+#content div#messages, #content div#errors {
+ position: inherit;
+ width: 50%;
+ background-color: #223;
+ border: 1px solid #334;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+#content #dismiss_messages, #content #dismiss_errors {
+ position: relative;
+ float: right;
+ top: -0.2em;
+ right: -1em;
+}
+
+a, a:link, a:visited {
+ color: #ddd;
+ text-decoration: underline;
+ font-weight: normal;
+}
+
+a:hover {
+ color: #fff;
+ text-decoration: none;
+ font-weight: normal;
+}
+
+/* Rounded boxes and titles */
+
+.roundbox {
+ border: 1px solid #334;
+ -moz-border-radius: 8px; -webkit-border-radius: 8px;
+ padding: 1em;
+ margin-top: 3em;
+}
+
+.roundbox h2 {
+ margin-left: 0;
+ padding-left: 0;
+ float: left;
+ margin-top: -1.7em;
+ -moz-border-radius: 5px; -webkit-border-radius: 5px;
+ padding: 0.2em 0.75em;
+ line-height: 1.4em;
+ float: left;
+ background: #112;
+ border: 1px solid #334;
+}
+
+.roundbox p {
+ clear: left;
+}
+
+/* Customizations */
+#replica_status {
+ width: 450px;
+ background: #223;
+}
+
+.replica {
+ clear: left;
+ padding-left: 60px;
+}
+
+.replica.status-light {
+ background-repeat: no-repeat;
+ background-position: 0 10px;
+}
+
+.status-light.loading { background-image: url(/static/images/status/blue.png); }
+.status-light.ok { background-image: url(/static/images/status/green.png); }
+.status-light.behind { background-image: url(/static/images/status/orange.png); }
+.status-light.offline { background-image: url(/static/images/status/red.png); }
+.status-light.failed { background-image: url(/static/images/status/red.png); }
+
+#advanced {
+ margin: 1em 0;
+ padding: 1em;
+ float: right;
+ background: #223;
+ -moz-border-radius: 5px; -webkit-border-radius: 5px;
+}
+
+.delete_replica, .remirror_replica {
+ padding: 1em;
+}
+
+.delete_replica input, .remirror_replica input {
+ border: 1px solid #334;
+ background: #223;
+ color: #ddd;
+ -moz-border-radius: 5px; -webkit-border-radius: 5px;
+ padding: 0.5em;
+ padding-left: 2.5em;
+ background-repeat: no-repeat;
+ background-position: 10px 7px;
+}
+
+.delete_replica input { background-image: url(/static/images/silk/database_delete.png); }
+.remirror_replica input { background-image: url(/static/images/silk/database_refresh.png); }
+
+.delete_replica p, .remirror_replica p {
+ margin: 0;
+ padding-left: 1em;
+ padding-top: 1em;
+}
+
+.delete_replica {
+ border-bottom: 1px solid #334;
+}
\ No newline at end of file
Added: Pushmi/trunk/Pushmi-Admin/share/web/static/images/silk/database_delete.png
==============================================================================
Binary file. No diff available.
Added: Pushmi/trunk/Pushmi-Admin/share/web/static/images/silk/database_refresh.png
==============================================================================
Binary file. No diff available.
Added: Pushmi/trunk/Pushmi-Admin/share/web/static/images/status/blue.png
==============================================================================
Binary file. No diff available.
Added: Pushmi/trunk/Pushmi-Admin/share/web/static/images/status/green.png
==============================================================================
Binary file. No diff available.
Added: Pushmi/trunk/Pushmi-Admin/share/web/static/images/status/orange.png
==============================================================================
Binary file. No diff available.
Added: Pushmi/trunk/Pushmi-Admin/share/web/static/images/status/red.png
==============================================================================
Binary file. No diff available.
More information about the Bps-public-commit
mailing list