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.
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 }