Commit dc526592cfaeb3a8bccbc4715c26c8f114f1c2a7
1 parent
e7ff4c6f
Exists in
master
and in
1 other branch
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.
Showing
8 changed files
with
83 additions
and
16 deletions
Show diff stats
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. | ... | ... |
... | ... | @@ -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 | ... | ... |