From 17d5bd235e109b2a475ed8ee27d26e8bb876f3c0 Mon Sep 17 00:00:00 2001 From: MAEDA Go Date: Mon, 28 Sep 2026 18:05:21 +0900 Subject: [PATCH] Add a link from each issue attachment to the note in which it was added --- app/assets/images/icons.svg | 4 ++++ app/assets/stylesheets/application.css | 1 + app/helpers/attachments_helper.rb | 4 +++- app/helpers/issues_helper.rb | 12 ++++++++++ app/views/attachments/_links.html.erb | 10 ++++++++ app/views/issues/show.html.erb | 2 +- config/icon_source.yml | 2 ++ test/functional/issues_controller_test.rb | 29 +++++++++++++++++++++++ test/helpers/issues_helper_test.rb | 14 +++++++++++ 9 files changed, 76 insertions(+), 2 deletions(-) diff --git a/app/assets/images/icons.svg b/app/assets/images/icons.svg index 9d7511d8f..721cfc301 100644 --- a/app/assets/images/icons.svg +++ b/app/assets/images/icons.svg @@ -136,6 +136,10 @@ + + + + diff --git a/app/assets/stylesheets/application.css b/app/assets/stylesheets/application.css index 7b6f6d863..5ae8e9db9 100644 --- a/app/assets/stylesheets/application.css +++ b/app/assets/stylesheets/application.css @@ -1454,6 +1454,7 @@ div.fileover, p.custom-field-filedroplistner.fileover { background-color: var(-- div.attachments img { vertical-align: middle; } div.attachments span.author { font-size: 0.9em; color: var(--oc-gray-6); } +div.attachments span.attachment-journal { display: inline-flex; inline-size: 18px; block-size: 18px; vertical-align: text-bottom; } div.thumbnails {margin:0.6em;} div.thumbnail { diff --git a/app/helpers/attachments_helper.rb b/app/helpers/attachments_helper.rb index 3514e28b3..b26c9b81f 100644 --- a/app/helpers/attachments_helper.rb +++ b/app/helpers/attachments_helper.rb @@ -34,8 +34,10 @@ module AttachmentsHelper # Options: # :author -- author names are not displayed if set to false # :thumbails -- display thumbnails if enabled in settings + # :journals -- hash of journals keyed by attachment id, used to display + # a link to the journal that added each attachment def link_to_attachments(container, options = {}) - options.assert_valid_keys(:author, :thumbnails) + options.assert_valid_keys(:author, :thumbnails, :journals) attachments = if container.attachments.loaded? container.attachments diff --git a/app/helpers/issues_helper.rb b/app/helpers/issues_helper.rb index dace64e06..7d490f220 100644 --- a/app/helpers/issues_helper.rb +++ b/app/helpers/issues_helper.rb @@ -691,6 +691,18 @@ module IssuesHelper end end + # Returns a hash of the journals that added an attachment, + # keyed by attachment id + def journals_by_attachment_id(journals) + journals.to_a.each_with_object({}) do |journal, h| + journal.details.each do |detail| + next unless detail.property == 'attachment' && detail.value.present? + + h[detail.prop_key.to_i] = journal + end + end + end + # Issue history tabs def issue_history_tabs tabs = [] diff --git a/app/views/attachments/_links.html.erb b/app/views/attachments/_links.html.erb index 8bfee8e95..eb2b9cdfd 100644 --- a/app/views/attachments/_links.html.erb +++ b/app/views/attachments/_links.html.erb @@ -21,6 +21,16 @@ <%= attachment.description unless attachment.description.blank? %> + <% if options[:journals].present? %> + + <% if journal = options[:journals][attachment.id] %> + <% anchor = "#note-#{journal.indice}" %> + <%= link_to sprite_icon('chevrons-down', anchor), anchor, + :title => anchor, + :class => 'icon-only icon-chevrons-down' %> + <% end %> + + <% end %> <% if options[:author] %> <%= attachment.author %>, <%= format_time(attachment.created_on) %> <% end %> diff --git a/app/views/issues/show.html.erb b/app/views/issues/show.html.erb index f1a50813a..3b5a19d41 100644 --- a/app/views/issues/show.html.erb +++ b/app/views/issues/show.html.erb @@ -123,7 +123,7 @@ end %> <% if @issue.attachments.any? %>

<%=l(:label_attachment_plural)%>

- <%= link_to_attachments @issue, :thumbnails => true %> + <%= link_to_attachments @issue, :thumbnails => true, :journals => journals_by_attachment_id(@journals) %> <% end %> <%= render_full_width_custom_fields_rows(@issue) %> diff --git a/config/icon_source.yml b/config/icon_source.yml index ee87c8865..d4527c412 100644 --- a/config/icon_source.yml +++ b/config/icon_source.yml @@ -199,6 +199,8 @@ svg: chevrons-right - name: chevrons-left svg: chevrons-left +- name: chevrons-down + svg: chevrons-down - name: key svg: key - name: search diff --git a/test/functional/issues_controller_test.rb b/test/functional/issues_controller_test.rb index 28374a90e..e167e8819 100644 --- a/test/functional/issues_controller_test.rb +++ b/test/functional/issues_controller_test.rb @@ -2319,6 +2319,35 @@ class IssuesControllerTest < Redmine::ControllerTest assert_select 'div#relations div.contextual a.icon.icon-link-add', :text => /Add/ end + def test_show_should_link_attachments_to_the_journal_that_added_them + @request.session[:user_id] = 2 + get(:show, :params => {:id => 2}) + + assert_response :success + # Attachment 4 was added by journal 3, which is the first journal of the issue + assert_select 'div.attachments a.icon-attachment[href=?]', '/attachments/4' + assert_select 'div.attachments span.attachment-journal a', 1 + assert_select 'div.attachments span.attachment-journal a[href=?][title=?]', '#note-1', '#note-1' do + assert_select "svg.icon-svg use:match('href', ?)", /assets\/icons-\w+.svg#icon--chevrons-down/ + end + end + + def test_show_should_not_link_attachments_to_invisible_private_notes + journal = Journal.find(3) + journal.update_columns(:private_notes => true, :user_id => 1) + @request.session[:user_id] = 2 + + get(:show, :params => {:id => 2}) + assert_response :success + assert_select 'div.attachments span.attachment-journal a[href=?]', '#note-1' + + Role.find(1).remove_permission! :view_private_notes + get(:show, :params => {:id => 2}) + assert_response :success + assert_select 'div.attachments a.icon-attachment[href=?]', '/attachments/4' + assert_select 'div.attachments span.attachment-journal', 0 + end + def test_show_should_display_attachment_icons_by_mime_type @request.session[:user_id] = 2 get(:show, :params => {:id => 3}) diff --git a/test/helpers/issues_helper_test.rb b/test/helpers/issues_helper_test.rb index 69679a5fb..d605542bd 100644 --- a/test/helpers/issues_helper_test.rb +++ b/test/helpers/issues_helper_test.rb @@ -456,4 +456,18 @@ class IssuesHelperTest < Redmine::HelperTest assert_include "1 open", html assert_include "1 closed", html end + + def test_journals_by_attachment_id + issue = Issue.find(2) + # Detail of a removed attachment + JournalDetail.create!(:journal => issue.journals.last, :property => 'attachment', + :prop_key => '99', :old_value => 'removed.txt') + journals = issue.visible_journals_with_index(User.find(2)) + + result = journals_by_attachment_id(journals) + + assert_equal [4], result.keys + assert_equal 3, result[4].id + assert_equal 1, result[4].indice + end end -- 2.55.0