additional_tags 1.0.2 → 1.0.5
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 -2
- data/.github/workflows/tests.yml +8 -6
- data/.gitignore +2 -1
- data/.rubocop.yml +31 -6
- data/README.md +17 -18
- data/additional_tags.gemspec +6 -4
- data/app/controllers/additional_tags_controller.rb +23 -0
- data/app/helpers/additional_tags_helper.rb +60 -19
- data/app/helpers/additional_tags_issues_helper.rb +12 -2
- data/app/helpers/additional_tags_wiki_helper.rb +1 -25
- data/app/jobs/additional_tags_remove_unused_tag_job.rb +5 -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/context_menu.html.slim +1 -4
- data/app/views/additional_tags/index.api.rsb +5 -0
- data/app/views/additional_tags/settings/_manage_tags.html.slim +23 -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 +4 -2
- data/app/views/issues/_tags_sidebar.html.slim +4 -1
- data/assets/javascripts/tags.js +4 -3
- data/assets/stylesheets/tags.css +27 -13
- data/config/initializers/zeitwerk.rb +4 -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 +1 -1
- data/db/migrate/20201123093214_migrate_existing_tags.rb +1 -1
- data/init.rb +9 -7
- data/lib/additional_tags/hooks/model_hook.rb +11 -0
- data/lib/additional_tags/hooks/view_hook.rb +79 -0
- data/lib/additional_tags/patches/auto_completes_controller_patch.rb +5 -6
- data/lib/additional_tags/patches/dashboard_content_patch.rb +28 -0
- data/lib/additional_tags/patches/issue_patch.rb +25 -28
- data/lib/additional_tags/patches/query_patch.rb +10 -3
- data/lib/additional_tags/patches/wiki_controller_patch.rb +1 -1
- data/lib/additional_tags/patches/wiki_page_patch.rb +50 -1
- data/lib/additional_tags/plugin_version.rb +7 -0
- data/lib/additional_tags/tags.rb +54 -4
- data/lib/additional_tags.rb +51 -65
- data/lib/tasks/additional_tags.rake +18 -0
- metadata +34 -12
- data/.github/workflows/brakeman.yml +0 -34
- data/app/views/reports/_tags_simple.html.slim +0 -11
- data/lib/additional_tags/hooks.rb +0 -75
- data/lib/additional_tags/patches/reports_controller_patch.rb +0 -34
- data/lib/additional_tags/version.rb +0 -5
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AdditionalTags
|
4
|
+
module Patches
|
5
|
+
module DashboardContentPatch
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
prepend InstanceOverwriteMethods
|
10
|
+
end
|
11
|
+
|
12
|
+
module InstanceOverwriteMethods
|
13
|
+
def block_definitions
|
14
|
+
blocks = super
|
15
|
+
|
16
|
+
blocks['issue_tags'] = {
|
17
|
+
label: l(:field_issue_tags),
|
18
|
+
permission: :view_issue_tags,
|
19
|
+
if: proc { AdditionalTags.setting?(:active_issue_tags) },
|
20
|
+
async: { partial: 'dashboards/blocks/issue_tags' }
|
21
|
+
}
|
22
|
+
|
23
|
+
blocks
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -6,12 +6,16 @@ module AdditionalTags
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
+
include Additionals::EntityMethodsGlobal
|
9
10
|
include InstanceMethods
|
10
11
|
acts_as_ordered_taggable
|
11
12
|
|
12
13
|
before_save :prepare_save_tag_change
|
13
14
|
before_save :sort_tag_list
|
14
15
|
|
16
|
+
after_commit :add_remove_unused_tags_job, on: %i[update destroy],
|
17
|
+
if: proc { AdditionalTags.setting?(:active_issue_tags) }
|
18
|
+
|
15
19
|
alias_method :safe_attributes_without_tags=, :safe_attributes=
|
16
20
|
alias_method :safe_attributes=, :safe_attributes_with_tags=
|
17
21
|
|
@@ -25,8 +29,11 @@ module AdditionalTags
|
|
25
29
|
tags.all? { |tag| allowed_tags.include? tag }
|
26
30
|
end
|
27
31
|
|
28
|
-
def
|
29
|
-
|
32
|
+
def group_by_status_with_tags(project = nil)
|
33
|
+
visible(User.current, project: project).joins(:status)
|
34
|
+
.joins(:tags)
|
35
|
+
.group(:is_closed, 'tag_id')
|
36
|
+
.count
|
30
37
|
end
|
31
38
|
|
32
39
|
def available_tags(**options)
|
@@ -37,10 +44,6 @@ module AdditionalTags
|
|
37
44
|
tags.joins("JOIN #{IssueStatus.table_name} ON #{IssueStatus.table_name}.id = #{table_name}.status_id")
|
38
45
|
.where(issue_statuses: { is_closed: false })
|
39
46
|
end
|
40
|
-
|
41
|
-
def remove_unused_tags!
|
42
|
-
AdditionalTagsRemoveUnusedTagJob.perform_later
|
43
|
-
end
|
44
47
|
end
|
45
48
|
|
46
49
|
module InstanceMethods
|
@@ -53,36 +56,30 @@ module AdditionalTags
|
|
53
56
|
end
|
54
57
|
|
55
58
|
def safe_attributes_with_tags=(attrs, user = User.current)
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
self.tag_list = tags
|
64
|
-
end
|
65
|
-
end
|
59
|
+
send :safe_attributes_without_tags=, attrs, user # required to fire first to get loaded project
|
60
|
+
return unless attrs && attrs[:tag_list]
|
61
|
+
|
62
|
+
tags = attrs.delete :tag_list
|
63
|
+
tags = Array(tags).reject(&:empty?)
|
64
|
+
|
65
|
+
Additionals.debug "tags: #{tags.inspect} - project: #{project&.id} - access: #{user.allowed_to? :create_issue_tags, project}"
|
66
66
|
|
67
|
-
|
67
|
+
if user.allowed_to?(:create_issue_tags, project) ||
|
68
|
+
user.allowed_to?(:edit_issue_tags, project) && Issue.allowed_tags?(tags)
|
69
|
+
attrs[:tag_list] = tags # required fix for journal details
|
70
|
+
self.tag_list = tags # required fix for tags
|
71
|
+
end
|
68
72
|
end
|
69
73
|
|
70
|
-
def copy_from_with_tags(arg,
|
71
|
-
|
74
|
+
def copy_from_with_tags(arg, options = nil)
|
75
|
+
options ||= {} # works with Ruby 3
|
76
|
+
|
77
|
+
copy_from_without_tags arg, **options
|
72
78
|
issue = arg.is_a?(Issue) ? arg : Issue.visible.find(arg)
|
73
79
|
self.tag_list = issue.tag_list
|
74
80
|
self
|
75
81
|
end
|
76
82
|
|
77
|
-
def tags_to_journal(old_tags, new_tags)
|
78
|
-
return if current_journal.blank? || old_tags == new_tags
|
79
|
-
|
80
|
-
current_journal.details << JournalDetail.new(property: 'attr',
|
81
|
-
prop_key: 'tag_list',
|
82
|
-
old_value: old_tags,
|
83
|
-
value: new_tags)
|
84
|
-
end
|
85
|
-
|
86
83
|
private
|
87
84
|
|
88
85
|
def sort_tag_list
|
@@ -35,14 +35,16 @@ module AdditionalTags
|
|
35
35
|
.map { |name| [name, name] }
|
36
36
|
end
|
37
37
|
|
38
|
-
def build_subquery_for_tags_field(klass:, operator:, values:, joined_table:, joined_field:,
|
38
|
+
def build_subquery_for_tags_field(klass:, operator:, values:, joined_table:, joined_field:,
|
39
|
+
source_field: 'id', target_field: 'issue_id')
|
39
40
|
quoted_joined_table = self.class.connection.quote_table_name joined_table
|
40
41
|
quoted_joined_field = self.class.connection.quote_column_name joined_field
|
42
|
+
quoted_source_field = self.class.connection.quote_column_name source_field
|
41
43
|
quoted_target_field = self.class.connection.quote_column_name target_field
|
42
44
|
subsql = ActsAsTaggableOn::Tagging.joins("INNER JOIN #{quoted_joined_table}" \
|
43
45
|
" ON additional_taggings.taggable_id = #{quoted_joined_table}.#{quoted_target_field}")
|
44
46
|
.where(taggable_type: klass.name)
|
45
|
-
.where("#{self.class.connection.quote_table_name queried_table_name}
|
47
|
+
.where("#{self.class.connection.quote_table_name queried_table_name}.#{quoted_source_field} ="\
|
46
48
|
" #{quoted_joined_table}.#{quoted_joined_field}")
|
47
49
|
.select(1)
|
48
50
|
|
@@ -63,7 +65,12 @@ module AdditionalTags
|
|
63
65
|
case operator
|
64
66
|
when '=', '!'
|
65
67
|
ids_list = klass.tagged_with(values, any: true).pluck :id
|
66
|
-
|
68
|
+
if ids_list.present?
|
69
|
+
"(#{klass.table_name}.id #{compare} (#{ids_list.join ','}))"
|
70
|
+
elsif values.present? && operator == '='
|
71
|
+
# special case: filter with deleted tag
|
72
|
+
'(1=0)'
|
73
|
+
end
|
67
74
|
else
|
68
75
|
entries = ActsAsTaggableOn::Tagging.where taggable_type: klass.name
|
69
76
|
id_table = klass.table_name
|
@@ -31,7 +31,7 @@ module AdditionalTags
|
|
31
31
|
@tag = params[:tag]
|
32
32
|
return super unless AdditionalTags.setting?(:active_wiki_tags) && @tag.present?
|
33
33
|
|
34
|
-
@pages =
|
34
|
+
@pages = WikiPage.with_tags @tag, project: @project
|
35
35
|
|
36
36
|
respond_to do |format|
|
37
37
|
format.html do
|
@@ -27,6 +27,55 @@ module AdditionalTags
|
|
27
27
|
options[:permission] = :view_wiki_pages
|
28
28
|
AdditionalTags::Tags.available_tags self, **options
|
29
29
|
end
|
30
|
+
|
31
|
+
def with_tags_scope(project: nil, wiki: nil)
|
32
|
+
scope = if wiki
|
33
|
+
wiki.pages
|
34
|
+
else
|
35
|
+
scope = WikiPage.joins wiki: :project
|
36
|
+
scope = scope.where wikis: { project_id: project.id } if project
|
37
|
+
scope
|
38
|
+
end
|
39
|
+
|
40
|
+
scope = scope.visible User.current, project: project if scope.respond_to? :visible
|
41
|
+
scope
|
42
|
+
end
|
43
|
+
|
44
|
+
def with_tags(tag, project: nil, order: 'title_asc', max_entries: nil)
|
45
|
+
wiki = project&.wiki
|
46
|
+
|
47
|
+
scope = with_tags_scope wiki: wiki, project: project
|
48
|
+
scope = scope.limit max_entries if max_entries
|
49
|
+
|
50
|
+
tags = Array tag
|
51
|
+
tags.map!(&:strip)
|
52
|
+
tags.compact_blank!
|
53
|
+
return [] if tags.count.zero?
|
54
|
+
|
55
|
+
tags.map!(&:downcase)
|
56
|
+
|
57
|
+
scope = scope.where(id: tagged_with(tags, any: true).ids)
|
58
|
+
.with_updated_on
|
59
|
+
|
60
|
+
return scope if order.nil?
|
61
|
+
|
62
|
+
sorted = order.split '_'
|
63
|
+
raise 'unsupported sort order' if sorted != 2 && %w[title date].exclude?(sorted.first)
|
64
|
+
|
65
|
+
order_dir = sorted.second == 'desc' ? 'DESC' : 'ASC'
|
66
|
+
|
67
|
+
case sorted.first
|
68
|
+
when 'date'
|
69
|
+
scope.joins(:content)
|
70
|
+
.reorder("#{WikiContent.table_name}.updated_on #{order_dir}")
|
71
|
+
else
|
72
|
+
if wiki.nil?
|
73
|
+
scope.order "#{Project.table_name}.name, #{WikiPage.table_name}.title #{order_dir}"
|
74
|
+
else
|
75
|
+
scope.includes(:parent).order "#{WikiPage.table_name}.title #{order_dir}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
30
79
|
end
|
31
80
|
|
32
81
|
module InstanceMethods
|
@@ -46,7 +95,7 @@ module AdditionalTags
|
|
46
95
|
end
|
47
96
|
end
|
48
97
|
|
49
|
-
send
|
98
|
+
send :safe_attributes_without_tags=, attrs, user
|
50
99
|
end
|
51
100
|
|
52
101
|
private
|
data/lib/additional_tags/tags.rb
CHANGED
@@ -25,7 +25,7 @@ module AdditionalTags
|
|
25
25
|
|
26
26
|
columns << "MIN(#{TAGGING_TABLE_NAME}.created_at) AS last_created" if options[:sort_by] == 'last_created'
|
27
27
|
|
28
|
-
scope.select(columns.
|
28
|
+
scope.select(columns.to_list)
|
29
29
|
.joins(tag_for_joins(klass, **options.slice(:project_join, :project, :without_projects)))
|
30
30
|
.group("#{TAG_TABLE_NAME}.id, #{TAG_TABLE_NAME}.name, #{TAG_TABLE_NAME}.taggings_count").having('COUNT(*) > 0')
|
31
31
|
.order(build_order_sql(options[:sort_by], options[:order]))
|
@@ -35,7 +35,7 @@ module AdditionalTags
|
|
35
35
|
ActsAsTaggableOn::Tag.all
|
36
36
|
.joins(tag_for_joins(klass, without_projects: without_projects))
|
37
37
|
.distinct
|
38
|
-
.order(
|
38
|
+
.order(:name)
|
39
39
|
end
|
40
40
|
|
41
41
|
def tag_to_joins(klass)
|
@@ -49,7 +49,8 @@ module AdditionalTags
|
|
49
49
|
end
|
50
50
|
|
51
51
|
def remove_unused_tags
|
52
|
-
ActsAsTaggableOn::Tag.
|
52
|
+
ActsAsTaggableOn::Tag.left_outer_joins(:taggings)
|
53
|
+
.where(taggings: { id: nil })
|
53
54
|
.each(&:destroy)
|
54
55
|
end
|
55
56
|
|
@@ -64,7 +65,8 @@ module AdditionalTags
|
|
64
65
|
tags_to_merge.reject { |t| t.id == tag.id }.each(&:destroy)
|
65
66
|
# remove duplicate taggings
|
66
67
|
dup_scope = ActsAsTaggableOn::Tagging.where tag_id: tag.id
|
67
|
-
valid_ids = dup_scope.group(:tag_id, :taggable_id, :taggable_type, :tagger_id, :tagger_type, :context)
|
68
|
+
valid_ids = dup_scope.group(:tag_id, :taggable_id, :taggable_type, :tagger_id, :tagger_type, :context)
|
69
|
+
.pluck(Arel.sql('MIN(id)'))
|
68
70
|
dup_scope.where.not(id: valid_ids).destroy_all if valid_ids.any?
|
69
71
|
# recalc count for new tag
|
70
72
|
ActsAsTaggableOn::Tag.reset_counters tag.id, :taggings
|
@@ -86,6 +88,7 @@ module AdditionalTags
|
|
86
88
|
end
|
87
89
|
|
88
90
|
def build_relation_tags(entries)
|
91
|
+
entries = Array entries
|
89
92
|
return [] if entries.none?
|
90
93
|
|
91
94
|
tags = entries.map(&:tags)
|
@@ -94,8 +97,55 @@ module AdditionalTags
|
|
94
97
|
tags.uniq
|
95
98
|
end
|
96
99
|
|
100
|
+
def entity_group_by(scope:, tags:, statuses: nil, sub_groups: nil, group_id_is_bool: false)
|
101
|
+
counts = {}
|
102
|
+
tags.each do |tag|
|
103
|
+
values = { tag: tag, total: 0, total_sub_groups: 0, groups: [] }
|
104
|
+
|
105
|
+
if statuses
|
106
|
+
statuses.each do |status|
|
107
|
+
group_id = status.first
|
108
|
+
group = status.second
|
109
|
+
values[group] = status_for_tag_value scope: scope,
|
110
|
+
tag_id: tag.id,
|
111
|
+
group_id: group_id,
|
112
|
+
group_id_is_bool: group_id_is_bool
|
113
|
+
values[:groups] << { id: group_id, group: group, count: values[group] }
|
114
|
+
values[:total] += values[group]
|
115
|
+
values[:total_sub_groups] += values[group] if sub_groups&.include? group_id
|
116
|
+
end
|
117
|
+
else
|
118
|
+
values[:total] += status_for_tag_value scope: scope, tag_id: tag.id
|
119
|
+
end
|
120
|
+
|
121
|
+
values[:total_without_sub_groups] = values[:total] - values[:total_sub_groups]
|
122
|
+
|
123
|
+
counts[tag.name] = values
|
124
|
+
end
|
125
|
+
|
126
|
+
counts
|
127
|
+
end
|
128
|
+
|
97
129
|
private
|
98
130
|
|
131
|
+
def status_for_tag_value(scope:, tag_id:, group_id: nil, group_id_is_bool: false)
|
132
|
+
value = if group_id_is_bool || group_id
|
133
|
+
if group_id_is_bool
|
134
|
+
if group_id
|
135
|
+
scope[[1, tag_id]] || scope[[true, tag_id]]
|
136
|
+
else
|
137
|
+
scope[[0, tag_id]] || scope[[false, tag_id]]
|
138
|
+
end
|
139
|
+
else
|
140
|
+
scope[[group_id, tag_id]]
|
141
|
+
end
|
142
|
+
else
|
143
|
+
scope[tag_id]
|
144
|
+
end
|
145
|
+
|
146
|
+
value || 0
|
147
|
+
end
|
148
|
+
|
99
149
|
def build_order_sql(sort_by, order)
|
100
150
|
order = order.present? && order == 'DESC' ? 'DESC' : 'ASC'
|
101
151
|
|
data/lib/additional_tags.rb
CHANGED
@@ -1,94 +1,80 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require '
|
4
|
-
require '
|
3
|
+
require 'redmine_plugin_kit'
|
4
|
+
require 'acts-as-taggable-on'
|
5
5
|
|
6
6
|
module AdditionalTags
|
7
7
|
TAG_TABLE_NAME = 'additional_tags'
|
8
8
|
TAGGING_TABLE_NAME = 'additional_taggings'
|
9
9
|
|
10
|
+
include RedminePluginKit::PluginBase
|
11
|
+
|
10
12
|
class << self
|
13
|
+
def show_sidebar_tags?
|
14
|
+
setting(:tags_sidebar).present? && setting(:tags_sidebar) != 'none'
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
11
19
|
def setup
|
12
20
|
raise 'Please install additionals plugin (https://github.com/alphanodes/additionals)' unless Redmine::Plugin.installed? 'additionals'
|
13
21
|
|
14
|
-
|
15
|
-
|
16
|
-
|
22
|
+
loader.incompatible? %w[redmine_tags
|
23
|
+
redmine_tagging
|
24
|
+
redmineup_tags]
|
17
25
|
|
18
26
|
# Patches
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
AgileBoardsController.include AdditionalTags::Patches::AgileBoardsControllerPatch
|
47
|
-
if AGILE_VERSION_TYPE == 'PRO version'
|
48
|
-
AgileVersionsController.include AdditionalTags::Patches::AgileVersionsControllerPatch
|
49
|
-
AgileVersionsQuery.include AdditionalTags::Patches::AgileVersionsQueryPatch
|
50
|
-
end
|
51
|
-
end
|
27
|
+
loader.add_patch %w[AutoCompletesController
|
28
|
+
CalendarsController
|
29
|
+
DashboardsController
|
30
|
+
DashboardAsyncBlocksController
|
31
|
+
GanttsController
|
32
|
+
MyController
|
33
|
+
Issue
|
34
|
+
DashboardContent
|
35
|
+
Journal
|
36
|
+
Query
|
37
|
+
IssuesController
|
38
|
+
ImportsController
|
39
|
+
QueriesHelper
|
40
|
+
SettingsController
|
41
|
+
TimeEntry
|
42
|
+
TimelogController
|
43
|
+
WikiController
|
44
|
+
WikiPage]
|
45
|
+
|
46
|
+
loader.add_patch({ target: Redmine::Helpers::TimeReport,
|
47
|
+
patch: 'TimeReport' })
|
48
|
+
|
49
|
+
loader.add_patch %w[IssueQuery TimeEntryQuery]
|
50
|
+
|
51
|
+
if Redmine::Plugin.installed? 'redmine_agile'
|
52
|
+
loader.add_patch %w[AgileQuery AgileBoardsController]
|
53
|
+
loader.add_patch %w[AgileVersionsController AgileVersionsQuery] if AGILE_VERSION_TYPE == 'PRO version'
|
52
54
|
end
|
53
55
|
|
54
|
-
#
|
55
|
-
|
56
|
-
end
|
57
|
-
|
58
|
-
# support with default setting as fall back
|
59
|
-
def setting(value)
|
60
|
-
if settings.key? value
|
61
|
-
settings[value]
|
62
|
-
else
|
63
|
-
Additionals.load_settings('additional_tags')[value]
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def setting?(value)
|
68
|
-
Additionals.true? settings[value]
|
69
|
-
end
|
70
|
-
|
71
|
-
def show_sidebar_tags?
|
72
|
-
setting(:tags_sidebar).present? && setting(:tags_sidebar) != 'none'
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
56
|
+
# Apply patches and helper
|
57
|
+
loader.apply!
|
76
58
|
|
77
|
-
|
78
|
-
|
59
|
+
# Load view hooks
|
60
|
+
loader.load_view_hooks!
|
79
61
|
end
|
80
62
|
end
|
81
63
|
|
82
64
|
# Run the classic redmine plugin initializer after rails boot
|
83
65
|
class Plugin < ::Rails::Engine
|
84
|
-
require '
|
66
|
+
require 'additional_tags/tags'
|
85
67
|
|
86
68
|
ActsAsTaggableOn.tags_table = TAG_TABLE_NAME
|
87
69
|
ActsAsTaggableOn.taggings_table = TAGGING_TABLE_NAME
|
70
|
+
# NOTE: remove_unused_tags cannot be used, because tag is deleted before assign for tagging
|
71
|
+
# @see https://github.com/mbleigh/acts-as-taggable-on/issues/946
|
72
|
+
# NOTE2: merging tags is not compatible, too.
|
73
|
+
ActsAsTaggableOn.remove_unused_tags = false
|
88
74
|
|
89
75
|
config.after_initialize do
|
90
76
|
# engine_name could be used (additional_tags_plugin), but can
|
91
|
-
# create some side
|
77
|
+
# create some side effects
|
92
78
|
plugin_id = 'additional_tags'
|
93
79
|
|
94
80
|
# if plugin is already in plugins directory, use this and leave here
|
@@ -96,7 +82,7 @@ module AdditionalTags
|
|
96
82
|
|
97
83
|
# gem is used as redmine plugin
|
98
84
|
require File.expand_path '../init', __dir__
|
99
|
-
AdditionalTags.setup
|
85
|
+
AdditionalTags.setup!
|
100
86
|
Additionals::Gemify.install_assets plugin_id
|
101
87
|
Additionals::Gemify.create_plugin_hint plugin_id
|
102
88
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
namespace :redmine do
|
4
|
+
namespace :additional_tags do
|
5
|
+
desc <<-DESCRIPTION
|
6
|
+
Remove unused tags.
|
7
|
+
|
8
|
+
Example:
|
9
|
+
bundle exec rake redmine:additional_tags:remove_unused_tags RAILS_ENV=production
|
10
|
+
DESCRIPTION
|
11
|
+
task remove_unused_tags: :environment do
|
12
|
+
AdditionalTags::Tags.remove_unused_tags
|
13
|
+
|
14
|
+
puts 'Unused tags has been removed.'
|
15
|
+
exit 0
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: additional_tags
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- AlphaNodes
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-06-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acts-as-taggable-on
|
@@ -16,14 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '9.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '9.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redmine_plugin_kit
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: bundler
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -60,7 +74,7 @@ extensions: []
|
|
60
74
|
extra_rdoc_files: []
|
61
75
|
files:
|
62
76
|
- ".eslintrc.yml"
|
63
|
-
- ".github/workflows/
|
77
|
+
- ".github/workflows/codeql-analysis.yml"
|
64
78
|
- ".github/workflows/linters.yml"
|
65
79
|
- ".github/workflows/tests.yml"
|
66
80
|
- ".gitignore"
|
@@ -81,16 +95,21 @@ files:
|
|
81
95
|
- app/models/migrate_tag.rb
|
82
96
|
- app/models/migrate_tagging.rb
|
83
97
|
- app/models/query_tags_column.rb
|
98
|
+
- app/views/additional_tags/_body_bottom.html.slim
|
84
99
|
- app/views/additional_tags/_html_head.html.slim
|
85
100
|
- app/views/additional_tags/_tag_list.html.slim
|
86
101
|
- app/views/additional_tags/context_menu.html.slim
|
87
102
|
- app/views/additional_tags/edit.html.slim
|
103
|
+
- app/views/additional_tags/index.api.rsb
|
88
104
|
- app/views/additional_tags/merge.html.slim
|
89
105
|
- app/views/additional_tags/settings/_general.html.slim
|
90
106
|
- app/views/additional_tags/settings/_manage_tags.html.slim
|
91
107
|
- app/views/additional_tags/settings/_settings.html.slim
|
92
108
|
- app/views/auto_completes/_additional_tag_list.slim
|
109
|
+
- app/views/common/_tag_summary_block.html.slim
|
93
110
|
- app/views/context_menus/_issues_tags.html.slim
|
111
|
+
- app/views/dashboards/blocks/_issue_tags.html.slim
|
112
|
+
- app/views/dashboards/blocks/_issue_tags_settings.html.slim
|
94
113
|
- app/views/issue_tags/_edit_modal.html.slim
|
95
114
|
- app/views/issue_tags/edit.js.erb
|
96
115
|
- app/views/issues/_tags.html.slim
|
@@ -98,7 +117,6 @@ files:
|
|
98
117
|
- app/views/issues/_tags_form.html.slim
|
99
118
|
- app/views/issues/_tags_form_details.html.slim
|
100
119
|
- app/views/issues/_tags_sidebar.html.slim
|
101
|
-
- app/views/reports/_tags_simple.html.slim
|
102
120
|
- app/views/wiki/_tags_form.html.slim
|
103
121
|
- app/views/wiki/_tags_form_bottom.html.slim
|
104
122
|
- app/views/wiki/_tags_show.html.slim
|
@@ -106,6 +124,7 @@ files:
|
|
106
124
|
- app/views/wiki/tag_index.html.slim
|
107
125
|
- assets/javascripts/tags.js
|
108
126
|
- assets/stylesheets/tags.css
|
127
|
+
- config/initializers/zeitwerk.rb
|
109
128
|
- config/locales/bg.yml
|
110
129
|
- config/locales/cs.yml
|
111
130
|
- config/locales/de.yml
|
@@ -126,7 +145,8 @@ files:
|
|
126
145
|
- doc/images/additional-tags.gif
|
127
146
|
- init.rb
|
128
147
|
- lib/additional_tags.rb
|
129
|
-
- lib/additional_tags/hooks.rb
|
148
|
+
- lib/additional_tags/hooks/model_hook.rb
|
149
|
+
- lib/additional_tags/hooks/view_hook.rb
|
130
150
|
- lib/additional_tags/patches/agile_boards_controller_patch.rb
|
131
151
|
- lib/additional_tags/patches/agile_query_patch.rb
|
132
152
|
- lib/additional_tags/patches/agile_versions_controller_patch.rb
|
@@ -134,6 +154,7 @@ files:
|
|
134
154
|
- lib/additional_tags/patches/auto_completes_controller_patch.rb
|
135
155
|
- lib/additional_tags/patches/calendars_controller_patch.rb
|
136
156
|
- lib/additional_tags/patches/dashboard_async_blocks_controller_patch.rb
|
157
|
+
- lib/additional_tags/patches/dashboard_content_patch.rb
|
137
158
|
- lib/additional_tags/patches/dashboards_controller_patch.rb
|
138
159
|
- lib/additional_tags/patches/gantts_controller_patch.rb
|
139
160
|
- lib/additional_tags/patches/imports_controller_patch.rb
|
@@ -144,7 +165,6 @@ files:
|
|
144
165
|
- lib/additional_tags/patches/my_controller_patch.rb
|
145
166
|
- lib/additional_tags/patches/queries_helper_patch.rb
|
146
167
|
- lib/additional_tags/patches/query_patch.rb
|
147
|
-
- lib/additional_tags/patches/reports_controller_patch.rb
|
148
168
|
- lib/additional_tags/patches/settings_controller_patch.rb
|
149
169
|
- lib/additional_tags/patches/time_entry_patch.rb
|
150
170
|
- lib/additional_tags/patches/time_entry_query_patch.rb
|
@@ -152,12 +172,14 @@ files:
|
|
152
172
|
- lib/additional_tags/patches/timelog_controller_patch.rb
|
153
173
|
- lib/additional_tags/patches/wiki_controller_patch.rb
|
154
174
|
- lib/additional_tags/patches/wiki_page_patch.rb
|
175
|
+
- lib/additional_tags/plugin_version.rb
|
155
176
|
- lib/additional_tags/tags.rb
|
156
|
-
- lib/additional_tags
|
177
|
+
- lib/tasks/additional_tags.rake
|
157
178
|
homepage: https://github.com/alphanodes/additional_tags
|
158
179
|
licenses:
|
159
180
|
- GPL-2.0
|
160
|
-
metadata:
|
181
|
+
metadata:
|
182
|
+
rubygems_mfa_required: 'true'
|
161
183
|
post_install_message:
|
162
184
|
rdoc_options: []
|
163
185
|
require_paths:
|
@@ -166,14 +188,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
166
188
|
requirements:
|
167
189
|
- - ">="
|
168
190
|
- !ruby/object:Gem::Version
|
169
|
-
version: '2.
|
191
|
+
version: '2.7'
|
170
192
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
193
|
requirements:
|
172
194
|
- - ">="
|
173
195
|
- !ruby/object:Gem::Version
|
174
196
|
version: '0'
|
175
197
|
requirements: []
|
176
|
-
rubygems_version: 3.
|
198
|
+
rubygems_version: 3.3.7
|
177
199
|
signing_key:
|
178
200
|
specification_version: 4
|
179
201
|
summary: Redmine plugin for adding tag functionality
|