redmine_extensions 0.1.16 → 0.1.17

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e9dafb1894abe51656840de62914a350b3c9d78c
4
- data.tar.gz: 6dcbff3717bfac6323606d4dffd6bb959ae5bf42
3
+ metadata.gz: 23ca96f77329db75217df08f43cdf52bbd7ed2e8
4
+ data.tar.gz: 16757b5cddacb84ec7d1bbe0637d034bfa8aeaaf
5
5
  SHA512:
6
- metadata.gz: 491d56cfee43c1daed176f2f94551daf40d02fb4718d215fb37743e634a8b439dd53f6db1c18f0be6a654c584ca0b6ebea8027018669b80a4077bd57b1e15d69
7
- data.tar.gz: 0f2b44330b8a107a674b06652acd5bc82f91354c60f58065ffec60e76d1a30903ae0d1552695b1f634f37cf379bef2e859d32517870f890b66423051cd11db37
6
+ metadata.gz: 1fcd410c0f9f7d0a095aff4547322f1681f7a940f25ccc0c46303f670c895386141a09c99d76198880c1fc00b02922b4d944eb25b7ce888520bf9798aeed466c
7
+ data.tar.gz: 4d0a6f90ea945c090d2be5a823814e402525ad1a4850b401f4bf365049bf48a0ccc988a1bd4ede7ac1dea47c9f380bb16da452689c3d589052ead86d18250733
data/Rakefile CHANGED
@@ -37,7 +37,7 @@ task :generate_test_plugin do
37
37
  require RedmineExtensions::Engine.root.join('spec', 'support', 'plugin_generator').to_s
38
38
  PluginGenerator.generate_test_plugin!
39
39
  end
40
- RSpec::Core::RakeTask.new(spec: :generate_test_plugin) do |spec|
40
+ RSpec::Core::RakeTask.new(spec: [:generate_test_plugin, 'app:redmine:plugins:migrate']) do |spec|
41
41
  spec.pattern = 'spec/**/*_spec.rb'
42
42
  spec.exclude_pattern = 'spec/redmine/**/*_spec.rb'
43
43
  end
@@ -205,7 +205,27 @@ module RedmineExtensions
205
205
 
206
206
  end
207
207
 
208
-
208
+ # Returns a multiselect autocomplete input tag tailored for selecting 1..N values from defined source by +jsonpath_or_array+.
209
+ # Preselected will be values in +selected_values+ parameter, or if those are empty, and +select_first_value+ option is set,
210
+ # it will select first value from source. See warning from this parameter!
211
+ # Additional options on the input tag can be passed as a hash with +options+.
212
+ # These options will be passed to the handling javascript.
213
+ # Available format for +selected_values+:
214
+ # * Array of values. It will search for the values in available_values for values names assigned.
215
+ # * Array of objects in format: {id: <value send in form>, value: <label - user shown value>}
216
+ # Available options are:
217
+ # * +multiple+ - tells if more than one value can be selected.
218
+ # * +preload+ - tells if values should be preloaded all at once - in one request - if jsonpathh is a source, this parameter expect it to return all available values.
219
+ # * +load_immediately+ - tells if values should be loaded immediatelly after page loaded, or wait for first use of the field.
220
+ # Warning! if this option is false, selected values passed in first format will be ignored till it is loaded.
221
+ # Please use second format for proper functionality.
222
+ # * +show_toggle_button+ - only valid with <tt>multiple: true, preload: true</tt> options set. Shows toggle button to expand select to the multiselect tag.
223
+ # * +select_first_value+ - if selectd_values are empty, with this option first available value will be selected.
224
+ # Available only with <tt>preload: true</tt> option.
225
+ # With <tt>load_immediately: false</tt> it will appear kinda weird for user because it will select the value after user starts to interact with input.
226
+ # please consider if this is what you want.
227
+ # * +rootElement+ - Has sence only if jsonpath is used for available values. It tells if the json response has values wrapped under root element.
228
+ # For response like <tt>{projects: [[<name>, <id>], [<name2>, <id2>]]}</tt> user option <tt>rootElement: 'projects'</tt>
209
229
  def autocomplete_field_tag(name, jsonpath_or_array, selected_values, options = {})
210
230
  options.reverse_merge!({select_first_value: false, show_toggle_button: false, load_immediately: false, preload: true, multiple: true})
211
231
  options[:id] ||= sanitize_to_id(name)
@@ -224,5 +244,29 @@ module RedmineExtensions
224
244
  end
225
245
  end
226
246
 
247
+ # Returns a multiselect autocomplete input tag tailored for accessing a specified attribute (identified by +method+) on an object
248
+ # assigned to the template (identified by +object+). Additional options on the input tag can be passed as a
249
+ # hash with +options+. These options will be passed to the handling javascript as in the example shown.
250
+ # Available values for select are passed as +choices+ attribute. It can be Array of values, or json path for later loading or autocomplete.
251
+ # Please see autocomplete_field_tag documentation for more information about options and available values format combinations.
252
+ # HTML options can be passed as a hash with +html_options+. These options will be passed to the input element.
253
+ #
254
+ # ==== Examples
255
+ # autocomplete_field(:issue, :tag_ids, Tag.all.pluck(:name, :id), multiple: true, show_toggle_button: true)
256
+ # # => <span class="easy-multiselect-tag-container"> \
257
+ # <input type="text" id="issue_tags" /> \
258
+ # <button type="button" tabindex="-1" class="..." role="button" ...>
259
+ # <span class="ui-button-icon-primary ui-icon ui-icon-triangle-1-s"></span><span class="ui-button-text">&nbsp;</span>
260
+ # </button>
261
+ # <a class="icon icon-add clear-link"></a> # toggle button to the multiselect tag from show_toggle_button option
262
+ # ...(wraping service tags)
263
+ # <input type="hidden" name="issue[tag_ids][]" value="#{@issue.tag_ids.first}" />
264
+ # <input type="hidden" name="issue[tag_ids][]" value="#{@issue.tag_ids.second}" />
265
+ # ...(wraping service tags end)
266
+ # </span>
267
+ def autocomplete_field(object_name, method, choices, options={}, html_options={})
268
+ Tags::AutocompleteField.new(object_name, method, self, choices, options, html_options).render
269
+ end
270
+
227
271
  end
228
272
  end
@@ -1,6 +1,6 @@
1
1
  Description:
2
- The plugin generator creates stubs for a new Redmine plugin.
3
- Plugin is prepared for use in Redmine and Easy Redmine as well.
2
+ The entity generator creates new entity for Redmine plugin.
3
+ New entity is prepared for use in Redmine and Easy Redmine as well.
4
4
 
5
5
  Example:
6
6
  rails g redmine_extensions:entity NameOfNewPlugin Post
@@ -49,6 +49,9 @@ module RedmineExtensions
49
49
  template 'edit.html.erb.erb', "#{plugin_path}/app/views/#{model_name_pluralize_underscored}/edit.html.erb"
50
50
  template 'edit.js.erb.erb', "#{plugin_path}/app/views/#{model_name_pluralize_underscored}/edit.js.erb"
51
51
 
52
+ template 'controller_spec.rb.erb', "#{plugin_path}/test/spec/controllers/#{model_name_pluralize_underscored}_controller_spec.rb"
53
+ template 'factories.rb.erb', "#{plugin_path}/test/factories/#{model_name_underscored}.rb"
54
+
52
55
  if File.exists?("#{plugin_path}/config/locales/en.yml")
53
56
  original_langfile = YAML.load_file("#{plugin_path}/config/locales/en.yml")
54
57
 
@@ -15,7 +15,7 @@
15
15
  </ul>
16
16
  </li>
17
17
  <%% end %>
18
- <li><%%= context_menu_link l(:button_delete), <%= model_name_pluralize_underscored %>_path(ids: @<%= model_name_underscored %>_ids, back_url: @back), method: :delete, data: {confirm: l(:text_are_you_sure)}, class: 'icon icon-del', disabled: !@can[:delete] %></li>
18
+ <li><%%= context_menu_link l(:button_delete), <%= model_name_underscored %>_path(id: @<%= model_name_underscored %>_ids, back_url: @back), method: :delete, data: {confirm: l(:text_are_you_sure)}, class: 'icon icon-del', disabled: !@can[:delete] %></li>
19
19
 
20
20
  <%%= call_hook(:view_<%= model_name_pluralize_underscored %>_context_menu_end, {<%= model_name_underscored %>: @<%= model_name_underscored %>, <%= model_name_pluralize_underscored %>: @<%= model_name_pluralize_underscored %>, can: @can, back: @back, project: @project}) %>
21
21
  </ul>
@@ -0,0 +1,78 @@
1
+ require Rails.root.join('plugins', 'easyproject', 'easy_plugins', 'easy_extensions/test/spec/spec_helper')
2
+
3
+ describe <%= controller_class %>Controller, logged: true do
4
+ let(:<%= model_name_underscored %>) { FactoryGirl.create(:<%= model_name_underscored %>) }
5
+ let(:<%= model_name_pluralize_underscored %>) { FactoryGirl.create_list(:<%= model_name_underscored %>, 5) }
6
+
7
+ before(:each) do
8
+ role = Role.non_member
9
+ role.add_permission! :view_<%= model_name_pluralize_underscored %>
10
+ role.add_permission! :manage_<%= model_name_pluralize_underscored %>
11
+ end
12
+
13
+ render_views
14
+
15
+ it 'index' do
16
+ <%= model_name_pluralize_underscored %>
17
+
18
+ get :index
19
+ expect(response).to have_http_status(:success)
20
+ expect(response).to render_template('<%= model_name_pluralize_underscored %>/index')
21
+ end
22
+
23
+ it 'show' do
24
+ get :index, {id: <%= model_name_underscored %>}
25
+ expect(response).to have_http_status(:success)
26
+ expect(response).to render_template('<%= model_name_pluralize_underscored %>/show')
27
+ end
28
+
29
+ it 'new' do
30
+ get :new
31
+ expect(response).to have_http_status(:success)
32
+ expect(response).to render_template('<%= model_name_pluralize_underscored %>/new')
33
+ end
34
+
35
+ it 'create with invalid' do
36
+ post :create, {<%= model_name_underscored %>: {}}
37
+ expect(response).to have_http_status(:success)
38
+ expect(assigns[:<%= model_name_underscored %>]).to be_a_new(<%= model_name %>)
39
+ expect(response).to render_template('<%= model_name_pluralize_underscored %>/new')
40
+ end
41
+
42
+ it 'create with valid' do
43
+ post :create, {<%= model_name_underscored %>: FactoryGirl.attributes_for(:<%= model_name_underscored %>)}
44
+ expect(response).to have_http_status(:success)
45
+ expect(assigns[:<%= model_name_underscored %>]).not_to be_a_new(<%= model_name %>)
46
+ expect(response).to redirect_to(<%= model_name_underscored %>_path(assigns[:<%= model_name_underscored %>]))
47
+ end
48
+
49
+ it 'edit' do
50
+ get :edit, {id: <%= model_name_underscored %>}
51
+ expect(response).to have_http_status(:success)
52
+ expect(response).to render_template('<%= model_name_pluralize_underscored %>/edit')
53
+ end
54
+
55
+ it 'update with invalid' do
56
+ put :update, {<%= model_name_underscored %>: {url: ''}}
57
+ expect(response).to have_http_status(:success)
58
+ expect(assigns[:<%= model_name_underscored %>].valid?).to be false
59
+ expect(response).to render_template('<%= model_name_pluralize_underscored %>/edit')
60
+ end
61
+
62
+ it 'update with valid' do
63
+ put :update, {<%= model_name_underscored %>: {url: 'http://tlapmazon.easy:123'}}
64
+ expect(response).to have_http_status(:success)
65
+ expect(assigns[:<%= model_name_underscored %>].valid?).to be true
66
+ expect(response).to redirect_to(<%= model_name_underscored %>_path(assigns[:<%= model_name_underscored %>]))
67
+ end
68
+
69
+ it 'destroy' do
70
+ <%= model_name_underscored %>
71
+ <%= model_name_pluralize_underscored %>
72
+
73
+ expect(<%= model_name %>.count).to eq(6)
74
+ expect {delete :destroy, {id: <%= model_name_underscored %>}}.to change(<%= model_name %>, :count).by(-1)
75
+ expect(response).to redirect_to(<%= model_name_pluralize_underscored %>_path)
76
+ expect(response).to redirect_to(<%= model_name_pluralize_underscored %>_path)
77
+ end
78
+ end
@@ -0,0 +1,12 @@
1
+ FactoryGirl.define do
2
+
3
+ factory :<%= model_name_underscored %> do
4
+ <%- string_columns.each_key do |c| -%>
5
+ sequence(:<%= c %>) { | n | "<%= c %>-#{n}"}
6
+ <%- end -%>
7
+ <%= 'association :author, factory: :user' if author? %>
8
+ <%= 'project' if project? %>
9
+
10
+ end
11
+
12
+ end
@@ -3,5 +3,7 @@
3
3
  <%%= context_menu context_menu_<%= model_name_pluralize_underscored %>_path(:project_id => @project) %>
4
4
  <%% content_for :sidebar do %>
5
5
  <%%= render :partial => '<%= model_name_pluralize_underscored %>/sidebar' %>
6
+ <% if Redmine::Plugin.installed?(:easy_extensions) %>
6
7
  <%%= render :partial => 'sidebar/saved_easyqueries_by_type', :locals => {:query_class => @query.class, :project => @project} %>
8
+ <% end %>
7
9
  <%% end %>
@@ -1,5 +1,5 @@
1
1
  Description:
2
- The plugin generator creates stubs for a new Redmine plugin.
2
+ The plugin generator creates stubs for new Redmine plugin.
3
3
  Plugin is prepared for use in Redmine and Easy Redmine as well.
4
4
  You can use --customer flag to generate a special plugin if you can make just a few changes to code. Backup this plugin before Redmine or Easy Redmine upgrade and move back for keep you changes.
5
5
 
@@ -46,7 +46,7 @@ module RedmineExtensions
46
46
  template 'Gemfile.erb', "#{plugin_path}/Gemfile"
47
47
  template 'init.rb.erb', "#{plugin_path}/init.rb"
48
48
  template 'javascript.js', "#{plugin_path}/assets/javascripts/#{plugin_name_underscored}.js"
49
- template 'stylesheet.js', "#{plugin_path}/assets/stylesheets/#{plugin_name_underscored}.css"
49
+ template 'stylesheet.css', "#{plugin_path}/assets/stylesheets/#{plugin_name_underscored}.css"
50
50
  template 'en.yml.erb', "#{plugin_path}/config/locales/en.yml"
51
51
  template 'routes.rb.erb', "#{plugin_path}/config/routes.rb"
52
52
  template 'hooks.rb.erb', "#{plugin_path}/lib/#{plugin_name_underscored}/hooks.rb"
@@ -57,6 +57,9 @@ module RedmineExtensions
57
57
  ActiveSupport.on_load(:active_record) do
58
58
  include RedmineExtensions::RailsPatches::ActiveRecord
59
59
  end
60
+ ActiveSupport.on_load(:action_view) do
61
+ default_form_builder.send(:include, RedmineExtensions::RailsPatches::FormBuilderPatch)
62
+ end
60
63
  end
61
64
 
62
65
  initializer 'redmine_extensions.initialize_easy_plugins', after: :load_config_initializers do
@@ -0,0 +1,12 @@
1
+ module RedmineExtensions
2
+ module RailsPatches
3
+ module FormBuilderPatch
4
+
5
+ # See documentation for autocomplete_field in helper
6
+ def autocomplete_field(method, choices, options={}, html_options={})
7
+ @template.autocomplete_field(@object_name, method, choices, objectify_options(options), html_options)
8
+ end
9
+
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,28 @@
1
+ require 'action_view/helpers/tags/placeholderable'
2
+
3
+ module RedmineExtensions
4
+ module Tags
5
+ class AutocompleteField < ActionView::Helpers::Tags::Base
6
+ include ActionView::Helpers::Tags::Placeholderable
7
+
8
+ def initialize(object_name, method_name, template_object, choices, options, html_options)
9
+ @choices = block_given? ? template_object.capture { yield || "" } : choices
10
+ @choices = @choices.to_a if @choices.is_a?(Range)
11
+
12
+ options[:multiple] = true unless options.key?(:multiple)
13
+
14
+ @html_options = html_options
15
+
16
+ super(object_name, method_name, template_object, html_options.merge(options))
17
+ end
18
+
19
+ def render
20
+ options = @options.stringify_keys
21
+ options["value"] = options.fetch("value") { value_before_type_cast(object) }
22
+ add_default_name_and_id(options)
23
+ @template_object.autocomplete_field_tag(options.delete('name'), @choices, options.delete('value'), options.symbolize_keys)
24
+ end
25
+
26
+ end
27
+ end
28
+ end
@@ -1,3 +1,3 @@
1
1
  module RedmineExtensions
2
- VERSION = '0.1.16'
2
+ VERSION = '0.1.17'
3
3
  end
@@ -8,6 +8,13 @@ RSpec.describe 'autocomplete', type: :feature, js: true do
8
8
  expect(page).to have_css('input#default[type="text"]')
9
9
  expect(page).to have_css('input[type="hidden"][name="default"][value="value1"]', visible: false)
10
10
  end
11
+
12
+ it 'generate autocomplete_field in form_for' do
13
+ visit '/dummy_autocompletes'
14
+ binding.pry
15
+ expect(page).to have_css('input#dummy_entities_autocomplete[type="text"]')
16
+ expect(page).to have_css('input[type="hidden"][name="dummy_entity[array_of_dummies][]"][value="value1"]', visible: false)
17
+ end
11
18
  end
12
19
 
13
20
  end
@@ -15,11 +15,60 @@ module PluginGenerator
15
15
  end
16
16
 
17
17
  def self.generate_autocomplete!
18
+ generate_dummy_entity!
18
19
  generate_autocomplete_controller!
19
20
  generate_autocomplete_routes!
20
21
  generate_autocomplete_view!
21
22
  end
22
23
 
24
+ def self.generate_dummy_entity!
25
+ File.open( Rails.root.join('plugins', 'dummy_plugin', 'db', 'migrate', '20162010160230_create_dummy_entities.rb'), 'w' ) do |file|
26
+ file.write( <<-END_RUBY )
27
+ class CreateDummyEntities < ActiveRecord::Migration
28
+ def change
29
+ create_table :dummy_entities do |t|
30
+ t.string :name
31
+ t.integer :value
32
+ t.references :project, index: true
33
+ t.text :array_of_dummies
34
+ end
35
+ end
36
+ end
37
+ END_RUBY
38
+ end
39
+
40
+ File.open( Rails.root.join('plugins', 'dummy_plugin', 'app', 'models', 'dummy_entity.rb'), 'w' ) do |file|
41
+ file.write( <<-END_RUBY )
42
+ class DummyEntity < ActiveRecord::Base
43
+ include Redmine::SafeAttributes
44
+ safe_attributes 'name',
45
+ 'value',
46
+ 'project_id',
47
+ 'array_of_dummies'
48
+
49
+ attr_protected :id
50
+
51
+ serialize :array_of_dummies, Array
52
+ end
53
+ END_RUBY
54
+ end
55
+
56
+ File.open(Rails.root.join('plugins', 'dummy_plugin', 'app', 'controllers', 'dummy_entities_controller.rb'), 'w') do |file|
57
+ file.write( <<-END_RUBY )
58
+ class DummyEntitiesController < ApplicationController
59
+ def index
60
+ end
61
+
62
+ def create
63
+ @entity = DummyEntity.new
64
+ @entity.safe_attributes = params[:dummy_entity]
65
+ @entity.save
66
+ end
67
+ end
68
+ END_RUBY
69
+ end
70
+ end
71
+
23
72
  def self.generate_autocomplete_controller!
24
73
  File.open(Rails.root.join('plugins', 'dummy_plugin', 'app', 'controllers', 'dummy_autocompletes_controller.rb'), 'w') do |file|
25
74
  file.write( <<-END_RUBY )
@@ -33,7 +82,10 @@ module PluginGenerator
33
82
 
34
83
  def self.generate_autocomplete_routes!
35
84
  File.open(Rails.root.join('plugins', 'dummy_plugin', 'config', 'routes.rb'), 'w') do |file|
36
- file.write("resources :dummy_autocompletes")
85
+ file.write( <<-END_ROUTES )
86
+ resources :dummy_autocompletes
87
+ resources :dummy_entities
88
+ END_ROUTES
37
89
  end
38
90
  end
39
91
 
@@ -41,11 +93,15 @@ module PluginGenerator
41
93
  dir = Rails.root.join('plugins', 'dummy_plugin', 'app', 'views', 'dummy_autocompletes')
42
94
  Dir.mkdir dir
43
95
  File.open(dir.join('index.html.erb'), 'w') do |file|
44
- file.write( <<-END_RUBY )
96
+ file.write( <<-END_ERB )
45
97
  <%= form_tag('/dummy_autocompletes', id: 'autocompletes_form') do %>
46
98
  <%= autocomplete_field_tag('default', ['value1', 'value2'], ['value1']) %>
47
99
  <% end %>
48
- END_RUBY
100
+
101
+ <%= form_for(DummyEntity.new(array_of_dummies: ['value1'])) do |f| %>
102
+ <%= f.autocomplete_field(:array_of_dummies, ['value1', 'value2'], {}, id: 'dummy_entities_autocomplete') %>
103
+ <% end %>
104
+ END_ERB
49
105
  end
50
106
  end
51
107
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redmine_extensions
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.16
4
+ version: 0.1.17
5
5
  platform: ruby
6
6
  authors:
7
7
  - Easy Software Ltd
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-15 00:00:00.000000000 Z
11
+ date: 2016-12-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -168,10 +168,12 @@ files:
168
168
  - lib/generators/redmine_extensions/entity/templates/_sidebar.html.erb.erb
169
169
  - lib/generators/redmine_extensions/entity/templates/context_menu.html.erb.erb
170
170
  - lib/generators/redmine_extensions/entity/templates/controller.rb.erb
171
+ - lib/generators/redmine_extensions/entity/templates/controller_spec.rb.erb
171
172
  - lib/generators/redmine_extensions/entity/templates/custom_field.rb.erb
172
173
  - lib/generators/redmine_extensions/entity/templates/edit.html.erb.erb
173
174
  - lib/generators/redmine_extensions/entity/templates/edit.js.erb.erb
174
175
  - lib/generators/redmine_extensions/entity/templates/en.yml.erb
176
+ - lib/generators/redmine_extensions/entity/templates/factories.rb.erb
175
177
  - lib/generators/redmine_extensions/entity/templates/helper.rb.erb
176
178
  - lib/generators/redmine_extensions/entity/templates/hooks.rb.erb
177
179
  - lib/generators/redmine_extensions/entity/templates/index.api.rsb.erb
@@ -228,9 +230,11 @@ files:
228
230
  - lib/redmine_extensions/query_outputs/list_output.rb
229
231
  - lib/redmine_extensions/query_outputs/tiles_output.rb
230
232
  - lib/redmine_extensions/rails_patches/active_record.rb
233
+ - lib/redmine_extensions/rails_patches/form_builder_patch.rb
231
234
  - lib/redmine_extensions/rails_patches/route_set_generator_patch.rb
232
235
  - lib/redmine_extensions/redmine_patches/controllers/application_controller_patch.rb
233
236
  - lib/redmine_extensions/redmine_patches/patches.rb
237
+ - lib/redmine_extensions/tags/autocomplete_field.rb
234
238
  - lib/redmine_extensions/version.rb
235
239
  - lib/tasks/redmine_extensions_tasks.rake
236
240
  - spec/factories/easy_queries.rb