diff --git a/app/assets/stylesheets/components/animations.css b/app/assets/stylesheets/components/animations.css index 23b7664..315ab7f 100644 --- a/app/assets/stylesheets/components/animations.css +++ b/app/assets/stylesheets/components/animations.css @@ -14,3 +14,27 @@ animation-duration: 0.15s; animation-timing-function: cubic-bezier(0.2, 0, 0.13, 1); } + +@keyframes removeRow { + from { + opacity: 1; + transform: translateX(0); + } + to { + opacity: 0; + transform: translateX(0.75rem); + } +} + +.animate-remove { + animation: removeRow 0.2s ease-out forwards; + pointer-events: none; +} + +@media (prefers-reduced-motion: reduce) { + /* Keep the animation, so the deferred removal still completes, but make it + effectively instant. */ + .animate-remove { + animation-duration: 0.01s; + } +} diff --git a/app/components/rs_auth_access_component.html.erb b/app/components/rs_auth_access_component.html.erb new file mode 100644 index 0000000..cc50b66 --- /dev/null +++ b/app/components/rs_auth_access_component.html.erb @@ -0,0 +1,7 @@ +
+
+ Access +
+ <%= render RsScopeListComponent.new(scopes: permissions, root: root_access?, + icon_class: "h-5 w-5") %> +
\ No newline at end of file diff --git a/app/components/rs_auth_access_component.rb b/app/components/rs_auth_access_component.rb new file mode 100644 index 0000000..605d742 --- /dev/null +++ b/app/components/rs_auth_access_component.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +class RsAuthAccessComponent < ViewComponent::Base + include RsAuthSummary + include RsAuthsHelper + + def initialize(authorizations:) + @authorizations = authorizations + @auth = authorizations.first + end + + def access_id + rs_app_dom_id(@auth.client_id, :access) + end +end \ No newline at end of file diff --git a/app/components/rs_auth_card_component.html.erb b/app/components/rs_auth_card_component.html.erb new file mode 100644 index 0000000..3ff311e --- /dev/null +++ b/app/components/rs_auth_card_component.html.erb @@ -0,0 +1,35 @@ + \ No newline at end of file diff --git a/app/components/rs_auth_card_component.rb b/app/components/rs_auth_card_component.rb new file mode 100644 index 0000000..ea8e7f1 --- /dev/null +++ b/app/components/rs_auth_card_component.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class RsAuthCardComponent < ViewComponent::Base + include RsAuthSummary + include RsAuthsHelper + + def initialize(authorizations:) + @authorizations = authorizations + @auth = authorizations.first + @web_app = @auth.web_app + end + + def card_id + rs_app_dom_id(@auth.client_id, :card) + end +end \ No newline at end of file diff --git a/app/components/rs_auth_component.html.erb b/app/components/rs_auth_component.html.erb index 3bc335e..2244194 100644 --- a/app/components/rs_auth_component.html.erb +++ b/app/components/rs_auth_component.html.erb @@ -1,38 +1,4 @@
- - + <%= render RsAuthCardComponent.new(authorizations: @authorizations) %> <%= render RsAuthDetailsModalComponent.new(authorizations: @authorizations) %> -
+ \ No newline at end of file diff --git a/app/components/rs_auth_component.rb b/app/components/rs_auth_component.rb index 5984941..cb29f0c 100644 --- a/app/components/rs_auth_component.rb +++ b/app/components/rs_auth_component.rb @@ -1,44 +1,10 @@ # frozen_string_literal: true +# Wrapper around one app's card and its details modal. The modal's open state +# lives on this element (via the `modal` controller), so the card and the modal +# can be re-rendered independently without closing it. class RsAuthComponent < ViewComponent::Base def initialize(authorizations:) @authorizations = authorizations - @auth = authorizations.first - @web_app = @auth.web_app end - - # The card summarises the app, so reflect the union of its authorizations' - # scopes (an older token may have broader access than the newest one). - def permissions - @authorizations.flat_map(&:permissions).uniq - end - - def root_access? - (permissions & [":r", ":rw"]).any? - end - - def category_summary - return "All categories and files" if root_access? - - count = permissions.size - "#{count} #{'category'.pluralize(count)}" - end - - def known_device_count - @authorizations.map(&:device_name).compact.uniq.size - end - - def unrecorded_device? - @authorizations.any? { |auth| auth.device_name.blank? } - end - - def device_summary - count = known_device_count - return "#{count} #{'device'.pluralize(count)}" unless unrecorded_device? - - # An authorization without a recorded user agent may cover several devices, - # so only a lower bound can be given. - lower_bound = count + 1 - "#{lower_bound}+ #{'device'.pluralize(lower_bound)}" - end -end +end \ No newline at end of file diff --git a/app/components/rs_auth_details_modal_component.html.erb b/app/components/rs_auth_details_modal_component.html.erb index 36da0f5..2462dc6 100644 --- a/app/components/rs_auth_details_modal_component.html.erb +++ b/app/components/rs_auth_details_modal_component.html.erb @@ -11,18 +11,14 @@ -
- Access -
- <%= render RsScopeListComponent.new(scopes: permissions, root: root_access?, - icon_class: "h-5 w-5") %> + <%= render RsAuthAccessComponent.new(authorizations: @authorizations) %>
Connected devices