Commit 889af62f910ad4d4ea4f1ef0d196c0f0983ee48d
1 parent
ed78ea13
Exists in
master
and in
1 other branch
Refactor the Issue Tracker forms in App
Showing
21 changed files
with
261 additions
and
30 deletions
Show diff stats
Gemfile
... | ... | @@ -25,6 +25,7 @@ gem 'rails_autolink' |
25 | 25 | # Please don't update hoptoad_notifier to airbrake. |
26 | 26 | # It's for internal use only, and we monkeypatch certain methods |
27 | 27 | gem 'hoptoad_notifier', "~> 2.4" |
28 | +gem 'draper', :require => false | |
28 | 29 | |
29 | 30 | |
30 | 31 | # Remove / comment out any of the gems below if you want to disable | ... | ... |
Gemfile.lock
... | ... | @@ -95,6 +95,10 @@ GEM |
95 | 95 | warden (~> 1.2.3) |
96 | 96 | diff-lcs (1.2.4) |
97 | 97 | dotenv (0.9.0) |
98 | + draper (1.2.1) | |
99 | + actionpack (>= 3.0) | |
100 | + activesupport (>= 3.0) | |
101 | + request_store (~> 1.0.3) | |
98 | 102 | email_spec (1.5.0) |
99 | 103 | launchy (~> 2.1) |
100 | 104 | mail (~> 2.2) |
... | ... | @@ -282,6 +286,7 @@ GEM |
282 | 286 | rdoc (3.12.2) |
283 | 287 | json (~> 1.4) |
284 | 288 | ref (1.0.5) |
289 | + request_store (1.0.5) | |
285 | 290 | rest-client (1.6.7) |
286 | 291 | mime-types (>= 1.16) |
287 | 292 | ri_cal (0.8.8) |
... | ... | @@ -382,6 +387,7 @@ DEPENDENCIES |
382 | 387 | debugger |
383 | 388 | decent_exposure |
384 | 389 | devise |
390 | + draper | |
385 | 391 | email_spec |
386 | 392 | execjs |
387 | 393 | fabrication | ... | ... |
app/controllers/apps_controller.rb
... | ... | @@ -0,0 +1,19 @@ |
1 | +class AppDecorator < Draper::Decorator | |
2 | + | |
3 | + decorates_association :watchers | |
4 | + decorates_association :issue_tracker, :with => IssueTrackerDecorator | |
5 | + delegate_all | |
6 | + | |
7 | + def email_at_notices | |
8 | + object.email_at_notices.join(', ') | |
9 | + end | |
10 | + | |
11 | + def notify_user_display | |
12 | + object.notify_all_users ? 'display: none;' : '' | |
13 | + end | |
14 | + | |
15 | + def notify_err_display | |
16 | + object.notify_on_errs ? '' : 'display: none;' | |
17 | + end | |
18 | + | |
19 | +end | ... | ... |
... | ... | @@ -0,0 +1,35 @@ |
1 | +class IssueTrackerDecorator < Draper::Decorator | |
2 | + | |
3 | + delegate_all | |
4 | + | |
5 | + def issue_trackers | |
6 | + @issue_trackers ||= [ | |
7 | + IssueTracker, | |
8 | + IssueTracker.subclasses | |
9 | + ].flatten | |
10 | + @issue_trackers.each do |it| | |
11 | + yield IssueTrackerDecorator.new(it) | |
12 | + end | |
13 | + end | |
14 | + | |
15 | + def note | |
16 | + object::Note.html_safe | |
17 | + end | |
18 | + | |
19 | + def fields | |
20 | + object::Fields.each do |field, field_info| | |
21 | + yield IssueTrackerFieldDecorator.new(field, field_info) | |
22 | + end | |
23 | + end | |
24 | + | |
25 | + def params_class(tracker) | |
26 | + [choosen?(tracker), label].join(" ").strip | |
27 | + end | |
28 | + | |
29 | + private | |
30 | + | |
31 | + def choosen?(issue_tracker) | |
32 | + object.to_s == issue_tracker._type ? 'chosen' : '' | |
33 | + end | |
34 | + | |
35 | +end | ... | ... |
... | ... | @@ -0,0 +1,27 @@ |
1 | +class IssueTrackerFieldDecorator < Draper::Decorator | |
2 | + | |
3 | + def initialize(field, field_info) | |
4 | + @object = field | |
5 | + @field_info = field_info | |
6 | + end | |
7 | + attr_reader :object, :field_info | |
8 | + | |
9 | + alias :key :object | |
10 | + | |
11 | + def label | |
12 | + field_info[:label] || object.to_s.titleize | |
13 | + end | |
14 | + | |
15 | + | |
16 | + def input(form) | |
17 | + form.send(input_field, object, | |
18 | + :placeholder => field_info[:placeholder], | |
19 | + :value => form.object.send(object)) | |
20 | + end | |
21 | + | |
22 | + private | |
23 | + | |
24 | + def input_field | |
25 | + object == :password ? :password_field : :text_field | |
26 | + end | |
27 | +end | ... | ... |
app/models/issue_tracker.rb
... | ... | @@ -3,6 +3,11 @@ class IssueTracker |
3 | 3 | include Mongoid::Timestamps |
4 | 4 | include HashHelper |
5 | 5 | include Rails.application.routes.url_helpers |
6 | + | |
7 | + Fields = [] | |
8 | + Note = 'When no issue tracker has been configured, you will be able to leave comments on errors.' | |
9 | + Label = 'none' | |
10 | + | |
6 | 11 | default_url_options[:host] = ActionMailer::Base.default_url_options[:host] |
7 | 12 | |
8 | 13 | embedded_in :app, :inverse_of => :issue_tracker |
... | ... | @@ -41,7 +46,6 @@ class IssueTracker |
41 | 46 | def url; nil; end |
42 | 47 | |
43 | 48 | # Retrieve tracker label from either class or instance. |
44 | - Label = '' | |
45 | 49 | def self.label; self::Label; end |
46 | 50 | def label; self.class.label; end |
47 | 51 | ... | ... |
app/views/apps/_fields.html.haml
... | ... | @@ -29,9 +29,9 @@ |
29 | 29 | = f.check_box :notify_on_errs, 'data-show-when-checked' => '.email_at_notices_nested' |
30 | 30 | = f.label :notify_on_errs, 'Notify on errors' |
31 | 31 | - if Errbit::Config.per_app_email_at_notices |
32 | - %div.email_at_notices_nested{:style => f.object.notify_on_errs ? '' : 'display: none;'} | |
32 | + %div.email_at_notices_nested{:style => app_decorate.notify_err_display} | |
33 | 33 | .field-helpertext Send a notification every |
34 | - = f.text_field :email_at_notices, :value => f.object.email_at_notices.join(", ") | |
34 | + = f.text_field :email_at_notices, :value => app_decorate.email_at_notices | |
35 | 35 | .field-helpertext times an error occurs (comma separated). |
36 | 36 | %div.checkbox |
37 | 37 | = f.check_box :notify_on_deploys |
... | ... | @@ -42,16 +42,16 @@ |
42 | 42 | = f.label :notify_all_users, 'Send notifications to all users' |
43 | 43 | |
44 | 44 | |
45 | -%fieldset.watchers.nested-wrapper{:style => f.object.notify_all_users ? 'display: none;' : ''} | |
45 | +%fieldset.watchers.nested-wrapper{:style => app_decorate.notify_user_display} | |
46 | 46 | %legend Watchers |
47 | 47 | = f.fields_for :watchers do |w| |
48 | 48 | %div.watcher.nested |
49 | 49 | %div.choose |
50 | 50 | = w.radio_button :watcher_type, :user |
51 | - = label_tag :watcher_type_user, 'User', :for => label_for_attr(w, 'watcher_type_user') | |
51 | + = w.label :watcher_type_user, 'User' | |
52 | 52 | = w.radio_button :watcher_type, :email |
53 | - = label_tag :watcher_type_email, 'Email Address', :for => label_for_attr(w, 'watcher_type_email') | |
54 | - %div.watcher_params.user{:class => w.object.email.blank? ? 'chosen' : nil} | |
53 | + = w.label :watcher_type_email, 'Email Address' | |
54 | + %div.watcher_params.user{:class => w.object.email_choosen} | |
55 | 55 | = w.select :user_id, User.all.map{|u| [u.name,u.id.to_s]}, :include_blank => '-- Select a User --' |
56 | 56 | %div.watcher_params.email{:class => w.object.email.present? ? 'chosen' : nil} |
57 | 57 | = w.text_field :email | ... | ... |
app/views/apps/_issue_tracker_fields.html.haml
1 | 1 | %fieldset |
2 | - %legend Issue tracker | |
2 | + %legend= t('.legend') | |
3 | 3 | = f.fields_for :issue_tracker do |w| |
4 | 4 | %div.issue_tracker.nested |
5 | 5 | %div.choose |
6 | - = label_tag :type_none, :for => label_for_attr(w, 'type_issuetracker'), :class => "label_radio none" do | |
7 | - = w.radio_button :type, "IssueTracker", 'data-section' => 'none' | |
8 | - (None) | |
9 | - - IssueTracker.subclasses.each do |tracker| | |
10 | - = label_tag "type_#{tracker.label}:", :for => label_for_attr(w, "type_#{tracker.name.downcase.gsub(':','')}"), :class => "label_radio #{tracker.label}" do | |
6 | + - w.object.issue_trackers do |tracker| | |
7 | + = w.label :type, :class => "label_radio #{tracker.label}", :value => tracker.name do | |
11 | 8 | = w.radio_button :type, tracker.name, 'data-section' => tracker.label |
12 | - = tracker.name[/::(.*)Tracker/,1].titleize | |
9 | + = tracker.label | |
13 | 10 | |
14 | - %div.tracker_params.none{:class => (w.object && !(w.object.class < IssueTracker)) ? 'chosen' : nil} | |
15 | - %p When no issue tracker has been configured, you will be able to leave comments on errors. | |
16 | - - IssueTracker.subclasses.each do |tracker| | |
17 | - %div.tracker_params{:class => (w.object.is_a?(tracker) ? 'chosen ' : '') << tracker.label} | |
18 | - - if defined?(tracker::Note) | |
19 | - %p= tracker::Note.html_safe | |
20 | - - tracker::Fields.each do |field, field_info| | |
21 | - = w.label field, field_info[:label] || field.to_s.titleize | |
22 | - - field_type = field == :password ? :password_field : :text_field | |
23 | - = w.send field_type, field, :placeholder => field_info[:placeholder], :value => w.object.send(field) | |
11 | + - w.object.issue_trackers do |tracker| | |
12 | + %div.tracker_params{:class => tracker.params_class(w.object)} | |
13 | + %p= tracker.note | |
14 | + - tracker.fields do |field| | |
15 | + = w.label field.key, field.label | |
16 | + = field.input(w) | |
24 | 17 | |
25 | 18 | .image_preloader |
26 | - - (IssueTracker.subclasses.map{|t| t.label } << 'none').each do |tracker| | |
27 | - = image_tag "#{tracker}_inactive.png" | |
28 | - = image_tag "#{tracker}_create.png" | |
19 | + - w.object.issue_trackers do |tracker| | |
20 | + = image_tag "#{tracker.label}_inactive.png" | |
21 | + = image_tag "#{tracker.label}_create.png" | |
29 | 22 | ... | ... |
app/views/apps/edit.html.haml
app/views/apps/new.html.haml
config/application.rb
... | ... | @@ -9,6 +9,8 @@ require "action_mailer/railtie" |
9 | 9 | require 'mongoid/railtie' |
10 | 10 | require "sprockets/railtie" |
11 | 11 | |
12 | +require 'draper' | |
13 | + | |
12 | 14 | if defined?(Bundler) |
13 | 15 | # If you precompile assets before deploying to production, use this line |
14 | 16 | Bundler.require(*Rails.groups(:assets => %w(development test))) | ... | ... |
config/locales/en.yml
spec/acceptance/app_regenerate_api_key_spec.rb
... | ... | @@ -0,0 +1,37 @@ |
1 | +require 'spec_helper' | |
2 | + | |
3 | +describe AppDecorator do | |
4 | + | |
5 | + describe "#email_at_notices" do | |
6 | + | |
7 | + it 'return the list separate by comma' do | |
8 | + expect(AppDecorator.new(double(:email_at_notices => [2,3])).email_at_notices).to eql '2, 3' | |
9 | + end | |
10 | + | |
11 | + end | |
12 | + | |
13 | + describe "#notify_user_display" do | |
14 | + | |
15 | + it 'return display:none if notify' do | |
16 | + expect(AppDecorator.new(double(:notify_all_users => true)).notify_user_display).to eql 'display: none;' | |
17 | + end | |
18 | + | |
19 | + it 'return blank if no notify' do | |
20 | + expect(AppDecorator.new(double(:notify_all_users => false)).notify_user_display).to eql '' | |
21 | + end | |
22 | + | |
23 | + end | |
24 | + | |
25 | + describe "#notify_err_display" do | |
26 | + | |
27 | + it 'return display:none if no notify' do | |
28 | + expect(AppDecorator.new(double(:notify_on_errs => false)).notify_err_display).to eql 'display: none;' | |
29 | + end | |
30 | + | |
31 | + it 'return blank if no notify' do | |
32 | + expect(AppDecorator.new(double(:notify_on_errs => true)).notify_err_display).to eql '' | |
33 | + end | |
34 | + | |
35 | + end | |
36 | + | |
37 | +end | ... | ... |
... | ... | @@ -0,0 +1,59 @@ |
1 | +require 'spec_helper' | |
2 | + | |
3 | +describe IssueTrackerDecorator do | |
4 | + | |
5 | + class Foo | |
6 | + Note = 'hello <strong></strong>' | |
7 | + Fields = [ | |
8 | + [:foo, :bar] | |
9 | + ] | |
10 | + Label = 'foo' | |
11 | + def self.label; Label; end | |
12 | + def _type | |
13 | + 'Foo' | |
14 | + end | |
15 | + end | |
16 | + | |
17 | + class Bar | |
18 | + Label = 'bar' | |
19 | + def self.label; Label; end | |
20 | + def _type | |
21 | + 'Bar' | |
22 | + end | |
23 | + end | |
24 | + | |
25 | + describe "#note" do | |
26 | + | |
27 | + | |
28 | + it 'return the html_safe of Note' do | |
29 | + expect(IssueTrackerDecorator.new(Foo).note).to eql 'hello <strong></strong>'.html_safe | |
30 | + end | |
31 | + end | |
32 | + | |
33 | + describe "#issue_trackers" do | |
34 | + it 'return an array of IssueTrackerDecorator' do | |
35 | + IssueTrackerDecorator.new(Foo).issue_trackers do |it| | |
36 | + expect(it).to be_a(IssueTrackerDecorator) | |
37 | + end | |
38 | + end | |
39 | + end | |
40 | + | |
41 | + describe "#fields" do | |
42 | + it 'return all Fields define decorate' do | |
43 | + IssueTrackerDecorator.new(Foo).fields do |itf| | |
44 | + expect(itf).to be_a(IssueTrackerFieldDecorator) | |
45 | + expect(itf.object).to eql :foo | |
46 | + expect(itf.field_info).to eql :bar | |
47 | + end | |
48 | + end | |
49 | + end | |
50 | + | |
51 | + describe "#params_class" do | |
52 | + it 'add the label in class' do | |
53 | + expect(IssueTrackerDecorator.new(Bar).params_class(Foo.new)).to eql 'bar' | |
54 | + end | |
55 | + it 'add chosen class if _type is same' do | |
56 | + expect(IssueTrackerDecorator.new(Foo).params_class(Foo.new)).to eql 'chosen foo' | |
57 | + end | |
58 | + end | |
59 | +end | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +require 'spec_helper' | |
2 | + | |
3 | +describe IssueTrackerFieldDecorator do | |
4 | + | |
5 | + describe "#label" do | |
6 | + it 'return the label of field_info by default' do | |
7 | + expect(IssueTrackerFieldDecorator.new(:foo, {:label => 'hello'}).label).to eq 'hello' | |
8 | + end | |
9 | + it 'return the key of field if no label define' do | |
10 | + expect(IssueTrackerFieldDecorator.new(:foo, {}).label).to eq 'foo' | |
11 | + end | |
12 | + end | |
13 | + | |
14 | +end | ... | ... |
... | ... | @@ -0,0 +1,17 @@ |
1 | +require 'spec_helper' | |
2 | + | |
3 | +describe WatcherDecorator do | |
4 | + describe "#email_choosen" do | |
5 | + context "with email define" do | |
6 | + it 'return blank' do | |
7 | + expect(WatcherDecorator.new(double(:email => 'foo')).email_choosen).to eql '' | |
8 | + end | |
9 | + end | |
10 | + | |
11 | + context "without email define" do | |
12 | + it 'return choosen' do | |
13 | + expect(WatcherDecorator.new(double(:email => '')).email_choosen).to eql 'chosen' | |
14 | + end | |
15 | + end | |
16 | + end | |
17 | +end | ... | ... |
spec/views/apps/edit.html.haml_spec.rb
... | ... | @@ -2,8 +2,10 @@ require 'spec_helper' |
2 | 2 | |
3 | 3 | describe "apps/edit.html.haml" do |
4 | 4 | let(:app) { stub_model(App) } |
5 | + let(:app_decorate) { AppDecorator.new(app) } | |
5 | 6 | before do |
6 | 7 | view.stub(:app).and_return(app) |
8 | + view.stub(:app_decorate).and_return(app_decorate) | |
7 | 9 | controller.stub(:current_user) { stub_model(User) } |
8 | 10 | end |
9 | 11 | ... | ... |
spec/views/apps/new.html.haml_spec.rb
... | ... | @@ -2,8 +2,10 @@ require 'spec_helper' |
2 | 2 | |
3 | 3 | describe "apps/new.html.haml" do |
4 | 4 | let(:app) { stub_model(App) } |
5 | + let(:app_decorate) { AppDecorator.new(app) } | |
5 | 6 | before do |
6 | 7 | view.stub(:app).and_return(app) |
8 | + view.stub(:app_decorate).and_return(app_decorate) | |
7 | 9 | controller.stub(:current_user) { stub_model(User) } |
8 | 10 | end |
9 | 11 | ... | ... |