From dc526592cfaeb3a8bccbc4715c26c8f114f1c2a7 Mon Sep 17 00:00:00 2001 From: Nathan Broadbent Date: Sat, 27 Aug 2011 18:24:18 +0800 Subject: [PATCH] Added a button to copy settings from another app when editing or creating an app. (We needed to set up 10+ apps using the same issue tracker and watcher email). Works great, and is tested, but I wouldn't mind some help on the UI. --- app/controllers/apps_controller.rb | 5 +++-- app/helpers/apps_helper.rb | 14 ++++++++++++++ app/models/app.rb | 16 ++++++++++++++++ app/views/apps/edit.html.haml | 11 +++++++---- app/views/apps/new.html.haml | 11 +++++++---- public/javascripts/application.js | 21 +++++++++++++++------ spec/controllers/apps_controller_spec.rb | 10 ++++++++++ spec/models/app_spec.rb | 11 +++++++++++ 8 files changed, 83 insertions(+), 16 deletions(-) create mode 100644 app/helpers/apps_helper.rb diff --git a/app/controllers/apps_controller.rb b/app/controllers/apps_controller.rb index 1cbf4ff..71e3a80 100644 --- a/app/controllers/apps_controller.rb +++ b/app/controllers/apps_controller.rb @@ -34,12 +34,12 @@ class AppsController < InheritedResources::Base end def new - plug_params build_resource + plug_params(build_resource) new! end def edit - plug_params resource + plug_params(resource) edit! end @@ -63,6 +63,7 @@ class AppsController < InheritedResources::Base def plug_params app app.watchers.build if app.watchers.none? app.issue_tracker = IssueTracker.new unless app.issue_tracker_configured? + app.copy_attributes_from(params[:copy_attributes_from]) if params[:copy_attributes_from] end # email_at_notices is edited as a string, and stored as an array. diff --git a/app/helpers/apps_helper.rb b/app/helpers/apps_helper.rb new file mode 100644 index 0000000..789ae38 --- /dev/null +++ b/app/helpers/apps_helper.rb @@ -0,0 +1,14 @@ +module AppsHelper + def link_to_copy_attributes_from_other_app + if App.count > 1 + html = link_to('copy settings from another app', '#', + :class => 'button copy_config') + html << select("duplicate", "app", + App.all.reject{|a| a == @app }. + collect{|p| [ p.name, p.id ] }, {:include_blank => "[choose app]"}, + {:class => "choose_other_app", :style => "display: none;"}) + return html + end + end +end + diff --git a/app/models/app.rb b/app/models/app.rb index a1963d4..6eba6fd 100644 --- a/app/models/app.rb +++ b/app/models/app.rb @@ -78,6 +78,22 @@ class App notify_all_users ? User.all.map(&:email).reject(&:blank?) : watchers.map(&:address) end + # Copy app attributes from another app. + def copy_attributes_from(app_id) + if copy_app = App.where(:_id => app_id).first + # Copy fields + (copy_app.fields.keys - %w(_id name created_at updated_at)).each do |k| + self.send("#{k}=", copy_app.send(k)) + end + # Clone the embedded objects that can be changed via apps/edit (ignore errs & deploys, etc.) + %w(watchers issue_tracker).each do |relation| + if obj = copy_app.send(relation) + self.send("#{relation}=", obj.is_a?(Array) ? obj.map(&:clone) : obj.clone) + end + end + end + end + protected def generate_api_key diff --git a/app/views/apps/edit.html.haml b/app/views/apps/edit.html.haml index 02162ed..97d4322 100644 --- a/app/views/apps/edit.html.haml +++ b/app/views/apps/edit.html.haml @@ -1,8 +1,11 @@ - content_for :title, 'Edit App' -- content_for :action_bar, link_to('cancel', app_path(@app), :class => 'button') +- content_for :action_bar do + = link_to_copy_attributes_from_other_app + = link_to('cancel', app_path(@app), :class => 'button') = form_for @app do |f| - + = render 'fields', :f => f - - %div.buttons= f.submit 'Update App' \ No newline at end of file + + %div.buttons= f.submit 'Update App' + diff --git a/app/views/apps/new.html.haml b/app/views/apps/new.html.haml index c6050aa..994b7a2 100644 --- a/app/views/apps/new.html.haml +++ b/app/views/apps/new.html.haml @@ -1,8 +1,11 @@ - content_for :title, 'Add App' -- content_for :action_bar, link_to('cancel', apps_path, :class => 'button') +- content_for :action_bar do + = link_to_copy_attributes_from_other_app + = link_to('cancel', apps_path, :class => 'button') = form_for @app do |f| - + = render 'fields', :f => f - - %div.buttons= f.submit 'Add App' \ No newline at end of file + + %div.buttons= f.submit 'Add App' + diff --git a/public/javascripts/application.js b/public/javascripts/application.js index 1bb920b..0b813eb 100644 --- a/public/javascripts/application.js +++ b/public/javascripts/application.js @@ -2,7 +2,7 @@ $(function(){ activateTabbedPanels(); - + $('#watcher_name').live("click", function() { $(this).closest('form').find('.show').removeClass('show'); $('#app_watchers_attributes_0_user_id').addClass('show'); @@ -13,6 +13,14 @@ $(function(){ $('#app_watchers_attributes_0_email').addClass('show'); }); + $('a.copy_config').live("click", function() { + $('select.choose_other_app').show().focus(); + }); + $('select.choose_other_app').live("change", function() { + var loc = window.location; + window.location.href = loc.protocol + "//" + loc.host + loc.pathname + + "?copy_attributes_from=" + $(this).val(); + }); }); function activateTabbedPanels() { @@ -22,8 +30,8 @@ function activateTabbedPanels() { panel.addClass('panel'); panel.find('h3').hide(); }) - - $('.tab-bar a').click(function(){ + + $('.tab-bar a').click(function(){ activateTab($(this)); return(false); }); @@ -33,10 +41,11 @@ function activateTabbedPanels() { function activateTab(tab) { tab = $(tab); var panel = $('#'+tab.attr('rel')); - + tab.closest('.tab-bar').find('a.active').removeClass('active'); tab.addClass('active'); - + $('.panel').hide(); panel.show(); -} \ No newline at end of file +} + diff --git a/spec/controllers/apps_controller_spec.rb b/spec/controllers/apps_controller_spec.rb index 95c66ed..9a5f845 100644 --- a/spec/controllers/apps_controller_spec.rb +++ b/spec/controllers/apps_controller_spec.rb @@ -173,6 +173,16 @@ describe AppsController do assigns(:app).should be_new_record assigns(:app).watchers.should_not be_empty end + + it "should copy attributes from an existing app" do + @app = Factory(:app, :name => "do not copy", + :github_url => "github.com/test/example") + get :new, :copy_attributes_from => @app.id + assigns(:app).should be_a(App) + assigns(:app).should be_new_record + assigns(:app).name.should be_blank + assigns(:app).github_url.should == "github.com/test/example" + end end describe "GET /apps/:id/edit" do diff --git a/spec/models/app_spec.rb b/spec/models/app_spec.rb index 2c1e8f6..a845c86 100644 --- a/spec/models/app_spec.rb +++ b/spec/models/app_spec.rb @@ -99,5 +99,16 @@ describe App do end end + context "copying attributes from existing app" do + it "should only copy the necessary fields" do + @app, @copy_app = Factory(:app, :name => "app", :github_url => "url"), + Factory(:app, :name => "copy_app", :github_url => "copy url") + @copy_watcher = Factory(:watcher, :email => "copywatcher@example.com", :app => @copy_app) + @app.copy_attributes_from(@copy_app.id) + @app.name.should == "app" + @app.github_url.should == "copy url" + @app.watchers.first.email.should == "copywatcher@example.com" + end + end end -- libgit2 0.21.2