additional_tags 1.0.2 → 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/codeql-analysis.yml +70 -0
  3. data/.github/workflows/linters.yml +6 -2
  4. data/.github/workflows/tests.yml +8 -6
  5. data/.gitignore +2 -1
  6. data/.rubocop.yml +31 -6
  7. data/README.md +17 -18
  8. data/additional_tags.gemspec +6 -4
  9. data/app/controllers/additional_tags_controller.rb +23 -0
  10. data/app/helpers/additional_tags_helper.rb +60 -19
  11. data/app/helpers/additional_tags_issues_helper.rb +12 -2
  12. data/app/helpers/additional_tags_wiki_helper.rb +1 -25
  13. data/app/jobs/additional_tags_remove_unused_tag_job.rb +5 -0
  14. data/app/views/additional_tags/_body_bottom.html.slim +19 -0
  15. data/app/views/additional_tags/_html_head.html.slim +1 -4
  16. data/app/views/additional_tags/_tag_list.html.slim +1 -1
  17. data/app/views/additional_tags/context_menu.html.slim +1 -4
  18. data/app/views/additional_tags/index.api.rsb +5 -0
  19. data/app/views/additional_tags/settings/_manage_tags.html.slim +23 -23
  20. data/app/views/common/_tag_summary_block.html.slim +11 -0
  21. data/app/views/context_menus/_issues_tags.html.slim +1 -1
  22. data/app/views/dashboards/blocks/_issue_tags.html.slim +58 -0
  23. data/app/views/dashboards/blocks/_issue_tags_settings.html.slim +20 -0
  24. data/app/views/issue_tags/_edit_modal.html.slim +4 -2
  25. data/app/views/issues/_tags_sidebar.html.slim +4 -1
  26. data/assets/javascripts/tags.js +4 -3
  27. data/assets/stylesheets/tags.css +27 -13
  28. data/config/initializers/zeitwerk.rb +4 -0
  29. data/config/locales/bg.yml +5 -0
  30. data/config/locales/cs.yml +5 -0
  31. data/config/locales/de.yml +5 -0
  32. data/config/locales/en.yml +5 -0
  33. data/config/locales/es.yml +5 -0
  34. data/config/locales/fr.yml +5 -0
  35. data/config/locales/it.yml +5 -0
  36. data/config/locales/ja.yml +5 -0
  37. data/config/locales/ko.yml +5 -0
  38. data/config/locales/pl.yml +5 -0
  39. data/config/locales/pt-BR.yml +5 -0
  40. data/config/locales/ru.yml +28 -23
  41. data/config/routes.rb +1 -1
  42. data/db/migrate/20201123093214_migrate_existing_tags.rb +1 -1
  43. data/init.rb +9 -7
  44. data/lib/additional_tags/hooks/model_hook.rb +11 -0
  45. data/lib/additional_tags/hooks/view_hook.rb +79 -0
  46. data/lib/additional_tags/patches/auto_completes_controller_patch.rb +5 -6
  47. data/lib/additional_tags/patches/dashboard_content_patch.rb +28 -0
  48. data/lib/additional_tags/patches/issue_patch.rb +25 -28
  49. data/lib/additional_tags/patches/query_patch.rb +10 -3
  50. data/lib/additional_tags/patches/wiki_controller_patch.rb +1 -1
  51. data/lib/additional_tags/patches/wiki_page_patch.rb +50 -1
  52. data/lib/additional_tags/plugin_version.rb +7 -0
  53. data/lib/additional_tags/tags.rb +54 -4
  54. data/lib/additional_tags.rb +51 -65
  55. data/lib/tasks/additional_tags.rake +18 -0
  56. metadata +34 -12
  57. data/.github/workflows/brakeman.yml +0 -34
  58. data/app/views/reports/_tags_simple.html.slim +0 -11
  59. data/lib/additional_tags/hooks.rb +0 -75
  60. data/lib/additional_tags/patches/reports_controller_patch.rb +0 -34
  61. data/lib/additional_tags/version.rb +0 -5
@@ -1,29 +1,29 @@
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
+ = delete_link additional_tags_path(ids: tag)
27
27
  - else
28
28
  p.nodata = l :label_no_data
29
29
 
@@ -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
@@ -22,9 +22,11 @@ h3.title = l :label_add_tags
22
22
  tags: User.current.allowed_to?(:create_issue_tags, @project)
23
23
  p.most_used_tags
24
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)}"
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)};
@@ -1,5 +1,8 @@
1
1
  - if AdditionalTags.setting?(:active_issue_tags) && \
2
- User.current.allowed_to?(:view_issue_tags, @project, global: true) && sidebar_tags.present?
2
+ User.current.allowed_to?(:view_issue_tags, @project, global: true) && \
3
+ defined?(sidebar_tags) && \
4
+ sidebar_tags.present?
5
+
3
6
  .sidebar-tags
4
7
  h3 = l :field_tags
5
8
  = render_sidebar_tags
@@ -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(', ');
@@ -26,8 +26,8 @@ ul.tags li { margin: 0.25em 0; }
26
26
 
27
27
  span.additional-tag-label-color {
28
28
  display: inline-block;
29
- margin-bottom: 5px !important;
30
- border-radius: 2px !important;
29
+ margin-bottom: 3px !important;
30
+ border-radius: 0.75rem !important;
31
31
  }
32
32
 
33
33
  td.tags span.additional-tag-label-color {
@@ -37,27 +37,41 @@ td.tags span.additional-tag-label-color {
37
37
  }
38
38
 
39
39
  .additional-tag-label-color {
40
- padding: 2px 4px;
41
- font-size: 10px !important;
40
+ padding: 0 5px;
41
+ line-height: initial;
42
+ font-size: 0.7rem !important;
42
43
  border: 1px solid rgba(0, 0, 0, 0.2);
43
- border-radius: 2px;
44
+ border-radius: 0.75rem;
44
45
  }
45
46
 
46
- .additional-tag-label-color a::before {
47
- font-family: Font Awesome\ 5 Free;
48
- font-size: 0.9em;
49
- font-weight: 900;
50
- content: "\f02b"; /* fas fa-tag */
51
- padding-right: 3px;
47
+ .additional-tag-label-color .tag-count {
48
+ display: inline-block;
49
+ background: #fff;
50
+ color: #1f1f1f;
51
+ padding-right: 5px;
52
+ border-top-right-radius: 0.7rem;
53
+ border-bottom-right-radius: 0.7rem;
54
+ margin-right: -5px;
55
+ padding-left: 3px;
56
+ }
57
+
58
+ .tag-label .tag-count {
59
+ background: #f1f5fa;
60
+ border-radius: 5px;
61
+ padding: 0 5px;
62
+ color: #666;
63
+ border: 1px solid #ddd;
64
+ vertical-align: middle;
52
65
  }
53
66
 
54
67
  .additional-tag-label-color .tag-count,
55
68
  .tag-label .tag-count {
56
- font-size: 0.75em;
69
+ font-size: 0.7rem;
57
70
  margin-left: 0.5em;
58
71
  }
59
72
 
60
- span.additional-tag-label-color:hover a {
73
+ span.additional-tag-label-color:hover a,
74
+ .tag-label .tag-count:hover a {
61
75
  text-decoration: none !important;
62
76
  }
63
77
 
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ plugin_dir = RedminePluginKit::Loader.plugin_dir plugin_id: 'additional_tags'
4
+ Rails.autoloaders.main.push_dir "#{plugin_dir}/lib"
@@ -31,3 +31,8 @@ bg:
31
31
  tags_sort_by_name: "Име"
32
32
  label_tags_sort_by: "Сортиране на маркерите по"
33
33
  label_tags_suggestion_order: "Ред на предлагане"
34
+ label_with_table_of_values: "С таблица на стойността"
35
+ label_with_chart: "С графиком"
36
+ label_amount_tags: "Теги Сумма"
37
+ label_amount_entities_with_tags: "Сумма %{name} с тегами"
38
+ label_quantity: "Количество"
@@ -31,3 +31,8 @@ cs:
31
31
  tags_sort_by_name: "Název"
32
32
  label_tags_sort_by: "Řazení značek podle"
33
33
  label_tags_suggestion_order: "Objednávka návrhu"
34
+ label_with_table_of_values: "S tabulkou hodnot"
35
+ label_with_chart: "S grafem"
36
+ label_amount_tags: "Částka TAGy"
37
+ label_amount_entities_with_tags: "Částka %{name} s TAGy"
38
+ label_quantity: "Množství"
@@ -31,3 +31,8 @@ de:
31
31
  tags_sort_by_name: Name
32
32
  label_tags_sort_by: Sortiere TAGs nach
33
33
  label_tags_suggestion_order: Reihenfolge der Vorschläge
34
+ label_with_table_of_values: Mit Wertetabelle
35
+ label_with_chart: Mit Chart
36
+ label_amount_tags: Anzahl TAGs
37
+ label_amount_entities_with_tags: Anzahl %{name} mit TAGs
38
+ label_quantity: Anzahl
@@ -31,3 +31,8 @@ en:
31
31
  tags_sort_by_name: "Name"
32
32
  label_tags_sort_by: "Sort tags by"
33
33
  label_tags_suggestion_order: "Suggestion order"
34
+ label_with_table_of_values: "With table of values"
35
+ label_with_chart: "With chart"
36
+ label_amount_tags: "Amount tags"
37
+ label_amount_entities_with_tags: "Amount %{name} with tags"
38
+ label_quantity: "Quantity"
@@ -31,3 +31,8 @@ es:
31
31
  tags_sort_by_name: "Nombre"
32
32
  label_tags_sort_by: "Ordenar las tags por"
33
33
  label_tags_suggestion_order: "Orden de sugerencia"
34
+ label_with_table_of_values: "Con tabla de valores"
35
+ label_with_chart: "Con tabla"
36
+ label_amount_tags: "Valor tags"
37
+ label_amount_entities_with_tags: "Cantidad %{name} con tags"
38
+ label_quantity: "Ctd."
@@ -31,3 +31,8 @@ fr:
31
31
  tags_sort_by_name: "Nom"
32
32
  label_tags_sort_by: "Trier les balises par"
33
33
  label_tags_suggestion_order: "Ordre de suggestion"
34
+ label_with_table_of_values: "Avec tableau de valeur"
35
+ label_with_chart: "Avec tableau"
36
+ label_amount_tags: "Montant tags"
37
+ label_amount_entities_with_tags: "Montant %{name} avec tags"
38
+ label_quantity: "Quantité"
@@ -31,3 +31,8 @@ it:
31
31
  tags_sort_by_name: "Nome"
32
32
  label_tags_sort_by: "Ordina i tag per"
33
33
  label_tags_suggestion_order: "Ordine di suggerimento"
34
+ label_with_table_of_values: With table of values
35
+ label_with_chart: With chart
36
+ label_amount_tags: Amount tags
37
+ label_amount_entities_with_tags: Amount %{name} with tags
38
+ label_quantity: "Numero"
@@ -31,3 +31,8 @@ ja:
31
31
  tags_sort_by_name: "名前"
32
32
  label_tags_sort_by: "タグを並べ替える"
33
33
  label_tags_suggestion_order: "ご提案の順番"
34
+ label_with_table_of_values: "価値観のテーブル付き"
35
+ label_with_chart: "チャート付き"
36
+ label_amount_tags: "金額 tags"
37
+ label_amount_entities_with_tags: "金額 %{name} tags付き"
38
+ label_quantity: "数量"
@@ -31,3 +31,8 @@ ko:
31
31
  tags_sort_by_name: "이름"
32
32
  label_tags_sort_by: "태그 정렬 기준"
33
33
  label_tags_suggestion_order: "제안 순서"
34
+ label_with_table_of_values: "가치 테이블"
35
+ label_with_chart: "차트 포함"
36
+ label_amount_tags: "금액 태그"
37
+ label_amount_entities_with_tags: "TAG가 있는 금액 %{name}"
38
+ label_quantity: "수량"
@@ -31,3 +31,8 @@ pl:
31
31
  tags_sort_by_name: "Nazwa"
32
32
  label_tags_sort_by: "Sortuj znaczniki według"
33
33
  label_tags_suggestion_order: "Zamówienie ofertowe"
34
+ label_with_table_of_values: "Z tabelą wartości"
35
+ label_with_chart: "Z wykresem"
36
+ label_amount_tags: "Kwota Tags"
37
+ label_amount_entities_with_tags: "Kwota %{name} z Tags"
38
+ label_quantity: "Ilość"
@@ -31,3 +31,8 @@ pt-BR:
31
31
  tags_sort_by_name: "Nome"
32
32
  label_tags_sort_by: "Ordenar tags por"
33
33
  label_tags_suggestion_order: "Pedido de sugestão"
34
+ label_with_table_of_values: "Com tabela de valores"
35
+ label_with_chart: "Com gráfico"
36
+ label_amount_tags: "Valor Etiquetas"
37
+ label_amount_entities_with_tags: "Quantidade %{name} com etiquetas"
38
+ label_quantity: "Quantidade"
@@ -1,33 +1,38 @@
1
1
  ru:
2
- field_tag_list: Tags
3
- field_tags: Tags
4
- field_issue_tags: Issue tags
5
- label_active_issue_tags: "Активировать теги проблем"
6
- label_active_wiki_tags: "Активировать вики-теги"
7
- label_add_tags: "Добавить теги"
2
+ field_tag_list: Теги
3
+ field_tags: Теги
4
+ field_issue_tags: Теги задач
5
+ label_active_issue_tags: "Активировать теги задач"
6
+ label_active_wiki_tags: "Активировать теги вики"
7
+ label_add_tags: "Добавьте теги"
8
8
  label_edit_tags: "Редактировать теги"
9
- label_manage_tags: "Управляющие метки"
9
+ label_manage_tags: "Управление тегами"
10
10
  label_merge_selected_tags: "Объединить выбранные теги"
11
- label_open_issues_only: "Отображать только открытые вопросы"
12
- label_show_with_count: "Отображаемое количество на теге"
13
- label_tags_tag: "Tag"
11
+ label_open_issues_only: "Отображать только открытые задачи"
12
+ label_show_with_count: "Отображать количество на теге"
13
+ label_tags_tag: "Тег"
14
14
  label_use_colors: "Использовать цвета"
15
15
  label_wiki_index_for_tag_html: "Вики-страницы с тегом <em>%{tag}</em>"
16
16
  notice_failed_to_add_tags: "Не удалось добавить теги"
17
17
  notice_tags_added: "Теги добавлены"
18
- permission_add_wiki_tags: "Добавить вики-теги"
19
- permission_create_issue_tags: "Добавить теги проблемы"
20
- permission_edit_issue_tags: "Редактирование тематических тегов"
21
- permission_view_issue_tags: "Отображать проблемные теги"
22
- tags_order_by_last_created: "Последний созданный"
23
- tags_order_by_count: "Наиболее часто используемый"
18
+ permission_add_wiki_tags: "Добавление тегов вики"
19
+ permission_create_issue_tags: "Добавление тегов задач"
20
+ permission_edit_issue_tags: "Редактирование тегов задач"
21
+ permission_view_issue_tags: "Просмотр тегов задач"
22
+ tags_order_by_last_created: "Недавно созданные"
23
+ tags_order_by_count: "Наиболее часто используемые"
24
24
  tags_order_by_name: "Имя"
25
- tags_sidebar_cloud: "Cloud"
25
+ tags_sidebar_cloud: "Облако"
26
26
  tags_sidebar_list: "Список"
27
27
  tags_sidebar_none: "Нет"
28
- tags_sidebar_simple_cloud: "Simple cloud"
29
- label_tags_sidebar: "DОтображать теги на боковой панели как"
30
- tags_sort_by_count: "Посчитать"
31
- tags_sort_by_name: "Имя"
32
- label_tags_sort_by: "Сортировать метки по"
33
- label_tags_suggestion_order: "Порядок предложения"
28
+ tags_sidebar_simple_cloud: "Простое облако"
29
+ label_tags_sidebar: "Способ отображения тегов на боковой панели"
30
+ tags_sort_by_count: "Количеству"
31
+ tags_sort_by_name: "Имени"
32
+ label_tags_sort_by: "Сортировать теги по"
33
+ label_tags_suggestion_order: "Порядок предложения при вводе"
34
+ label_with_table_of_values: "С таблицей значений"
35
+ label_with_chart: "С графиком"
36
+ label_amount_tags: "Теги Сумма"
37
+ label_amount_entities_with_tags: "Сумма %{name} с тегами"
38
+ label_quantity: "Количество"
data/config/routes.rb CHANGED
@@ -9,7 +9,7 @@ Rails.application.routes.draw do
9
9
  end
10
10
  end
11
11
 
12
- resources :additional_tags, only: %i[edit update] do
12
+ resources :additional_tags, only: %i[index edit update] do
13
13
  collection do
14
14
  post :merge
15
15
  get :context_menu, :merge
@@ -14,7 +14,7 @@ class MigrateExistingTags < ActiveRecord::Migration[5.2]
14
14
  next if excluded_taggable_types.include? tagging.taggable_type
15
15
 
16
16
  tag = ActsAsTaggableOn::Tag.create! name: old_tag.name if cnt.zero? && tag.nil?
17
- context = tagging.respond_to?('context') && tagging.context.present? ? tagging.context : 'tags'
17
+ context = tagging.respond_to?(:context) && tagging.context.present? ? tagging.context : 'tags'
18
18
 
19
19
  # old data can include dups
20
20
  next if ActsAsTaggableOn::Tagging.exists? tag_id: tag.id,
data/init.rb CHANGED
@@ -1,17 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'additional_tags/plugin_version'
4
+
5
+ loader = RedminePluginKit::Loader.new plugin_id: 'additional_tags'
6
+
3
7
  Redmine::Plugin.register :additional_tags do
4
8
  name 'Additional Tags'
5
9
  author 'AlphaNodes GmbH'
6
10
  description 'Redmine tagging support'
7
- version AdditionalTags::VERSION
11
+ version AdditionalTags::PluginVersion::VERSION
8
12
  url 'https://github.com/alphanodes/additional_tags/'
9
- author_url 'https://alphanodes.com/'
13
+ author_url 'https://alphanodes.com/'
10
14
  directory __dir__
11
15
 
12
- requires_redmine version_or_higher: '4.1'
16
+ requires_redmine version_or_higher: '5.0'
13
17
 
14
- settings default: Additionals.load_settings('additional_tags'),
18
+ settings default: loader.default_settings,
15
19
  partial: 'additional_tags/settings/settings'
16
20
 
17
21
  project_module :issue_tracking do
@@ -30,6 +34,4 @@ Redmine::Plugin.register :additional_tags do
30
34
  caption: :field_tags
31
35
  end
32
36
 
33
- Rails.configuration.to_prepare do
34
- AdditionalTags.setup
35
- end
37
+ RedminePluginKit::Loader.persisting { loader.load_model_hooks! }
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AdditionalTags
4
+ module Hooks
5
+ class ModelHook < Redmine::Hook::Listener
6
+ def after_plugins_loaded(_context = {})
7
+ AdditionalTags.setup!
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AdditionalTags
4
+ module Hooks
5
+ class ViewHook < Redmine::Hook::ViewListener
6
+ render_on :view_issues_bulk_edit_details_bottom,
7
+ partial: 'issues/tags_form_details',
8
+ locals: { tags_form: 'issues/tags_bulk_edit' }
9
+ render_on :view_issues_context_menu_end, partial: 'context_menus/issues_tags'
10
+ render_on :view_issues_form_details_bottom,
11
+ partial: 'issues/tags_form_details',
12
+ locals: { tags_form: 'issues/tags_form' }
13
+ render_on :view_issues_show_details_bottom, partial: 'issues/tags'
14
+ render_on :view_issues_sidebar_planning_bottom, partial: 'issues/tags_sidebar'
15
+ render_on :view_layouts_base_html_head, partial: 'additional_tags/html_head'
16
+ render_on :view_layouts_base_body_bottom, partial: 'additional_tags/body_bottom'
17
+ render_on :view_wiki_form_bottom, partial: 'tags_form_bottom'
18
+ render_on :view_wiki_show_bottom, partial: 'tags_show'
19
+ render_on :view_wiki_show_sidebar_bottom, partial: 'wiki/tags_sidebar'
20
+
21
+ def controller_issues_edit_before_save(context = {})
22
+ tags_journal context[:issue], context[:params]
23
+ end
24
+
25
+ def controller_issues_bulk_edit_before_save(context = {})
26
+ issue = context[:issue]
27
+ params = context[:params]
28
+
29
+ issues_bulk_tags_fix issue, params
30
+ tags_journal issue, params
31
+ end
32
+
33
+ # this hook is missing in redmine core at the moment
34
+ def view_issue_pdf_fields(context = {})
35
+ issue = context[:issue]
36
+ right = context[:right]
37
+
38
+ if AdditionalTags.setting?(:active_issue_tags) &&
39
+ User.current.allowed_to?(:view_issue_tags, issue.project)
40
+ right << [l(:field_tag_list), issue.tag_list]
41
+ end
42
+ end
43
+
44
+ # this hook is missing in redmine core at the moment
45
+ def view_wiki_pdf_buttom(context = {})
46
+ page = context[:page]
47
+ pdf = context[:pdf]
48
+
49
+ return if page.tag_list.blank?
50
+
51
+ pdf.ln 5
52
+ pdf.SetFontStyle 'B', 9
53
+ pdf.RDMCell 190, 5, l(:field_tag_list), 'B'
54
+
55
+ pdf.ln
56
+ pdf.SetFontStyle '', 8
57
+ pdf.RDMCell 190, 5, page.tag_list.to_list
58
+ pdf.ln
59
+ end
60
+
61
+ private
62
+
63
+ def issues_bulk_tags_fix(issue, params)
64
+ return unless params && params[:issue]
65
+
66
+ old_tags = issue.tags.map(&:name)
67
+ new_tags = Array(params[:issue][:tag_list]).reject(&:empty?)
68
+ issue.tag_list = (old_tags + new_tags).uniq
69
+ end
70
+
71
+ def tags_journal(issue, params)
72
+ return unless params && params[:issue] && params[:issue][:tag_list]
73
+
74
+ issue.tags_to_journal Issue.find_by(id: issue.id)&.tag_list&.to_s,
75
+ issue.tag_list.to_s
76
+ end
77
+ end
78
+ end
79
+ end
@@ -12,8 +12,7 @@ module AdditionalTags
12
12
  module InstanceMethods
13
13
  def issue_tags
14
14
  suggestion_order = AdditionalTags.setting(:tags_suggestion_order) || 'name'
15
- @name = (params[:q] || params[:term]).to_s.strip
16
- @tags = Issue.available_tags name_like: @name,
15
+ @tags = Issue.available_tags name_like: build_search_query_term(params),
17
16
  sort_by: suggestion_order,
18
17
  order: (suggestion_order == 'name' ? 'ASC' : 'DESC')
19
18
 
@@ -23,17 +22,17 @@ module AdditionalTags
23
22
  end
24
23
 
25
24
  def wiki_tags
26
- @name = params[:q].to_s
27
- @tags = WikiPage.available_tags project: nil, name_like: @name
25
+ @tags = WikiPage.available_tags project: nil,
26
+ name_like: build_search_query_term(params)
28
27
  render layout: false, partial: 'additional_tag_list', locals: { unsorted: true }
29
28
  end
30
29
 
31
30
  def all_tags
32
31
  return render_403 unless User.current.admin?
33
32
 
34
- @name = params[:q].to_s
33
+ q = build_search_query_term params
35
34
  sql_for_where = "LOWER(#{ActiveRecord::Base.connection.quote_table_name ActsAsTaggableOn.tags_table}.name) LIKE ?"
36
- @tags = ActsAsTaggableOn::Tag.where(sql_for_where, "%#{@name.downcase}%")
35
+ @tags = ActsAsTaggableOn::Tag.where(sql_for_where, "%#{q.downcase}%")
37
36
  .order(name: :asc)
38
37
 
39
38
  render layout: false, partial: 'additional_tag_list', locals: { unsorted: true }