spree_admin 5.2.0.rc2 → 5.2.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.
Files changed (188) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/spree/admin/application.scss +1 -1
  3. data/app/assets/stylesheets/spree/admin/components/_alerts.scss +1 -1
  4. data/app/assets/stylesheets/spree/admin/components/_buttons.scss +5 -4
  5. data/app/assets/stylesheets/spree/admin/components/_dialogs.scss +0 -1
  6. data/app/assets/stylesheets/spree/admin/components/_dropdowns.scss +6 -0
  7. data/app/assets/stylesheets/spree/admin/components/_main.scss +2 -233
  8. data/app/assets/stylesheets/spree/admin/components/_sidebar.scss +693 -0
  9. data/app/assets/stylesheets/spree/admin/components/_tables.scss +2 -2
  10. data/app/assets/stylesheets/spree/admin/components/_variants_form.scss +1 -2
  11. data/app/assets/stylesheets/spree/admin/global/_variables.scss +15 -12
  12. data/app/assets/stylesheets/spree/admin/shared/_base.scss +9 -3
  13. data/app/assets/stylesheets/spree/admin/shared/_forms.scss +5 -6
  14. data/app/assets/stylesheets/spree/admin/views/_dashboard.scss +14 -0
  15. data/app/controllers/spree/admin/admin_users_controller.rb +0 -2
  16. data/app/controllers/spree/admin/checkouts_controller.rb +1 -4
  17. data/app/controllers/spree/admin/coupon_codes_controller.rb +0 -14
  18. data/app/controllers/spree/admin/customer_returns_controller.rb +0 -13
  19. data/app/controllers/spree/admin/digital_assets_controller.rb +2 -2
  20. data/app/controllers/spree/admin/exports_controller.rb +2 -9
  21. data/app/controllers/spree/admin/gift_cards_controller.rb +7 -14
  22. data/app/controllers/spree/admin/integrations_controller.rb +1 -1
  23. data/app/controllers/spree/admin/invitations_controller.rb +0 -2
  24. data/app/controllers/spree/admin/metafields_controller.rb +1 -1
  25. data/app/controllers/spree/admin/oauth_applications_controller.rb +0 -10
  26. data/app/controllers/spree/admin/option_types_controller.rb +0 -10
  27. data/app/controllers/spree/admin/orders_controller.rb +1 -1
  28. data/app/controllers/spree/admin/page_blocks_controller.rb +1 -1
  29. data/app/controllers/spree/admin/pages_controller.rb +1 -1
  30. data/app/controllers/spree/admin/payment_methods_controller.rb +1 -11
  31. data/app/controllers/spree/admin/policies_controller.rb +4 -0
  32. data/app/controllers/spree/admin/posts_controller.rb +2 -10
  33. data/app/controllers/spree/admin/promotion_actions_controller.rb +1 -1
  34. data/app/controllers/spree/admin/promotion_rules_controller.rb +1 -1
  35. data/app/controllers/spree/admin/promotions_controller.rb +1 -1
  36. data/app/controllers/spree/admin/properties_controller.rb +0 -12
  37. data/app/controllers/spree/admin/reports_controller.rb +1 -1
  38. data/app/controllers/spree/admin/resource_controller.rb +27 -17
  39. data/app/controllers/spree/admin/return_authorizations_controller.rb +0 -10
  40. data/app/controllers/spree/admin/shipping_methods_controller.rb +4 -0
  41. data/app/controllers/spree/admin/stock_items_controller.rb +8 -11
  42. data/app/controllers/spree/admin/stock_locations_controller.rb +1 -1
  43. data/app/controllers/spree/admin/stock_transfers_controller.rb +0 -10
  44. data/app/controllers/spree/admin/store_credits_controller.rb +35 -35
  45. data/app/controllers/spree/admin/taxonomies_controller.rb +0 -10
  46. data/app/controllers/spree/admin/taxons_controller.rb +1 -1
  47. data/app/controllers/spree/admin/themes_controller.rb +6 -2
  48. data/app/controllers/spree/admin/translations_controller.rb +1 -1
  49. data/app/controllers/spree/admin/users_controller.rb +7 -17
  50. data/app/controllers/spree/admin/webhooks_subscribers_controller.rb +0 -10
  51. data/app/controllers/spree/admin/zones_controller.rb +0 -7
  52. data/app/helpers/spree/admin/base_helper.rb +1 -1
  53. data/app/helpers/spree/admin/drawer_helper.rb +6 -6
  54. data/app/helpers/spree/admin/dropdown_helper.rb +26 -16
  55. data/app/helpers/spree/admin/modal_helper.rb +2 -0
  56. data/app/helpers/spree/admin/navigation_helper.rb +47 -4
  57. data/app/helpers/spree/admin/orders_filters_helper.rb +3 -0
  58. data/app/helpers/spree/admin/promotion_actions_helper.rb +1 -1
  59. data/app/helpers/spree/admin/promotion_rules_helper.rb +1 -1
  60. data/app/helpers/spree/admin/translations_helper.rb +1 -1
  61. data/app/javascript/spree/admin/application.js +2 -1
  62. data/app/javascript/spree/admin/controllers/dropdown_controller.js +85 -14
  63. data/app/javascript/spree/admin/controllers/sidebar_controller.js +231 -0
  64. data/app/javascript/spree/admin/controllers/tooltip_controller.js +84 -31
  65. data/app/models/spree/admin/form_builder.rb +76 -17
  66. data/app/models/spree/admin/navigation/builder.rb +82 -0
  67. data/app/models/spree/admin/navigation/item.rb +177 -0
  68. data/app/models/spree/admin/navigation.rb +193 -0
  69. data/app/views/layouts/spree/admin.html.erb +1 -1
  70. data/app/views/spree/admin/assets/edit.html.erb +1 -1
  71. data/app/views/spree/admin/custom_domains/_custom_domains.html.erb +1 -1
  72. data/app/views/spree/admin/custom_domains/_form.html.erb +2 -14
  73. data/app/views/spree/admin/digital_assets/_table.html.erb +1 -1
  74. data/app/views/spree/admin/gift_cards/_filters.html.erb +25 -16
  75. data/app/views/spree/admin/gift_cards/index.html.erb +1 -1
  76. data/app/views/spree/admin/integrations/index.html.erb +20 -8
  77. data/app/views/spree/admin/invitations/new.html.erb +2 -1
  78. data/app/views/spree/admin/metafield_definitions/_filters.html.erb +1 -1
  79. data/app/views/spree/admin/newsletter_subscribers/_filters.html.erb +1 -1
  80. data/app/views/spree/admin/newsletter_subscribers/_table_header.html.erb +2 -2
  81. data/app/views/spree/admin/oauth_applications/_table_header.html.erb +1 -1
  82. data/app/views/spree/admin/orders/_customer.html.erb +3 -3
  83. data/app/views/spree/admin/orders/_filters.html.erb +33 -25
  84. data/app/views/spree/admin/orders/_header.html.erb +0 -5
  85. data/app/views/spree/admin/orders/_list.html.erb +3 -3
  86. data/app/views/spree/admin/orders/_table_filter_dropdown.html.erb +1 -1
  87. data/app/views/spree/admin/page_blocks/edit.html.erb +3 -3
  88. data/app/views/spree/admin/page_blocks/forms/_image.html.erb +2 -5
  89. data/app/views/spree/admin/page_builder/_add_block.html.erb +1 -1
  90. data/app/views/spree/admin/page_builder/_header.html.erb +1 -1
  91. data/app/views/spree/admin/page_builder/_pages_dropdown.html.erb +2 -2
  92. data/app/views/spree/admin/page_builder/_sidebar_block.html.erb +1 -1
  93. data/app/views/spree/admin/page_builder/_sidebar_colors.html.erb +2 -2
  94. data/app/views/spree/admin/page_builder/_sidebar_fonts.html.erb +3 -3
  95. data/app/views/spree/admin/page_builder/_sidebar_section.html.erb +1 -1
  96. data/app/views/spree/admin/page_links/_form.html.erb +4 -13
  97. data/app/views/spree/admin/page_links/_list.html.erb +1 -1
  98. data/app/views/spree/admin/page_links/edit.html.erb +1 -1
  99. data/app/views/spree/admin/page_sections/edit.html.erb +3 -3
  100. data/app/views/spree/admin/page_sections/forms/_header.html.erb +0 -2
  101. data/app/views/spree/admin/page_sections/new.html.erb +1 -1
  102. data/app/views/spree/admin/pages/_table_header.html.erb +3 -3
  103. data/app/views/spree/admin/payment_methods/index.html.erb +5 -1
  104. data/app/views/spree/admin/payments/_payment.html.erb +7 -0
  105. data/app/views/spree/admin/policies/_filters.html.erb +1 -1
  106. data/app/views/spree/admin/posts/_form.html.erb +1 -4
  107. data/app/views/spree/admin/posts/filters.html.erb +18 -8
  108. data/app/views/spree/admin/products/_bulk_operations.html.erb +2 -2
  109. data/app/views/spree/admin/products/_filters.html.erb +17 -6
  110. data/app/views/spree/admin/products/_table_filter_dropdown.html.erb +1 -1
  111. data/app/views/spree/admin/products/edit.html.erb +0 -2
  112. data/app/views/spree/admin/products/form/_status.html.erb +0 -3
  113. data/app/views/spree/admin/products/form/_variants.html.erb +1 -1
  114. data/app/views/spree/admin/profile/edit.html.erb +9 -61
  115. data/app/views/spree/admin/promotions/_filters.html.erb +23 -13
  116. data/app/views/spree/admin/promotions/_table_filter_dropdown.html.erb +1 -1
  117. data/app/views/spree/admin/promotions/_table_header.html.erb +1 -1
  118. data/app/views/spree/admin/promotions/form/_kind.html.erb +4 -4
  119. data/app/views/spree/admin/promotions/form/_settings.html.erb +2 -13
  120. data/app/views/spree/admin/refund_reasons/_table_header.html.erb +1 -1
  121. data/app/views/spree/admin/refunds/_form.html.erb +1 -9
  122. data/app/views/spree/admin/reimbursement_types/_table_header.html.erb +1 -1
  123. data/app/views/spree/admin/return_authorization_reasons/_table_header.html.erb +1 -1
  124. data/app/views/spree/admin/return_authorizations/filters.html.erb +1 -1
  125. data/app/views/spree/admin/roles/index.html.erb +1 -1
  126. data/app/views/spree/admin/shared/_audit_nav.html.erb +2 -0
  127. data/app/views/spree/admin/shared/_calendar_range_picker.html.erb +2 -2
  128. data/app/views/spree/admin/shared/_content_header.html.erb +5 -2
  129. data/app/views/spree/admin/shared/_developers_nav.html.erb +2 -4
  130. data/app/views/spree/admin/shared/_header.html.erb +5 -7
  131. data/app/views/spree/admin/shared/_index_table.html.erb +5 -4
  132. data/app/views/spree/admin/shared/_index_table_options.html.erb +1 -1
  133. data/app/views/spree/admin/shared/_navigation.html.erb +5 -0
  134. data/app/views/spree/admin/shared/_navigation_item.html.erb +64 -0
  135. data/app/views/spree/admin/shared/_new_item_dropdown.html.erb +2 -2
  136. data/app/views/spree/admin/shared/_page_section_image.html.erb +2 -5
  137. data/app/views/spree/admin/shared/_page_section_logo.html.erb +1 -1
  138. data/app/views/spree/admin/shared/_returns_and_refunds_nav.html.erb +2 -3
  139. data/app/views/spree/admin/shared/_shipping_nav.html.erb +3 -2
  140. data/app/views/spree/admin/shared/_sidebar.html.erb +33 -7
  141. data/app/views/spree/admin/shared/_stock_nav.html.erb +6 -3
  142. data/app/views/spree/admin/shared/_tax_nav.html.erb +1 -2
  143. data/app/views/spree/admin/shared/_team_nav.html.erb +2 -3
  144. data/app/views/spree/admin/shared/_user_dropdown.html.erb +29 -19
  145. data/app/views/spree/admin/shared/sidebar/_customers_nav.html.erb +7 -0
  146. data/app/views/spree/admin/shared/sidebar/_orders_nav.html.erb +22 -2
  147. data/app/views/spree/admin/shared/sidebar/_products_nav.html.erb +21 -0
  148. data/app/views/spree/admin/shared/sidebar/_promotions_nav.html.erb +8 -0
  149. data/app/views/spree/admin/shared/sidebar/_returns_nav.html.erb +12 -0
  150. data/app/views/spree/admin/shared/sidebar/_store_dropdown.html.erb +4 -2
  151. data/app/views/spree/admin/shared/sidebar/_store_nav.html.erb +15 -1
  152. data/app/views/spree/admin/shared/sidebar/_storefront_nav.html.erb +25 -3
  153. data/app/views/spree/admin/shared/sortable_tree/_taxonomy.html.erb +1 -1
  154. data/app/views/spree/admin/shipping_categories/_table_header.html.erb +1 -1
  155. data/app/views/spree/admin/shipping_methods/_table_header.html.erb +1 -1
  156. data/app/views/spree/admin/stock_items/_filters.html.erb +18 -8
  157. data/app/views/spree/admin/stock_locations/_table_header.html.erb +2 -2
  158. data/app/views/spree/admin/stock_locations/_table_row.html.erb +1 -1
  159. data/app/views/spree/admin/stock_transfers/_filters.html.erb +19 -9
  160. data/app/views/spree/admin/store_credit_categories/index.html.erb +1 -1
  161. data/app/views/spree/admin/store_credits/_list.html.erb +3 -3
  162. data/app/views/spree/admin/storefront/edit.html.erb +2 -14
  163. data/app/views/spree/admin/stores/form/_basic.html.erb +2 -8
  164. data/app/views/spree/admin/stores/form/_checkout.html.erb +2 -2
  165. data/app/views/spree/admin/stores/form/_checkout_links.html.erb +1 -1
  166. data/app/views/spree/admin/stores/form/_emails.html.erb +1 -1
  167. data/app/views/spree/admin/tax_categories/_table_header.html.erb +2 -2
  168. data/app/views/spree/admin/tax_rates/_form.html.erb +1 -10
  169. data/app/views/spree/admin/tax_rates/_table_header.html.erb +2 -2
  170. data/app/views/spree/admin/taxonomies/_table_header.html.erb +1 -1
  171. data/app/views/spree/admin/taxons/_form.html.erb +2 -9
  172. data/app/views/spree/admin/themes/_theme.html.erb +1 -1
  173. data/app/views/spree/admin/translations/translation_rows/_permalink_field_row.html.erb +1 -12
  174. data/app/views/spree/admin/users/_filters.html.erb +26 -17
  175. data/app/views/spree/admin/users/index.html.erb +1 -1
  176. data/config/initializers/spree_admin_navigation.rb +510 -0
  177. data/config/locales/en.yml +6 -0
  178. data/lib/generators/spree/admin/scaffold/templates/controller.rb.tt +3 -1
  179. data/lib/generators/spree/admin/scaffold/templates/views/_filters.html.erb.tt +1 -1
  180. data/lib/generators/spree/admin/scaffold/templates/views/_table_header.html.erb.tt +2 -2
  181. data/lib/generators/spree/admin/scaffold/templates/views/_table_row.html.erb.tt +8 -6
  182. data/lib/spree/admin/engine.rb +64 -2
  183. data/lib/spree/admin/runtime_configuration.rb +1 -0
  184. data/lib/spree/admin.rb +20 -0
  185. metadata +17 -15
  186. data/app/assets/stylesheets/spree/admin/components/_offcanvas.scss +0 -26
  187. data/app/javascript/spree/admin/helpers/canvas.js +0 -29
  188. data/app/views/spree/admin/shared/_offcanvas_nav.html.erb +0 -12
@@ -25,10 +25,7 @@
25
25
  <div class="col-lg-4">
26
26
  <div class="card mb-4">
27
27
  <div class="card-body">
28
- <div class="form-group">
29
- <%= f.label :image, Spree.t(:featured_image) %>
30
- <%= render 'active_storage/upload_form', form: f, field_name: :image, width: 1200, height: 600, crop: true, css: 'flex-col' %>
31
- </div>
28
+ <%= f.spree_file_field :image, width: 1200, height: 600, crop: true, css: 'flex-col', label: Spree.t(:featured_image) %>
32
29
  </div>
33
30
  </div>
34
31
 
@@ -1,10 +1,16 @@
1
- <%= search_form_for [:admin, @search], class: "filter-wrap", data: {controller: "filters dropdown"} do |f| %>
2
- <div class="d-flex flex-column flex-lg-row gap-2">
3
- <%= render 'spree/admin/shared/filters_search_bar', param: :search_by_title, label: Spree.t(:title) %>
1
+ <%= search_form_for [:admin, @search], class: "filter-wrap", data: {controller: "filters dialog"} do |f| %>
2
+ <div class="d-flex flex-column flex-lg-row gap-2">
3
+ <%= render 'spree/admin/shared/filters_search_bar', param: :search_by_title, label: Spree.t(:title) %>
4
4
 
5
- <%= render 'spree/admin/shared/filters_button' %>
6
- </div>
7
- <div data-dropdown-target="menu" id="table-filter" class="hidden">
5
+ <%= button_tag type: 'button', class: 'btn btn-light d-flex align-items-center', data: { action: 'dialog#open' } do %>
6
+ <%= icon "adjustments", class: "mr-1" %>
7
+ <%= Spree.t("admin.filters") %>
8
+ <% end %>
9
+ </div>
10
+
11
+ <dialog class="drawer" data-dialog-target="dialog" id="posts-filters-drawer">
12
+ <%= drawer_header(Spree.t(:filter), 'dialog') %>
13
+ <div class="drawer-body">
8
14
  <div class="form-group">
9
15
  <%= f.label :author_id_eq, Spree.t(:author) %>
10
16
  <%= f.select :author_id_eq,
@@ -20,8 +26,12 @@
20
26
  { data: { filters_target: :input, controller: 'autocomplete-select' } } %>
21
27
  </div>
22
28
  <%= render_admin_partials(:posts_filters_partials, f: f) %>
23
- <%= render 'spree/admin/shared/filter_submit' %>
24
- </div>
29
+ </div>
30
+ <div class="drawer-footer">
31
+ <%= drawer_discard_button('dialog') %>
32
+ <%= render 'spree/admin/shared/filter_submit' %>
33
+ </div>
34
+ </dialog>
25
35
 
26
36
  <%= render "spree/admin/shared/filter_badge_template" %>
27
37
 
@@ -18,11 +18,11 @@
18
18
  url: spree.bulk_status_update_admin_products_path(status: :draft)
19
19
  ) %>
20
20
 
21
- <%= dropdown do %>
21
+ <%= dropdown direction: 'top', portal: false do %>
22
22
  <%= dropdown_toggle do %>
23
23
  <%= icon('dots-vertical', class: "mr-0") %>
24
24
  <% end %>
25
- <%= dropdown_menu direction: 'top', class: 'mb-2' do %>
25
+ <%= dropdown_menu class: 'mb-2' do %>
26
26
  <%= bulk_action_link(
27
27
  Spree.t("admin.bulk_ops.products.title.set_status", status: :archived),
28
28
  spree.bulk_modal_admin_products_path(kind: :set_status, status: :archived),
@@ -1,9 +1,10 @@
1
1
  <% frame_name ||= nil %>
2
2
 
3
+
3
4
  <%= search_form_for product_list_filters_search_form_path,
4
5
  class: "filter-wrap",
5
6
  data: {
6
- controller: "filters dropdown",
7
+ controller: "filters dialog",
7
8
  filters_url_value: request.url
8
9
  } do |f| %>
9
10
  <%= hidden_field_tag :frame_name, frame_name if frame_name.present? %>
@@ -11,9 +12,15 @@
11
12
  <div class="d-flex flex-column flex-lg-row gap-2">
12
13
  <%= render 'spree/admin/shared/filters_search_bar', param: :multi_search %>
13
14
  <%= render "spree/admin/products/table_filter_dropdown" %>
14
- <%= render 'spree/admin/shared/filters_button' %>
15
+ <%= button_tag type: 'button', class: 'btn btn-light d-flex align-items-center', data: { action: 'dialog#open' } do %>
16
+ <%= icon "adjustments", class: "mr-1" %>
17
+ <%= Spree.t("admin.filters") %>
18
+ <% end %>
15
19
  </div>
16
- <div data-dropdown-target="menu" id="table-filter" class="hidden">
20
+
21
+ <dialog class="drawer" data-dialog-target="dialog" id="product-filters-drawer">
22
+ <%= drawer_header(Spree.t(:filter), 'dialog') %>
23
+ <div class="drawer-body">
17
24
  <%= f.hidden_field :status_eq, value: params.dig(:q, :status_eq) %>
18
25
  <div class="form-group">
19
26
  <%= f.label :taxons_id_in, Spree.t(:taxons) %>
@@ -44,10 +51,14 @@
44
51
  filters_target: "input",
45
52
  } %>
46
53
  </div>
47
-
54
+
48
55
  <%= render_admin_partials(:products_filters_partials, f: f) %>
49
- <%= render 'spree/admin/shared/filter_submit' %>
50
- </div>
56
+ </div>
57
+ <div class="drawer-footer">
58
+ <%= drawer_discard_button('dialog') %>
59
+ <%= render 'spree/admin/shared/filter_submit' %>
60
+ </div>
61
+ </dialog>
51
62
 
52
63
  <%= render "spree/admin/shared/filter_badge_template" %>
53
64
 
@@ -13,7 +13,7 @@
13
13
  <%= product_filter_stock_dropdown_value if product_filter_stock_dropdown_value != Spree.t('admin.products.any_stock') %>
14
14
  <% end %>
15
15
  <% end %>
16
- <%= dropdown_menu class: 'w-100', style: 'min-width: 200px' do %>
16
+ <%= dropdown_menu do %>
17
17
  <h6 class="dropdown-header"><%= Spree.t('admin.products.by_status') %>:</h6>
18
18
 
19
19
  <%= active_link_to Spree.t('admin.products.all_statuses'), params.to_unsafe_h.deep_merge({page: nil, q: {status_eq: nil}}), class: 'dropdown-item', active: (params[:q] || {}).values_at(*%w[status_eq in_stock_items out_of_stock_items] ).all?(&:blank?) %>
@@ -8,8 +8,6 @@
8
8
 
9
9
  <%= render_admin_partials(:product_dropdown_partials, product: @product) %>
10
10
 
11
- <div class="dropdown-divider"></div>
12
-
13
11
  <%= external_page_preview_link(@product) %>
14
12
 
15
13
  <% if can?(:clone, @product) %>
@@ -1,7 +1,4 @@
1
1
  <div class="card mb-4">
2
- <div class="card-header">
3
- <h5 class="card-title"><%= Spree.t(:status) %></h5>
4
- </div>
5
2
  <div class="card-body">
6
3
  <div class="row mb-3">
7
4
  <div class="col-6">
@@ -162,7 +162,7 @@
162
162
  <%= render 'spree/admin/products/form/variants/variant_template', default_stock_location: default_stock_location_for_product(@product) %>
163
163
  <div class="variants-table__body" data-variants-form-target="variantsContainer" data-test-id="product-variants-table">
164
164
  </div>
165
- <div class="variants-table__footer">
165
+ <div class="variants-table__footer font-size-sm">
166
166
  <%= Spree.t('admin.variants_form.total_inventory_html', stock_location: current_store.default_stock_location.name, count: raw("<span data-variants-form-target='stockItemsCount'>#{@product.total_on_hand}</span>") )%>
167
167
  </div>
168
168
  </div>
@@ -6,72 +6,20 @@
6
6
  <%= turbo_save_button_tag Spree.t('actions.update'), form: 'edit_user', data: { admin_target: 'save' } %>
7
7
  <% end %>
8
8
 
9
- <%= form_for @user, url: spree.admin_profile_path, method: :put, as: :user do |f| %>
10
- <div class="row">
11
- <div class="col-lg-6 offset-lg-3">
9
+ <div class="row">
10
+ <div class="col-lg-6 offset-lg-3">
11
+ <%= form_for @user, url: spree.admin_profile_path, method: :put, as: :user do |f| %>
12
12
  <div class="card mb-4">
13
13
  <div class="card-header">
14
14
  <h5 class="card-title"><%= Spree.t('admin.personal_details') %></h5>
15
15
  </div>
16
16
  <div class="card-body">
17
- <div class="form-group mb-4">
18
- <%= f.label :email, class: 'form-label' %>
19
- <%= f.email_field :email, class: 'form-control', required: true %>
20
- </div>
21
- <div class="form-group mb-4">
22
- <%= f.label :first_name, class: 'form-label' %>
23
- <%= f.text_field :first_name, class: 'form-control', required: true %>
24
- </div>
25
- <div class="form-group mb-4">
26
- <%= f.label :last_name, class: 'form-label' %>
27
- <%= f.text_field :last_name, class: 'form-control', required: true %>
28
- </div>
29
- <div class="form-group mb-0">
30
- <div>
31
- <%= f.label :avatar, class: 'form-label' %>
32
- </div>
33
- <%= render 'active_storage/upload_form', form: f, field_name: :avatar, crop: true %>
34
- </div>
17
+ <%= f.spree_email_field :email, required: true %>
18
+ <%= f.spree_text_field :first_name, required: true %>
19
+ <%= f.spree_text_field :last_name, required: true %>
20
+ <%= f.spree_file_field :avatar, crop: true %>
35
21
  </div>
36
22
  </div>
37
-
38
- <div class="card">
39
- <div class="card-header">
40
- <h5 class="card-title"><%= Spree.t('admin.notifications') %></h5>
41
- </div>
42
- <div class="card-body">
43
- <% if @user.respond_to?(:deliver_invitation_accepted_email) %>
44
- <div class="custom-control custom-switch mb-3">
45
- <%= f.check_box :deliver_invitation_accepted_email, class: 'custom-control-input' %>
46
- <%= f.label :deliver_invitation_accepted_email, 'Someone accepted your team invitation', class: 'custom-control-label' %>
47
- </div>
48
- <% end %>
49
-
50
- <% if @user.respond_to?(:deliver_vendor_new_order_email) %>
51
- <hr />
52
- <div class="custom-control custom-switch mb-3">
53
- <%= f.check_box :deliver_vendor_new_order_email, class: 'custom-control-input' %>
54
- <%= f.label :deliver_vendor_new_order_email, 'New order notification', class: 'custom-control-label' %>
55
- </div>
56
- <% end %>
57
-
58
- <% if @user.respond_to?(:deliver_vendor_onboarding_started_email) %>
59
- <hr />
60
- <div class="custom-control custom-switch mb-3">
61
- <%= f.check_box :deliver_vendor_onboarding_started_email, class: 'custom-control-input' %>
62
- <%= f.label :deliver_vendor_onboarding_started_email, 'Vendor started onboarding', class: 'custom-control-label' %>
63
- </div>
64
- <div class="custom-control custom-switch mb-3">
65
- <%= f.check_box :deliver_vendor_onboarding_completed_email, class: 'custom-control-input' %>
66
- <%= f.label :deliver_vendor_onboarding_completed_email, 'Vendor completed onboarding', class: 'custom-control-label' %>
67
- </div>
68
- <div class="custom-control custom-switch mb-3">
69
- <%= f.check_box :deliver_vendor_approved_email, class: 'custom-control-input' %>
70
- <%= f.label :deliver_vendor_approved_email, 'Vendor has been approved', class: 'custom-control-label' %>
71
- </div>
72
- <% end %>
73
- </div>
74
- </div>
75
- </div>
23
+ <% end %>
76
24
  </div>
77
- <% end %>
25
+ </div>
@@ -1,17 +1,27 @@
1
- <%= search_form_for [:admin, @search], class: "filter-wrap", data: {controller: "filters dropdown"} do |f| %>
2
- <div class="d-flex flex-column flex-lg-row gap-2">
3
- <%= render 'spree/admin/shared/filters_search_bar', param: :name_cont, label: Spree.t(:name) %>
4
- <%= render "spree/admin/promotions/table_filter_dropdown" %>
5
- <%= render 'spree/admin/shared/filters_button' %>
6
- </div>
7
- <div data-dropdown-target="menu" id="table-filter" class="hidden">
8
- <div class="form-group">
9
- <%= label_tag :q_code_or_coupon_codes_code_eq, Spree.t(:code) %>
10
- <%= f.search_field :code_or_coupon_codes_code_eq, class: "form-control", data: { filters_target: :input } %>
1
+ <%= search_form_for [:admin, @search], class: "filter-wrap", data: {controller: "filters dialog"} do |f| %>
2
+ <div class="d-flex flex-column flex-lg-row gap-2">
3
+ <%= render 'spree/admin/shared/filters_search_bar', param: :name_cont, label: Spree.t(:name) %>
4
+ <%= render "spree/admin/promotions/table_filter_dropdown" %>
5
+ <%= button_tag type: 'button', class: 'btn btn-light d-flex align-items-center', data: { action: 'dialog#open' } do %>
6
+ <%= icon "adjustments", class: "mr-1" %>
7
+ <%= Spree.t("admin.filters") %>
8
+ <% end %>
11
9
  </div>
12
- <%= render_admin_partials(:promotions_filters_partials, f: f) %>
13
- <%= render 'spree/admin/shared/filter_submit' %>
14
- </div>
10
+
11
+ <dialog class="drawer" data-dialog-target="dialog" id="promotion-filters-drawer">
12
+ <%= drawer_header(Spree.t(:filter), 'dialog') %>
13
+ <div class="drawer-body">
14
+ <div class="form-group">
15
+ <%= label_tag :q_code_or_coupon_codes_code_eq, Spree.t(:code) %>
16
+ <%= f.search_field :code_or_coupon_codes_code_eq, class: "form-control", data: { filters_target: :input } %>
17
+ </div>
18
+ <%= render_admin_partials(:promotions_filters_partials, f: f) %>
19
+ </div>
20
+ <div class="drawer-footer">
21
+ <%= drawer_discard_button('dialog') %>
22
+ <%= render 'spree/admin/shared/filter_submit' %>
23
+ </div>
24
+ </dialog>
15
25
 
16
26
  <%= render "spree/admin/shared/filter_badge_template" %>
17
27
 
@@ -5,7 +5,7 @@
5
5
  </span>
6
6
  <%= promotion_filter_dropdown_value %>
7
7
  <% end %>
8
- <%= dropdown_menu class: 'dropdown-menu-right w-100', style: 'min-width: 200px' do %>
8
+ <%= dropdown_menu do %>
9
9
  <%= active_link_to 'All Promotions', params.to_unsafe_h.deep_merge({page: nil, q: {active: nil, expired: nil}}), class: 'dropdown-item', active: (params[:q] || {}).values_at(*%w[expired active] ).all?(&:blank?) %>
10
10
  <%= link_to Spree.t(:expired),
11
11
  params.to_unsafe_h.deep_merge({page: nil, q: {active: nil, expired: true}}),
@@ -1,5 +1,5 @@
1
1
  <tr>
2
- <th scope="col"><%= sort_link search_collection, :name, Spree.t(:name) %></th>
2
+ <th scope="col"><%= sort_link @search, :name, Spree.t(:name) %></th>
3
3
  <th scope="col"><%= Spree.t(:code) %></th>
4
4
  <th scope="col"><%= Spree.t(:kind) %></th>
5
5
  <th scope="col"><%= Spree.t(:usage_limit) %></th>
@@ -9,7 +9,7 @@
9
9
  <%= f.radio_button :multi_codes, false, data: { action: 'change->reveal#toggle' }, class: 'custom-control-input' %>
10
10
  <%= f.label :multi_codes_false, class: 'custom-control-label' do %>
11
11
  One code for all customers
12
- <span class="form-text font-weight-normal mr-1">
12
+ <span class="form-text font-weight-normal mr-1 mt-2">
13
13
  You can limit the number of times this code can be used.
14
14
  </span>
15
15
  <% end %>
@@ -22,7 +22,7 @@
22
22
  <%= f.radio_button :multi_codes, true, data: { action: 'change->reveal#toggle' }, class: 'custom-control-input' %>
23
23
  <%= f.label :multi_codes_true, class: 'custom-control-label' do %>
24
24
  Generate unique codes
25
- <span class="form-text font-weight-normal mr-1">
25
+ <span class="form-text font-weight-normal mr-1 mt-2">
26
26
  These codes are generated automatically and can be downloaded as a CSV file. Codes are unique and can only be used once.
27
27
  </span>
28
28
  <% end %>
@@ -30,7 +30,7 @@
30
30
  <div data-reveal-target="item" class="ml-3 mt-2 row <% unless @promotion.multi_codes? %>hidden<% end %>">
31
31
  <div class="col-6">
32
32
  <%= f.text_field :code_prefix, class: 'form-control text-uppercase', placeholder: 'Coupon Prefix (optional)' %>
33
- <span class="form-text">
33
+ <span class="form-text mt-2">
34
34
  eg. <strong>ABC</strong>
35
35
  </span>
36
36
  </div>
@@ -38,7 +38,7 @@
38
38
  <% minimum_number_of_codes = @promotion.persisted? && @promotion.coupon_codes.count.positive? ? @promotion.coupon_codes.count : 1 %>
39
39
  <% maximum_number_of_codes = ENV.fetch('PROMOTION_MAX_NUMBER_OF_CODES', 5000) %>
40
40
  <%= f.number_field :number_of_codes, class: 'form-control', placeholder: 'Number of codes', min: minimum_number_of_codes, max: maximum_number_of_codes, step: 1 %>
41
- <span class="form-text">
41
+ <span class="form-text mt-2">
42
42
  How many codes you want to generate.
43
43
  <% if @promotion.persisted? %>
44
44
  To add more codes just increase this number
@@ -2,17 +2,6 @@
2
2
  <%= f.spree_number_field :usage_limit, min: 0, step: 1, help: 'Leave this field blank for unlimited usage.' %>
3
3
  <% end %>
4
4
 
5
- <div class="form-group">
6
- <%= f.label :starts_at %>
7
- <%= f.datetime_field :starts_at, class: 'form-control' %>
8
- <%= f.error_message_on :starts_at %>
9
- </div>
5
+ <%= f.spree_datetime_field :starts_at %>
10
6
 
11
- <div class="form-group">
12
- <%= f.label :expires_at %>
13
- <%= f.datetime_field :expires_at, class: 'form-control' %>
14
- <%= f.error_message_on :expires_at %>
15
- <span class="form-text mt-2">
16
- Leave this field blank for no expiration.
17
- </span>
18
- </div>
7
+ <%= f.spree_datetime_field :expires_at, help: 'Leave this field blank for no expiration.' %>
@@ -1,5 +1,5 @@
1
1
  <tr>
2
- <th scope="col"><%= sort_link search_collection, :name, Spree.t(:name) %></th>
2
+ <th scope="col"><%= sort_link @search, :name, Spree.t(:name) %></th>
3
3
  <th scope="col"><%= Spree.t(:status) %></th>
4
4
  <th scope="col"><%= Spree.t(:mutable) %></th>
5
5
  <th scope="col"></th>
@@ -1,13 +1,5 @@
1
1
  <% if f.object.new_record? %>
2
- <div class="form-group">
3
- <%= f.label :amount, Spree.t(:amount) %>
4
- <div class="input-group">
5
- <%= f.text_field :amount, class: 'form-control', required: true %>
6
- <div class="input-group-append">
7
- <span class="input-group-text"><%= currency_symbol(@order.currency) %></span>
8
- </div>
9
- </div>
10
- </div>
2
+ <%= f.spree_text_field :amount, label: Spree.t(:amount), append: currency_symbol(@order.currency), required: true %>
11
3
  <% end %>
12
4
 
13
5
  <%= f.spree_collection_select :refund_reason_id, refund_reasons, :id, :name, { include_blank: true, label: Spree.t(:reason), required: true } %>
@@ -1,5 +1,5 @@
1
1
  <tr>
2
- <th scope="col"><%= sort_link search_collection, :name, Spree.t(:name) %></th>
2
+ <th scope="col"><%= sort_link @search, :name, Spree.t(:name) %></th>
3
3
  <th scope="col"><%= Spree.t(:type) %></th>
4
4
  <th scope="col"><%= Spree.t(:status) %></th>
5
5
  <th scope="col"><%= Spree.t(:mutable) %></th>
@@ -1,5 +1,5 @@
1
1
  <tr>
2
- <th scope="col"><%= sort_link search_collection, :name, Spree.t(:name) %></th>
2
+ <th scope="col"><%= sort_link @search, :name, Spree.t(:name) %></th>
3
3
  <th scope="col"><%= Spree.t(:status) %></th>
4
4
  <th scope="col"></th>
5
5
  </tr>
@@ -13,7 +13,7 @@
13
13
  <%= Spree.t(:all) %>
14
14
  <% end %>
15
15
  <% end %>
16
- <%= dropdown_menu class: 'dropdown-menu-right w-100', style: 'min-width: 200px' do %>
16
+ <%= dropdown_menu do %>
17
17
  <%= active_link_to Spree.t(:all),
18
18
  params.to_unsafe_h.deep_merge({ q: { state_eq: "" } }),
19
19
  class: "dropdown-item",
@@ -13,7 +13,7 @@
13
13
  <table class="table">
14
14
  <thead>
15
15
  <tr>
16
- <th scope="col"><%= sort_link search_collection, :name, Spree.t(:name) %></th>
16
+ <th scope="col"><%= sort_link @search, :name, Spree.t(:name) %></th>
17
17
  <th scope="col"><%= Spree.t(:permissions) %></th>
18
18
  <th scope="col"></th>
19
19
  </tr>
@@ -1,3 +1,5 @@
1
1
  <% content_for :page_title do %>
2
2
  <%= Spree.t('admin.audit_log') %>
3
3
  <% end %>
4
+
5
+ <%= render_tab_navigation(:audit_tabs) %>
@@ -7,7 +7,7 @@
7
7
 
8
8
  <% dropdown_direction ||= 'left' %>
9
9
 
10
- <%= dropdown data: { controller: 'dropdown calendar-range', action: 'click->calendar-range#open' }, class: 'h-100' do %>
10
+ <%= dropdown direction: dropdown_direction, data: { controller: 'dropdown calendar-range', action: 'click->calendar-range#open' }, class: 'h-100', portal: false do %>
11
11
  <%= dropdown_toggle class: css_classes do %>
12
12
  <%= icon('calendar', class: 'mr-2') %>
13
13
  <div data-calendar-range-target="label">
@@ -18,7 +18,7 @@
18
18
  <% end %>
19
19
  </div>
20
20
  <% end %>
21
- <%= dropdown_menu direction: dropdown_direction, class: "pt-2 px-2 pb-1" do %>
21
+ <%= dropdown_menu class: "pt-2 px-2 pb-1", style: 'min-width: 29rem' do %>
22
22
  <div data-calendar-range-target="picker" class="d-none"></div>
23
23
  <% end %>
24
24
 
@@ -22,12 +22,15 @@
22
22
  <% end %>
23
23
 
24
24
  <% if show_record_subtitle || content_for(:page_actions_dropdown) %>
25
- <%= dropdown id: 'page_actions_dropdown', class: 'h-100' do %>
25
+ <%= dropdown id: 'page_actions_dropdown', class: 'h-100', portal: false do %>
26
26
  <%= dropdown_toggle id: 'more-actions-link', class: 'btn-light h-100 p-2' do %>
27
27
  <%= icon 'dots-vertical', class: 'mr-0' %>
28
28
  <% end %>
29
29
  <%= dropdown_menu id: 'page_actions_dropdown_menu' do %>
30
- <%= yield :page_actions_dropdown if content_for(:page_actions_dropdown) %>
30
+ <% if content_for?(:page_actions_dropdown) %>
31
+ <%= yield :page_actions_dropdown %>
32
+ <div class="dropdown-divider"></div>
33
+ <% end %>
31
34
  <% if record && record.persisted? %>
32
35
  <%= link_to_edit_metafields(record) %>
33
36
  <%= link_to_edit_translations(record) %>
@@ -1,7 +1,5 @@
1
1
  <%= content_for :page_title do %>
2
2
  <%= Spree.t(:developers) %>
3
3
  <% end %>
4
- <%= content_for :page_tabs do %>
5
- <%= nav_item(Spree.t(:api_keys), spree.admin_oauth_applications_path) if can?(:manage, Spree::OauthApplication) %>
6
- <%= nav_item(Spree.t(:webhooks), spree.admin_webhooks_subscribers_path) if can?(:manage, Spree::Webhooks::Subscriber) %>
7
- <% end %>
4
+
5
+ <%= render_tab_navigation(:developers_tabs) %>
@@ -1,11 +1,9 @@
1
1
  <div id="scroll-header"></div>
2
2
 
3
- <%= render 'spree/admin/shared/offcanvas_nav' %>
4
-
5
3
  <header id="header" class="sticky-top py-0">
6
4
  <nav class="navbar navbar-expand-lg p-0 d-flex align-items-center pr-3">
7
5
  <div class="d-lg-none pr-3 border-right">
8
- <button type="button" class="btn btn-light pull-bs-canvas-left px-2 ml-3 text-decoration-none">
6
+ <button type="button" class="btn btn-light px-2 ml-3 text-decoration-none" data-action="click->sidebar#openMobile">
9
7
  <%= icon('menu-2', class: 'mr-0') %>
10
8
  </button>
11
9
  </div>
@@ -20,13 +18,13 @@
20
18
  <% end %>
21
19
  <% end %>
22
20
 
21
+ <button type="button" class="sidebar-toggle-btn ml-3 mr-3 d-none d-lg-block" data-action="click->sidebar#toggle" aria-label="<%= Spree.t('admin.expand_sidebar') %>">
22
+ <%= icon('layout-sidebar-left-collapse') %>
23
+ </button>
24
+
23
25
  <div class="d-none d-lg-block">
24
26
  <%= render 'spree/admin/shared/breadcrumbs' %>
25
27
  </div>
26
-
27
- <div class="ml-auto d-flex align-items-center">
28
- <%= render 'spree/admin/shared/user_dropdown' %>
29
- </div>
30
28
  </nav>
31
29
  </header>
32
30
 
@@ -1,13 +1,14 @@
1
1
  <% sortable = local_assigns[:sortable] %>
2
+ <% frame_name = local_assigns[:frame_name] || controller_name %>
2
3
 
3
- <%= turbo_frame_tag controller_name, autoscroll: true, data: { autoscroll_block: :start, autoscroll_behavior: :smooth, turbo_action: 'advance' } do %>
4
+ <%= turbo_frame_tag frame_name, autoscroll: true, data: { autoscroll_block: :start, autoscroll_behavior: :smooth, turbo_action: 'advance' } do %>
4
5
  <%= render 'spree/admin/shared/export_modal', export_type: export_type if local_assigns[:export_type] %>
5
6
  <div class="card-lg">
6
7
  <% if lookup_context.template_exists?('filters', lookup_context.prefixes, true) %>
7
8
  <%= render 'filters' %>
8
9
  <% end %>
9
10
 
10
- <% if paginated_collection.any? %>
11
+ <% if @collection.any? %>
11
12
  <div class="<% if lookup_context.template_exists?('filters', lookup_context.prefixes, true) %>with-filters<% end %>" id="listing_<%= controller_name %>">
12
13
  <table class="table">
13
14
  <thead>
@@ -21,12 +22,12 @@
21
22
  data-sortable-response-kind-value="turbo-stream"
22
23
  <% end %>
23
24
  >
24
- <%= render partial: 'table_row', collection: paginated_collection, as: controller_name.singularize %>
25
+ <%= render partial: 'table_row', collection: @collection, as: controller_name.singularize %>
25
26
  </tbody>
26
27
  </table>
27
28
  </div>
28
29
 
29
- <%= render 'spree/admin/shared/index_table_options', collection: paginated_collection %>
30
+ <%= render 'spree/admin/shared/index_table_options', collection: @collection %>
30
31
  <% else %>
31
32
  <%= render 'spree/admin/shared/no_resource_found', new_object_url: (new_object_url if can?(:create, model_class)) %>
32
33
  <% end %>
@@ -12,7 +12,7 @@
12
12
  <div class="d-none d-lg-block text-center text-muted">
13
13
  <%= page_entries_info(collection, entry_name: entry_name) %>
14
14
  </div>
15
- <div class="text-right pr-lg-2">
15
+ <div class="text-right">
16
16
  <%= paginate collection, theme: 'admin-twitter-bootstrap-4' %>
17
17
  </div>
18
18
  </div>
@@ -0,0 +1,5 @@
1
+ <ul class="nav flex-column">
2
+ <% items.each do |item| %>
3
+ <%= render 'spree/admin/shared/navigation_item', item: item, context: context %>
4
+ <% end %>
5
+ </ul>
@@ -0,0 +1,64 @@
1
+ <%
2
+ # Resolve item properties (pass self as context for route helpers)
3
+ item_url = item.resolve_url(self)
4
+ item_label = item.resolve_label
5
+ badge_value = item.badge_value(self)
6
+ is_active = item.active?(request.path, self)
7
+ has_children = item.children.present?
8
+ tooltip_text = item.tooltip
9
+
10
+ # Build data attributes - only add tooltip controller if tooltip is present
11
+ data_attrs = item.data_attributes.dup
12
+ if tooltip_text.present?
13
+ data_attrs[:controller] = 'tooltip'
14
+ end
15
+
16
+ # Build additional HTML options (like target)
17
+ html_options = {}
18
+ html_options[:target] = item.target if item.target.present?
19
+ html_options[:id] = "nav-link-#{item.key}" if item.key.present?
20
+
21
+ # Build complete label with badge (like old menu pattern)
22
+ complete_label = item_label
23
+ if badge_value.present?
24
+ badge_class = item.badge_class.presence || 'badge-light'
25
+ complete_label += content_tag(:span, badge_value, class: "badge ml-auto #{badge_class}")
26
+ end
27
+ # Add tooltip if present
28
+ if tooltip_text.present?
29
+ complete_label += tooltip(tooltip_text)
30
+ end
31
+ complete_label = complete_label&.html_safe
32
+ %>
33
+
34
+ <% if item.section? %>
35
+ <%# Section header %>
36
+ <li class="nav-item nav-section-header mt-3 border-top pt-3 pl-2">
37
+ <span class="text-muted text-uppercase font-weight-light font-size-sm"><%= item.section_label %></span>
38
+ </li>
39
+ <% else %>
40
+ <% if has_children %>
41
+ <%# Item with children (submenu shows when parent is active) %>
42
+ <%= nav_item(complete_label, item_url, icon: item.icon, active: is_active, data: data_attrs, **html_options) %>
43
+
44
+ <%# Submenu for expanded sidebar (only shown when active) %>
45
+ <ul class="nav-submenu <% unless is_active %>d-none<% end %>" id="nav-submenu-<%= item.key %>">
46
+ <% item.children.select { |child| child.visible?(self) }.each do |child_item| %>
47
+ <%= render 'spree/admin/shared/navigation_item', item: child_item, context: context %>
48
+ <% end %>
49
+ </ul>
50
+
51
+ <%# Submenu dropdown for collapsed sidebar (always rendered, shown on hover) %>
52
+ <ul class="nav-submenu-dropdown d-none dropdown-container" id="nav-submenu-dropdown-<%= item.key %>">
53
+ <%# Add parent item as first item in dropdown %>
54
+ <%= nav_item(item_label, item_url, icon: nil) %>
55
+
56
+ <% item.children.select { |child| child.visible?(self) }.each do |child_item| %>
57
+ <%= render 'spree/admin/shared/navigation_item', item: child_item, context: context %>
58
+ <% end %>
59
+ </ul>
60
+ <% else %>
61
+ <%# Regular item without children %>
62
+ <%= nav_item(complete_label, item_url, icon: item.icon, active: is_active, data: data_attrs, **html_options) %>
63
+ <% end %>
64
+ <% end %>
@@ -1,8 +1,8 @@
1
- <%= dropdown do %>
1
+ <%= dropdown id: 'new-item-dropdown' do %>
2
2
  <%= dropdown_toggle class: 'btn-light btn-sm px-1' do %>
3
3
  <%= icon 'plus', class: 'mr-0' %>
4
4
  <% end %>
5
- <%= dropdown_menu direction: 'left' do %>
5
+ <%= dropdown_menu do %>
6
6
  <%= link_to_with_icon 'shopping-bag-plus', Spree.t(:new_order), spree.new_admin_order_path, class: "dropdown-item" if can?(:manage, Spree::Order) %>
7
7
 
8
8
  <%= link_to spree.new_admin_product_path, class: 'dropdown-item' do %>