additional_tags 1.0.1 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codeql-analysis.yml +70 -0
  3. data/.github/workflows/linters.yml +6 -1
  4. data/.github/workflows/tests.yml +11 -2
  5. data/.gitignore +2 -0
  6. data/.rubocop.yml +55 -5
  7. data/.slim-lint.yml +3 -2
  8. data/README.md +16 -17
  9. data/Rakefile +2 -0
  10. data/additional_tags.gemspec +10 -6
  11. data/app/controllers/additional_tags_controller.rb +4 -1
  12. data/app/controllers/issue_tags_controller.rb +6 -4
  13. data/app/helpers/additional_tags_helper.rb +91 -52
  14. data/app/helpers/additional_tags_issues_helper.rb +15 -3
  15. data/app/helpers/additional_tags_wiki_helper.rb +4 -26
  16. data/app/jobs/additional_tags_job.rb +2 -0
  17. data/app/jobs/additional_tags_remove_unused_tag_job.rb +7 -0
  18. data/app/models/migrate_tag.rb +2 -0
  19. data/app/models/migrate_tagging.rb +2 -0
  20. data/app/models/query_tags_column.rb +7 -0
  21. data/app/views/additional_tags/_body_bottom.html.slim +19 -0
  22. data/app/views/additional_tags/_html_head.html.slim +1 -4
  23. data/app/views/additional_tags/_tag_list.html.slim +1 -1
  24. data/app/views/additional_tags/merge.html.slim +4 -3
  25. data/app/views/additional_tags/settings/_manage_tags.html.slim +24 -23
  26. data/app/views/common/_tag_summary_block.html.slim +11 -0
  27. data/app/views/context_menus/_issues_tags.html.slim +1 -1
  28. data/app/views/dashboards/blocks/_issue_tags.html.slim +58 -0
  29. data/app/views/dashboards/blocks/_issue_tags_settings.html.slim +20 -0
  30. data/app/views/issue_tags/_edit_modal.html.slim +6 -4
  31. data/app/views/issues/_tags_form.html.slim +1 -1
  32. data/assets/javascripts/tags.js +4 -3
  33. data/assets/stylesheets/tags.css +27 -13
  34. data/config/initializers/zeitwerk.rb +6 -0
  35. data/config/locales/bg.yml +5 -0
  36. data/config/locales/cs.yml +5 -0
  37. data/config/locales/de.yml +5 -0
  38. data/config/locales/en.yml +5 -0
  39. data/config/locales/es.yml +5 -0
  40. data/config/locales/fr.yml +5 -0
  41. data/config/locales/it.yml +5 -0
  42. data/config/locales/ja.yml +5 -0
  43. data/config/locales/ko.yml +5 -0
  44. data/config/locales/pl.yml +5 -0
  45. data/config/locales/pt-BR.yml +5 -0
  46. data/config/locales/ru.yml +28 -23
  47. data/config/routes.rb +2 -0
  48. data/db/migrate/20201116145429_acts_as_taggable_migration.rb +3 -1
  49. data/db/migrate/20201123093214_migrate_existing_tags.rb +5 -3
  50. data/init.rb +11 -6
  51. data/lib/additional_tags/hooks/model_hook.rb +13 -0
  52. data/lib/additional_tags/hooks/view_hook.rb +77 -0
  53. data/lib/additional_tags/patches/agile_boards_controller_patch.rb +2 -0
  54. data/lib/additional_tags/patches/agile_query_patch.rb +11 -9
  55. data/lib/additional_tags/patches/agile_versions_controller_patch.rb +2 -0
  56. data/lib/additional_tags/patches/agile_versions_query_patch.rb +3 -1
  57. data/lib/additional_tags/patches/auto_completes_controller_patch.rb +8 -7
  58. data/lib/additional_tags/patches/calendars_controller_patch.rb +2 -0
  59. data/lib/additional_tags/patches/dashboard_async_blocks_controller_patch.rb +2 -0
  60. data/lib/additional_tags/patches/dashboard_content_patch.rb +28 -0
  61. data/lib/additional_tags/patches/dashboards_controller_patch.rb +2 -0
  62. data/lib/additional_tags/patches/gantts_controller_patch.rb +2 -0
  63. data/lib/additional_tags/patches/imports_controller_patch.rb +2 -0
  64. data/lib/additional_tags/patches/issue_patch.rb +19 -20
  65. data/lib/additional_tags/patches/issue_query_patch.rb +17 -14
  66. data/lib/additional_tags/patches/issues_controller_patch.rb +2 -0
  67. data/lib/additional_tags/patches/journal_patch.rb +2 -0
  68. data/lib/additional_tags/patches/my_controller_patch.rb +2 -0
  69. data/lib/additional_tags/patches/queries_helper_patch.rb +3 -15
  70. data/lib/additional_tags/patches/query_patch.rb +83 -0
  71. data/lib/additional_tags/patches/settings_controller_patch.rb +2 -0
  72. data/lib/additional_tags/patches/time_entry_patch.rb +2 -0
  73. data/lib/additional_tags/patches/time_entry_query_patch.rb +5 -15
  74. data/lib/additional_tags/patches/time_report_patch.rb +2 -0
  75. data/lib/additional_tags/patches/timelog_controller_patch.rb +2 -0
  76. data/lib/additional_tags/patches/wiki_controller_patch.rb +3 -1
  77. data/lib/additional_tags/patches/wiki_page_patch.rb +54 -3
  78. data/lib/additional_tags/plugin_version.rb +7 -0
  79. data/lib/additional_tags/tags.rb +78 -18
  80. data/lib/additional_tags.rb +53 -74
  81. data/lib/tasks/additional_tags.rake +18 -0
  82. metadata +32 -9
  83. data/.github/workflows/brakeman.yml +0 -33
  84. data/app/views/reports/_tags_simple.html.slim +0 -11
  85. data/lib/additional_tags/hooks.rb +0 -73
  86. data/lib/additional_tags/patches/reports_controller_patch.rb +0 -32
  87. data/lib/additional_tags/version.rb +0 -3
@@ -1,4 +1,4 @@
1
- require 'digest/md5'
1
+ # frozen_string_literal: true
2
2
 
3
3
  module AdditionalTagsHelper
4
4
  include ActsAsTaggableOn::TagsHelper
@@ -12,15 +12,15 @@ module AdditionalTagsHelper
12
12
 
13
13
  columns = {}
14
14
 
15
- if AdditionalTags.setting?(:active_issue_tags)
15
+ if AdditionalTags.setting? :active_issue_tags
16
16
  columns[:issue] = { label: l(:label_issue_plural),
17
17
  tag_controller: :issues,
18
- counts: Issue.available_tags.map { |tag| [tag.id, tag.count] }.to_h }
18
+ counts: Issue.available_tags.to_h { |tag| [tag.id, tag.count] } }
19
19
  end
20
20
 
21
- if AdditionalTags.setting?(:active_wiki_tags)
21
+ if AdditionalTags.setting? :active_wiki_tags
22
22
  columns[:wiki] = { label: l(:label_wiki),
23
- counts: WikiPage.available_tags.map { |tag| [tag.id, tag.count] }.to_h }
23
+ counts: WikiPage.available_tags.to_h { |tag| [tag.id, tag.count] } }
24
24
  end
25
25
 
26
26
  call_hook :helper_additional_manageable_tag_columns, columns: columns
@@ -43,13 +43,13 @@ module AdditionalTagsHelper
43
43
  columns
44
44
  end
45
45
 
46
- def render_tags_list(tags, options = {})
47
- return if tags.blank?
46
+ def sort_tags_for_list(tags, sort_by: nil, sort_order: nil)
47
+ return tags if tags.size < 2
48
48
 
49
- style = options.delete(:style)
50
- tags = tags.all.to_a if tags.respond_to?(:all)
49
+ sort_by = AdditionalTags.setting :tags_sort_by if sort_by.blank?
50
+ sort_order = AdditionalTags.setting :tags_sort_order if sort_order.blank?
51
51
 
52
- case "#{AdditionalTags.setting :tags_sort_by}:#{AdditionalTags.setting :tags_sort_order}"
52
+ case "#{sort_by}:#{sort_order}"
53
53
  when 'name:desc'
54
54
  tags = AdditionalTags::Tags.sort_tag_list(tags).reverse
55
55
  when 'count:asc'
@@ -60,6 +60,16 @@ module AdditionalTagsHelper
60
60
  tags = AdditionalTags::Tags.sort_tag_list tags
61
61
  end
62
62
 
63
+ tags
64
+ end
65
+
66
+ def render_tags_list(tags, **options)
67
+ return if tags.blank?
68
+
69
+ style = options.delete :style
70
+ tags = tags.all.to_a if tags.respond_to? :all
71
+ tags = sort_tags_for_list tags
72
+
63
73
  case style
64
74
  when :list
65
75
  list_el = 'ul'
@@ -71,7 +81,7 @@ module AdditionalTagsHelper
71
81
  raise 'Unknown list style'
72
82
  end
73
83
 
74
- content = ''.html_safe
84
+ content = +''.html_safe
75
85
  if style == :list && AdditionalTags.setting(:tags_sort_by) == 'name'
76
86
  tags.group_by { |tag| tag.name.downcase.first }.each do |letter, grouped_tags|
77
87
  content << content_tag(item_el, letter.upcase, class: 'letter')
@@ -84,26 +94,30 @@ module AdditionalTagsHelper
84
94
  content_tag(list_el, content, class: 'tags-cloud', style: (style == :simple_cloud ? 'text-align: left;' : ''))
85
95
  end
86
96
 
87
- def additional_tag_link(tag_object, options = {})
97
+ def additional_tag_link(tag_object, link: nil, link_wiki_tag: false, show_count: false, use_colors: nil, name: nil, **options)
88
98
  tag_name = []
89
- tag_name << tag_object.name
99
+ tag_name << if name.nil?
100
+ tag_object.name
101
+ else
102
+ name
103
+ end
90
104
 
91
105
  options[:project] = @project if options[:project].blank? && @project.present?
106
+ use_colors = AdditionalTags.setting? :use_colors if use_colors.nil?
92
107
 
93
- use_colors = AdditionalTags.setting?(:use_colors)
94
- if use_colors
95
- tag_bg_color = additional_tag_color tag_object.name
96
- tag_fg_color = additional_tag_fg_color tag_bg_color
97
- tag_style = "background-color: #{tag_bg_color}; color: #{tag_fg_color}"
98
- end
108
+ tag_style = if use_colors
109
+ tag_bg_color = additional_tag_color tag_object.name
110
+ tag_fg_color = additional_tag_fg_color tag_bg_color
111
+ "background-color: #{tag_bg_color}; color: #{tag_fg_color}"
112
+ end
99
113
 
100
- tag_name << tag.span("(#{tag_object.count})", class: 'tag-count') if options[:show_count]
114
+ tag_name << tag.span(tag_object.count, class: 'tag-count') if show_count
101
115
 
102
- content = if options[:link]
116
+ content = if link
103
117
  link_to safe_join(tag_name),
104
- options[:link],
118
+ link,
105
119
  style: tag_style
106
- elsif options[:link_wiki_tag]
120
+ elsif link_wiki_tag
107
121
  link = if options[:project].present?
108
122
  project_wiki_index_path options[:project], tag: tag_object.name
109
123
  else
@@ -112,7 +126,7 @@ module AdditionalTagsHelper
112
126
  link_to safe_join(tag_name), link, style: tag_style
113
127
  else
114
128
  link_to safe_join(tag_name),
115
- tag_url(tag_object.name, options),
129
+ tag_url(tag_object.name, **options),
116
130
  style: tag_style
117
131
  end
118
132
 
@@ -122,11 +136,11 @@ module AdditionalTagsHelper
122
136
  { class: 'tag-label' }
123
137
  end
124
138
 
125
- tag.span content, style
139
+ tag.span content, **style
126
140
  end
127
141
 
128
142
  def additional_tag_color(tag_name)
129
- "##{Digest::MD5.hexdigest(tag_name)[0..5]}"
143
+ "##{Digest::SHA256.hexdigest(tag_name)[0..5]}"
130
144
  end
131
145
 
132
146
  def additional_tag_fg_color(bg_color)
@@ -140,53 +154,78 @@ module AdditionalTagsHelper
140
154
  end
141
155
 
142
156
  # plain list of tags
143
- def additional_plain_tag_list(tags, sep = ' ')
144
- s = if tags.blank?
145
- ['']
146
- else
147
- tags.map(&:name)
148
- end
157
+ def additional_plain_tag_list(tags, sep: nil)
158
+ sep ||= "#{Query.additional_csv_separator} "
159
+
160
+ s = tags.present? ? tags.map(&:name) : ['']
149
161
  s.join sep
150
162
  end
151
163
 
152
- def additional_tag_sep(use_colors)
153
- if use_colors.nil? || use_colors
154
- ' '
155
- else
156
- ', '
157
- end
164
+ def additional_tag_sep(use_colors: true)
165
+ use_colors ? ' ' : ', '
166
+ end
167
+
168
+ def additional_tags_from_params(str)
169
+ tags = str.is_a?(Array) ? str : str.to_s.split(',')
170
+ tags.map!(&:strip)
171
+ tags.reject(&:blank?)
158
172
  end
159
173
 
160
- def additional_tag_links(tag_list, options = {})
174
+ def additional_tag_links(tag_list, **options)
161
175
  return if tag_list.blank?
162
176
 
163
- unsorted = options.delete(:unsorted)
164
- tag_list = AdditionalTags::Tags.sort_tag_list(tag_list) unless unsorted
177
+ unsorted = options.delete :unsorted
178
+ tag_list = AdditionalTags::Tags.sort_tag_list tag_list unless unsorted
179
+
180
+ safe_join tag_list.map { |tag| additional_tag_link tag, **options },
181
+ additional_tag_sep(use_colors: options[:use_colors])
182
+ end
183
+
184
+ def link_to_issue_tags_totals(entries:, project:, open_issues_only:)
185
+ sum = if entries.blank? || entries.size.zero?
186
+ 0
187
+ else
188
+ query = IssueQuery.new project: project, name: '_'
189
+ query.add_filter 'tags', '*'
190
+ query.filters['status_id'][:operator] = '*' if !open_issues_only && query.filters.key?('status_id')
191
+
192
+ query.issue_count
193
+ end
194
+
195
+ link_to sum, _project_issues_path(project,
196
+ set_filter: 1,
197
+ tags: '*',
198
+ status_id: open_issues_only ? 'o' : '*')
199
+ end
165
200
 
166
- safe_join tag_list.map { |tag| additional_tag_link tag, options },
167
- additional_tag_sep(options[:use_colors])
201
+ def issue_tag_status_filter(operator: nil, open_issues_only: false)
202
+ if operator
203
+ { field: :status_id, operator: operator }
204
+ elsif open_issues_only
205
+ { field: :status_id, operator: 'o' }
206
+ end
168
207
  end
169
208
 
170
209
  private
171
210
 
172
- def tag_url(tag_name, options = {})
173
- action = options[:tag_action].presence || (controller_name == 'hrm_user_resources' ? 'show' : 'index')
211
+ def tag_url(tag_name, filter: nil, tag_action: nil, tag_controller: nil, project: nil)
212
+ action = tag_action.presence || (controller_name == 'hrm_user_resources' ? 'show' : 'index')
174
213
 
175
214
  fields = [:tags]
176
215
  values = { tags: [tag_name] }
177
216
  operators = { tags: '=' }
178
217
 
179
- if options[:filter].present?
180
- field = options[:filter][:field]
218
+ if filter.present?
219
+ field = filter[:field]
181
220
  fields << field
182
- operators[field] = options[:filter][:operator]
183
- values[field] = options[:filter][:value] if options[:filter].key?(:value)
221
+ operators[field] = filter[:operator]
222
+ values[field] = filter[:value] if filter.key? :value
184
223
  end
185
224
 
186
- { controller: options[:tag_controller].presence || controller_name,
225
+ { controller: tag_controller.presence || controller_name,
187
226
  action: action,
188
227
  set_filter: 1,
189
- project_id: options[:project],
228
+ project_id: project,
190
229
  f: fields,
191
230
  v: values,
192
231
  op: operators }
@@ -195,7 +234,7 @@ module AdditionalTagsHelper
195
234
  def add_tags(style, tags, content, item_el, options)
196
235
  tag_cloud tags, (1..8).to_a do |tag, weight|
197
236
  content << ' '.html_safe + content_tag(item_el,
198
- additional_tag_link(tag, options),
237
+ additional_tag_link(tag, **options),
199
238
  class: "tag-nube-#{weight}",
200
239
  style: (style == :simple_cloud ? 'font-size: 1em;' : '')) + ' '.html_safe
201
240
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTagsIssuesHelper
2
4
  # Hacked render_api_custom_values to add plugin values to issue api
3
5
  def render_api_custom_values(custom_values, api)
@@ -5,11 +7,21 @@ module AdditionalTagsIssuesHelper
5
7
 
6
8
  if @issue.present? &&
7
9
  (defined?(controller_name) && controller_name == 'issues' && action_name == 'show' || !defined?(controller_name)) &&
8
- User.current.allowed_to?(:view_issues, @project)
10
+ AdditionalTags.setting?(:active_issue_tags) && User.current.allowed_to?(:view_issue_tags, @project)
9
11
 
10
12
  api.array :tags do
11
13
  @issue.tags.each do |tag|
12
- api.tag(id: tag.id, name: tag.name)
14
+ api.tag id: tag.id, name: tag.name
15
+ end
16
+ end
17
+ end
18
+
19
+ if @time_entry.present? &&
20
+ (defined?(controller_name) && controller_name == 'timelog' && action_name == 'show' || !defined?(controller_name)) &&
21
+ AdditionalTags.setting?(:active_issue_tags) && User.current.allowed_to?(:view_issue_tags, @project)
22
+ api.array :issue_tags do
23
+ @time_entry.issue_tags.each do |tag|
24
+ api.tag id: tag.id, name: tag.name
13
25
  end
14
26
  end
15
27
  end
@@ -38,6 +50,6 @@ module AdditionalTagsIssuesHelper
38
50
  project: @project }
39
51
 
40
52
  options[:tag_action] = 'show' if %w[gantts calendars].include? controller_name
41
- render_tags_list sidebar_tags, options
53
+ render_tags_list sidebar_tags, **options
42
54
  end
43
55
  end
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module AdditionalTagsWikiHelper
2
4
  def sidebar_tags
3
5
  unless @sidebar_tags
4
6
  @sidebar_tags = []
5
- @sidebar_tags = WikiPage.available_tags(project: @project) if AdditionalTags.show_sidebar_tags?
7
+ @sidebar_tags = WikiPage.available_tags project: @project if AdditionalTags.show_sidebar_tags?
6
8
  end
7
9
  @sidebar_tags
8
10
  end
@@ -13,7 +15,7 @@ module AdditionalTagsWikiHelper
13
15
  link_wiki_tag: true,
14
16
  project: @project }
15
17
 
16
- render_tags_list sidebar_tags, options
18
+ render_tags_list sidebar_tags, **options
17
19
  end
18
20
 
19
21
  def render_wiki_index_title(project, tag = nil)
@@ -30,28 +32,4 @@ module AdditionalTagsWikiHelper
30
32
  l :label_wiki
31
33
  end
32
34
  end
33
-
34
- def wiki_pages_with_tag(tag, project = nil)
35
- wiki = project&.wiki
36
-
37
- scope = if wiki
38
- wiki.pages
39
- else
40
- WikiPage.joins(wiki: :project)
41
- end
42
-
43
- scope = scope.visible(User.current, project: project) if scope.respond_to? :visible
44
-
45
- scope = scope.joins(AdditionalTags::Tags.tag_to_joins(WikiPage))
46
- .where("LOWER(#{ActiveRecord::Base.connection.quote_table_name(ActsAsTaggableOn.tags_table)}.name) = LOWER(:p)",
47
- p: tag.to_s.strip)
48
- .with_updated_on
49
- .joins(wiki: :project)
50
-
51
- if wiki.nil?
52
- scope.order "#{Project.table_name}.name, #{WikiPage.table_name}.title"
53
- else
54
- scope.includes(:parent).order "#{WikiPage.table_name}.title"
55
- end
56
- end
57
35
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class AdditionalTagsJob < AdditionalsJob
2
4
  queue_as :additional_tags
3
5
  end
@@ -1,5 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class AdditionalTagsRemoveUnusedTagJob < AdditionalTagsJob
2
4
  def perform
5
+ # only once a minute to reduce load
6
+ cache_key = self.class.to_s
7
+ return if Rails.cache.read(cache_key) && !Rails.env.test?
8
+
9
+ Rails.cache.write cache_key, true, expires_in: 60
3
10
  AdditionalTags::Tags.remove_unused_tags
4
11
  end
5
12
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MigrateTag < ActiveRecord::Base
2
4
  self.table_name = 'tags'
3
5
  has_many :migrate_taggings, dependent: :destroy, foreign_key: :tag_id, inverse_of: :migrate_tag
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class MigrateTagging < ActiveRecord::Base
2
4
  self.table_name = 'taggings'
3
5
  belongs_to :migrate_tag, foreign_key: :tag_id, inverse_of: :migrate_taggings
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class QueryTagsColumn < QueryRelationsColumn
4
+ def initialize(name = :tags, **options)
5
+ super name, **options
6
+ end
7
+ end
@@ -0,0 +1,19 @@
1
+ = additionals_transform_to_select2 'assignee',
2
+ format_state: 'formatNameWithIcon',
3
+ multiple: true,
4
+ url: assignee_auto_completes_path(project_id: @project)
5
+
6
+ = additionals_transform_to_select2 'author',
7
+ format_state: 'formatNameWithIcon',
8
+ multiple: true,
9
+ url: grouped_users_auto_completes_path(project_id: @project, with_ano: true, with_me: true)
10
+
11
+ = additionals_transform_to_select2 'user_with_me',
12
+ format_state: 'formatNameWithIcon',
13
+ multiple: true,
14
+ url: grouped_users_auto_completes_path(project_id: @project, with_me: true)
15
+
16
+ = additionals_transform_to_select2 'user',
17
+ format_state: 'formatNameWithIcon',
18
+ multiple: true,
19
+ url: grouped_users_auto_completes_path(project_id: @project)
@@ -1,6 +1,3 @@
1
1
  = stylesheet_link_tag 'tags', plugin: 'additional_tags'
2
2
  = javascript_include_tag 'tags', plugin: 'additional_tags'
3
- - if User.current.allowed_to?(:edit_issue_tags, @project, global: true) || \
4
- User.current.allowed_to?(:create_issue_tags, @project, global: true) || \
5
- User.current.allowed_to?(:add_wiki_tags, @project, global: true)
6
- = additionals_library_load :select2
3
+ = additionals_library_load :select2
@@ -2,7 +2,7 @@
2
2
  .tags.attribute
3
3
  - unless defined? hide_label
4
4
  span.label
5
- = l(:field_tag_list)
5
+ = l :field_tag_list
6
6
  ' :
7
7
  - if defined?(editable) && editable
8
8
  #tags-data
@@ -6,9 +6,10 @@ h2
6
6
 
7
7
  = form_tag merge_additional_tags_path(ids: @tags.map(&:id)), class: 'tabular' do
8
8
  = error_messages_for 'tag'
9
- = additional_tag_links @tags, { show_count: true,
10
- use_colors: AdditionalTags.setting?(:use_colors),
11
- link: '#' }
9
+ = additional_tag_links @tags,
10
+ show_count: true,
11
+ use_colors: AdditionalTags.setting?(:use_colors),
12
+ link: '#'
12
13
  .box
13
14
  p
14
15
  label[for="tag_name"]
@@ -1,29 +1,30 @@
1
1
  - tags = manageable_tags
2
2
  - if tags.present?
3
- table.list.issues
4
- thead
5
- tr
6
- th.checkbox.hide-when-print
7
- = check_box_tag 'ids[]', '', false, class: 'toggle-selection',
8
- title: "#{l :button_check_all}/#{l :button_uncheck_all}"
3
+ .autoscroll
4
+ table.list.issues
5
+ thead
6
+ tr
7
+ th.checkbox.hide-when-print
8
+ = check_box_tag 'ids[]', '', false, class: 'toggle-selection',
9
+ title: "#{l :button_check_all}/#{l :button_uncheck_all}"
9
10
 
10
- th = l :field_name
11
- - manageable_tag_columns.each do |_column, column_values|
12
- th = column_values[:label]
13
- th
14
- tbody
15
- - tags.each do |tag|
16
- tr.hascontextmenu id="#{tag.id}"
17
- td.checkbox.hide-when-print
18
- = check_box_tag('ids[]', tag.id, false, id: nil)
19
- td = additional_tag_link tag, link: edit_additional_tag_path(tag)
20
- - manageable_tag_column_values(tag).each do |column|
21
- td = column
22
- td.buttons
23
- = link_to l(:button_edit), edit_additional_tag_path(tag),
24
- class: 'icon icon-edit'
25
- = link_to l(:button_delete), additional_tags_path(ids: tag), method: :delete,
26
- data: { confirm: l(:text_are_you_sure) }, class: 'icon icon-del'
11
+ th = l :field_name
12
+ - manageable_tag_columns.each do |_column, column_values|
13
+ th = column_values[:label]
14
+ th
15
+ tbody
16
+ - tags.each do |tag|
17
+ tr.hascontextmenu id="#{tag.id}"
18
+ td.checkbox.hide-when-print
19
+ = check_box_tag 'ids[]', tag.id, false, id: nil
20
+ td = additional_tag_link tag, link: edit_additional_tag_path(tag)
21
+ - manageable_tag_column_values(tag).each do |column|
22
+ td = column
23
+ td.buttons
24
+ = link_to l(:button_edit), edit_additional_tag_path(tag),
25
+ class: 'icon icon-edit'
26
+ = link_to l(:button_delete), additional_tags_path(ids: tag), method: :delete,
27
+ data: { confirm: l(:text_are_you_sure) }, class: 'icon icon-del'
27
28
  - else
28
29
  p.nodata = l :label_no_data
29
30
 
@@ -0,0 +1,11 @@
1
+ ul.reporting-list.tag-summary
2
+ li.amount-tags
3
+ = l :label_amount_tags
4
+ ' :
5
+ span.value
6
+ = tags.to_a.size
7
+ li.amount-entities-with-tags
8
+ = l :label_amount_entities_with_tags, name: entities_label
9
+ ' :
10
+ span.value
11
+ = totals_link
@@ -5,6 +5,6 @@
5
5
  ul
6
6
  li
7
7
  = context_menu_link l(:button_add),
8
- edit_issue_tags_path(ids: @issue_ids),
8
+ edit_issue_tags_path(ids: @issue_ids, search: params[:search]),
9
9
  remote: true,
10
10
  class: 'icon icon-add'
@@ -0,0 +1,58 @@
1
+ h3 = block_definition[:label]
2
+
3
+ - open_issues_only = RedminePluginKit.true? settings[:open_issues_only]
4
+ - tags = Issue.available_tags project: @project, open_issues_only: open_issues_only
5
+ - counts = AdditionalTags::Tags.entity_group_by scope: Issue.group_by_status_with_tags(@project),
6
+ tags: tags,
7
+ statuses: { true => :closed, false => :open },
8
+ group_id_is_bool: true
9
+
10
+ = render partial: 'common/tag_summary_block',
11
+ locals: { tags: tags,
12
+ entities_label: l(:label_issue_plural),
13
+ totals_link: link_to_issue_tags_totals(entries: counts,
14
+ project: @project,
15
+ open_issues_only: open_issues_only) }
16
+
17
+ - if RedminePluginKit.true? settings[:with_table_of_values]
18
+ - if tags.present?
19
+ - tags = sort_tags_for_list tags.to_a
20
+ table.list.tags
21
+ thead
22
+ tr
23
+ th = l :field_name
24
+ - if open_issues_only
25
+ th = l :label_quantity
26
+ - else
27
+ th = l :label_open_issues_plural
28
+ th = l :label_closed_issues_plural
29
+ th = l :label_total
30
+ tbody
31
+ - tags.each do |tag|
32
+ tr
33
+ td.name = additional_tag_link tag,
34
+ tag_action: 'index',
35
+ tag_controller: 'issues',
36
+ filter: issue_tag_status_filter(open_issues_only: open_issues_only),
37
+ use_colors: RedminePluginKit.true?(settings[:use_colors])
38
+ - unless open_issues_only
39
+ td.value = additional_tag_link tag,
40
+ tag_action: 'index',
41
+ tag_controller: 'issues',
42
+ filter: issue_tag_status_filter(operator: 'o'),
43
+ use_colors: false,
44
+ name: counts[tag.name][:open]
45
+ td.value = additional_tag_link tag,
46
+ tag_action: 'index',
47
+ tag_controller: 'issues',
48
+ filter: issue_tag_status_filter(operator: 'c'),
49
+ use_colors: false,
50
+ name: counts[tag.name][:closed]
51
+ td.value = additional_tag_link tag,
52
+ tag_action: 'index',
53
+ tag_controller: 'issues',
54
+ filter: issue_tag_status_filter(open_issues_only: open_issues_only),
55
+ use_colors: false,
56
+ name: open_issues_only ? counts[tag.name][:open] : counts[tag.name][:total]
57
+ - else
58
+ p.nodata = l :label_no_data
@@ -0,0 +1,20 @@
1
+ .box.tabular.settings
2
+ p
3
+ = additionals_settings_checkbox :with_table_of_values,
4
+ active_value: settings[:with_table_of_values],
5
+ tag_name: "settings[#{block}][with_table_of_values]"
6
+
7
+ / p
8
+ / = additionals_settings_checkbox :with_chart,
9
+ / active_value: settings[:with_chart],
10
+ / tag_name: "settings[#{block}][with_chart]"
11
+
12
+ p
13
+ = additionals_settings_checkbox :open_issues_only,
14
+ active_value: settings[:open_issues_only],
15
+ tag_name: "settings[#{block}][open_issues_only]"
16
+
17
+ p
18
+ = additionals_settings_checkbox :use_colors,
19
+ active_value: settings[:use_colors],
20
+ tag_name: "settings[#{block}][use_colors]"
@@ -9,7 +9,7 @@ h3.title = l :label_add_tags
9
9
  h3
10
10
  span = link_to_issue @issues.first
11
11
 
12
- = form_tag issue_tags_path(ids: @issue_ids) do
12
+ = form_tag issue_tags_path(ids: @issue_ids, search: params[:search]) do
13
13
  fieldset.box
14
14
  legend = l :field_tags
15
15
  #issue_tags
@@ -21,10 +21,12 @@ h3.title = l :label_add_tags
21
21
  placeholder: @is_bulk_editing ? t(:label_no_change_option) : '+ add tag',
22
22
  tags: User.current.allowed_to?(:create_issue_tags, @project)
23
23
  p.most_used_tags
24
- = safe_join @most_used_tags.collect { |t| tag.span(t.name, class: 'most_used_tag') }, ', '
25
- = javascript_tag "var mostUsedTags = #{@most_used_tags.map(&:name)}"
24
+ = safe_join @most_used_tags.collect { |t| tag.span t.name, class: 'most_used_tag' }, ', '
26
25
 
27
26
  .buttons
28
27
  = submit_tag l(:button_add), name: nil
29
28
  '
30
- = submit_tag l(:button_cancel), name: nil, onclick: 'hideModal(this);', type: 'button'
29
+ = link_to_function l(:button_cancel), 'hideModal(this);'
30
+
31
+ javascript:
32
+ var mostUsedTags = #{raw @most_used_tags.map(&:name)};
@@ -1,4 +1,4 @@
1
- - project = defined?(project) ? project : @project
1
+ - project = @project unless defined?(project)
2
2
  - options = { multiple: true,
3
3
  width: '95%',
4
4
  url: issue_tags_auto_completes_path(project_id: project),
@@ -1,5 +1,6 @@
1
- $(function () {
2
- $('body').on('click', '.most_used_tags .most_used_tag', function (e) {
1
+ /* global mostUsedTags:writable */
2
+ $(function() {
3
+ $('body').on('click', '.most_used_tags .most_used_tag', function(e) {
3
4
  var $tagsSelect = $('select#issue_tag_list');
4
5
  var tag = e.target.innerText;
5
6
  if ($tagsSelect.find('option[value=\'' + tag + '\']').length === 0) {
@@ -7,7 +8,7 @@ $(function () {
7
8
  $tagsSelect.append(newOption).trigger('change');
8
9
  }
9
10
 
10
- var mostUsedTags = $.grep(mostUsedTags, function(t) { return t != tag; });
11
+ mostUsedTags = $.grep(mostUsedTags, function(t) { return t != tag; });
11
12
  var tagsHtml = mostUsedTags.map(function(tag) {
12
13
  return '<span class="most_used_tag">' + tag + '</span>';
13
14
  }).join(', ');