[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