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.
- checksums.yaml +4 -4
- data/.github/workflows/codeql-analysis.yml +70 -0
- data/.github/workflows/linters.yml +6 -1
- data/.github/workflows/tests.yml +11 -2
- data/.gitignore +2 -0
- data/.rubocop.yml +55 -5
- data/.slim-lint.yml +3 -2
- data/README.md +16 -17
- data/Rakefile +2 -0
- data/additional_tags.gemspec +10 -6
- data/app/controllers/additional_tags_controller.rb +4 -1
- data/app/controllers/issue_tags_controller.rb +6 -4
- data/app/helpers/additional_tags_helper.rb +91 -52
- data/app/helpers/additional_tags_issues_helper.rb +15 -3
- data/app/helpers/additional_tags_wiki_helper.rb +4 -26
- data/app/jobs/additional_tags_job.rb +2 -0
- data/app/jobs/additional_tags_remove_unused_tag_job.rb +7 -0
- data/app/models/migrate_tag.rb +2 -0
- data/app/models/migrate_tagging.rb +2 -0
- data/app/models/query_tags_column.rb +7 -0
- data/app/views/additional_tags/_body_bottom.html.slim +19 -0
- data/app/views/additional_tags/_html_head.html.slim +1 -4
- data/app/views/additional_tags/_tag_list.html.slim +1 -1
- data/app/views/additional_tags/merge.html.slim +4 -3
- data/app/views/additional_tags/settings/_manage_tags.html.slim +24 -23
- data/app/views/common/_tag_summary_block.html.slim +11 -0
- data/app/views/context_menus/_issues_tags.html.slim +1 -1
- data/app/views/dashboards/blocks/_issue_tags.html.slim +58 -0
- data/app/views/dashboards/blocks/_issue_tags_settings.html.slim +20 -0
- data/app/views/issue_tags/_edit_modal.html.slim +6 -4
- data/app/views/issues/_tags_form.html.slim +1 -1
- data/assets/javascripts/tags.js +4 -3
- data/assets/stylesheets/tags.css +27 -13
- data/config/initializers/zeitwerk.rb +6 -0
- data/config/locales/bg.yml +5 -0
- data/config/locales/cs.yml +5 -0
- data/config/locales/de.yml +5 -0
- data/config/locales/en.yml +5 -0
- data/config/locales/es.yml +5 -0
- data/config/locales/fr.yml +5 -0
- data/config/locales/it.yml +5 -0
- data/config/locales/ja.yml +5 -0
- data/config/locales/ko.yml +5 -0
- data/config/locales/pl.yml +5 -0
- data/config/locales/pt-BR.yml +5 -0
- data/config/locales/ru.yml +28 -23
- data/config/routes.rb +2 -0
- data/db/migrate/20201116145429_acts_as_taggable_migration.rb +3 -1
- data/db/migrate/20201123093214_migrate_existing_tags.rb +5 -3
- data/init.rb +11 -6
- data/lib/additional_tags/hooks/model_hook.rb +13 -0
- data/lib/additional_tags/hooks/view_hook.rb +77 -0
- data/lib/additional_tags/patches/agile_boards_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/agile_query_patch.rb +11 -9
- data/lib/additional_tags/patches/agile_versions_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/agile_versions_query_patch.rb +3 -1
- data/lib/additional_tags/patches/auto_completes_controller_patch.rb +8 -7
- data/lib/additional_tags/patches/calendars_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/dashboard_async_blocks_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/dashboard_content_patch.rb +28 -0
- data/lib/additional_tags/patches/dashboards_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/gantts_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/imports_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/issue_patch.rb +19 -20
- data/lib/additional_tags/patches/issue_query_patch.rb +17 -14
- data/lib/additional_tags/patches/issues_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/journal_patch.rb +2 -0
- data/lib/additional_tags/patches/my_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/queries_helper_patch.rb +3 -15
- data/lib/additional_tags/patches/query_patch.rb +83 -0
- data/lib/additional_tags/patches/settings_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/time_entry_patch.rb +2 -0
- data/lib/additional_tags/patches/time_entry_query_patch.rb +5 -15
- data/lib/additional_tags/patches/time_report_patch.rb +2 -0
- data/lib/additional_tags/patches/timelog_controller_patch.rb +2 -0
- data/lib/additional_tags/patches/wiki_controller_patch.rb +3 -1
- data/lib/additional_tags/patches/wiki_page_patch.rb +54 -3
- data/lib/additional_tags/plugin_version.rb +7 -0
- data/lib/additional_tags/tags.rb +78 -18
- data/lib/additional_tags.rb +53 -74
- data/lib/tasks/additional_tags.rake +18 -0
- metadata +32 -9
- data/.github/workflows/brakeman.yml +0 -33
- data/app/views/reports/_tags_simple.html.slim +0 -11
- data/lib/additional_tags/hooks.rb +0 -73
- data/lib/additional_tags/patches/reports_controller_patch.rb +0 -32
- data/lib/additional_tags/version.rb +0 -3
@@ -1,4 +1,4 @@
|
|
1
|
-
|
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?
|
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.
|
18
|
+
counts: Issue.available_tags.to_h { |tag| [tag.id, tag.count] } }
|
19
19
|
end
|
20
20
|
|
21
|
-
if AdditionalTags.setting?
|
21
|
+
if AdditionalTags.setting? :active_wiki_tags
|
22
22
|
columns[:wiki] = { label: l(:label_wiki),
|
23
|
-
counts: WikiPage.available_tags.
|
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
|
47
|
-
return if tags.
|
46
|
+
def sort_tags_for_list(tags, sort_by: nil, sort_order: nil)
|
47
|
+
return tags if tags.size < 2
|
48
48
|
|
49
|
-
|
50
|
-
|
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 "#{
|
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,
|
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 <<
|
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
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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(
|
114
|
+
tag_name << tag.span(tag_object.count, class: 'tag-count') if show_count
|
101
115
|
|
102
|
-
content = if
|
116
|
+
content = if link
|
103
117
|
link_to safe_join(tag_name),
|
104
|
-
|
118
|
+
link,
|
105
119
|
style: tag_style
|
106
|
-
elsif
|
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::
|
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
|
-
|
145
|
-
|
146
|
-
|
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
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
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
|
164
|
-
tag_list = AdditionalTags::Tags.sort_tag_list
|
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
|
-
|
167
|
-
|
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,
|
173
|
-
action =
|
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
|
180
|
-
field =
|
218
|
+
if filter.present?
|
219
|
+
field = filter[:field]
|
181
220
|
fields << field
|
182
|
-
operators[field] =
|
183
|
-
values[field] =
|
221
|
+
operators[field] = filter[:operator]
|
222
|
+
values[field] = filter[:value] if filter.key? :value
|
184
223
|
end
|
185
224
|
|
186
|
-
{ controller:
|
225
|
+
{ controller: tag_controller.presence || controller_name,
|
187
226
|
action: action,
|
188
227
|
set_filter: 1,
|
189
|
-
project_id:
|
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?(:
|
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
|
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
|
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,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
|
data/app/models/migrate_tag.rb
CHANGED
@@ -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
|
-
|
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
|
@@ -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,
|
10
|
-
|
11
|
-
|
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
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
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
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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,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
|
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
|
-
=
|
29
|
+
= link_to_function l(:button_cancel), 'hideModal(this);'
|
30
|
+
|
31
|
+
javascript:
|
32
|
+
var mostUsedTags = #{raw @most_used_tags.map(&:name)};
|
data/assets/javascripts/tags.js
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
|
2
|
-
|
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
|
-
|
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(', ');
|