diff --git a/app/components/avo/fields/common/files/view_type/grid_item_component.html.erb b/app/components/avo/fields/common/files/view_type/grid_item_component.html.erb
index cb5910355d..83883f32c6 100644
--- a/app/components/avo/fields/common/files/view_type/grid_item_component.html.erb
+++ b/app/components/avo/fields/common/files/view_type/grid_item_component.html.erb
@@ -7,11 +7,11 @@
<% elsif is_video? %>
<%= video_tag(helpers.main_app.url_for(file), controls: true, preload: false, class: 'w-full') %>
<% else %>
-
+ <%= content_tag file.representable? ? :a : :div, **document_arguments do %>
<%= helpers.svg "heroicons/outline/document-text", class: 'h-10 text-gray-600 mb-2' %>
-
+ <% end %>
<% end %>
<% if @field.display_filename %>
<%= file.filename %>
diff --git a/app/components/avo/fields/common/files/view_type/grid_item_component.rb b/app/components/avo/fields/common/files/view_type/grid_item_component.rb
index 013596eaac..28540e092e 100644
--- a/app/components/avo/fields/common/files/view_type/grid_item_component.rb
+++ b/app/components/avo/fields/common/files/view_type/grid_item_component.rb
@@ -1,6 +1,8 @@
# frozen_string_literal: true
class Avo::Fields::Common::Files::ViewType::GridItemComponent < Avo::BaseComponent
+ include Avo::Fields::Concerns::FileAuthorization
+
prop :field
prop :resource
prop :file
@@ -45,4 +47,27 @@ def record_persisted?
ActiveStorage::Blob.destroy(file.blob_id) if file.blob_id.present?
false
end
+
+ def document_arguments
+ args = {
+ class: class_names(
+ "relative flex flex-col justify-evenly items-center px-2 rounded-lg border bg-white border-gray-500 min-h-24",
+ {
+ "hover:bg-gray-100 transition": file.representable?
+ }
+ )
+ }
+
+ if file.representable? && can_download_file?
+ args.merge!(
+ {
+ href: helpers.main_app.url_for(file),
+ target: "_blank",
+ rel: "noopener noreferrer"
+ }
+ )
+ end
+
+ args
+ end
end
diff --git a/spec/dummy/app/assets/csvs/sample.csv b/spec/dummy/app/assets/csvs/sample.csv
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/spec/dummy/app/assets/pdfs/cv_sample.pdf b/spec/dummy/app/assets/pdfs/cv_sample.pdf
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/spec/system/avo/open_field_attachment_spec.rb b/spec/system/avo/open_field_attachment_spec.rb
new file mode 100644
index 0000000000..5c2c6974e8
--- /dev/null
+++ b/spec/system/avo/open_field_attachment_spec.rb
@@ -0,0 +1,57 @@
+require "rails_helper"
+
+RSpec.describe "OpenFieldAttachment", type: :system do
+ let!(:user) { User.first }
+ let!(:cv_file) { Rails.root.join("app", "assets", "pdfs", "cv_sample.pdf") }
+ let!(:csv_file) { Rails.root.join("app", "assets", "csvs", "sample.csv") }
+ let(:path) { "/admin/resources/field_discovery_users/#{user.slug}" }
+
+ context "with PDF attachment" do
+ before do
+ user.cv.attach(io: File.open(cv_file), filename: "cv_sample.pdf", content_type: "application/pdf")
+ end
+
+ it "opens attachment in new window without download" do
+ test_open_PDF_attachment(path)
+ end
+ end
+
+ context "with CSV attachment" do
+ before do
+ user.cv.attach(io: File.open(csv_file), filename: "sample.csv", content_type: "application/csv")
+ end
+
+ it "can not open or download attachment in new window" do
+ test_open_CSV_attachment(path)
+ end
+ end
+
+ def test_open_PDF_attachment(path)
+ visit path
+
+ link = find('a[rel="noopener noreferrer"][target="_blank"]', visible: :all)
+
+ expect(link).to be_present
+ expect(link[:target]).to eq("_blank")
+ expect(link[:rel]).to eq("noopener noreferrer")
+ link.click
+
+ expect(page.driver.browser.current_url).not_to include("download")
+ expect(page.driver.browser.window_handles.length).to eq 2
+ end
+
+ def test_open_CSV_attachment(path)
+ visit path
+
+ div = find('span[title="' + csv_file.basename.to_s + '"]').find(:xpath, './ancestor::div[@class="flex flex-col h-full"]')
+
+ link = div.find("a")
+ expect(link[:rel]).to eq("")
+ expect(link[:target]).to eq("")
+
+ div.find('svg[data-slot="icon"]').find(:xpath, "./ancestor::a").click
+
+ expect(page.driver.browser.current_url).not_to include("download")
+ expect(page.driver.browser.window_handles.length).to eq 1
+ end
+end