practical 3.0.0.pre.alpha2 → 3.0.0.pre.alpha4

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/app/components/practical/views/button_to_component.rb +23 -0
  3. data/app/components/practical/views/flash_messages_component.rb +15 -7
  4. data/app/components/practical/views/form/error_list_component.rb +1 -1
  5. data/app/components/practical/views/form/error_list_item_component.rb +1 -2
  6. data/app/components/practical/views/form/fallback_errors_section_component.html.erb +8 -5
  7. data/app/components/practical/views/form/fallback_errors_section_component.rb +0 -1
  8. data/app/components/practical/views/form/field_errors_component.html.erb +8 -0
  9. data/app/components/practical/views/form/field_errors_component.rb +14 -11
  10. data/app/components/practical/views/form/input_component.html.erb +1 -1
  11. data/app/components/practical/views/form/input_component.rb +15 -1
  12. data/app/components/practical/views/modal_dialog_component.html.erb +1 -1
  13. data/app/components/practical/views/modal_dialog_component.rb +1 -1
  14. data/app/components/practical/views/navigation/pagination/goto_form_component.html.erb +4 -10
  15. data/app/components/practical/views/navigation/pagination/goto_form_component.rb +17 -2
  16. data/app/components/practical/views/navigation/pagination_component.rb +17 -28
  17. data/app/components/practical/views/open_drawer_button_component.rb +16 -0
  18. data/app/components/practical/views/page_component.html.erb +13 -1
  19. data/app/components/practical/views/page_component.rb +2 -0
  20. data/app/components/practical/views/toast_component.html.erb +1 -1
  21. data/app/components/practical/views/toast_component.rb +1 -3
  22. data/app/concerns/practical/auth/passkeys/controllers/emergency_registrations.rb +1 -1
  23. data/app/lib/practical/loaders/base.rb +15 -7
  24. data/app/lib/practical/test/helpers/integration/assertions.rb +1 -1
  25. data/app/lib/practical/test/helpers/passkey/system/selenium.rb +3 -1
  26. data/app/lib/practical/test/helpers/setup/debug.rb +7 -4
  27. data/app/lib/practical/test/helpers/system/assertions.rb +1 -1
  28. data/app/lib/practical/test/shared/auth/passkeys/controllers/emergency_registration/base.rb +18 -18
  29. data/app/lib/practical/test/shared/auth/passkeys/controllers/emergency_registration/self_service.rb +2 -2
  30. data/app/lib/practical/test/shared/auth/passkeys/controllers/passkey_management/base.rb +2 -2
  31. data/app/lib/practical/test/shared/auth/passkeys/controllers/registrations/self_signup.rb +1 -1
  32. data/app/lib/practical/test/shared/auth/passkeys/controllers/registrations/update.rb +2 -2
  33. data/app/lib/practical/test/shared/auth/passkeys/controllers/sessions/base.rb +2 -2
  34. data/app/lib/practical/test/shared/auth/passkeys/controllers/sessions/cross_pollination.rb +1 -1
  35. data/app/lib/practical/test/shared/memberships/controllers/membership_invitations/base.rb +1 -1
  36. data/app/lib/practical/test/shared/memberships/controllers/membership_invitations/register_with_passkey.rb +3 -3
  37. data/app/lib/practical/test/shared/memberships/controllers/organization/membership.rb +13 -11
  38. data/app/lib/practical/test/shared/memberships/controllers/user/membership.rb +7 -5
  39. data/app/lib/practical/views/button/styling.rb +8 -0
  40. data/app/lib/practical/views/error_response.rb +2 -2
  41. data/app/lib/practical/views/form_builders/base.rb +1 -0
  42. data/app/lib/practical/views/icon_set.rb +18 -8
  43. data/app/lib/practical/views/web_awesome/style_utility/appearance_variant.rb +4 -0
  44. data/app/lib/practical/views/web_awesome/style_utility/base.rb +4 -0
  45. data/app/lib/practical/views/web_awesome/style_utility/color_variant.rb +1 -1
  46. data/app/lib/practical/views/web_awesome/style_utility/size.rb +19 -2
  47. data/lib/generators/practical/views/component/component_generator.rb +2 -2
  48. data/lib/practical/pagy.rb +11 -0
  49. data/lib/practical/version.rb +1 -1
  50. data/lib/practical.rb +2 -1
  51. metadata +8 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5cd9e0fb40bc07050d68f122c8f99b2769ebc047de756ba4baba2df7eb5a5fd
4
- data.tar.gz: 4f9ea83a5bd5dc2b6da7a8a7b50321b185a1368abf820ba2c7abaac9e82468ae
3
+ metadata.gz: 9e7a07f1391054c9ea8b5743e39aa4a57cabc1da209f3b5d1fff81939f20d041
4
+ data.tar.gz: 6d8a26dc1d531ada515b79913137ff063f8ce0470b4e9cf3feb212bbd0188698
5
5
  SHA512:
6
- metadata.gz: 790f33b8ef5decf8588d588f798f2e9ac65cb8b776eb0ca108a124e361bed765ba8230d8637918a3e904db2c497237064421028993b876081130efab9482f3d3
7
- data.tar.gz: 0f07a49cd479ce6ff63d3627b1111e0908536e3b81807aec6daae24b913b342ab54d285b3c33e591d08071737a1da6007ced40112f21f62444efab9089aa4cc9
6
+ metadata.gz: 565c40aad6bf9c924c2941d27eb657994b22dc457ea0ccca2b54e9af3ee67db11f5a659403752e6ce085c864c0e1613d5536dc610206ffa0613d73f9f8e84086
7
+ data.tar.gz: b2d4c7c1d63b42edb948a5f99890eeaa253152a24af75d0fa8319c627fb1c6c07dc51254d396e6a20503fec304d488bed87604e62b1797c5626234a61bef88af
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Practical::Views::ButtonToComponent < Practical::Views::BaseComponent
4
+ include Practical::Views::Button::Styling
5
+ attr_accessor :url, :options, :appearance, :color_variant, :size, :html_options
6
+
7
+ def initialize(url:, options:, appearance: nil, color_variant: nil, size: nil, html_options: {})
8
+ self.url = url
9
+ self.options = options
10
+ self.html_options = html_options
11
+ initialize_style_utilities(appearance: appearance, color_variant: color_variant, size: size)
12
+ end
13
+
14
+ def call
15
+ html_option_defaults = {
16
+ class: css_classes_from_style_utilities,
17
+ data: {disable: true}
18
+ }
19
+
20
+ finalized_html_options = mix(html_option_defaults, html_options)
21
+ helpers.button_to(url, **options, **finalized_html_options) { content }
22
+ end
23
+ end
@@ -2,15 +2,20 @@
2
2
 
3
3
  class Practical::Views::FlashMessagesComponent < Practical::Views::BaseComponent
4
4
  def call
5
+ messages = toasts
5
6
  tag.aside(class: 'notification-messages wa-stack') do
6
- safe_join([
7
- alert_toast,
8
- notice_toast,
9
- success_toast,
10
- ])
7
+ safe_join(messages) if messages.present?
11
8
  end
12
9
  end
13
10
 
11
+ def toasts
12
+ [
13
+ alert_toast,
14
+ notice_toast,
15
+ success_toast,
16
+ ].compact
17
+ end
18
+
14
19
  def success_toast
15
20
  render_toast(
16
21
  color_variant: :success,
@@ -51,8 +56,11 @@ class Practical::Views::FlashMessagesComponent < Practical::Views::BaseComponent
51
56
  component = Practical::Views::ToastComponent.new(color_variant: color_variant)
52
57
 
53
58
  render component do |component|
54
- if icon.present? && icon.is_a?(Hash)
55
- icon = Practical::Views::IconComponent.new(**icon.to_h.symbolize_keys)
59
+ if icon.present? && (icon.is_a?(Hash) || icon.is_a?(ViewComponent::Base))
60
+ if icon.is_a?(Hash)
61
+ icon = Practical::Views::IconComponent.new(**icon.to_h.symbolize_keys)
62
+ end
63
+
56
64
  component.with_icon do
57
65
  render icon
58
66
  end
@@ -8,7 +8,7 @@ class Practical::Views::Form::ErrorListComponent < Practical::Views::BaseCompone
8
8
  end
9
9
 
10
10
  def call
11
- tag.ul(data: {'data-pf-error-container': true}) {
11
+ tag.ul {
12
12
  safe_join(errors.map{|error| render Practical::Views::Form::ErrorListItemComponent.new(error: error) })
13
13
  }
14
14
  end
@@ -12,8 +12,7 @@ class Practical::Views::Form::ErrorListItemComponent < Practical::Views::BaseCom
12
12
  end
13
13
 
14
14
  def call
15
- tag.li(class: 'wa-flank', data: {"pf-error-type": error.type, "pf-error-visible": true}) {
16
- render(icon_set.error_list_icon) +
15
+ tag.li(data: {"pf-error-type": error.type, "pf-error-visible": true}) {
17
16
  tag.span(error.message, data: { "pf-error-message": true })
18
17
  }
19
18
  end
@@ -1,7 +1,10 @@
1
- <%= tag.section(**finalized_options) do %>
2
- <header>
3
- <strong><%= blurb %></strong>
4
- </header>
1
+ <%= tag.wa_callout(variant: :danger) do %>
2
+ <%= render icon_set.error_callout_icon %>
3
+ <%= tag.section(**finalized_options) do %>
4
+ <header>
5
+ <strong><%= blurb %></strong>
6
+ </header>
5
7
 
6
- <%= render Practical::Views::Form::ErrorListComponent.new(errors: remaining_errors) %>
8
+ <%= render Practical::Views::Form::ErrorListComponent.new(errors: remaining_errors) %>
9
+ <% end %>
7
10
  <% end %>
@@ -11,7 +11,6 @@ class Practical::Views::Form::FallbackErrorsSectionComponent < Practical::Views:
11
11
 
12
12
  def finalized_options
13
13
  mix({
14
- class: ["wa-callout", "wa-danger"],
15
14
  data: {"pf-error-container": true, "pf-fallback-error-section": true},
16
15
  id: id
17
16
  }, @options)
@@ -0,0 +1,8 @@
1
+ <wa-callout variant="danger">
2
+ <%= render icon_set.error_callout_icon %>
3
+
4
+ <%= label(object_method, nil, finalized_options) do %>
5
+ <header data-pf-field-multiple-errors-blurb><strong><%= multiple_errors_blurb %></strong></header>
6
+ <%= render Practical::Views::Form::ErrorListComponent.new(errors: errors) %>
7
+ <% end %>
8
+ </wa-callout>
@@ -1,28 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Practical::Views::Form::FieldErrorsComponent < Practical::Views::BaseComponent
4
- attr_reader :f, :object_method, :options
4
+ attr_reader :f, :object_method, :multiple_errors_blurb, :options
5
5
 
6
- def initialize(f:, object_method:, options:)
6
+ def initialize(f:, object_method:, multiple_errors_blurb:, options:)
7
7
  @f = f
8
8
  @object_method = object_method
9
+ @multiple_errors_blurb = multiple_errors_blurb
9
10
  @options = options
10
11
  end
11
12
 
12
- def call
13
+ def errors
14
+ f.errors_for(object_method) || []
15
+ end
16
+
17
+ def finalized_options
13
18
  id = f.field_errors_id(object_method)
14
- classes = ["error-section", "wa-callout", "wa-danger"]
15
- errors = f.errors_for(object_method)
19
+ classes = ["error-section"]
16
20
 
17
21
  if errors.blank?
18
22
  classes << ["no-server-errors"]
19
- errors = []
20
23
  end
21
24
 
22
- finalized_options = mix({id: id, class: classes}, options)
23
-
24
- return label(object_method, nil, finalized_options) {
25
- render Practical::Views::Form::ErrorListComponent.new(errors: errors)
26
- }
25
+ return mix({
26
+ id: id,
27
+ class: classes,
28
+ data: {'pf-error-container': true}
29
+ }, options)
27
30
  end
28
31
  end
@@ -1,4 +1,4 @@
1
- <section class='wa-stack wa-gap-3xs'>
1
+ <section class='wa-stack wa-gap-2xs'>
2
2
  <%= tag.label(**label_options) do %>
3
3
  <%= label %>
4
4
  <%= field %>
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Practical::Views::Form::InputComponent < Practical::Views::BaseComponent
4
+ class FieldOptionsNotCalledError < StandardError; end
4
5
  attr_accessor :f, :object_method, :label_options
5
6
 
6
7
  renders_one :label
@@ -17,6 +18,19 @@ class Practical::Views::Form::InputComponent < Practical::Views::BaseComponent
17
18
  end
18
19
 
19
20
  def field_options(**options)
20
- mix({"aria-describedby": field_errors_id}, options)
21
+ @_field_options_called = true
22
+ return mix({
23
+ "aria-describedby": field_errors_id,
24
+ "data": {"pf-initial-load-errors": f.errors_for(object_method)&.any? }
25
+ }, options)
26
+ end
27
+
28
+ def around_render
29
+ result = yield
30
+ unless @_field_options_called
31
+ raise FieldOptionsNotCalledError, "field_options was not called when rendering an InputComponent; which means this the input & its error container are not connected."
32
+ end
33
+
34
+ return result
21
35
  end
22
36
  end
@@ -1,5 +1,5 @@
1
1
  <%= tag.dialog(**finalized_options) do %>
2
- <header>
2
+ <header class="wa-flank:end">
3
3
  <h2><%= header %></h2>
4
4
  <form method="dialog">
5
5
  <button class="wa-plain"><%= render icon_set.dialog_close_icon %></button>
@@ -11,6 +11,6 @@ class Practical::Views::ModalDialogComponent < Practical::Views::BaseComponent
11
11
  end
12
12
 
13
13
  def finalized_options
14
- mix({id: id, open: open, data: {ensure_modal: true}, class: 'wa-dialog-stack-patch'}, options)
14
+ mix({id: id, open: open, data: {ensure_modal: true}, class: 'wa-dialog-stack-patch wa-dialog-contents-patch'}, options)
15
15
  end
16
16
  end
@@ -1,21 +1,15 @@
1
1
  <%= render Practical::Views::OpenDialogButtonComponent.new(dialog_id: dialog_id, appearance: "filled outlined", size: :small) do %>
2
- <%= pagy_t('pagy.nav.gap').html_safe %>
2
+ <%= Pagy::I18n.translate('pagy.nav.gap').html_safe %>
3
3
  <% end %>
4
4
 
5
5
  <%= render Practical::Views::ModalDialogComponent.new(id: dialog_id) do |component| %>
6
6
 
7
7
  <% component.with_header do %>
8
- <%= pagy_t("pagy.nav.goto_page_form.legend") %>
8
+ <%= Pagy::I18n.translate("pagy.nav.goto_page_form.legend") %>
9
9
  <% end %>
10
10
  <section class="wa-stack">
11
11
  <p><%= page_detail_text %></p>
12
- <%= helpers.webawesome_form_with(
13
- url: uri_parts.uri.to_s,
14
- method: :get,
15
- local: true,
16
- builder: NewApplicationFormBuilder,
17
- class: 'pagination-goto-form wa-size-s'
18
- ) do |f| %>
12
+ <%= form_wrapper do |f| %>
19
13
  <% uri_parts.params.each do |key, value| %>
20
14
  <%= hidden_field_for_goto_form(key: key, value: value) %>
21
15
  <% end %>
@@ -23,7 +17,7 @@
23
17
  <section class="wa-cluster">
24
18
  <%= f.number_field :page, value: pagy.page, placeholder: pagy.page.to_s, required: true, min: 1, max: pagy.last %>
25
19
  <%= f.button_component(type: :submit, color_variant: :neutral, appearance: :filled) do
26
- pagy_t("pagy.nav.goto_page_form.button")
20
+ Pagy::I18n.translate("pagy.nav.goto_page_form.button")
27
21
  end %>
28
22
  </section>
29
23
  <% end %>
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Practical::Views::Navigation::Pagination::GotoFormComponent < Practical::Views::BaseComponent
4
- include Pagy::Frontend
4
+ include Practical::Views::FormWrapper
5
5
  attr_accessor :pagy, :dialog_id, :page_detail_text
6
6
 
7
7
  URIParts = Data.define(:uri, :params)
@@ -13,7 +13,7 @@ class Practical::Views::Navigation::Pagination::GotoFormComponent < Practical::V
13
13
  end
14
14
 
15
15
  def uri_parts
16
- uri = URI.parse(pagy_url_for(pagy, nil))
16
+ uri = URI.parse(pagy.page_url)
17
17
  params = Rack::Utils.parse_query(uri.query)
18
18
  params.delete("page")
19
19
  uri.query = ""
@@ -31,4 +31,19 @@ class Practical::Views::Navigation::Pagination::GotoFormComponent < Practical::V
31
31
  helpers.hidden_field_tag key, value
32
32
  end
33
33
  end
34
+
35
+ def generic_errors_id
36
+ "#{dialog_id}_pagination"
37
+ end
38
+
39
+ def form_wrapper(&block)
40
+ wrapped_form_with(
41
+ url: uri_parts.uri.to_s,
42
+ method: :get,
43
+ local: true,
44
+ builder: ApplicationFormBuilder,
45
+ class: 'pagination-goto-form wa-size-s',
46
+ &block
47
+ )
48
+ end
34
49
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Practical::Views::Navigation::PaginationComponent < ApplicationComponent
4
- include Pagy::Frontend
5
4
  attr_reader :request
6
5
  attr_accessor :pagy, :item_name, :i18n_key
7
6
 
@@ -15,40 +14,35 @@ class Practical::Views::Navigation::PaginationComponent < ApplicationComponent
15
14
  def page_detail_text
16
15
  pagy_count = pagy.count
17
16
  if pagy_count == 0
18
- key = "pagy.info.no_items"
17
+ key = "pagy.info_tag.no_items"
19
18
  elsif pagy.pages == 1
20
- key = "pagy.info.single_page"
19
+ key = "pagy.info_tag.single_page"
21
20
  else
22
- key = "pagy.info.multiple_pages"
21
+ key = "pagy.info_tag.multiple_pages"
23
22
  end
24
23
 
25
- item_name = item_name.presence || pagy_t(i18n_key || pagy.vars[:i18n_key], count: pagy_count)
24
+ item_name = item_name.presence || Pagy::I18n.translate(i18n_key || pagy.vars[:i18n_key], count: pagy_count)
26
25
 
27
- item_text = pagy_t(key,
26
+ item_text = Pagy::I18n.translate(key,
28
27
  item_name: item_name,
29
28
  count: pagy_count, from: pagy.from, to: pagy.to
30
29
  )
31
30
 
32
- page_count_text = pagy_t("pagy.info.page_count", page: pagy.page, count: pagy.pages)
31
+ page_count_text = Pagy::I18n.translate("pagy.info_tag.page_count", page: pagy.page, count: pagy.pages)
33
32
 
34
- return pagy_t("pagy.info.page_detail_text", item_text: item_text, page_count_text: page_count_text)
33
+ return Pagy::I18n.translate("pagy.info_tag.page_detail_text", item_text: item_text, page_count_text: page_count_text)
35
34
  end
36
35
 
37
36
  def previous_item
38
- classes = helpers.class_names(:page, :previous, disabled: !pagy.prev)
39
-
40
- text = icon_text(
41
- icon: icon_set.previous_arrow,
42
- text: pagy_t('pagy.nav.v2_prev')
43
- )
37
+ classes = helpers.class_names(:page, :previous, disabled: !pagy.previous)
44
38
 
45
39
  tag.div(class: classes, role: :listitem){
46
- if pagy.prev
47
- tag.a(href: pagy_url_for(pagy, pagy.prev), title: pagy_t("pagy.nav.prev_page_title")) {
48
- text
40
+ if pagy.previous
41
+ tag.a(href: pagy.page_url(pagy.previous), title: Pagy::I18n.translate("pagy.aria_label.previous")) {
42
+ render icon_set.previous_arrow
49
43
  }
50
44
  else
51
- text
45
+ render icon_set.previous_arrow
52
46
  end
53
47
  }
54
48
  end
@@ -56,18 +50,13 @@ class Practical::Views::Navigation::PaginationComponent < ApplicationComponent
56
50
  def next_item
57
51
  classes = helpers.class_names(:page, :next, disabled: !pagy.next)
58
52
 
59
- text = icon_text(
60
- icon: icon_set.next_arrow,
61
- text: pagy_t('pagy.nav.v2_next')
62
- )
63
-
64
53
  tag.div(class: classes, role: :listitem){
65
54
  if pagy.next
66
- tag.a(href: pagy_url_for(pagy, pagy.next), title: pagy_t("pagy.nav.next_page_title")) {
67
- text
55
+ tag.a(href: pagy.page_url(pagy.next), title: Pagy::I18n.translate("pagy.aria_label.next")) {
56
+ render icon_set.next_arrow
68
57
  }
69
58
  else
70
- text
59
+ render icon_set.next_arrow
71
60
  end
72
61
  }
73
62
  end
@@ -80,12 +69,12 @@ class Practical::Views::Navigation::PaginationComponent < ApplicationComponent
80
69
  case item
81
70
  when Integer
82
71
  tag.div(class: :page, role: :listitem) {
83
- tag.a(item, href: pagy_url_for(pagy, item), title: pagy_t("pagy.nav.page_title", page_number: item))
72
+ tag.a(item, href: pagy.page_url(item), title: Pagy::I18n.translate("pagy.nav.page_title", page_number: item))
84
73
  }
85
74
  when String
86
75
  tag.div(
87
76
  item,
88
- class: "page current", role: :listitem, title: pagy_t("pagy.nav.current_page_title", page_number: item)
77
+ class: "page current", role: :listitem, title: Pagy::I18n.translate("pagy.nav.current_page_title", page_number: item)
89
78
  )
90
79
  when :gap
91
80
  render Practical::Views::Navigation::Pagination::GotoFormComponent.new(
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Practical::Views::OpenDrawerButtonComponent < Practical::Views::ButtonComponent
4
+ attr_accessor :drawer_id
5
+
6
+ def initialize(drawer_id:, appearance: nil, color_variant: nil, size: nil, options: {})
7
+ options = options.with_defaults(
8
+ onclick: self.class.inline_js_to_open_dialog(drawer_id: drawer_id)
9
+ )
10
+ super(type: :button, appearance: appearance, color_variant: color_variant, size: size, options: options)
11
+ end
12
+
13
+ def self.inline_js_to_open_dialog(drawer_id:)
14
+ return "document.getElementById(`#{drawer_id}`).open = true"
15
+ end
16
+ end
@@ -41,10 +41,22 @@
41
41
  </aside>
42
42
  <% end %>
43
43
 
44
- <main class="wa-body-l">
44
+ <main>
45
45
  <%= content %>
46
46
  </main>
47
47
 
48
+ <% if aside? %>
49
+ <aside slot="aside">
50
+ <%= aside %>
51
+ </aside>
52
+ <% end %>
53
+
54
+ <% if main_footer? %>
55
+ <footer slot="main-footer">
56
+ <%= main_footer %>
57
+ </footer>
58
+ <% end %>
59
+
48
60
  <% if footer? %>
49
61
  <footer slot="footer">
50
62
  <%= footer %>
@@ -6,7 +6,9 @@ class Practical::Views::PageComponent < Practical::Views::BaseComponent
6
6
  renders_one :subheader
7
7
  renders_one :footer
8
8
  renders_one :main_header
9
+ renders_one :main_footer
9
10
  renders_one :navigation
10
11
  renders_one :navigation_header
11
12
  renders_one :navigation_footer
13
+ renders_one :aside
12
14
  end
@@ -1,6 +1,6 @@
1
1
  <toast-dialog>
2
2
  <dialog open class='wa-off toast'>
3
- <%= tag.section(**finalized_callout_options) do %>
3
+ <%= tag.wa_callout(**finalized_callout_options) do %>
4
4
  <div class="wa-flank:end wa-gap-xs">
5
5
  <% if icon? %>
6
6
  <section class='wa-flank'>
@@ -12,8 +12,6 @@ class Practical::Views::ToastComponent < Practical::Views::BaseComponent
12
12
  end
13
13
 
14
14
  def finalized_callout_options
15
- mix({
16
- class: class_names("wa-callout", css_classes_from_style_utilities)
17
- }, options)
15
+ mix(attributes_from_style_utilities, options)
18
16
  end
19
17
  end
@@ -52,6 +52,6 @@ module Practical::Auth::Passkeys::Controllers::EmergencyRegistrations
52
52
  helpers: helpers
53
53
  )
54
54
 
55
- render json: errors, status: :unprocessable_entity
55
+ render json: errors, status: :unprocessable_content
56
56
  end
57
57
  end
@@ -1,17 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Practical::Loaders::Base
4
- include Pagy::Backend
4
+ include Pagy::Method
5
5
 
6
- attr_accessor :params, :base_relation, :datatable_form, :relation_builder, :pagy_instance, :records
6
+ attr_accessor :request, :base_relation, :datatable_form,
7
+ :relation_builder, :pagy_instance, :records
7
8
 
8
- def initialize(params:, base_relation:)
9
- self.params = params
9
+ delegate :params, to: :request
10
+
11
+ def initialize(request:, base_relation:)
12
+ self.request = request
10
13
  self.base_relation = base_relation
11
14
  end
12
15
 
13
- def self.load(params:, base_relation:)
14
- instance = self.new(params: params, base_relation: base_relation)
16
+ def self.load(request:, base_relation:)
17
+ instance = self.new(request: request, base_relation: base_relation)
15
18
  instance.load
16
19
  return instance
17
20
  end
@@ -19,7 +22,7 @@ class Practical::Loaders::Base
19
22
  def load
20
23
  self.datatable_form = build_datatable_form
21
24
  self.relation_builder = build_relation_builder
22
- self.pagy_instance, self.records = pagy(relation_builder.applied_relation, overflow: :last_page)
25
+ self.pagy_instance, self.records = pagy(relation_builder.applied_relation)
23
26
  end
24
27
 
25
28
  def datatable_payload
@@ -41,4 +44,9 @@ class Practical::Loaders::Base
41
44
  def default_payload
42
45
  raise NotImplementedError
43
46
  end
47
+
48
+ def params
49
+ return request.params if request.params.kind_of?(ActionController::Parameters)
50
+ return ActionController::Parameters.new(request.params)
51
+ end
44
52
  end
@@ -18,6 +18,6 @@ module Practical::Test::Helpers::Integration::Assertions
18
18
  end
19
19
 
20
20
  def assert_error_dom(container_id:, message:)
21
- assert_dom("##{container_id}", text: message)
21
+ assert_dom("##{container_id}", text: %r{#{message}})
22
22
  end
23
23
  end
@@ -24,7 +24,9 @@ module Practical::Test::Helpers::Passkey::System::Selenium
24
24
 
25
25
  driven_by :selenium, using: selenium_driver_key, screen_size: [1400, 1400] do |options|
26
26
  options.accept_insecure_certs = true
27
- options.args << "--auto-open-devtools-for-tabs"
27
+ if ENV.has_key?("HEADLESS_TESTS")
28
+ options.args << "--headless=new"
29
+ end
28
30
  end
29
31
  end
30
32
 
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Practical::Test::Helpers::Setup::Debug
4
- # rubocop:disable Rails/Output
5
- puts "MINITEST_PARALLEL_EXECUTOR_SIZE: #{Minitest.parallel_executor.size}"
6
- puts "PARALLEL_WORKERS: #{ENV["PARALLEL_WORKERS"]}"
7
- # rubocop:enable Rails/Output
4
+ extend ActiveSupport::Concern
5
+ included do
6
+ # rubocop:disable Rails/Output
7
+ puts "MINITEST_PARALLEL_EXECUTOR_SIZE: #{Minitest.parallel_executor.size}"
8
+ puts "PARALLEL_WORKERS: #{ENV["PARALLEL_WORKERS"]}"
9
+ # rubocop:enable Rails/Output
10
+ end
8
11
  end
@@ -3,7 +3,7 @@
3
3
  module Practical::Test::Helpers::System::Assertions
4
4
  def assert_toast_message(text:)
5
5
  within(".notification-messages") do
6
- assert_selector("dialog", text: text)
6
+ assert_selector("dialog", text: text, visible: :all)
7
7
  end
8
8
  end
9
9