avo 1.17.0 → 1.18.0.pre.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of avo might be problematic. Click here for more details.

Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/Gemfile.lock +15 -13
  4. data/app/components/avo/fields/common/multiple_file_viewer_component.html.erb +2 -0
  5. data/app/components/avo/fields/common/multiple_file_viewer_component.rb +2 -1
  6. data/app/components/avo/fields/common/single_file_viewer_component.rb +2 -1
  7. data/app/components/avo/fields/file_field/edit_component.html.erb +1 -1
  8. data/app/components/avo/fields/files_field/edit_component.html.erb +3 -1
  9. data/app/controllers/avo/attachments_controller.rb +1 -2
  10. data/app/packs/entrypoints/application.css +1 -0
  11. data/app/packs/entrypoints/application.js +3 -0
  12. data/app/packs/js/active-storage.js +45 -0
  13. data/app/packs/js/controllers/filter_controller.js +19 -2
  14. data/app/packs/stylesheets/active-storage.css +37 -0
  15. data/config/routes.rb +1 -0
  16. data/lib/avo/app.rb +2 -2
  17. data/lib/avo/engine.rb +5 -1
  18. data/lib/avo/fields/date_time_field.rb +1 -1
  19. data/lib/avo/fields/file_field.rb +2 -0
  20. data/lib/avo/fields/files_field.rb +7 -0
  21. data/lib/avo/version.rb +1 -1
  22. data/lib/generators/avo/templates/filters/boolean_filter.tt +1 -1
  23. data/public/avo-packs/css/{application-2b4685ca.css → application-f9191617.css} +39 -1
  24. data/public/avo-packs/css/application-f9191617.css.br +0 -0
  25. data/public/avo-packs/css/application-f9191617.css.gz +0 -0
  26. data/public/avo-packs/css/application-f9191617.css.map +1 -0
  27. data/public/avo-packs/css/application-f9191617.css.map.br +0 -0
  28. data/public/avo-packs/css/application-f9191617.css.map.gz +0 -0
  29. data/public/avo-packs/js/application-cc89f096028eb1d4d971.js +26 -0
  30. data/public/avo-packs/js/{application-124d087ff9491dbf3511.js.LICENSE.txt → application-cc89f096028eb1d4d971.js.LICENSE.txt} +0 -0
  31. data/public/avo-packs/js/application-cc89f096028eb1d4d971.js.br +0 -0
  32. data/public/avo-packs/js/application-cc89f096028eb1d4d971.js.gz +0 -0
  33. data/public/avo-packs/js/application-cc89f096028eb1d4d971.js.map +1 -0
  34. data/public/avo-packs/js/application-cc89f096028eb1d4d971.js.map.br +0 -0
  35. data/public/avo-packs/js/application-cc89f096028eb1d4d971.js.map.gz +0 -0
  36. data/public/avo-packs/manifest.json +15 -15
  37. metadata +19 -17
  38. data/public/avo-packs/css/application-2b4685ca.css.br +0 -0
  39. data/public/avo-packs/css/application-2b4685ca.css.gz +0 -0
  40. data/public/avo-packs/css/application-2b4685ca.css.map +0 -1
  41. data/public/avo-packs/css/application-2b4685ca.css.map.br +0 -0
  42. data/public/avo-packs/css/application-2b4685ca.css.map.gz +0 -0
  43. data/public/avo-packs/js/application-124d087ff9491dbf3511.js +0 -26
  44. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.br +0 -0
  45. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.gz +0 -0
  46. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.map +0 -1
  47. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.map.br +0 -0
  48. data/public/avo-packs/js/application-124d087ff9491dbf3511.js.map.gz +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afbc7118164b7104453b9440a65ee4ff84a9b2dc6a42f30cf39aaeaca93fc4e3
4
- data.tar.gz: a37f8c6890e565c80f668d630795cfa15422c1d69f443e97542409afc7d6a9ef
3
+ metadata.gz: 8641081b1ddc20d52bc0b4d8a1c0172ab6c0923f0ebd1c166e335d50796411d8
4
+ data.tar.gz: 62d1fc74704027954f28dc1f962670966c1ccbb85a6440f19a28b797c479b805
5
5
  SHA512:
6
- metadata.gz: 86bc59793edb35cc7af577d2145d20ae83fc964d7163fa647c53e6d3e560dfadbd5ef79650b45f15d621ee7aab89d2164302ec34e9547381cceacdf8e1613922
7
- data.tar.gz: 1d012fb769f7f297f8eead60bbc296b01666e5d8852f3943c2706ad76bce0ae3ed3b8ac55a1509a84475436ca3cc70b6941070161467e51627561d98045bbff4
6
+ metadata.gz: 0ec3407fec3fa1dcb18054ca58692ee6d3e276a7c8ed911ffa43d1146f3b6a93f6a796393b9201957b63c02d0f9630107f5e8ab6add53c6108b19928d2566bf4
7
+ data.tar.gz: 2e1be9f862c67502c2dfddd004d4fceafdb9afbff3bb2e5ae7cbe29120d96e520c8cc79423408c8284713603aecedc96517b0ab9f38d91d00eb91fb2bbb55357
data/Gemfile CHANGED
@@ -115,7 +115,7 @@ gem "hotwire-rails"
115
115
 
116
116
  gem "active_link_to"
117
117
 
118
- gem "view_component", require: "view_component/engine"
118
+ gem "view_component"
119
119
 
120
120
  gem "addressable"
121
121
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- avo (1.17.0)
4
+ avo (1.18.0.pre.3)
5
5
  active_link_to
6
6
  addressable
7
7
  breadcrumbs_on_rails
@@ -107,7 +107,7 @@ GEM
107
107
  aws-eventstream (~> 1, >= 1.0.2)
108
108
  bcrypt (3.1.16)
109
109
  bindex (0.8.1)
110
- bootsnap (1.7.3)
110
+ bootsnap (1.9.3)
111
111
  msgpack (~> 1.0)
112
112
  breadcrumbs_on_rails (4.0.0)
113
113
  rails (>= 5.0)
@@ -123,7 +123,7 @@ GEM
123
123
  regexp_parser (~> 1.5)
124
124
  xpath (~> 3.2)
125
125
  childprocess (3.0.0)
126
- concurrent-ruby (1.1.8)
126
+ concurrent-ruby (1.1.9)
127
127
  countries (3.1.0)
128
128
  i18n_data (~> 0.11.0)
129
129
  sixarm_ruby_unaccent (~> 1.1)
@@ -131,7 +131,7 @@ GEM
131
131
  crack (0.4.4)
132
132
  crass (1.0.6)
133
133
  database_cleaner (1.8.5)
134
- devise (4.7.3)
134
+ devise (4.8.1)
135
135
  bcrypt (~> 3.0)
136
136
  orm_adapter (~> 0.1)
137
137
  railties (>= 4.1.0)
@@ -168,7 +168,7 @@ GEM
168
168
  httparty (0.18.1)
169
169
  mime-types (~> 3.0)
170
170
  multi_xml (>= 0.5.2)
171
- i18n (1.8.10)
171
+ i18n (1.8.11)
172
172
  concurrent-ruby (~> 1.0)
173
173
  i18n_data (0.11.0)
174
174
  image_processing (1.12.1)
@@ -184,7 +184,7 @@ GEM
184
184
  listen (3.5.1)
185
185
  rb-fsevent (~> 0.10, >= 0.10.3)
186
186
  rb-inotify (~> 0.9, >= 0.9.10)
187
- loofah (2.9.1)
187
+ loofah (2.13.0)
188
188
  crass (~> 1.0.2)
189
189
  nokogiri (>= 1.5.9)
190
190
  mail (2.7.1)
@@ -202,15 +202,17 @@ GEM
202
202
  mini_magick (4.11.0)
203
203
  mini_mime (1.0.3)
204
204
  mini_portile2 (2.6.1)
205
- minitest (5.14.4)
205
+ minitest (5.15.0)
206
206
  msgpack (1.4.2)
207
207
  multi_xml (0.6.0)
208
208
  nio4r (2.5.8)
209
209
  nokogiri (1.12.5)
210
210
  mini_portile2 (~> 2.6.1)
211
211
  racc (~> 1.4)
212
+ nokogiri (1.12.5-x86_64-linux)
213
+ racc (~> 1.4)
212
214
  orm_adapter (0.5.0)
213
- pagy (4.11.0)
215
+ pagy (5.6.10)
214
216
  parallel (1.20.1)
215
217
  parser (3.0.0.0)
216
218
  ast (~> 2.4.1)
@@ -220,7 +222,7 @@ GEM
220
222
  nio4r (~> 2.0)
221
223
  pundit (2.1.0)
222
224
  activesupport (>= 3.0.0)
223
- racc (1.5.2)
225
+ racc (1.6.0)
224
226
  rack (2.2.3)
225
227
  rack-proxy (0.6.5)
226
228
  rack
@@ -248,7 +250,7 @@ GEM
248
250
  rails-dom-testing (2.0.3)
249
251
  activesupport (>= 4.2.0)
250
252
  nokogiri (>= 1.6)
251
- rails-html-sanitizer (1.3.0)
253
+ rails-html-sanitizer (1.4.2)
252
254
  loofah (~> 2.3)
253
255
  railties (6.1.3.2)
254
256
  actionpack (= 6.1.3.2)
@@ -257,7 +259,7 @@ GEM
257
259
  rake (>= 0.8.7)
258
260
  thor (~> 1.0)
259
261
  rainbow (3.0.0)
260
- rake (13.0.3)
262
+ rake (13.0.6)
261
263
  ransack (2.4.2)
262
264
  activerecord (>= 5.2.4)
263
265
  activesupport (>= 5.2.4)
@@ -379,7 +381,7 @@ GEM
379
381
  websocket-extensions (0.1.5)
380
382
  xpath (3.2.0)
381
383
  nokogiri (~> 1.8)
382
- zeitwerk (2.4.2)
384
+ zeitwerk (2.5.2)
383
385
 
384
386
  PLATFORMS
385
387
  ruby
@@ -439,4 +441,4 @@ DEPENDENCIES
439
441
  zeitwerk (~> 2.3)
440
442
 
441
443
  BUNDLED WITH
442
- 2.2.29
444
+ 2.2.32
@@ -1,4 +1,6 @@
1
1
  <div class="relative min-h-full max-w-full flex-1 flex flex-col justify-between space-y-3">
2
+ <%= @file.inspect %>
3
+ <%= @id.inspect %>
2
4
  <% if @file.present? %>
3
5
  <% if @file.representable? && @is_image %>
4
6
  <%= image_tag helpers.main_app.url_for(@file), class: 'rounded-lg max-h-168 max-w-full' %>
@@ -3,10 +3,11 @@
3
3
  class Avo::Fields::Common::MultipleFileViewerComponent < ViewComponent::Base
4
4
  include Avo::ApplicationHelper
5
5
 
6
- def initialize(id:, file:, is_image:, resource:, button_size: :md)
6
+ def initialize(id:, file:, is_image:, direct_upload: false, resource:, button_size: :md)
7
7
  @id = id
8
8
  @file = file
9
9
  @is_image = is_image
10
+ @direct_upload = direct_upload
10
11
  @button_size = button_size
11
12
  @resource = resource
12
13
  end
@@ -3,10 +3,11 @@
3
3
  class Avo::Fields::Common::SingleFileViewerComponent < ViewComponent::Base
4
4
  include Avo::ApplicationHelper
5
5
 
6
- def initialize(id:, file:, is_image:, resource:, button_size: :md)
6
+ def initialize(id:, file:, is_image:, direct_upload: false, resource:, button_size: :md)
7
7
  @id = id
8
8
  @file = file
9
9
  @is_image = is_image
10
+ @direct_upload = direct_upload
10
11
  @button_size = button_size
11
12
  @resource = resource
12
13
  end
@@ -6,6 +6,6 @@
6
6
  <% end %>
7
7
 
8
8
  <% if @resource.authorization.authorize_action(:upload_attachments?, raise_exception: false) %>
9
- <%= @form.file_field @field.id, disabled: @field.readonly %>
9
+ <%= @form.file_field @field.id, disabled: @field.readonly, direct_upload: @field.direct_upload %>
10
10
  <% end %>
11
11
  <% end %>
@@ -2,6 +2,8 @@
2
2
  <%= render Avo::Fields::Common::FilesListViewerComponent.new(field: @field, resource: @resource) if @field.value.present? %>
3
3
 
4
4
  <% if @resource.authorization.authorize_action(:upload_attachments?, raise_exception: false) %>
5
- <%= @form.file_field @field.id, disabled: @field.readonly, multiple: true %>
5
+ <div class="mt-2">
6
+ <%= @form.file_field @field.id, disabled: @field.readonly, multiple: true, direct_upload: @field.direct_upload %>
7
+ </div>
6
8
  <% end %>
7
9
  <% end %>
@@ -21,8 +21,7 @@ module Avo
21
21
  end
22
22
 
23
23
  def destroy
24
- blob = ActiveStorage::Blob.find(params[:signed_attachment_id])
25
- attachment = blob.attachments.find_by record_id: params[:id], record_type: @model.class.to_s
24
+ attachment = ActiveStorage::Attachment.find(params[:signed_attachment_id])
26
25
 
27
26
  if attachment.present?
28
27
  attachment.destroy
@@ -16,6 +16,7 @@
16
16
  @import './../stylesheets/pagination.css';
17
17
  @import './../stylesheets/breadcrumbs.css';
18
18
  @import './../stylesheets/search.css';
19
+ @import './../stylesheets/active-storage.css';
19
20
 
20
21
  @import './../stylesheets/components/status.css';
21
22
  @import './../stylesheets/components/code.css';
@@ -2,6 +2,7 @@
2
2
  import 'core-js/stable'
3
3
  // eslint-disable-next-line import/no-extraneous-dependencies
4
4
  import 'regenerator-runtime/runtime'
5
+ import * as ActiveStorage from '@rails/activestorage'
5
6
  import * as Mousetrap from 'mousetrap'
6
7
  import { Application } from 'stimulus'
7
8
  import { Turbo } from '@hotwired/turbo-rails'
@@ -10,6 +11,7 @@ import Rails from '@rails/ujs'
10
11
  import tippy from 'tippy.js'
11
12
 
12
13
  // Toastr alerts
14
+ import '../js/active-storage'
13
15
  import '../js/toastr'
14
16
 
15
17
  Rails.start()
@@ -32,6 +34,7 @@ function initTippy() {
32
34
  window.initTippy = initTippy
33
35
 
34
36
  const application = Application.start()
37
+ ActiveStorage.start()
35
38
 
36
39
  const context = require.context('./../js/controllers', true, /\.js$/)
37
40
  application.load(definitionsFromContext(context))
@@ -0,0 +1,45 @@
1
+ document.addEventListener('direct-upload:initialize', (event) => {
2
+ const { target, detail } = event
3
+ const { id, file } = detail
4
+
5
+ target.insertAdjacentHTML(
6
+ 'beforebegin',
7
+ `
8
+ <div id="direct-upload-${id}" class="direct-upload direct-upload--pending">
9
+ <div id="direct-upload-progress-${id}" class="direct-upload__progress" style="width: 0%"></div>
10
+ <span class="direct-upload__filename"></span>
11
+ </div>
12
+ `,
13
+ )
14
+ target.previousElementSibling.querySelector(
15
+ '.direct-upload__filename',
16
+ ).textContent = file.name
17
+ })
18
+
19
+ document.addEventListener('direct-upload:start', (event) => {
20
+ const { id } = event.detail
21
+ const element = document.getElementById(`direct-upload-${id}`)
22
+ element.classList.remove('direct-upload--pending')
23
+ })
24
+
25
+ document.addEventListener('direct-upload:progress', (event) => {
26
+ const { id, progress } = event.detail
27
+ const progressElement = document.getElementById(
28
+ `direct-upload-progress-${id}`,
29
+ )
30
+ progressElement.style.width = `${progress}%`
31
+ })
32
+
33
+ document.addEventListener('direct-upload:error', (event) => {
34
+ event.preventDefault()
35
+ const { id, error } = event.detail
36
+ const element = document.getElementById(`direct-upload-${id}`)
37
+ element.classList.add('direct-upload--error')
38
+ element.setAttribute('title', error)
39
+ })
40
+
41
+ document.addEventListener('direct-upload:end', (event) => {
42
+ const { id } = event.detail
43
+ const element = document.getElementById(`direct-upload-${id}`)
44
+ element.classList.add('direct-upload--complete')
45
+ })
@@ -21,6 +21,23 @@ export default class extends Controller {
21
21
  return param
22
22
  }
23
23
 
24
+ b64EncodeUnicode(str) {
25
+ // first we use encodeURIComponent to get percent-encoded UTF-8,
26
+ // then we convert the percent encodings into raw bytes which
27
+ // can be fed into btoa.
28
+ return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g,
29
+ function toSolidBytes(match, p1) {
30
+ return String.fromCharCode('0x' + p1);
31
+ }));
32
+ }
33
+
34
+ b64DecodeUnicode(str) {
35
+ // Going backwards: from bytestream, to percent-encoding, to original string.
36
+ return decodeURIComponent(atob(str).split('').map(function(c) {
37
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
38
+ }).join(''));
39
+ }
40
+
24
41
  changeFilter() {
25
42
  const value = this.getFilterValue()
26
43
  const filterClass = this.getFilterClass()
@@ -28,7 +45,7 @@ export default class extends Controller {
28
45
  let filters = this.uriParams()[this.uriParam('filters')]
29
46
 
30
47
  if (filters) {
31
- filters = JSON.parse(atob(filters))
48
+ filters = JSON.parse(this.b64DecodeUnicode(filters))
32
49
  } else {
33
50
  filters = {}
34
51
  }
@@ -46,7 +63,7 @@ export default class extends Controller {
46
63
  let encodedFilters
47
64
 
48
65
  if (filtered && Object.keys(filtered).length > 0) {
49
- encodedFilters = btoa(JSON.stringify(filtered))
66
+ encodedFilters = this.b64EncodeUnicode(JSON.stringify(filtered))
50
67
  }
51
68
 
52
69
  const url = new URI(this.urlRedirectTarget.href)
@@ -0,0 +1,37 @@
1
+ .direct-upload {
2
+ display: inline-block;
3
+ position: relative;
4
+ padding: 2px 4px;
5
+ margin: 0 3px 3px 0;
6
+ border: 1px solid rgba(0, 0, 0, 0.3);
7
+ border-radius: 3px;
8
+ font-size: 11px;
9
+ line-height: 13px;
10
+ }
11
+
12
+ .direct-upload--pending {
13
+ opacity: 0.6;
14
+ }
15
+
16
+ .direct-upload__progress {
17
+ position: absolute;
18
+ top: 0;
19
+ left: 0;
20
+ bottom: 0;
21
+ opacity: 0.2;
22
+ background: #0076ff;
23
+ transition: width 120ms ease-out, opacity 60ms 60ms ease-in;
24
+ transform: translate3d(0, 0, 0);
25
+ }
26
+
27
+ .direct-upload--complete .direct-upload__progress {
28
+ opacity: 0.4;
29
+ }
30
+
31
+ .direct-upload--error {
32
+ border-color: red;
33
+ }
34
+
35
+ input[type=file][data-direct-upload-url][disabled] {
36
+ display: none;
37
+ }
data/config/routes.rb CHANGED
@@ -2,6 +2,7 @@ Avo::Engine.routes.draw do
2
2
  root "home#index"
3
3
 
4
4
  get "resources", to: redirect("/admin")
5
+ post "/rails/active_storage/direct_uploads", to: "/active_storage/direct_uploads#create"
5
6
 
6
7
  scope "avo_api", as: "avo_api" do
7
8
  get "/search", to: "search#index"
data/lib/avo/app.rb CHANGED
@@ -32,9 +32,9 @@ module Avo
32
32
 
33
33
  # Set the current host for ActiveStorage
34
34
  begin
35
- ActiveStorage::Current.host = request.base_url
35
+ ActiveStorage::Current.url_options = request.base_url
36
36
  rescue => exception
37
- Rails.logger.debug "[Avo] Failed to set ActiveStorage::Current.host, #{exception.inspect}"
37
+ Rails.logger.debug "[Avo] Failed to set ActiveStorage::Current.url_options, #{exception.inspect}"
38
38
  end
39
39
 
40
40
  init_resources
data/lib/avo/engine.rb CHANGED
@@ -2,7 +2,11 @@
2
2
  Gem.loaded_specs["avo"].dependencies.each do |d|
3
3
  require d.name
4
4
  end
5
- require "view_component/engine"
5
+
6
+ # In development we should load the engine so we get the autoload for components
7
+ if ENV["RAILS_ENV"] === "development"
8
+ require "view_component/engine"
9
+ end
6
10
 
7
11
  module Avo
8
12
  class Engine < ::Rails::Engine
@@ -17,7 +17,7 @@ module Avo
17
17
  return nil if value.nil?
18
18
 
19
19
  if @format.is_a?(Symbol)
20
- value.to_time.in_time_zone(timezone).to_s(@format)
20
+ value.to_time.in_time_zone(timezone).to_formatted_s(@format)
21
21
  else
22
22
  value.to_time.in_time_zone(timezone).strftime(@format)
23
23
  end
@@ -4,6 +4,7 @@ module Avo
4
4
  attr_accessor :link_to_resource
5
5
  attr_accessor :is_avatar
6
6
  attr_accessor :is_image
7
+ attr_accessor :direct_upload
7
8
 
8
9
  def initialize(id, **args, &block)
9
10
  super(id, **args, &block)
@@ -11,6 +12,7 @@ module Avo
11
12
  @link_to_resource = args[:link_to_resource].present? ? args[:link_to_resource] : false
12
13
  @is_avatar = args[:is_avatar].present? ? args[:is_avatar] : false
13
14
  @is_image = args[:is_image].present? ? args[:is_image] : @is_avatar
15
+ @direct_upload = args[:direct_upload].present? ? args[:direct_upload] : false
14
16
  end
15
17
 
16
18
  def path
@@ -2,11 +2,13 @@ module Avo
2
2
  module Fields
3
3
  class FilesField < BaseField
4
4
  attr_accessor :is_image
5
+ attr_accessor :direct_upload
5
6
 
6
7
  def initialize(id, **args, &block)
7
8
  super(id, **args, &block)
8
9
 
9
10
  @is_image = args[:is_image].present? ? args[:is_image] : @is_avatar
11
+ @direct_upload = args[:direct_upload].present? ? args[:direct_upload] : false
10
12
  end
11
13
 
12
14
  def view_component_name
@@ -21,6 +23,11 @@ module Avo
21
23
  return model unless model.methods.include? key.to_sym
22
24
 
23
25
  value.each do |file|
26
+ # Skip empty values
27
+ next unless file.present?
28
+ # Keep only String values
29
+ next unless file.class === String
30
+
24
31
  model.send(key).attach file
25
32
  end
26
33
 
data/lib/avo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Avo
2
- VERSION = "1.17.0"
2
+ VERSION = "1.18.0.pre.3"
3
3
  end
@@ -1,7 +1,7 @@
1
1
  class <%= class_name.camelize %> < Avo::Filters::BooleanFilter
2
2
  self.name = '<%= name.underscore.humanize %>'
3
3
 
4
- def apply(request, query, value)
4
+ def apply(request, query, values)
5
5
  query
6
6
  end
7
7
 
@@ -3220,6 +3220,44 @@ svg.tea #steamR {
3220
3220
  color: rgba(255, 255, 255, var(--tw-text-opacity));
3221
3221
  }
3222
3222
 
3223
+ .direct-upload {
3224
+ display: inline-block;
3225
+ position: relative;
3226
+ padding: 2px 4px;
3227
+ margin: 0 3px 3px 0;
3228
+ border: 1px solid rgba(0, 0, 0, 0.3);
3229
+ border-radius: 3px;
3230
+ font-size: 11px;
3231
+ line-height: 13px;
3232
+ }
3233
+
3234
+ .direct-upload--pending {
3235
+ opacity: 0.6;
3236
+ }
3237
+
3238
+ .direct-upload__progress {
3239
+ position: absolute;
3240
+ top: 0;
3241
+ left: 0;
3242
+ bottom: 0;
3243
+ opacity: 0.2;
3244
+ background: #0076ff;
3245
+ transition: width 120ms ease-out, opacity 60ms 60ms ease-in;
3246
+ transform: translate3d(0, 0, 0);
3247
+ }
3248
+
3249
+ .direct-upload--complete .direct-upload__progress {
3250
+ opacity: 0.4;
3251
+ }
3252
+
3253
+ .direct-upload--error {
3254
+ border-color: red;
3255
+ }
3256
+
3257
+ input[type=file][data-direct-upload-url][disabled] {
3258
+ display: none;
3259
+ }
3260
+
3223
3261
  .spinner {
3224
3262
  width: 16px;
3225
3263
  height: 16px;
@@ -6246,4 +6284,4 @@ html, body{
6246
6284
  }
6247
6285
 
6248
6286
 
6249
- /*# sourceMappingURL=application-2b4685ca.css.map*/
6287
+ /*# sourceMappingURL=application-f9191617.css.map*/