spree_admin 5.3.5 → 5.4.0.beta

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 (123) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/app/controllers/concerns/spree/admin/order_concern.rb +1 -1
  4. data/app/controllers/spree/admin/action_text/video_embeds_controller.rb +1 -1
  5. data/app/controllers/spree/admin/addresses_controller.rb +1 -1
  6. data/app/controllers/spree/admin/admin_users_controller.rb +3 -3
  7. data/app/controllers/spree/admin/api_keys_controller.rb +56 -0
  8. data/app/controllers/spree/admin/assets_controller.rb +2 -2
  9. data/app/controllers/spree/admin/base_controller.rb +4 -4
  10. data/app/controllers/spree/admin/classifications_controller.rb +5 -4
  11. data/app/controllers/spree/admin/coupon_codes_controller.rb +1 -1
  12. data/app/controllers/spree/admin/customer_group_users_controller.rb +3 -2
  13. data/app/controllers/spree/admin/dashboard_controller.rb +2 -1
  14. data/app/controllers/spree/admin/digital_assets_controller.rb +1 -1
  15. data/app/controllers/spree/admin/exports_controller.rb +1 -2
  16. data/app/controllers/spree/admin/gift_cards_controller.rb +5 -5
  17. data/app/controllers/spree/admin/import_mappings_controller.rb +1 -1
  18. data/app/controllers/spree/admin/import_rows_controller.rb +1 -1
  19. data/app/controllers/spree/admin/integrations_controller.rb +1 -1
  20. data/app/controllers/spree/admin/invitations_controller.rb +6 -5
  21. data/app/controllers/spree/admin/line_items_controller.rb +1 -1
  22. data/app/controllers/spree/admin/markets_controller.rb +28 -0
  23. data/app/controllers/spree/admin/option_values_controller.rb +1 -1
  24. data/app/controllers/spree/admin/orders/adjustments_controller.rb +4 -4
  25. data/app/controllers/spree/admin/orders/billing_address_controller.rb +4 -4
  26. data/app/controllers/spree/admin/orders/customer_returns_controller.rb +1 -1
  27. data/app/controllers/spree/admin/orders/shipping_address_controller.rb +3 -3
  28. data/app/controllers/spree/admin/orders/user_controller.rb +4 -4
  29. data/app/controllers/spree/admin/orders_controller.rb +8 -4
  30. data/app/controllers/spree/admin/payments_controller.rb +3 -3
  31. data/app/controllers/spree/admin/price_list_products_controller.rb +1 -1
  32. data/app/controllers/spree/admin/price_rules_controller.rb +1 -1
  33. data/app/controllers/spree/admin/products_controller.rb +24 -15
  34. data/app/controllers/spree/admin/profile_controller.rb +1 -1
  35. data/app/controllers/spree/admin/promotion_actions_controller.rb +1 -1
  36. data/app/controllers/spree/admin/promotion_rules_controller.rb +1 -1
  37. data/app/controllers/spree/admin/promotions_controller.rb +1 -1
  38. data/app/controllers/spree/admin/refunds_controller.rb +1 -1
  39. data/app/controllers/spree/admin/reimbursements_controller.rb +2 -2
  40. data/app/controllers/spree/admin/resource_controller.rb +30 -11
  41. data/app/controllers/spree/admin/shipments_controller.rb +3 -3
  42. data/app/controllers/spree/admin/shipping_methods_controller.rb +1 -1
  43. data/app/controllers/spree/admin/store_credits_controller.rb +5 -5
  44. data/app/controllers/spree/admin/stores_controller.rb +1 -32
  45. data/app/controllers/spree/admin/taxons_controller.rb +3 -3
  46. data/app/controllers/spree/admin/translations_controller.rb +1 -0
  47. data/app/controllers/spree/admin/users_controller.rb +2 -2
  48. data/app/helpers/spree/admin/api_keys_helper.rb +32 -0
  49. data/app/helpers/spree/admin/base_helper.rb +6 -1
  50. data/app/helpers/spree/admin/json_preview_helper.rb +29 -25
  51. data/app/helpers/spree/admin/orders_filters_helper.rb +1 -1
  52. data/app/helpers/spree/admin/sortable_tree_helper.rb +1 -1
  53. data/app/helpers/spree/admin/stores_helper.rb +0 -4
  54. data/app/javascript/spree/admin/controllers/autocomplete_select_controller.js +5 -1
  55. data/app/javascript/spree/admin/controllers/search_clear_controller.js +1 -1
  56. data/app/javascript/spree/admin/controllers/select_controller.js +4 -0
  57. data/app/javascript/spree/admin/controllers/variants_form_controller.js +4 -3
  58. data/app/views/spree/admin/api_keys/_details.html.erb +51 -0
  59. data/app/views/spree/admin/api_keys/_form.html.erb +26 -0
  60. data/app/views/spree/admin/api_keys/_token_card.html.erb +28 -0
  61. data/app/views/spree/admin/api_keys/_usage_info.html.erb +16 -0
  62. data/app/views/spree/admin/api_keys/index.html.erb +9 -0
  63. data/app/views/spree/admin/api_keys/show.html.erb +26 -0
  64. data/app/views/spree/admin/classifications/_classification.html.erb +2 -2
  65. data/app/views/spree/admin/classifications/index.html.erb +1 -1
  66. data/app/views/spree/admin/classifications/new.html.erb +1 -1
  67. data/app/views/spree/admin/exports/create.turbo_stream.erb +1 -1
  68. data/app/views/spree/admin/exports/new.html.erb +3 -3
  69. data/app/views/spree/admin/json_previews/show.html.erb +6 -6
  70. data/app/views/spree/admin/markets/_form.html.erb +28 -0
  71. data/app/views/spree/admin/markets/edit.html.erb +1 -0
  72. data/app/views/spree/admin/markets/index.html.erb +9 -0
  73. data/app/views/spree/admin/markets/new.html.erb +1 -0
  74. data/app/views/spree/admin/orders/billing_address/_form.html.erb +2 -2
  75. data/app/views/spree/admin/orders/shipping_address/_form.html.erb +2 -2
  76. data/app/views/spree/admin/payment_methods/_form.html.erb +0 -12
  77. data/app/views/spree/admin/price_rules/forms/_market_rule.html.erb +7 -0
  78. data/app/views/spree/admin/products/_form.html.erb +0 -1
  79. data/app/views/spree/admin/products/form/_variants.html.erb +4 -3
  80. data/app/views/spree/admin/promotion_rules/forms/_country.html.erb +1 -1
  81. data/app/views/spree/admin/shared/_content_header.html.erb +1 -1
  82. data/app/views/spree/admin/shared/sidebar/_store_dropdown.html.erb +0 -33
  83. data/app/views/spree/admin/shared/sidebar/_store_nav.html.erb +2 -2
  84. data/app/views/spree/admin/shared/sortable_tree/_taxonomy.html.erb +2 -2
  85. data/app/views/spree/admin/stores/form/_basic.html.erb +10 -7
  86. data/app/views/spree/admin/stores/form/_checkout.html.erb +5 -8
  87. data/app/views/spree/admin/tables/columns/_api_key_status.html.erb +2 -0
  88. data/app/views/spree/admin/tables/columns/_api_key_type.html.erb +2 -0
  89. data/app/views/spree/admin/taxonomies/show.html.erb +1 -1
  90. data/app/views/spree/admin/taxons/_form.html.erb +2 -2
  91. data/app/views/spree/admin/taxons/edit.html.erb +1 -2
  92. data/app/views/spree/admin/taxons/update.turbo_stream.erb +1 -1
  93. data/app/views/spree/admin/users/_billing.html.erb +2 -2
  94. data/app/views/spree/admin/users/_shipping.html.erb +1 -1
  95. data/app/views/spree/admin/variants/_variant.html.erb +1 -1
  96. data/config/brakeman.ignore +28 -0
  97. data/config/initializers/spree_admin_navigation.rb +16 -16
  98. data/config/initializers/spree_admin_tables.rb +94 -0
  99. data/config/locales/en.yml +31 -0
  100. data/config/routes.rb +6 -6
  101. data/lib/spree/admin/engine.rb +1 -0
  102. data/lib/spree/admin/tailwind_helper.rb +11 -1
  103. data/lib/spree/admin/testing_support/tom_select.rb +1 -1
  104. metadata +30 -27
  105. data/LICENSE.md +0 -13
  106. data/app/controllers/spree/admin/custom_domains_controller.rb +0 -21
  107. data/app/controllers/spree/admin/oauth_applications_controller.rb +0 -23
  108. data/app/views/spree/admin/custom_domains/_custom_domain.html.erb +0 -11
  109. data/app/views/spree/admin/custom_domains/_custom_domains.html.erb +0 -19
  110. data/app/views/spree/admin/custom_domains/_form.html.erb +0 -7
  111. data/app/views/spree/admin/custom_domains/index.html.erb +0 -65
  112. data/app/views/spree/admin/oauth_applications/_form.html.erb +0 -6
  113. data/app/views/spree/admin/oauth_applications/_table_header.html.erb +0 -7
  114. data/app/views/spree/admin/oauth_applications/_table_row.html.erb +0 -34
  115. data/app/views/spree/admin/oauth_applications/create.turbo_stream.erb +0 -31
  116. data/app/views/spree/admin/oauth_applications/edit.html.erb +0 -1
  117. data/app/views/spree/admin/oauth_applications/index.html.erb +0 -21
  118. data/app/views/spree/admin/oauth_applications/new.html.erb +0 -1
  119. data/app/views/spree/admin/products/form/_stores.html.erb +0 -27
  120. data/app/views/spree/admin/stores/new.html.erb +0 -128
  121. data/app/views/spree/admin/stores/new.turbo_stream.erb +0 -1
  122. /data/app/views/spree/admin/{custom_domains → api_keys}/edit.html.erb +0 -0
  123. /data/app/views/spree/admin/{custom_domains → api_keys}/new.html.erb +0 -0
@@ -34,6 +34,7 @@ export default class extends CheckboxSelectAll {
34
34
  currentCurrency: String,
35
35
  currencies: Array,
36
36
  variantIds: Object,
37
+ variantPrefixIds: Object,
37
38
  currentStockLocationId: String,
38
39
  stockLocations: Array,
39
40
  optionValuesSelectOptions: Array,
@@ -522,12 +523,12 @@ export default class extends CheckboxSelectAll {
522
523
  const variantTarget = template.querySelector('[data-variants-form-target="variant"]')
523
524
  variantTarget.dataset.variantName = internalName
524
525
 
525
- const variantId = this.variantIdsValue[internalName]
526
- if (variantId) {
526
+ const variantPrefixId = this.variantPrefixIdsValue?.[internalName] || this.variantIdsValue[internalName]
527
+ if (variantPrefixId) {
527
528
  const variantEditButton = variantTarget.querySelector('[data-slot="variantEditButton"]')
528
529
 
529
530
  if (variantEditButton) {
530
- variantEditButton.href = `${Spree.adminPath}/products/${this.productIdValue}/variants/${variantId}/edit`
531
+ variantEditButton.href = `${Spree.adminPath}/products/${this.productIdValue}/variants/${variantPrefixId}/edit`
531
532
  variantEditButton.classList.remove('invisible')
532
533
  }
533
534
  }
@@ -0,0 +1,51 @@
1
+ <div class="card mb-6">
2
+ <div class="card-header">
3
+ <h5 class="card-title"><%= Spree.t(:details) %></h5>
4
+ </div>
5
+ <div class="card-body">
6
+ <dl class="space-y-4">
7
+ <div>
8
+ <dt class="text-sm text-gray-500"><%= Spree.t(:status) %></dt>
9
+ <dd class="mt-1"><%= api_key_status_badge(@api_key) %></dd>
10
+ </div>
11
+
12
+ <div>
13
+ <dt class="text-sm text-gray-500"><%= Spree.t(:type) %></dt>
14
+ <dd class="mt-1"><%= api_key_type_badge(@api_key) %></dd>
15
+ </div>
16
+
17
+ <div>
18
+ <dt class="text-sm text-gray-500"><%= Spree.t(:created_at) %></dt>
19
+ <dd class="mt-1"><%= l(@api_key.created_at, format: :long) %></dd>
20
+ </div>
21
+
22
+ <% if @api_key.created_by.present? %>
23
+ <div>
24
+ <dt class="text-sm text-gray-500"><%= Spree.t(:created_by) %></dt>
25
+ <dd class="mt-1"><%= @api_key.created_by.try(:email) || @api_key.created_by.to_s %></dd>
26
+ </div>
27
+ <% end %>
28
+
29
+ <% if @api_key.last_used_at.present? %>
30
+ <div>
31
+ <dt class="text-sm text-gray-500"><%= Spree.t('admin.api_keys.last_used_at') %></dt>
32
+ <dd class="mt-1"><%= l(@api_key.last_used_at, format: :long) %></dd>
33
+ </div>
34
+ <% end %>
35
+
36
+ <% if @api_key.revoked_at.present? %>
37
+ <div>
38
+ <dt class="text-sm text-gray-500"><%= Spree.t('admin.api_keys.revoked_at') %></dt>
39
+ <dd class="mt-1 text-red-600"><%= l(@api_key.revoked_at, format: :long) %></dd>
40
+ </div>
41
+
42
+ <% if @api_key.revoked_by.present? %>
43
+ <div>
44
+ <dt class="text-sm text-gray-500"><%= Spree.t('admin.api_keys.revoked_by') %></dt>
45
+ <dd class="mt-1"><%= @api_key.revoked_by.try(:email) || @api_key.revoked_by.to_s %></dd>
46
+ </div>
47
+ <% end %>
48
+ <% end %>
49
+ </dl>
50
+ </div>
51
+ </div>
@@ -0,0 +1,26 @@
1
+ <div class="card mb-6">
2
+ <div class="card-body">
3
+ <%= f.spree_text_field :name, required: true, autofocus: f.object.new_record?,
4
+ placeholder: Spree.t('admin.api_keys.name_placeholder') %>
5
+
6
+ <% if f.object.new_record? %>
7
+ <%= f.spree_select :key_type, api_key_type_options,
8
+ { prompt: Spree.t(:select_key_type), label: Spree.t(:type) },
9
+ { required: true } %>
10
+ <p class="text-sm text-gray-500 mt-2">
11
+ <strong><%= Spree.t('admin.api_keys.key_types.publishable') %>:</strong>
12
+ <%= Spree.t('admin.api_keys.key_type_descriptions.publishable') %>
13
+ <br>
14
+ <strong><%= Spree.t('admin.api_keys.key_types.secret') %>:</strong>
15
+ <%= Spree.t('admin.api_keys.key_type_descriptions.secret') %>
16
+ </p>
17
+ <% else %>
18
+ <div class="form-group">
19
+ <label class="form-label"><%= Spree.t(:type) %></label>
20
+ <div class="form-control-plaintext">
21
+ <%= api_key_type_badge(@api_key) %>
22
+ </div>
23
+ </div>
24
+ <% end %>
25
+ </div>
26
+ </div>
@@ -0,0 +1,28 @@
1
+ <div class="card mb-6">
2
+ <div class="card-header">
3
+ <h5 class="card-title"><%= Spree.t(:api_key) %></h5>
4
+ </div>
5
+ <div class="card-body">
6
+ <% if @api_key.active? %>
7
+ <div data-controller="password-visibility" class="input-group gap-0 pr-1">
8
+ <input type="password" class="grow text-truncate" data-password-visibility-target="input" spellcheck="false" value="<%= @api_key.token %>" readonly>
9
+
10
+ <button type="button" class="btn hover:bg-gray-100 p-1 mr-1 rounded" data-action="password-visibility#toggle">
11
+ <span data-password-visibility-target="icon"><%= icon 'eye', class: 'mr-0' %></span>
12
+ <span data-password-visibility-target="icon" class="hidden"><%= icon 'eye-off', class: 'mr-0' %></span>
13
+ </button>
14
+
15
+ <%= clipboard_component(@api_key.token,
16
+ button_class: 'btn hover:bg-gray-100 p-1 rounded',
17
+ icon_class: 'mr-0') %>
18
+ </div>
19
+ <% else %>
20
+ <div class="bg-red-50 border border-red-200 rounded-md p-4">
21
+ <div class="flex items-center">
22
+ <%= icon 'alert-triangle', class: 'text-red-500 mr-2' %>
23
+ <span class="text-red-700"><%= Spree.t('admin.api_keys.key_revoked_message') %></span>
24
+ </div>
25
+ </div>
26
+ <% end %>
27
+ </div>
28
+ </div>
@@ -0,0 +1,16 @@
1
+ <div class="card mb-6">
2
+ <div class="card-header">
3
+ <h5 class="card-title"><%= Spree.t('admin.api_keys.usage') %></h5>
4
+ </div>
5
+ <div class="card-body">
6
+ <p class="text-sm text-gray-600 mb-4">
7
+ <%= Spree.t("admin.api_keys.usage_instructions.#{@api_key.key_type}") %>
8
+ </p>
9
+
10
+ <h6 class="font-medium text-sm mb-2"><%= Spree.t('admin.api_keys.example_request') %></h6>
11
+ <div class="bg-gray-900 rounded-md p-4 overflow-x-auto">
12
+ <pre class="text-green-400 text-sm font-mono whitespace-pre-wrap"><code>curl -X GET "https://your-store.com/api/v3/store/products" \
13
+ -H "X-Spree-Api-Key: <%= @api_key.token %>"</code></pre>
14
+ </div>
15
+ </div>
16
+ </div>
@@ -0,0 +1,9 @@
1
+ <%= render 'spree/admin/shared/developers_nav' %>
2
+
3
+ <%= content_for(:title, Spree.t(:api_keys)) %>
4
+
5
+ <% content_for :page_actions do %>
6
+ <%= link_to_with_icon 'plus', Spree.t(:new_api_key), new_object_url, class: "btn btn-primary" if can? :create, Spree::ApiKey %>
7
+ <% end %>
8
+
9
+ <%= render_table @collection, :api_keys %>
@@ -0,0 +1,26 @@
1
+ <%= content_for :page_title do %>
2
+ <%= page_header_back_button(collection_url) %>
3
+ <%= @api_key.name %>
4
+ <% end %>
5
+
6
+ <% content_for :page_actions do %>
7
+ <% if @api_key.active? && can?(:update, @api_key) %>
8
+ <%= link_to Spree.t(:edit), edit_object_url(@api_key), class: 'btn btn-light' %>
9
+ <%= button_to Spree.t('admin.api_keys.revoke'),
10
+ spree.revoke_admin_api_key_path(@api_key),
11
+ method: :put,
12
+ class: 'btn btn-danger',
13
+ data: { confirm: Spree.t('admin.api_keys.revoke_confirmation') } %>
14
+ <% end %>
15
+ <% end %>
16
+
17
+ <div class="grid grid-cols-12 gap-6">
18
+ <div class="col-span-12 lg:col-span-8">
19
+ <%= render 'token_card' %>
20
+ <%= render 'usage_info' %>
21
+ </div>
22
+
23
+ <div class="col-span-12 lg:col-span-4">
24
+ <%= render 'details' %>
25
+ </div>
26
+ </div>
@@ -1,4 +1,4 @@
1
- <div class="grid grid-cols-12 gap-6 mx-0 hover:bg-gray-25 rounded" id="<%= spree_dom_id(classification) %>" data-sortable-update-url="<%= spree.admin_taxon_classification_path(classification.taxon_id, classification, format: :turbo_stream) %>">
1
+ <div class="grid grid-cols-12 gap-6 mx-0 hover:bg-gray-25 rounded" id="<%= spree_dom_id(classification) %>" data-sortable-update-url="<%= spree.admin_taxon_classification_path(classification.taxon, classification, format: :turbo_stream) %>">
2
2
  <% if classification.taxon.manual_sort_order? %>
3
3
  <div class="col-span-1 text-center self-center">
4
4
  <span class="rounded-md p-2 hover:bg-gray-100 move-handle cursor-grab">
@@ -31,7 +31,7 @@
31
31
  </div>
32
32
 
33
33
  <div class="col-span-2 text-center self-center">
34
- <%= button_to spree.admin_taxon_classification_path(classification.taxon_id, classification), class: 'btn btn-danger btn-sm', method: :delete, data: { controller: 'tooltip', turbo_confirm: Spree.t(:are_you_sure) } do %>
34
+ <%= button_to spree.admin_taxon_classification_path(classification.taxon, classification), class: 'btn btn-danger btn-sm', method: :delete, data: { controller: 'tooltip', turbo_confirm: Spree.t(:are_you_sure) } do %>
35
35
  <%= icon 'trash', class: 'mr-0', style: 'pointer-events: none' %>
36
36
  <%= tooltip(Spree.t('actions.destroy')) %>
37
37
  <% end if classification.taxon.manual? && can?(:delete, classification) %>
@@ -14,7 +14,7 @@
14
14
  </p>
15
15
  <p class="text-center">
16
16
  <% if can?(:create, Spree::Classification) && @taxon.manual? %>
17
- <%= link_to_with_icon 'plus', Spree.t(:add_products), spree.new_admin_taxon_classification_path(@taxon.id), class: 'btn btn-secondary', data: { turbo_frame: 'dialog', action: 'dialog#open' } %>
17
+ <%= link_to_with_icon 'plus', Spree.t(:add_products), spree.new_admin_taxon_classification_path(@taxon), class: 'btn btn-secondary', data: { turbo_frame: 'dialog', action: 'dialog#open' } %>
18
18
  <% end %>
19
19
  <% end %>
20
20
  <% end %>
@@ -1 +1 @@
1
- <%= render 'spree/admin/shared/multi_product_picker', parent: @parent, url: spree.admin_taxon_classifications_path(@parent.id) %>
1
+ <%= render 'spree/admin/shared/multi_product_picker', parent: @parent, url: spree.admin_taxon_classifications_path(@parent) %>
@@ -1,5 +1,5 @@
1
1
  <%= turbo_render_alerts %>
2
2
 
3
3
  <%= turbo_stream.replace 'export-dialog' do %>
4
- <%= render 'spree/admin/shared/export_modal', export_type: @object.type %>
4
+ <%= render 'spree/admin/shared/export_modal', export_type: @export.type %>
5
5
  <% end %>
@@ -1,15 +1,15 @@
1
1
  <%= turbo_frame_tag :export_dialog do %>
2
- <%= form_for @object, url: spree.admin_exports_path, as: :export do |f| %>
2
+ <%= form_for @export, url: spree.admin_exports_path do |f| %>
3
3
  <%= f.hidden_field :type %>
4
4
  <%= f.hidden_field :search_params %>
5
5
  <div class="dialog-header">
6
6
  <h5 class="dialog-title">
7
- <%= Spree.t(:export) + ' ' + plural_resource_name(@object.model_class) %>
7
+ <%= Spree.t(:export) + ' ' + plural_resource_name(@export.model_class) %>
8
8
  </h5>
9
9
  <button type="button" class="btn-close" data-action="click->export-dialog#close" aria-label="Close"></button>
10
10
  </div>
11
11
  <div class="dialog-body">
12
- <%= render 'spree/admin/shared/error_messages', target: @object %>
12
+ <%= render 'spree/admin/shared/error_messages', target: @export %>
13
13
  <div class="custom-control custom-radio hover:bg-gray-50 rounded-lg p-3">
14
14
  <%= f.radio_button :record_selection, 'filtered', class: 'custom-control-input' %>
15
15
  <%= f.label :record_selection, for: :export_record_selection_filtered, class: 'custom-control-label flex-col items-start' do %>
@@ -3,15 +3,15 @@
3
3
  <div class="drawer-body" data-controller="highlight tabs">
4
4
  <ul class="nav nav-pills mb-3">
5
5
  <li class="nav-item">
6
- <a class="nav-link active" data-tabs-target="tab" data-action="click->tabs#select"><%= Spree.t('apis.storefront') %></a>
6
+ <a class="nav-link active" data-tabs-target="tab" data-action="click->tabs#select"><%= Spree.t('apis.store') %></a>
7
7
  </li>
8
8
  <li class="nav-item">
9
- <a class="nav-link" data-tabs-target="tab" data-action="click->tabs#select"><%= Spree.t('apis.platform') %></a>
9
+ <a class="nav-link" data-tabs-target="tab" data-action="click->tabs#select"><%= Spree.t('apis.admin') %></a>
10
10
  </li>
11
11
  </ul>
12
12
  <div data-tabs-target="panel" class="animate-fade-in">
13
- <% if storefront_serializer_exists?(@object) %>
14
- <%= code_block serialize_to_json(@object, api_type: :storefront), style: 'height: calc(100dvh - 11rem);' %>
13
+ <% if store_serializer_exists?(@object) %>
14
+ <%= code_block serialize_to_json(@object, api_type: :store), style: 'height: calc(100dvh - 11rem);' %>
15
15
  <% else %>
16
16
  <div class="text-gray-600 p-12 flex items-center w-full justify-center flex-col">
17
17
  <%= icon 'map-search', class: 'mb-12 opacity-50 text-4xl' %>
@@ -22,8 +22,8 @@
22
22
  <% end %>
23
23
  </div>
24
24
  <div data-tabs-target="panel" class="animate-fade-in" hidden>
25
- <% if platform_serializer_exists?(@object) %>
26
- <%= code_block serialize_to_json(@object, api_type: :platform), style: 'height: calc(100dvh - 11rem);' %>
25
+ <% if admin_serializer_exists?(@object) %>
26
+ <%= code_block serialize_to_json(@object, api_type: :admin), style: 'height: calc(100dvh - 11rem);' %>
27
27
  <% else %>
28
28
  <div class="text-gray-600 p-12 flex items-center w-full justify-center flex-col">
29
29
  <%= icon 'map-search', class: 'mb-12 opacity-50 text-4xl' %>
@@ -0,0 +1,28 @@
1
+ <div class="card mb-6">
2
+ <div class="card-header">
3
+ <h5 class="card-title">
4
+ <%= Spree.t(:general_settings) %>
5
+ </h5>
6
+ </div>
7
+
8
+ <div class="card-body">
9
+ <%= f.spree_text_field :name, required: true %>
10
+
11
+ <%= f.spree_select :country_ids, @countries.map { |country| ["#{Spree::Country.iso_to_emoji_flag(country.iso)} #{country.name}", country.id] }, { include_blank: false, label: Spree.t(:default_country), autocomplete: true, multiple: true } %>
12
+
13
+ <%= f.spree_select :currency, currency_options(f.object.currency), { label: Spree.t(:currency), required: true, autocomplete: true } %>
14
+
15
+ <%= f.spree_select :default_locale,
16
+ options_from_collection_for_select(all_locales_options, :last, :first, f.object.default_locale || I18n.locale),
17
+ { required: true, autocomplete: true } %>
18
+
19
+ <%= f.spree_select :supported_locales,
20
+ options_from_collection_for_select(all_locales_options, :last, :first, f.object.supported_locales&.split(',')),
21
+ { multiple: true, autocomplete: true, hint: Spree.t('admin.markets.supported_locales_hint') } %>
22
+
23
+ <hr class="my-6">
24
+
25
+ <%= f.spree_check_box :tax_inclusive %>
26
+ <%= f.spree_check_box :default %>
27
+ </div>
28
+ </div>
@@ -0,0 +1 @@
1
+ <%= render 'spree/admin/shared/edit_resource' %>
@@ -0,0 +1,9 @@
1
+ <%= content_for :page_title do %>
2
+ <%= Spree.t('admin.markets.list') %>
3
+ <% end %>
4
+
5
+ <% content_for :page_actions do %>
6
+ <%= link_to_with_icon 'plus', Spree.t('admin.markets.new'), new_object_url, class: 'btn btn-primary' if can?(:create, Spree::Market) %>
7
+ <% end %>
8
+
9
+ <%= render_table @collection, :markets %>
@@ -0,0 +1 @@
1
+ <%= render 'spree/admin/shared/new_resource' %>
@@ -9,8 +9,8 @@
9
9
  <% if @order.user.present? && @order.user.addresses.many? %>
10
10
  <div data-form="existing_address" class="hidden">
11
11
  <%= label_tag :billing_address_id, Spree.t(:existing_address), class: 'sr-only' %>
12
- <%= select_tag :billing_address_id,
13
- options_for_select(@order.user.addresses.map { |a| [a.to_s.gsub('<br/>', ", "), a.id]}),
12
+ <%= select_tag :billing_address_id,
13
+ options_for_select(@order.user.addresses.map { |a| [a.to_s.gsub('<br/>', ", "), a.to_param]}),
14
14
  { include_blank: Spree.t(:select_existing_address), class: "form-select", data: { action: 'auto-submit#submit' } } %>
15
15
  </div>
16
16
  <% end %>
@@ -8,8 +8,8 @@
8
8
  <div>
9
9
  <div class="w-full text-center mb-2"><%= Spree.t(:or_select_other_address) %></div>
10
10
  <%= label_tag :shipping_address_id, Spree.t(:existing_address), class: 'sr-only' %>
11
- <%= select_tag :shipping_address_id,
12
- options_for_select(@order.user.addresses.map { |a| [a.to_s.gsub('<br/>', ", "), a.id]}),
11
+ <%= select_tag :shipping_address_id,
12
+ options_for_select(@order.user.addresses.map { |a| [a.to_s.gsub('<br/>', ", "), a.to_param]}),
13
13
  { include_blank: Spree.t(:select_existing_address), class: "form-select", data: { action: 'auto-submit#submit' } } %>
14
14
  </div>
15
15
  <% end %>
@@ -24,18 +24,6 @@
24
24
  <div class="card-body">
25
25
  <%= f.spree_text_field :name, help: 'This name will be used to identify the payment method on the storefront' %>
26
26
 
27
- <% if can?(:manage, Spree::Store) && available_stores.count > 1 %>
28
- <div class="form-group">
29
- <%= label_tag :payment_method_stores, Spree.t(:stores) %>
30
- <%= f.collection_check_boxes :store_ids, available_stores, :id, :name do |b| %>
31
- <div class="custom-control form-checkbox mb-1">
32
- <%= b.check_box(class: 'custom-control-input') %>
33
- <%= b.label(class: 'custom-control-label') %>
34
- </div>
35
- <% end %>
36
- </div>
37
- <% end %>
38
-
39
27
  <%= f.spree_select :display_on, display_on_options, { label: Spree.t(:display) } %>
40
28
  <%= f.spree_select :auto_capture, [["#{Spree.t(:use_app_default)} (#{Spree::Config[:auto_capture]})", ''], [Spree.t(:say_yes).to_s, true], [Spree.t(:say_no).to_s, false]], { label: Spree.t(:auto_capture) } %>
41
29
 
@@ -0,0 +1,7 @@
1
+ <div class="form-group">
2
+ <%= f.label :preferred_market_ids, Spree.t(:markets) %>
3
+ <%= f.select :preferred_market_ids,
4
+ current_store.markets.order(:name).pluck(:name, :id),
5
+ { selected: f.object.preferred_market_ids },
6
+ { multiple: true, data: { controller: 'autocomplete-select' } } %>
7
+ </div>
@@ -16,7 +16,6 @@
16
16
  <%= render 'spree/admin/products/form/categorization', f: f %>
17
17
  <%= render 'spree/admin/products/form/shipping', f: f %>
18
18
  <%= render 'spree/admin/products/form/tax', f: f %>
19
- <%= render 'spree/admin/products/form/stores', f: f if available_stores.count > 1 %>
20
19
  <%= render_admin_partials(:product_form_sidebar_partials, f: f, product: @product) %>
21
20
 
22
21
  <%= render 'spree/admin/shared/seo',
@@ -3,7 +3,7 @@
3
3
  <div class="card-header">
4
4
  <h5 class="card-title"><%= Spree.t(:variants) %></h5>
5
5
  </div>
6
- <% option_types_for_select = @option_types.pluck(:presentation, :id) %>
6
+ <% option_types_for_select = @option_types.map { |ot| [ot.presentation, ot.prefixed_id] } %>
7
7
  <div class="card-body p-0">
8
8
  <div
9
9
  data-controller="variants-form"
@@ -21,13 +21,14 @@
21
21
  <% if @product_stock.present? %> data-variants-form-stock-value="<%= @product_stock.to_json %>" <% end %>
22
22
  <% if @product_prices.present? %> data-variants-form-prices-value="<%= @product_prices.to_json %>" <% end %>
23
23
  <% if @product_variant_ids.present? %> data-variants-form-variant-ids-value="<%= @product_variant_ids.to_json %>" <% end %>
24
+ <% if @product_variant_prefix_ids.present? %> data-variants-form-variant-prefix-ids-value="<%= @product_variant_prefix_ids.to_json %>" <% end %>
24
25
  >
25
26
  <div class="options-creator">
26
27
  <%= render 'spree/admin/products/form/variants/option_template', option_types_for_select: option_types_for_select %>
27
28
  <div data-variants-form-target="optionsContainer" class="options-creator__options_container">
28
29
  <% @product.product_option_types.includes(:option_type).reorder('spree_product_option_types.position').each do |product_option_type| %>
29
30
  <% option_type = product_option_type.option_type %>
30
- <div class="options-creator__option" data-variants-form-target="option" id="option-<%= option_type.id %>">
31
+ <div class="options-creator__option" data-variants-form-target="option" id="option-<%= option_type.prefixed_id %>">
31
32
  <% if can?(:manage_option_types, @product) %>
32
33
  <button class="draggable" type="button">
33
34
  <i class="ti ti-grip-vertical"></i>
@@ -37,7 +38,7 @@
37
38
  <div class="flex justify-between items-center">
38
39
  <h6 data-slot="optionName"><%= option_type.presentation %></h6>
39
40
  <% if can?(:manage_option_types, @product) %>
40
- <button class="btn btn-light btn-sm" type="button" data-action="variants-form#editOption" data-variants-form-option-id-param="<%= option_type.id %>"><%= Spree.t(:edit) %></button>
41
+ <button class="btn btn-light btn-sm" type="button" data-action="variants-form#editOption" data-variants-form-option-id-param="<%= option_type.prefixed_id %>"><%= Spree.t(:edit) %></button>
41
42
  <% end %>
42
43
  </div>
43
44
  <div data-slot="optionValuesContainer">
@@ -2,6 +2,6 @@
2
2
  <%= f.label :preferred_country_iso, Spree.t(:country) %>
3
3
  <%= f.select :preferred_country_iso,
4
4
  available_countries_iso.map { |iso| [Spree.t(iso, scope: 'country_names', default: iso), iso] },
5
- { selected: f.object.preferred_country_iso || current_store.default_country_iso },
5
+ { selected: f.object.preferred_country_iso || current_store.default_market&.default_country&.iso },
6
6
  { data: { controller: 'autocomplete-select' } } %>
7
7
  </div>
@@ -52,7 +52,7 @@
52
52
  </div>
53
53
  <% end %>
54
54
  <div data-controller="clipboard" data-clipboard-success-content-value='<%= icon('check') + ' ' + Spree.t(:copied) %>'>
55
- <%= hidden_field_tag :record_id, record.id, data: { clipboard_target: 'source' } %>
55
+ <%= hidden_field_tag :record_id, record.respond_to?(:prefixed_id) ? record.prefixed_id : record.id, data: { clipboard_target: 'source' } %>
56
56
  <button data-action="clipboard#copy" class="text-left dropdown-item" data-clipboard-target="button">
57
57
  <%= icon 'copy' %>
58
58
  <%= Spree.t(:copy_id) %>
@@ -15,39 +15,6 @@
15
15
  <%= icon 'tools' %>
16
16
  <%= Spree.t('admin.edit_theme') %>
17
17
  <% end if current_store.respond_to?(:default_theme) && current_store.default_theme && can?(:manage, Spree::Theme) %>
18
-
19
- <% if available_stores.count > 1 %>
20
- <div class="dropdown-divider"></div>
21
- <h6 class="dropdown-header">
22
- <%= Spree.t(:switch_store) %>
23
- </h6>
24
- <div class="store-chooser">
25
- <% available_stores.each do |store| %>
26
- <% if store.id == current_store.id %>
27
- <div class="store-chooser-item active">
28
- <%= store_admin_icon(store, height: 32, width: 32) %>
29
- <span class="flex flex-col mr-2">
30
- <%= store.name %>
31
- <small class="text-gray-600">
32
- <%= store.url_or_custom_domain %>
33
- </small>
34
- </span>
35
- <%= icon('check', class: 'ml-auto') %>
36
- </div>
37
- <% else %>
38
- <%= link_to spree.admin_dashboard_url(host: store.url), class: 'store-chooser-item' do %>
39
- <%= store_admin_icon(store, height: 32, width: 32) %>
40
- <span class="flex flex-col">
41
- <%= store.name %>
42
- <small class="text-gray-600">
43
- <%= store.url_or_custom_domain %>
44
- </small>
45
- </span>
46
- <% end %>
47
- <% end %>
48
- <% end %>
49
- </div>
50
- <% end %>
51
18
  <% end %>
52
19
  <% end %>
53
20
 
@@ -15,7 +15,7 @@
15
15
  <%= nav_item(Spree.t(:checkout), spree.edit_admin_store_path(section: 'checkout'), icon: 'shopping-cart', active: params[:section] == 'checkout') if can?(:manage, current_store) %>
16
16
  <%= render_admin_partials(:store_settings_nav_partials) %>
17
17
 
18
- <% if can?(:manage, Spree::CustomDomain) %>
18
+ <% if defined?(Spree::CustomDomain) && can?(:manage, Spree::CustomDomain) %>
19
19
  <%= nav_item(Spree.t(:domains), spree.admin_custom_domains_path, icon: 'world-www') %>
20
20
  <% end %>
21
21
 
@@ -65,7 +65,7 @@
65
65
  <% end %>
66
66
  <% end %>
67
67
 
68
- <% if can?(:manage, Spree::OauthApplication) %>
68
+ <% if defined?(Spree::OauthApplication) && can?(:manage, Spree::OauthApplication) %>
69
69
  <%= nav_item(Spree.t(:developers), spree.admin_oauth_applications_path, icon: 'terminal', active: %w[oauth_applications webhooks_subscribers].include?(controller_name)) %>
70
70
  <% end %>
71
71
 
@@ -27,7 +27,7 @@
27
27
  </div>
28
28
 
29
29
  <div class="flex items-center px-3 ml-3 gap-2">
30
- <%= link_to_edit(taxon, url: spree.edit_admin_taxonomy_taxon_path(taxonomy, taxon.id), data: { row_link_target: :link, turbo_frame: '_top' }) if can?(:edit, taxon) %>
30
+ <%= link_to_edit(taxon, url: spree.edit_admin_taxonomy_taxon_path(taxonomy, taxon), data: { row_link_target: :link, turbo_frame: '_top' }) if can?(:edit, taxon) %>
31
31
 
32
32
  <%= dropdown class: 'h-full' do %>
33
33
  <%= dropdown_toggle class: 'btn-sm btn-light px-1 h-full' do %>
@@ -38,7 +38,7 @@
38
38
  <%= link_to_with_icon 'plus', Spree.t(:new_nested_taxon), spree.new_admin_taxonomy_taxon_path(taxonomy, taxon: { parent_id: taxon.id }), class: 'dropdown-item' %>
39
39
  <div class="dropdown-divider"></div>
40
40
  <% end %>
41
- <%= link_to_delete(taxon, icon: 'trash', url: spree.admin_taxonomy_taxon_path(taxonomy, taxon.id), class: 'dropdown-item text-red-600 hover:bg-red-100') if can?(:destroy, taxon) %>
41
+ <%= link_to_delete(taxon, icon: 'trash', url: spree.admin_taxonomy_taxon_path(taxonomy, taxon), class: 'dropdown-item text-red-600 hover:bg-red-100') if can?(:destroy, taxon) %>
42
42
  <% end %>
43
43
  <% end %>
44
44
  </div>
@@ -22,11 +22,11 @@
22
22
  <h5 class="card-title"><%= Spree.t(:currencies) %> & <%= Spree.t(:translations) %></h5>
23
23
  </div>
24
24
  <div class="card-body">
25
- <%= f.spree_select :default_currency, currency_options(@store.default_currency), { label: Spree.t(:default_currency), autocomplete: true } %>
26
- <%= f.spree_select :supported_currencies, currency_options(@store.supported_currencies&.split(',')), { prompt: false, multiple: true, autocomplete: true } %>
27
- <hr class="my-6" />
28
- <%= f.spree_select :default_locale, options_from_collection_for_select(all_locales_options, :last, :first, @store.default_locale || I18n.locale), { autocomplete: true } %>
29
- <%= f.spree_select :supported_locales, options_from_collection_for_select(all_locales_options, :last, :first, @store.supported_locales&.split(',')), { multiple: true, autocomplete: true } %>
25
+ <div class="alert alert-info w-full mb-0">
26
+ <span>
27
+ Currencies and locales are now managed by <%= link_to 'Markets', spree.admin_markets_path %>.
28
+ </span>
29
+ </div>
30
30
  </div>
31
31
  </div>
32
32
 
@@ -35,9 +35,12 @@
35
35
  <h5 class="card-title"><%= Spree.t(:standards_and_formats) %></h5>
36
36
  </div>
37
37
  <div class="card-body">
38
- <p class="text-gray-600">
38
+ <p class="text-gray-600 mb-3">
39
39
  <%= Spree.t(:standards_and_formats_help) %>
40
40
  </p>
41
+ <%= f.spree_select :preferred_admin_locale,
42
+ options_from_collection_for_select(all_locales_options, :last, :first, @store.preferred_admin_locale || I18n.default_locale),
43
+ { label: Spree.t(:admin_locale), help_bubble: Spree.t(:admin_locale_help), autocomplete: true } %>
41
44
  <div class="form-group mb-6">
42
45
  <%= label_tag :preferred_timezone, raw(Spree.t(:timezone) + required_span_tag) %>
43
46
  <%= time_zone_select :store, :preferred_timezone, nil, {}, { data: { controller: 'autocomplete-select' } } %>
@@ -73,7 +76,7 @@
73
76
  <%= f.spree_number_field :preferred_digital_asset_authorized_days, min: 1 %>
74
77
  </div>
75
78
  </div>
76
- <hr class="my-6" />
79
+ <hr class="my-6">
77
80
  <div data-controller="reveal">
78
81
  <%= f.spree_check_box :preferred_limit_digital_download_count, data: { action: 'reveal#toggle' } %>
79
82
  <div data-reveal-target="item" <% unless f.object.preferred_limit_digital_download_count %>class="hidden"<% end %>>
@@ -8,15 +8,12 @@
8
8
  </div>
9
9
 
10
10
  <div class="card-body">
11
- <%= f.spree_select :checkout_zone_id, options_for_select(@zones, @store.checkout_zone_id), { label: Spree.t(:shipping_zone), autocomplete: true } %>
12
- <span class="form-text mb-4">
13
- <%= Spree.t(:shipping_zone_help) %>
14
- <%= link_to Spree.t('admin.manage_zones'), spree.admin_zones_path, class: 'text-blue' %>
15
- </span>
11
+ <p class="text-muted mb-4">
12
+ <%= Spree.t('admin.checkout_settings.countries_managed_by_markets_html',
13
+ link: link_to(Spree.t('admin.markets.list'), spree.admin_markets_path)).html_safe %>
14
+ </p>
16
15
 
17
- <%= f.spree_select :default_country_iso, Spree::Country.pluck(:name, :iso), { include_blank: false, label: Spree.t(:default_country), autocomplete: true, help: Spree.t(:default_country_help) } %>
18
-
19
- <hr class="my-6" />
16
+ <hr class="my-6">
20
17
 
21
18
  <%= f.spree_check_box :preferred_guest_checkout, label: Spree.t('admin.checkout_settings.guest_checkout.label'), help: Spree.t('admin.checkout_settings.guest_checkout.description') %>
22
19
  <%= f.spree_check_box :preferred_company_field_enabled, label: Spree.t('admin.store_form.company_field.label'), help: Spree.t('admin.store_form.company_field.description') %>
@@ -0,0 +1,2 @@
1
+ <%# locals: (record:, column:, value:) %>
2
+ <%= api_key_status_badge(record) %>
@@ -0,0 +1,2 @@
1
+ <%# locals: (record:, column:, value:) %>
2
+ <%= api_key_type_badge(record) %>
@@ -8,7 +8,7 @@
8
8
  <% end if can?(:create, Spree::Taxon) %>
9
9
 
10
10
  <% content_for :page_actions_dropdown do %>
11
- <%= link_to_edit(@taxonomy.root, url: spree.edit_admin_taxonomy_taxon_path(@taxonomy, @taxonomy.root.id), class: 'text-left dropdown-item') %>
11
+ <%= link_to_edit(@taxonomy.root, url: spree.edit_admin_taxonomy_taxon_path(@taxonomy, @taxonomy.root), class: 'text-left dropdown-item') %>
12
12
  <% end if can?(:edit, @taxonomy) %>
13
13
 
14
14
  <div id="sortableTreeArea">
@@ -54,7 +54,7 @@
54
54
  </h5>
55
55
 
56
56
  <% if @taxon.manual? && can?(:create, Spree::Classification) %>
57
- <%= link_to_with_icon 'plus', Spree.t(:add_products), spree.new_admin_taxon_classification_path(@taxon.id), class: 'btn btn-secondary btn-sm', data: { turbo_frame: 'dialog', action: 'dialog#open' } %>
57
+ <%= link_to_with_icon 'plus', Spree.t(:add_products), spree.new_admin_taxon_classification_path(@taxon), class: 'btn btn-secondary btn-sm', data: { turbo_frame: 'dialog', action: 'dialog#open' } %>
58
58
  <% end %>
59
59
  </div>
60
60
 
@@ -67,7 +67,7 @@
67
67
 
68
68
  <div class="card-body min-h-[300px] p-0">
69
69
  <div class="block overflow-y-auto overflow-x-hidden max-h-[300px]">
70
- <%= turbo_frame_tag :classifications, src: spree.admin_taxon_classifications_path(@taxon.id), loading: :lazy do %>
70
+ <%= turbo_frame_tag :classifications, src: spree.admin_taxon_classifications_path(@taxon), loading: :lazy do %>
71
71
  <%= render 'spree/admin/shared/spinner' %>
72
72
  <% end %>
73
73
  </div>