Specify explicitly whether a blob viewer should be loaded asynchronously
This commit is contained in:
parent
4328bc1769
commit
acffc06213
|
@ -14,7 +14,7 @@ module RendersBlob
|
|||
return render_404 unless viewer
|
||||
|
||||
render json: {
|
||||
html: view_to_html_string("projects/blob/_viewer", viewer: viewer, load_asynchronously: false)
|
||||
html: view_to_html_string("projects/blob/_viewer", viewer: viewer, load_async: false)
|
||||
}
|
||||
end
|
||||
|
||||
|
|
|
@ -2,11 +2,11 @@ module BlobViewer
|
|||
class Base
|
||||
PARTIAL_PATH_PREFIX = 'projects/blob/viewers'.freeze
|
||||
|
||||
class_attribute :partial_name, :loading_partial_name, :type, :extensions, :file_types, :client_side, :binary, :switcher_icon, :switcher_title, :max_size, :absolute_max_size
|
||||
class_attribute :partial_name, :loading_partial_name, :type, :extensions, :file_types, :load_async, :binary, :switcher_icon, :switcher_title, :max_size, :absolute_max_size
|
||||
|
||||
self.loading_partial_name = 'loading'
|
||||
|
||||
delegate :partial_path, :loading_partial_path, :rich?, :simple?, :client_side?, :server_side?, :text?, :binary?, to: :class
|
||||
delegate :partial_path, :loading_partial_path, :rich?, :simple?, :text?, :binary?, to: :class
|
||||
|
||||
attr_reader :blob
|
||||
attr_accessor :override_max_size
|
||||
|
@ -35,12 +35,8 @@ module BlobViewer
|
|||
type == :auxiliary
|
||||
end
|
||||
|
||||
def self.client_side?
|
||||
client_side
|
||||
end
|
||||
|
||||
def self.server_side?
|
||||
!client_side?
|
||||
def self.load_async?
|
||||
load_async
|
||||
end
|
||||
|
||||
def self.binary?
|
||||
|
@ -59,6 +55,10 @@ module BlobViewer
|
|||
false
|
||||
end
|
||||
|
||||
def load_async?
|
||||
self.class.load_async? && render_error.nil?
|
||||
end
|
||||
|
||||
def too_large?
|
||||
max_size && blob.raw_size > max_size
|
||||
end
|
||||
|
@ -83,29 +83,13 @@ module BlobViewer
|
|||
# binary from `blob_raw_url` and does its own format validation and error
|
||||
# rendering, especially for potentially large binary formats.
|
||||
def render_error
|
||||
return @render_error if defined?(@render_error)
|
||||
|
||||
@render_error =
|
||||
if server_side_but_stored_externally?
|
||||
# Files that are not stored in the repository, like LFS files and
|
||||
# build artifacts, can only be rendered using a client-side viewer,
|
||||
# since we do not want to read large amounts of data into memory on the
|
||||
# server side. Client-side viewers use JS and can fetch the file from
|
||||
# `blob_raw_url` using AJAX.
|
||||
:server_side_but_stored_externally
|
||||
elsif override_max_size ? absolutely_too_large? : too_large?
|
||||
:too_large
|
||||
end
|
||||
if override_max_size ? absolutely_too_large? : too_large?
|
||||
:too_large
|
||||
end
|
||||
end
|
||||
|
||||
def prepare!
|
||||
# To be overridden by subclasses
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def server_side_but_stored_externally?
|
||||
server_side? && blob.stored_externally?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ module BlobViewer
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
self.client_side = true
|
||||
self.load_async = false
|
||||
self.max_size = 10.megabytes
|
||||
self.absolute_max_size = 50.megabytes
|
||||
end
|
||||
|
|
|
@ -1,17 +1,9 @@
|
|||
module BlobViewer
|
||||
class Download < Base
|
||||
include Simple
|
||||
# We treat the Download viewer as if it renders the content client-side,
|
||||
# so that it doesn't attempt to load the entire blob contents and is
|
||||
# rendered synchronously instead of loaded asynchronously.
|
||||
include ClientSide
|
||||
include Static
|
||||
|
||||
self.partial_name = 'download'
|
||||
self.binary = true
|
||||
|
||||
# We can always render the Download viewer, even if the blob is in LFS or too large.
|
||||
def render_error
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
module BlobViewer
|
||||
class License < Base
|
||||
# We treat the License viewer as if it renders the content client-side,
|
||||
# so that it doesn't attempt to load the entire blob contents and is
|
||||
# rendered synchronously instead of loaded asynchronously.
|
||||
include ClientSide
|
||||
include Auxiliary
|
||||
include Static
|
||||
|
||||
self.partial_name = 'license'
|
||||
self.file_types = %i(license)
|
||||
|
|
|
@ -3,7 +3,7 @@ module BlobViewer
|
|||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
self.client_side = false
|
||||
self.load_async = true
|
||||
self.max_size = 2.megabytes
|
||||
self.absolute_max_size = 5.megabytes
|
||||
end
|
||||
|
@ -13,5 +13,18 @@ module BlobViewer
|
|||
blob.load_all_data!(blob.project.repository)
|
||||
end
|
||||
end
|
||||
|
||||
def render_error
|
||||
if blob.stored_externally?
|
||||
# Files that are not stored in the repository, like LFS files and
|
||||
# build artifacts, can only be rendered using a client-side viewer,
|
||||
# since we do not want to read large amounts of data into memory on the
|
||||
# server side. Client-side viewers use JS and can fetch the file from
|
||||
# `blob_raw_url` using AJAX.
|
||||
return :server_side_but_stored_externally
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
module BlobViewer
|
||||
module Static
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
self.load_async = false
|
||||
end
|
||||
|
||||
# We can always render a static viewer, even if the blob is too large.
|
||||
def render_error
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,10 +1,10 @@
|
|||
- hidden = local_assigns.fetch(:hidden, false)
|
||||
- render_error = viewer.render_error
|
||||
- load_asynchronously = local_assigns.fetch(:load_asynchronously, viewer.server_side?) && render_error.nil?
|
||||
- load_async = local_assigns.fetch(:load_async, viewer.load_async?)
|
||||
|
||||
- viewer_url = local_assigns.fetch(:viewer_url) { url_for(params.merge(viewer: viewer.type, format: :json)) } if load_asynchronously
|
||||
- viewer_url = local_assigns.fetch(:viewer_url) { url_for(params.merge(viewer: viewer.type, format: :json)) } if load_async
|
||||
.blob-viewer{ data: { type: viewer.type, url: viewer_url }, class: ('hidden' if hidden) }
|
||||
- if load_asynchronously
|
||||
- if load_async
|
||||
= render viewer.loading_partial_path, viewer: viewer
|
||||
- elsif render_error
|
||||
= render 'projects/blob/render_error', viewer: viewer
|
||||
|
|
|
@ -116,10 +116,11 @@ describe BlobHelper do
|
|||
|
||||
let(:viewer_class) do
|
||||
Class.new(BlobViewer::Base) do
|
||||
include BlobViewer::ServerSide
|
||||
|
||||
self.max_size = 1.megabyte
|
||||
self.absolute_max_size = 5.megabytes
|
||||
self.type = :rich
|
||||
self.client_side = false
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -7,11 +7,12 @@ describe BlobViewer::Base, model: true do
|
|||
|
||||
let(:viewer_class) do
|
||||
Class.new(described_class) do
|
||||
include BlobViewer::ServerSide
|
||||
|
||||
self.extensions = %w(pdf)
|
||||
self.binary = true
|
||||
self.max_size = 1.megabyte
|
||||
self.absolute_max_size = 5.megabytes
|
||||
self.client_side = false
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -38,10 +39,10 @@ describe BlobViewer::Base, model: true do
|
|||
|
||||
context 'when the file type is supported' do
|
||||
before do
|
||||
viewer_class.file_type = :license
|
||||
viewer_class.file_types = %i(license)
|
||||
viewer_class.binary = false
|
||||
end
|
||||
|
||||
|
||||
context 'when the binaryness matches' do
|
||||
let(:blob) { fake_blob(path: 'LICENSE', binary: false) }
|
||||
|
||||
|
@ -172,19 +173,5 @@ describe BlobViewer::Base, model: true do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the viewer is server side but the blob is stored externally' do
|
||||
let(:project) { build(:empty_project, lfs_enabled: true) }
|
||||
|
||||
let(:blob) { fake_blob(path: 'file.pdf', lfs: true) }
|
||||
|
||||
before do
|
||||
allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
|
||||
end
|
||||
|
||||
it 'return :server_side_but_stored_externally' do
|
||||
expect(viewer.render_error).to eq(:server_side_but_stored_externally)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,4 +22,20 @@ describe BlobViewer::ServerSide, model: true do
|
|||
subject.prepare!
|
||||
end
|
||||
end
|
||||
|
||||
describe '#render_error' do
|
||||
context 'when the blob is stored externally' do
|
||||
let(:project) { build(:empty_project, lfs_enabled: true) }
|
||||
|
||||
let(:blob) { fake_blob(path: 'file.pdf', lfs: true) }
|
||||
|
||||
before do
|
||||
allow(Gitlab.config.lfs).to receive(:enabled).and_return(true)
|
||||
end
|
||||
|
||||
it 'return :server_side_but_stored_externally' do
|
||||
expect(subject.render_error).to eq(:server_side_but_stored_externally)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -12,7 +12,7 @@ describe 'projects/blob/_viewer.html.haml', :view do
|
|||
self.partial_name = 'text'
|
||||
self.max_size = 1.megabyte
|
||||
self.absolute_max_size = 5.megabytes
|
||||
self.client_side = false
|
||||
self.load_async = true
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -35,9 +35,9 @@ describe 'projects/blob/_viewer.html.haml', :view do
|
|||
render partial: 'projects/blob/viewer', locals: { viewer: viewer }
|
||||
end
|
||||
|
||||
context 'when the viewer is server side' do
|
||||
context 'when the viewer is loaded asynchronously' do
|
||||
before do
|
||||
viewer_class.client_side = false
|
||||
viewer_class.load_async = true
|
||||
end
|
||||
|
||||
context 'when there is no render error' do
|
||||
|
@ -65,9 +65,9 @@ describe 'projects/blob/_viewer.html.haml', :view do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when the viewer is client side' do
|
||||
context 'when the viewer is loaded synchronously' do
|
||||
before do
|
||||
viewer_class.client_side = true
|
||||
viewer_class.load_async = false
|
||||
end
|
||||
|
||||
context 'when there is no render error' do
|
||||
|
|
Loading…
Reference in New Issue