diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_article_attachments.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_article_attachments.coffee
index 728cc00fb..743cb38ac 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_article_attachments.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/sidebar_article_attachments.coffee
@@ -16,17 +16,36 @@ class SidebarArticleAttachments extends App.Controller
if _.isEmpty(@ticket) || _.isEmpty(@ticket.article_ids)
@el.html("
#{App.i18n.translateInline('none')}
")
return
- html = ''
- for ticket_article_id in @ticket.article_ids.sort((a, b) -> b - a)
- if App.TicketArticle.exists(ticket_article_id)
- article = App.TicketArticle.find(ticket_article_id)
- attachments = App.TicketArticle.contentAttachments(article)
- if !_.isEmpty(attachments)
- html += App.view('ticket_zoom/sidebar_article_attachment')(article: article, attachments: attachments)
+
+ articleIDs = _.clone(@ticket.article_ids)
+ articleIDs.sort((a, b) -> a - b)
+
+ uniqueAttachments = {}
+ ticketAttachments = []
+ for articleID in articleIDs
+ continue if !App.TicketArticle.exists(articleID)
+
+ article = App.TicketArticle.find(articleID)
+ attachments = App.TicketArticle.contentAttachments(article)
+ for attachment in attachments
+ continue if uniqueAttachments[attachment.store_file_id]
+ uniqueAttachments[attachment.store_file_id] = true
+
+ ticketAttachments.push({ attachment: attachment, article: article })
+
+ ticketAttachments = ticketAttachments.reverse()
+
+ html = App.view('ticket_zoom/sidebar_article_attachment')(
+ ticketAttachments: ticketAttachments,
+ )
+
@el.html(html)
@el.on('click', '.js-attachments img', (e) =>
@imageView(e)
)
+ @controllerBind('ui::ticket::load', =>
+ @showObjects(el)
+ )
imageView: (e) ->
e.preventDefault()
diff --git a/app/assets/javascripts/app/views/ticket_zoom/sidebar_article_attachment.jst.eco b/app/assets/javascripts/app/views/ticket_zoom/sidebar_article_attachment.jst.eco
index b8bf35a33..18927c739 100644
--- a/app/assets/javascripts/app/views/ticket_zoom/sidebar_article_attachment.jst.eco
+++ b/app/assets/javascripts/app/views/ticket_zoom/sidebar_article_attachment.jst.eco
@@ -1,12 +1,11 @@
diff --git a/app/models/store.rb b/app/models/store.rb
index c9f5cef56..0a956ec56 100644
--- a/app/models/store.rb
+++ b/app/models/store.rb
@@ -216,7 +216,7 @@ returns
end
def attributes_for_display
- slice :id, :filename, :size, :preferences
+ slice :id, :store_file_id, :filename, :size, :preferences
end
RESIZABLE_MIME_REGEXP = %r{image/(jpeg|jpg|png)}i.freeze
diff --git a/spec/system/ticket/zoom_spec.rb b/spec/system/ticket/zoom_spec.rb
index bd5bb44bb..59ae0cff4 100644
--- a/spec/system/ticket/zoom_spec.rb
+++ b/spec/system/ticket/zoom_spec.rb
@@ -2542,4 +2542,52 @@ RSpec.describe 'Ticket zoom', type: :system do
expect(page).to have_text('SOLUTION TIME')
end
end
+
+ context 'Make sidebar attachments unique #3930', authenticated_as: :authenticate do
+ let(:ticket) { create(:ticket, group: Group.find_by(name: 'Users')) }
+ let(:article1) { create(:ticket_article, ticket: ticket) }
+ let(:article2) { create(:ticket_article, ticket: ticket) }
+
+ def attachment_add(article, filename)
+ Store.add(
+ object: 'Ticket::Article',
+ o_id: article.id,
+ data: "content #{filename}",
+ filename: filename,
+ preferences: {
+ 'Content-Type' => 'text/plain',
+ },
+ created_by_id: 1,
+ )
+ end
+
+ def authenticate
+ attachment_add(article1, 'some_file.txt')
+ attachment_add(article2, 'some_file.txt')
+ attachment_add(article2, 'some_file2.txt')
+ Setting.set('ui_ticket_zoom_sidebar_article_attachments', true)
+
+ true
+ end
+
+ before do
+ visit "#ticket/zoom/#{ticket.id}"
+ page.find(".tabsSidebar-tabs .tabsSidebar-tab[data-tab='attachment']").click
+ end
+
+ it 'does show the attachment once' do
+ expect(page).to have_selector('.sidebar-content .attachment.attachment--preview', count: 2)
+ expect(page).to have_selector('.sidebar-content', text: 'some_file.txt')
+ expect(page).to have_selector('.sidebar-content', text: 'some_file2.txt')
+ end
+
+ it 'does show up new attachments' do
+ page.find('.js-textarea').send_keys('new article with attachment')
+ page.find('input#fileUpload_1', visible: :all).set(Rails.root.join('test/data/mail/mail001.box'))
+ expect(page).to have_text('mail001.box')
+ wait.until { Taskbar.find_by(key: "Ticket-#{ticket.id}").attributes_with_association_ids['attachments'].present? }
+ click '.js-submit'
+ expect(page).to have_selector('.sidebar-content', text: 'mail001.box')
+ end
+ end
end