summaryrefslogtreecommitdiff
path: root/app/models/blob_viewer
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/blob_viewer')
-rw-r--r--app/models/blob_viewer/auxiliary.rb18
-rw-r--r--app/models/blob_viewer/balsamiq.rb12
-rw-r--r--app/models/blob_viewer/base.rb105
-rw-r--r--app/models/blob_viewer/binary_stl.rb10
-rw-r--r--app/models/blob_viewer/cartfile.rb15
-rw-r--r--app/models/blob_viewer/changelog.rb16
-rw-r--r--app/models/blob_viewer/client_side.rb11
-rw-r--r--app/models/blob_viewer/composer_json.rb23
-rw-r--r--app/models/blob_viewer/contributing.rb10
-rw-r--r--app/models/blob_viewer/dependency_manager.rb43
-rw-r--r--app/models/blob_viewer/download.rb9
-rw-r--r--app/models/blob_viewer/empty.rb9
-rw-r--r--app/models/blob_viewer/gemfile.rb15
-rw-r--r--app/models/blob_viewer/gemspec.rb27
-rw-r--r--app/models/blob_viewer/gitlab_ci_yml.rb23
-rw-r--r--app/models/blob_viewer/godeps_json.rb15
-rw-r--r--app/models/blob_viewer/image.rb12
-rw-r--r--app/models/blob_viewer/license.rb20
-rw-r--r--app/models/blob_viewer/markup.rb11
-rw-r--r--app/models/blob_viewer/notebook.rb12
-rw-r--r--app/models/blob_viewer/package_json.rb23
-rw-r--r--app/models/blob_viewer/pdf.rb12
-rw-r--r--app/models/blob_viewer/podfile.rb15
-rw-r--r--app/models/blob_viewer/podspec.rb27
-rw-r--r--app/models/blob_viewer/podspec_json.rb9
-rw-r--r--app/models/blob_viewer/readme.rb14
-rw-r--r--app/models/blob_viewer/requirements_txt.rb15
-rw-r--r--app/models/blob_viewer/rich.rb11
-rw-r--r--app/models/blob_viewer/route_map.rb30
-rw-r--r--app/models/blob_viewer/server_side.rb30
-rw-r--r--app/models/blob_viewer/simple.rb11
-rw-r--r--app/models/blob_viewer/sketch.rb12
-rw-r--r--app/models/blob_viewer/static.rb14
-rw-r--r--app/models/blob_viewer/svg.rb12
-rw-r--r--app/models/blob_viewer/text.rb11
-rw-r--r--app/models/blob_viewer/text_stl.rb5
-rw-r--r--app/models/blob_viewer/video.rb12
-rw-r--r--app/models/blob_viewer/yarn_lock.rb15
38 files changed, 694 insertions, 0 deletions
diff --git a/app/models/blob_viewer/auxiliary.rb b/app/models/blob_viewer/auxiliary.rb
new file mode 100644
index 00000000000..07a207730cf
--- /dev/null
+++ b/app/models/blob_viewer/auxiliary.rb
@@ -0,0 +1,18 @@
+module BlobViewer
+ module Auxiliary
+ extend ActiveSupport::Concern
+
+ include Gitlab::Allowable
+
+ included do
+ self.loading_partial_name = 'loading_auxiliary'
+ self.type = :auxiliary
+ self.overridable_max_size = 100.kilobytes
+ self.max_size = 100.kilobytes
+ end
+
+ def visible_to?(current_user)
+ true
+ end
+ end
+end
diff --git a/app/models/blob_viewer/balsamiq.rb b/app/models/blob_viewer/balsamiq.rb
new file mode 100644
index 00000000000..f982521db99
--- /dev/null
+++ b/app/models/blob_viewer/balsamiq.rb
@@ -0,0 +1,12 @@
+module BlobViewer
+ class Balsamiq < Base
+ include Rich
+ include ClientSide
+
+ self.partial_name = 'balsamiq'
+ self.extensions = %w(bmpr)
+ self.binary = true
+ self.switcher_icon = 'file-image-o'
+ self.switcher_title = 'preview'
+ end
+end
diff --git a/app/models/blob_viewer/base.rb b/app/models/blob_viewer/base.rb
new file mode 100644
index 00000000000..26a3778c2a3
--- /dev/null
+++ b/app/models/blob_viewer/base.rb
@@ -0,0 +1,105 @@
+module BlobViewer
+ class Base
+ PARTIAL_PATH_PREFIX = 'projects/blob/viewers'.freeze
+
+ class_attribute :partial_name, :loading_partial_name, :type, :extensions, :file_types, :load_async, :binary, :switcher_icon, :switcher_title, :overridable_max_size, :max_size
+
+ self.loading_partial_name = 'loading'
+
+ delegate :partial_path, :loading_partial_path, :rich?, :simple?, :text?, :binary?, to: :class
+
+ attr_reader :blob
+ attr_accessor :override_max_size
+
+ delegate :project, to: :blob
+
+ def initialize(blob)
+ @blob = blob
+ end
+
+ def self.partial_path
+ File.join(PARTIAL_PATH_PREFIX, partial_name)
+ end
+
+ def self.loading_partial_path
+ File.join(PARTIAL_PATH_PREFIX, loading_partial_name)
+ end
+
+ def self.rich?
+ type == :rich
+ end
+
+ def self.simple?
+ type == :simple
+ end
+
+ def self.auxiliary?
+ type == :auxiliary
+ end
+
+ def self.load_async?
+ load_async
+ end
+
+ def self.binary?
+ binary
+ end
+
+ def self.text?
+ !binary?
+ end
+
+ def self.can_render?(blob, verify_binary: true)
+ return false if verify_binary && binary? != blob.binary?
+ return true if extensions&.include?(blob.extension)
+ return true if file_types&.include?(Gitlab::FileDetector.type_of(blob.path))
+
+ false
+ end
+
+ def load_async?
+ self.class.load_async? && render_error.nil?
+ end
+
+ def exceeds_overridable_max_size?
+ overridable_max_size && blob.raw_size > overridable_max_size
+ end
+
+ def exceeds_max_size?
+ max_size && blob.raw_size > max_size
+ end
+
+ def can_override_max_size?
+ exceeds_overridable_max_size? && !exceeds_max_size?
+ end
+
+ def too_large?
+ if override_max_size
+ exceeds_max_size?
+ else
+ exceeds_overridable_max_size?
+ end
+ end
+
+ # This method is used on the server side to check whether we can attempt to
+ # render the blob at all. Human-readable error messages are found in the
+ # `BlobHelper#blob_render_error_reason` helper.
+ #
+ # This method does not and should not load the entire blob contents into
+ # memory, and should not be overridden to do so in order to validate the
+ # format of the blob.
+ #
+ # Prefer to implement a client-side viewer, where the JS component loads the
+ # binary from `blob_raw_url` and does its own format validation and error
+ # rendering, especially for potentially large binary formats.
+ def render_error
+ if too_large?
+ :too_large
+ end
+ end
+
+ def prepare!
+ # To be overridden by subclasses
+ end
+ end
+end
diff --git a/app/models/blob_viewer/binary_stl.rb b/app/models/blob_viewer/binary_stl.rb
new file mode 100644
index 00000000000..80393471ef2
--- /dev/null
+++ b/app/models/blob_viewer/binary_stl.rb
@@ -0,0 +1,10 @@
+module BlobViewer
+ class BinarySTL < Base
+ include Rich
+ include ClientSide
+
+ self.partial_name = 'stl'
+ self.extensions = %w(stl)
+ self.binary = true
+ end
+end
diff --git a/app/models/blob_viewer/cartfile.rb b/app/models/blob_viewer/cartfile.rb
new file mode 100644
index 00000000000..d8471bc33c0
--- /dev/null
+++ b/app/models/blob_viewer/cartfile.rb
@@ -0,0 +1,15 @@
+module BlobViewer
+ class Cartfile < DependencyManager
+ include Static
+
+ self.file_types = %i(cartfile)
+
+ def manager_name
+ 'Carthage'
+ end
+
+ def manager_url
+ 'https://github.com/Carthage/Carthage'
+ end
+ end
+end
diff --git a/app/models/blob_viewer/changelog.rb b/app/models/blob_viewer/changelog.rb
new file mode 100644
index 00000000000..0464ae27f71
--- /dev/null
+++ b/app/models/blob_viewer/changelog.rb
@@ -0,0 +1,16 @@
+module BlobViewer
+ class Changelog < Base
+ include Auxiliary
+ include Static
+
+ self.partial_name = 'changelog'
+ self.file_types = %i(changelog)
+ self.binary = false
+
+ def render_error
+ return if project.repository.tag_count > 0
+
+ :no_tags
+ end
+ end
+end
diff --git a/app/models/blob_viewer/client_side.rb b/app/models/blob_viewer/client_side.rb
new file mode 100644
index 00000000000..cc68236f92b
--- /dev/null
+++ b/app/models/blob_viewer/client_side.rb
@@ -0,0 +1,11 @@
+module BlobViewer
+ module ClientSide
+ extend ActiveSupport::Concern
+
+ included do
+ self.load_async = false
+ self.overridable_max_size = 10.megabytes
+ self.max_size = 50.megabytes
+ end
+ end
+end
diff --git a/app/models/blob_viewer/composer_json.rb b/app/models/blob_viewer/composer_json.rb
new file mode 100644
index 00000000000..ef8b4aef8e8
--- /dev/null
+++ b/app/models/blob_viewer/composer_json.rb
@@ -0,0 +1,23 @@
+module BlobViewer
+ class ComposerJson < DependencyManager
+ include ServerSide
+
+ self.file_types = %i(composer_json)
+
+ def manager_name
+ 'Composer'
+ end
+
+ def manager_url
+ 'https://getcomposer.com/'
+ end
+
+ def package_name
+ @package_name ||= package_name_from_json('name')
+ end
+
+ def package_url
+ "https://packagist.org/packages/#{package_name}"
+ end
+ end
+end
diff --git a/app/models/blob_viewer/contributing.rb b/app/models/blob_viewer/contributing.rb
new file mode 100644
index 00000000000..fbd1dd48697
--- /dev/null
+++ b/app/models/blob_viewer/contributing.rb
@@ -0,0 +1,10 @@
+module BlobViewer
+ class Contributing < Base
+ include Auxiliary
+ include Static
+
+ self.partial_name = 'contributing'
+ self.file_types = %i(contributing)
+ self.binary = false
+ end
+end
diff --git a/app/models/blob_viewer/dependency_manager.rb b/app/models/blob_viewer/dependency_manager.rb
new file mode 100644
index 00000000000..a8d9be945dc
--- /dev/null
+++ b/app/models/blob_viewer/dependency_manager.rb
@@ -0,0 +1,43 @@
+module BlobViewer
+ class DependencyManager < Base
+ include Auxiliary
+
+ self.partial_name = 'dependency_manager'
+ self.binary = false
+
+ def manager_name
+ raise NotImplementedError
+ end
+
+ def manager_url
+ raise NotImplementedError
+ end
+
+ def package_type
+ 'package'
+ end
+
+ def package_name
+ nil
+ end
+
+ def package_url
+ nil
+ end
+
+ private
+
+ def package_name_from_json(key)
+ prepare!
+
+ JSON.parse(blob.data)[key] rescue nil
+ end
+
+ def package_name_from_method_call(name)
+ prepare!
+
+ match = blob.data.match(/#{name}\s*=\s*["'](?<name>[^"']+)["']/)
+ match[:name] if match
+ end
+ end
+end
diff --git a/app/models/blob_viewer/download.rb b/app/models/blob_viewer/download.rb
new file mode 100644
index 00000000000..074e7204814
--- /dev/null
+++ b/app/models/blob_viewer/download.rb
@@ -0,0 +1,9 @@
+module BlobViewer
+ class Download < Base
+ include Simple
+ include Static
+
+ self.partial_name = 'download'
+ self.binary = true
+ end
+end
diff --git a/app/models/blob_viewer/empty.rb b/app/models/blob_viewer/empty.rb
new file mode 100644
index 00000000000..d9d128eb273
--- /dev/null
+++ b/app/models/blob_viewer/empty.rb
@@ -0,0 +1,9 @@
+module BlobViewer
+ class Empty < Base
+ include Simple
+ include ServerSide
+
+ self.partial_name = 'empty'
+ self.binary = true
+ end
+end
diff --git a/app/models/blob_viewer/gemfile.rb b/app/models/blob_viewer/gemfile.rb
new file mode 100644
index 00000000000..fae8c8df23f
--- /dev/null
+++ b/app/models/blob_viewer/gemfile.rb
@@ -0,0 +1,15 @@
+module BlobViewer
+ class Gemfile < DependencyManager
+ include Static
+
+ self.file_types = %i(gemfile gemfile_lock)
+
+ def manager_name
+ 'Bundler'
+ end
+
+ def manager_url
+ 'http://bundler.io/'
+ end
+ end
+end
diff --git a/app/models/blob_viewer/gemspec.rb b/app/models/blob_viewer/gemspec.rb
new file mode 100644
index 00000000000..7802edeb754
--- /dev/null
+++ b/app/models/blob_viewer/gemspec.rb
@@ -0,0 +1,27 @@
+module BlobViewer
+ class Gemspec < DependencyManager
+ include ServerSide
+
+ self.file_types = %i(gemspec)
+
+ def manager_name
+ 'RubyGems'
+ end
+
+ def manager_url
+ 'https://rubygems.org/'
+ end
+
+ def package_type
+ 'gem'
+ end
+
+ def package_name
+ @package_name ||= package_name_from_method_call('name')
+ end
+
+ def package_url
+ "https://rubygems.org/gems/#{package_name}"
+ end
+ end
+end
diff --git a/app/models/blob_viewer/gitlab_ci_yml.rb b/app/models/blob_viewer/gitlab_ci_yml.rb
new file mode 100644
index 00000000000..7267c3965d3
--- /dev/null
+++ b/app/models/blob_viewer/gitlab_ci_yml.rb
@@ -0,0 +1,23 @@
+module BlobViewer
+ class GitlabCiYml < Base
+ include ServerSide
+ include Auxiliary
+
+ self.partial_name = 'gitlab_ci_yml'
+ self.loading_partial_name = 'gitlab_ci_yml_loading'
+ self.file_types = %i(gitlab_ci)
+ self.binary = false
+
+ def validation_message
+ return @validation_message if defined?(@validation_message)
+
+ prepare!
+
+ @validation_message = Ci::GitlabCiYamlProcessor.validation_message(blob.data)
+ end
+
+ def valid?
+ validation_message.blank?
+ end
+ end
+end
diff --git a/app/models/blob_viewer/godeps_json.rb b/app/models/blob_viewer/godeps_json.rb
new file mode 100644
index 00000000000..e19a602603b
--- /dev/null
+++ b/app/models/blob_viewer/godeps_json.rb
@@ -0,0 +1,15 @@
+module BlobViewer
+ class GodepsJson < DependencyManager
+ include Static
+
+ self.file_types = %i(godeps_json)
+
+ def manager_name
+ 'godep'
+ end
+
+ def manager_url
+ 'https://github.com/tools/godep'
+ end
+ end
+end
diff --git a/app/models/blob_viewer/image.rb b/app/models/blob_viewer/image.rb
new file mode 100644
index 00000000000..c4eae5c79c2
--- /dev/null
+++ b/app/models/blob_viewer/image.rb
@@ -0,0 +1,12 @@
+module BlobViewer
+ class Image < Base
+ include Rich
+ include ClientSide
+
+ self.partial_name = 'image'
+ self.extensions = UploaderHelper::IMAGE_EXT
+ self.binary = true
+ self.switcher_icon = 'picture-o'
+ self.switcher_title = 'image'
+ end
+end
diff --git a/app/models/blob_viewer/license.rb b/app/models/blob_viewer/license.rb
new file mode 100644
index 00000000000..57355f2c3aa
--- /dev/null
+++ b/app/models/blob_viewer/license.rb
@@ -0,0 +1,20 @@
+module BlobViewer
+ class License < Base
+ include Auxiliary
+ include Static
+
+ self.partial_name = 'license'
+ self.file_types = %i(license)
+ self.binary = false
+
+ def license
+ project.repository.license
+ end
+
+ def render_error
+ return if license
+
+ :unknown_license
+ end
+ end
+end
diff --git a/app/models/blob_viewer/markup.rb b/app/models/blob_viewer/markup.rb
new file mode 100644
index 00000000000..33b59c4f512
--- /dev/null
+++ b/app/models/blob_viewer/markup.rb
@@ -0,0 +1,11 @@
+module BlobViewer
+ class Markup < Base
+ include Rich
+ include ServerSide
+
+ self.partial_name = 'markup'
+ self.extensions = Gitlab::MarkupHelper::EXTENSIONS
+ self.file_types = %i(readme)
+ self.binary = false
+ end
+end
diff --git a/app/models/blob_viewer/notebook.rb b/app/models/blob_viewer/notebook.rb
new file mode 100644
index 00000000000..8632b8a9885
--- /dev/null
+++ b/app/models/blob_viewer/notebook.rb
@@ -0,0 +1,12 @@
+module BlobViewer
+ class Notebook < Base
+ include Rich
+ include ClientSide
+
+ self.partial_name = 'notebook'
+ self.extensions = %w(ipynb)
+ self.binary = false
+ self.switcher_icon = 'file-text-o'
+ self.switcher_title = 'notebook'
+ end
+end
diff --git a/app/models/blob_viewer/package_json.rb b/app/models/blob_viewer/package_json.rb
new file mode 100644
index 00000000000..09221efb56c
--- /dev/null
+++ b/app/models/blob_viewer/package_json.rb
@@ -0,0 +1,23 @@
+module BlobViewer
+ class PackageJson < DependencyManager
+ include ServerSide
+
+ self.file_types = %i(package_json)
+
+ def manager_name
+ 'npm'
+ end
+
+ def manager_url
+ 'https://www.npmjs.com/'
+ end
+
+ def package_name
+ @package_name ||= package_name_from_json('name')
+ end
+
+ def package_url
+ "https://www.npmjs.com/package/#{package_name}"
+ end
+ end
+end
diff --git a/app/models/blob_viewer/pdf.rb b/app/models/blob_viewer/pdf.rb
new file mode 100644
index 00000000000..65805f5f388
--- /dev/null
+++ b/app/models/blob_viewer/pdf.rb
@@ -0,0 +1,12 @@
+module BlobViewer
+ class PDF < Base
+ include Rich
+ include ClientSide
+
+ self.partial_name = 'pdf'
+ self.extensions = %w(pdf)
+ self.binary = true
+ self.switcher_icon = 'file-pdf-o'
+ self.switcher_title = 'PDF'
+ end
+end
diff --git a/app/models/blob_viewer/podfile.rb b/app/models/blob_viewer/podfile.rb
new file mode 100644
index 00000000000..507bc734cb4
--- /dev/null
+++ b/app/models/blob_viewer/podfile.rb
@@ -0,0 +1,15 @@
+module BlobViewer
+ class Podfile < DependencyManager
+ include Static
+
+ self.file_types = %i(podfile)
+
+ def manager_name
+ 'CocoaPods'
+ end
+
+ def manager_url
+ 'https://cocoapods.org/'
+ end
+ end
+end
diff --git a/app/models/blob_viewer/podspec.rb b/app/models/blob_viewer/podspec.rb
new file mode 100644
index 00000000000..a4c242db3a9
--- /dev/null
+++ b/app/models/blob_viewer/podspec.rb
@@ -0,0 +1,27 @@
+module BlobViewer
+ class Podspec < DependencyManager
+ include ServerSide
+
+ self.file_types = %i(podspec)
+
+ def manager_name
+ 'CocoaPods'
+ end
+
+ def manager_url
+ 'https://cocoapods.org/'
+ end
+
+ def package_type
+ 'pod'
+ end
+
+ def package_name
+ @package_name ||= package_name_from_method_call('name')
+ end
+
+ def package_url
+ "https://cocoapods.org/pods/#{package_name}"
+ end
+ end
+end
diff --git a/app/models/blob_viewer/podspec_json.rb b/app/models/blob_viewer/podspec_json.rb
new file mode 100644
index 00000000000..602f4a51fd9
--- /dev/null
+++ b/app/models/blob_viewer/podspec_json.rb
@@ -0,0 +1,9 @@
+module BlobViewer
+ class PodspecJson < Podspec
+ self.file_types = %i(podspec_json)
+
+ def package_name
+ @package_name ||= package_name_from_json('name')
+ end
+ end
+end
diff --git a/app/models/blob_viewer/readme.rb b/app/models/blob_viewer/readme.rb
new file mode 100644
index 00000000000..75c373a03bb
--- /dev/null
+++ b/app/models/blob_viewer/readme.rb
@@ -0,0 +1,14 @@
+module BlobViewer
+ class Readme < Base
+ include Auxiliary
+ include Static
+
+ self.partial_name = 'readme'
+ self.file_types = %i(readme)
+ self.binary = false
+
+ def visible_to?(current_user)
+ can?(current_user, :read_wiki, project)
+ end
+ end
+end
diff --git a/app/models/blob_viewer/requirements_txt.rb b/app/models/blob_viewer/requirements_txt.rb
new file mode 100644
index 00000000000..83ac55f61d0
--- /dev/null
+++ b/app/models/blob_viewer/requirements_txt.rb
@@ -0,0 +1,15 @@
+module BlobViewer
+ class RequirementsTxt < DependencyManager
+ include Static
+
+ self.file_types = %i(requirements_txt)
+
+ def manager_name
+ 'pip'
+ end
+
+ def manager_url
+ 'https://pip.pypa.io/'
+ end
+ end
+end
diff --git a/app/models/blob_viewer/rich.rb b/app/models/blob_viewer/rich.rb
new file mode 100644
index 00000000000..be373dbc948
--- /dev/null
+++ b/app/models/blob_viewer/rich.rb
@@ -0,0 +1,11 @@
+module BlobViewer
+ module Rich
+ extend ActiveSupport::Concern
+
+ included do
+ self.type = :rich
+ self.switcher_icon = 'file-text-o'
+ self.switcher_title = 'rendered file'
+ end
+ end
+end
diff --git a/app/models/blob_viewer/route_map.rb b/app/models/blob_viewer/route_map.rb
new file mode 100644
index 00000000000..153b4eeb2c9
--- /dev/null
+++ b/app/models/blob_viewer/route_map.rb
@@ -0,0 +1,30 @@
+module BlobViewer
+ class RouteMap < Base
+ include ServerSide
+ include Auxiliary
+
+ self.partial_name = 'route_map'
+ self.loading_partial_name = 'route_map_loading'
+ self.file_types = %i(route_map)
+ self.binary = false
+
+ def validation_message
+ return @validation_message if defined?(@validation_message)
+
+ prepare!
+
+ @validation_message =
+ begin
+ Gitlab::RouteMap.new(blob.data)
+
+ nil
+ rescue Gitlab::RouteMap::FormatError => e
+ e.message
+ end
+ end
+
+ def valid?
+ validation_message.blank?
+ end
+ end
+end
diff --git a/app/models/blob_viewer/server_side.rb b/app/models/blob_viewer/server_side.rb
new file mode 100644
index 00000000000..87884dcd6bf
--- /dev/null
+++ b/app/models/blob_viewer/server_side.rb
@@ -0,0 +1,30 @@
+module BlobViewer
+ module ServerSide
+ extend ActiveSupport::Concern
+
+ included do
+ self.load_async = true
+ self.overridable_max_size = 2.megabytes
+ self.max_size = 5.megabytes
+ end
+
+ def prepare!
+ if blob.project
+ 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
diff --git a/app/models/blob_viewer/simple.rb b/app/models/blob_viewer/simple.rb
new file mode 100644
index 00000000000..454a20495fc
--- /dev/null
+++ b/app/models/blob_viewer/simple.rb
@@ -0,0 +1,11 @@
+module BlobViewer
+ module Simple
+ extend ActiveSupport::Concern
+
+ included do
+ self.type = :simple
+ self.switcher_icon = 'code'
+ self.switcher_title = 'source'
+ end
+ end
+end
diff --git a/app/models/blob_viewer/sketch.rb b/app/models/blob_viewer/sketch.rb
new file mode 100644
index 00000000000..818456778e1
--- /dev/null
+++ b/app/models/blob_viewer/sketch.rb
@@ -0,0 +1,12 @@
+module BlobViewer
+ class Sketch < Base
+ include Rich
+ include ClientSide
+
+ self.partial_name = 'sketch'
+ self.extensions = %w(sketch)
+ self.binary = true
+ self.switcher_icon = 'file-image-o'
+ self.switcher_title = 'preview'
+ end
+end
diff --git a/app/models/blob_viewer/static.rb b/app/models/blob_viewer/static.rb
new file mode 100644
index 00000000000..c9e257e5388
--- /dev/null
+++ b/app/models/blob_viewer/static.rb
@@ -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
diff --git a/app/models/blob_viewer/svg.rb b/app/models/blob_viewer/svg.rb
new file mode 100644
index 00000000000..b7e5cd71e6b
--- /dev/null
+++ b/app/models/blob_viewer/svg.rb
@@ -0,0 +1,12 @@
+module BlobViewer
+ class SVG < Base
+ include Rich
+ include ServerSide
+
+ self.partial_name = 'svg'
+ self.extensions = %w(svg)
+ self.binary = false
+ self.switcher_icon = 'picture-o'
+ self.switcher_title = 'image'
+ end
+end
diff --git a/app/models/blob_viewer/text.rb b/app/models/blob_viewer/text.rb
new file mode 100644
index 00000000000..eddca50b4d4
--- /dev/null
+++ b/app/models/blob_viewer/text.rb
@@ -0,0 +1,11 @@
+module BlobViewer
+ class Text < Base
+ include Simple
+ include ServerSide
+
+ self.partial_name = 'text'
+ self.binary = false
+ self.overridable_max_size = 1.megabyte
+ self.max_size = 10.megabytes
+ end
+end
diff --git a/app/models/blob_viewer/text_stl.rb b/app/models/blob_viewer/text_stl.rb
new file mode 100644
index 00000000000..8184dc0104c
--- /dev/null
+++ b/app/models/blob_viewer/text_stl.rb
@@ -0,0 +1,5 @@
+module BlobViewer
+ class TextSTL < BinarySTL
+ self.binary = false
+ end
+end
diff --git a/app/models/blob_viewer/video.rb b/app/models/blob_viewer/video.rb
new file mode 100644
index 00000000000..057f9fe516f
--- /dev/null
+++ b/app/models/blob_viewer/video.rb
@@ -0,0 +1,12 @@
+module BlobViewer
+ class Video < Base
+ include Rich
+ include ClientSide
+
+ self.partial_name = 'video'
+ self.extensions = UploaderHelper::VIDEO_EXT
+ self.binary = true
+ self.switcher_icon = 'film'
+ self.switcher_title = 'video'
+ end
+end
diff --git a/app/models/blob_viewer/yarn_lock.rb b/app/models/blob_viewer/yarn_lock.rb
new file mode 100644
index 00000000000..31588ddcbab
--- /dev/null
+++ b/app/models/blob_viewer/yarn_lock.rb
@@ -0,0 +1,15 @@
+module BlobViewer
+ class YarnLock < DependencyManager
+ include Static
+
+ self.file_types = %i(yarn_lock)
+
+ def manager_name
+ 'Yarn'
+ end
+
+ def manager_url
+ 'https://yarnpkg.com/'
+ end
+ end
+end