active_storage-async_variants-ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +24 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Appraisals +11 -0
- data/CHANGELOG.md +8 -0
- data/CLAUDE.md +35 -0
- data/LICENSE.txt +21 -0
- data/README.md +89 -0
- data/Rakefile +27 -0
- data/app/assets/javascripts/progress-bar.js +347 -0
- data/app/assets/javascripts/retry.js +11 -0
- data/app/assets/stylesheets/progress.css +35 -0
- data/app/assets/stylesheets/retry.css +98 -0
- data/app/controllers/active_storage/async_variants/states_controller.rb +71 -0
- data/app/views/active_storage/async_variants/states/_failed.html.erb +44 -0
- data/app/views/active_storage/async_variants/states/_pending.html.erb +1 -0
- data/app/views/active_storage/async_variants/states/_processed.html.erb +5 -0
- data/app/views/active_storage/async_variants/states/_processing.html.erb +15 -0
- data/app/views/active_storage/async_variants/states/show.html.erb +10 -0
- data/config/routes.rb +20 -0
- data/features/retry_flow.feature +20 -0
- data/features/retry_visibility.feature +23 -0
- data/features/state_rendering.feature +40 -0
- data/features/step_definitions/dummy_steps.rb +144 -0
- data/features/support/env.rb +28 -0
- data/gemfiles/rails_7.2.gemfile +18 -0
- data/gemfiles/rails_8.0.gemfile +18 -0
- data/gemfiles/rails_8.1.gemfile +18 -0
- data/lib/active_storage/async_variants/asset_tag_helper_extension.rb +59 -0
- data/lib/active_storage/async_variants/helper.rb +80 -0
- data/lib/active_storage/async_variants/ui/version.rb +9 -0
- data/lib/active_storage/async_variants/ui.rb +45 -0
- data/log/.gitkeep +0 -0
- metadata +118 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveStorage
|
|
4
|
+
module AsyncVariants
|
|
5
|
+
# View/controller helper methods. Included in the AssetTagHelperExtension
|
|
6
|
+
# (so image_tag/video_tag can use them) and added to StatesController via
|
|
7
|
+
# `helper ActiveStorage::AsyncVariants::Helper` (so the state partials can
|
|
8
|
+
# use them).
|
|
9
|
+
module Helper
|
|
10
|
+
# Invisible box reserving layout for the progress bar. The image src is a
|
|
11
|
+
# tiny gem GIF whose URL ends in the media filename (no original fetched);
|
|
12
|
+
# the video placeholder carries no <source>.
|
|
13
|
+
def async_variant_placeholder_tag(variant, html_options = {}, kind: :image)
|
|
14
|
+
opts = async_variant_box_dimensions(variant)
|
|
15
|
+
.merge(html_options.symbolize_keys.except(:src, :controls, :autoplay, :preload, :poster))
|
|
16
|
+
if kind == :video
|
|
17
|
+
content_tag(:video, "", opts)
|
|
18
|
+
else
|
|
19
|
+
src = Rails.application.routes.url_helpers.async_variant_placeholder_path(variant.blob.filename.to_s)
|
|
20
|
+
image_tag(src, opts)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def async_variant_box_dimensions(variant)
|
|
25
|
+
resize = variant.variation.transformations
|
|
26
|
+
.values_at(:resize_to_limit, :resize_to_fit, :resize_to_fill)
|
|
27
|
+
.compact.first
|
|
28
|
+
resize.is_a?(Array) ? { width: resize[0], height: resize[1] } : {}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# In test with non-bucket-backed services, the gem defers to vanilla
|
|
32
|
+
# ActiveStorage (synchronous vips transform) -- inline rendering keeps
|
|
33
|
+
# those environments simple. Otherwise, only inline a normal <img> when
|
|
34
|
+
# the variant has reached the processed terminal state.
|
|
35
|
+
def async_variant_processed_inline?(variant)
|
|
36
|
+
!variant.blob.bucket_backed? || variant.async_state == "processed"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def async_variant_resolved_src(variant, direct:)
|
|
40
|
+
if direct && variant.async_state == "processed"
|
|
41
|
+
async_variant_direct_url(variant)
|
|
42
|
+
else
|
|
43
|
+
variant.processed if variant.blob.bucket_backed?
|
|
44
|
+
async_variant_representation_path(variant)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def async_variant_frame_id(variant)
|
|
49
|
+
digest = variant.variation.digest.gsub(/[^a-zA-Z0-9_-]/, "")
|
|
50
|
+
"async-variant-#{variant.blob.id}-#{digest}"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def async_variant_frame_src(variant, kind:, direct:, html_options: {})
|
|
54
|
+
async_variant_state_path(
|
|
55
|
+
signed_blob_id: variant.blob.signed_id,
|
|
56
|
+
variation_key: variant.variation.key,
|
|
57
|
+
kind:,
|
|
58
|
+
direct:,
|
|
59
|
+
opts: html_options.slice(*PASS_THROUGH_HTML_OPTIONS),
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def async_variant_direct_url(variant)
|
|
64
|
+
if cdn = ActiveStorage::AsyncVariants.cdn_host
|
|
65
|
+
"#{cdn}/#{variant.key}"
|
|
66
|
+
else
|
|
67
|
+
variant.image.url
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def async_variant_representation_path(variant)
|
|
72
|
+
Rails.application.routes.url_helpers.rails_blob_representation_path(
|
|
73
|
+
variant.blob.signed_id,
|
|
74
|
+
variant.variation.key,
|
|
75
|
+
variant.blob.filename.to_s,
|
|
76
|
+
)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_storage/async_variants" # the plumbing gem
|
|
4
|
+
require "turbo-rails"
|
|
5
|
+
require "isolate_assets"
|
|
6
|
+
require_relative "ui/version"
|
|
7
|
+
require_relative "helper"
|
|
8
|
+
require_relative "asset_tag_helper_extension"
|
|
9
|
+
|
|
10
|
+
module ActiveStorage
|
|
11
|
+
module AsyncVariants
|
|
12
|
+
# HTML attributes round-tripped through the state-endpoint URL so the
|
|
13
|
+
# eventual processed-state render can apply them to the inner <img>/<video>.
|
|
14
|
+
PASS_THROUGH_HTML_OPTIONS = %i[alt width height controls autoplay preload].freeze
|
|
15
|
+
|
|
16
|
+
mattr_accessor :cdn_host
|
|
17
|
+
mattr_accessor :retry_visible_proc, default: ->(_view) { false }
|
|
18
|
+
|
|
19
|
+
# Lets the host app plug its auth chain (and thus `current_user`) into the
|
|
20
|
+
# gem's StatesController. Set to a string so resolution is deferred until
|
|
21
|
+
# the host's class is autoloadable. Defaults to ActionController::Base.
|
|
22
|
+
mattr_accessor :parent_controller, default: "ActionController::Base"
|
|
23
|
+
|
|
24
|
+
# Gates the failed-state retry affordance; the block runs in the view context.
|
|
25
|
+
def self.retry_visible_if(&block)
|
|
26
|
+
self.retry_visible_proc = block
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def self.retry_visible?(view)
|
|
30
|
+
!!view.instance_exec(&retry_visible_proc)
|
|
31
|
+
rescue StandardError
|
|
32
|
+
false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class UIEngine < ::Rails::Engine
|
|
36
|
+
config.after_initialize do
|
|
37
|
+
ActionView::Helpers::AssetTagHelper.prepend(
|
|
38
|
+
ActiveStorage::AsyncVariants::AssetTagHelperExtension
|
|
39
|
+
)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
Assets = IsolateAssets.register(namespace: self, engine: UIEngine, route_name: :async_variant_asset)
|
|
44
|
+
end
|
|
45
|
+
end
|
data/log/.gitkeep
ADDED
|
File without changes
|
metadata
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: active_storage-async_variants-ui
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Micah Geisel
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 2026-06-10 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: active_storage-async_variants
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0.9'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0.9'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: turbo-rails
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - ">="
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: '2.0'
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - ">="
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: '2.0'
|
|
40
|
+
- !ruby/object:Gem::Dependency
|
|
41
|
+
name: isolate_assets
|
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: '0.4'
|
|
47
|
+
type: :runtime
|
|
48
|
+
prerelease: false
|
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
50
|
+
requirements:
|
|
51
|
+
- - ">="
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0.4'
|
|
54
|
+
email:
|
|
55
|
+
- micah@botandrose.com
|
|
56
|
+
executables: []
|
|
57
|
+
extensions: []
|
|
58
|
+
extra_rdoc_files: []
|
|
59
|
+
files:
|
|
60
|
+
- ".github/workflows/ci.yml"
|
|
61
|
+
- ".ruby-gemset"
|
|
62
|
+
- ".ruby-version"
|
|
63
|
+
- Appraisals
|
|
64
|
+
- CHANGELOG.md
|
|
65
|
+
- CLAUDE.md
|
|
66
|
+
- LICENSE.txt
|
|
67
|
+
- README.md
|
|
68
|
+
- Rakefile
|
|
69
|
+
- app/assets/javascripts/progress-bar.js
|
|
70
|
+
- app/assets/javascripts/retry.js
|
|
71
|
+
- app/assets/stylesheets/progress.css
|
|
72
|
+
- app/assets/stylesheets/retry.css
|
|
73
|
+
- app/controllers/active_storage/async_variants/states_controller.rb
|
|
74
|
+
- app/views/active_storage/async_variants/states/_failed.html.erb
|
|
75
|
+
- app/views/active_storage/async_variants/states/_pending.html.erb
|
|
76
|
+
- app/views/active_storage/async_variants/states/_processed.html.erb
|
|
77
|
+
- app/views/active_storage/async_variants/states/_processing.html.erb
|
|
78
|
+
- app/views/active_storage/async_variants/states/show.html.erb
|
|
79
|
+
- config/routes.rb
|
|
80
|
+
- features/retry_flow.feature
|
|
81
|
+
- features/retry_visibility.feature
|
|
82
|
+
- features/state_rendering.feature
|
|
83
|
+
- features/step_definitions/dummy_steps.rb
|
|
84
|
+
- features/support/env.rb
|
|
85
|
+
- gemfiles/rails_7.2.gemfile
|
|
86
|
+
- gemfiles/rails_8.0.gemfile
|
|
87
|
+
- gemfiles/rails_8.1.gemfile
|
|
88
|
+
- lib/active_storage/async_variants/asset_tag_helper_extension.rb
|
|
89
|
+
- lib/active_storage/async_variants/helper.rb
|
|
90
|
+
- lib/active_storage/async_variants/ui.rb
|
|
91
|
+
- lib/active_storage/async_variants/ui/version.rb
|
|
92
|
+
- log/.gitkeep
|
|
93
|
+
homepage: https://github.com/botandrose/active_storage-async_variants-ui
|
|
94
|
+
licenses:
|
|
95
|
+
- MIT
|
|
96
|
+
metadata:
|
|
97
|
+
homepage_uri: https://github.com/botandrose/active_storage-async_variants-ui
|
|
98
|
+
source_code_uri: https://github.com/botandrose/active_storage-async_variants-ui
|
|
99
|
+
changelog_uri: https://github.com/botandrose/active_storage-async_variants-ui/blob/master/CHANGELOG.md
|
|
100
|
+
rdoc_options: []
|
|
101
|
+
require_paths:
|
|
102
|
+
- lib
|
|
103
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
104
|
+
requirements:
|
|
105
|
+
- - ">="
|
|
106
|
+
- !ruby/object:Gem::Version
|
|
107
|
+
version: 3.3.0
|
|
108
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
109
|
+
requirements:
|
|
110
|
+
- - ">="
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: '0'
|
|
113
|
+
requirements: []
|
|
114
|
+
rubygems_version: 3.6.2
|
|
115
|
+
specification_version: 4
|
|
116
|
+
summary: 'Turbo-frame UI for active_storage-async_variants: image_tag/video_tag rendering,
|
|
117
|
+
progress bars, and retry.'
|
|
118
|
+
test_files: []
|