Commit dc526592cfaeb3a8bccbc4715c26c8f114f1c2a7

Authored by Nathan Broadbent
1 parent e7ff4c6f
Exists in master and in 1 other branch production

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
... ... @@ -34,12 +34,12 @@ class AppsController < InheritedResources::Base
34 34 end
35 35  
36 36 def new
37   - plug_params build_resource
  37 + plug_params(build_resource)
38 38 new!
39 39 end
40 40  
41 41 def edit
42   - plug_params resource
  42 + plug_params(resource)
43 43 edit!
44 44 end
45 45  
... ... @@ -63,6 +63,7 @@ class AppsController < InheritedResources::Base
63 63 def plug_params app
64 64 app.watchers.build if app.watchers.none?
65 65 app.issue_tracker = IssueTracker.new unless app.issue_tracker_configured?
  66 + app.copy_attributes_from(params[:copy_attributes_from]) if params[:copy_attributes_from]
66 67 end
67 68  
68 69 # email_at_notices is edited as a string, and stored as an array.
... ...
app/helpers/apps_helper.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +module AppsHelper
  2 + def link_to_copy_attributes_from_other_app
  3 + if App.count > 1
  4 + html = link_to('copy settings from another app', '#',
  5 + :class => 'button copy_config')
  6 + html << select("duplicate", "app",
  7 + App.all.reject{|a| a == @app }.
  8 + collect{|p| [ p.name, p.id ] }, {:include_blank => "[choose app]"},
  9 + {:class => "choose_other_app", :style => "display: none;"})
  10 + return html
  11 + end
  12 + end
  13 +end
  14 +
... ...
app/models/app.rb
... ... @@ -78,6 +78,22 @@ class App
78 78 notify_all_users ? User.all.map(&:email).reject(&:blank?) : watchers.map(&:address)
79 79 end
80 80  
  81 + # Copy app attributes from another app.
  82 + def copy_attributes_from(app_id)
  83 + if copy_app = App.where(:_id => app_id).first
  84 + # Copy fields
  85 + (copy_app.fields.keys - %w(_id name created_at updated_at)).each do |k|
  86 + self.send("#{k}=", copy_app.send(k))
  87 + end
  88 + # Clone the embedded objects that can be changed via apps/edit (ignore errs & deploys, etc.)
  89 + %w(watchers issue_tracker).each do |relation|
  90 + if obj = copy_app.send(relation)
  91 + self.send("#{relation}=", obj.is_a?(Array) ? obj.map(&:clone) : obj.clone)
  92 + end
  93 + end
  94 + end
  95 + end
  96 +
81 97 protected
82 98  
83 99 def generate_api_key
... ...
app/views/apps/edit.html.haml
1 1 - content_for :title, 'Edit App'
2   -- content_for :action_bar, link_to('cancel', app_path(@app), :class => 'button')
  2 +- content_for :action_bar do
  3 + = link_to_copy_attributes_from_other_app
  4 + = link_to('cancel', app_path(@app), :class => 'button')
3 5  
4 6 = form_for @app do |f|
5   -
  7 +
6 8 = render 'fields', :f => f
7   -
8   - %div.buttons= f.submit 'Update App'
9 9 \ No newline at end of file
  10 +
  11 + %div.buttons= f.submit 'Update App'
  12 +
... ...
app/views/apps/new.html.haml
1 1 - content_for :title, 'Add App'
2   -- content_for :action_bar, link_to('cancel', apps_path, :class => 'button')
  2 +- content_for :action_bar do
  3 + = link_to_copy_attributes_from_other_app
  4 + = link_to('cancel', apps_path, :class => 'button')
3 5  
4 6 = form_for @app do |f|
5   -
  7 +
6 8 = render 'fields', :f => f
7   -
8   - %div.buttons= f.submit 'Add App'
9 9 \ No newline at end of file
  10 +
  11 + %div.buttons= f.submit 'Add App'
  12 +
... ...
public/javascripts/application.js
... ... @@ -2,7 +2,7 @@
2 2  
3 3 $(function(){
4 4 activateTabbedPanels();
5   -
  5 +
6 6 $('#watcher_name').live("click", function() {
7 7 $(this).closest('form').find('.show').removeClass('show');
8 8 $('#app_watchers_attributes_0_user_id').addClass('show');
... ... @@ -13,6 +13,14 @@ $(function(){
13 13 $('#app_watchers_attributes_0_email').addClass('show');
14 14 });
15 15  
  16 + $('a.copy_config').live("click", function() {
  17 + $('select.choose_other_app').show().focus();
  18 + });
  19 + $('select.choose_other_app').live("change", function() {
  20 + var loc = window.location;
  21 + window.location.href = loc.protocol + "//" + loc.host + loc.pathname +
  22 + "?copy_attributes_from=" + $(this).val();
  23 + });
16 24 });
17 25  
18 26 function activateTabbedPanels() {
... ... @@ -22,8 +30,8 @@ function activateTabbedPanels() {
22 30 panel.addClass('panel');
23 31 panel.find('h3').hide();
24 32 })
25   -
26   - $('.tab-bar a').click(function(){
  33 +
  34 + $('.tab-bar a').click(function(){
27 35 activateTab($(this));
28 36 return(false);
29 37 });
... ... @@ -33,10 +41,11 @@ function activateTabbedPanels() {
33 41 function activateTab(tab) {
34 42 tab = $(tab);
35 43 var panel = $('#'+tab.attr('rel'));
36   -
  44 +
37 45 tab.closest('.tab-bar').find('a.active').removeClass('active');
38 46 tab.addClass('active');
39   -
  47 +
40 48 $('.panel').hide();
41 49 panel.show();
42   -}
43 50 \ No newline at end of file
  51 +}
  52 +
... ...
spec/controllers/apps_controller_spec.rb
... ... @@ -173,6 +173,16 @@ describe AppsController do
173 173 assigns(:app).should be_new_record
174 174 assigns(:app).watchers.should_not be_empty
175 175 end
  176 +
  177 + it "should copy attributes from an existing app" do
  178 + @app = Factory(:app, :name => "do not copy",
  179 + :github_url => "github.com/test/example")
  180 + get :new, :copy_attributes_from => @app.id
  181 + assigns(:app).should be_a(App)
  182 + assigns(:app).should be_new_record
  183 + assigns(:app).name.should be_blank
  184 + assigns(:app).github_url.should == "github.com/test/example"
  185 + end
176 186 end
177 187  
178 188 describe "GET /apps/:id/edit" do
... ...
spec/models/app_spec.rb
... ... @@ -99,5 +99,16 @@ describe App do
99 99 end
100 100 end
101 101  
  102 + context "copying attributes from existing app" do
  103 + it "should only copy the necessary fields" do
  104 + @app, @copy_app = Factory(:app, :name => "app", :github_url => "url"),
  105 + Factory(:app, :name => "copy_app", :github_url => "copy url")
  106 + @copy_watcher = Factory(:watcher, :email => "copywatcher@example.com", :app => @copy_app)
  107 + @app.copy_attributes_from(@copy_app.id)
  108 + @app.name.should == "app"
  109 + @app.github_url.should == "copy url"
  110 + @app.watchers.first.email.should == "copywatcher@example.com"
  111 + end
  112 + end
102 113 end
103 114  
... ...