spree_admin 5.4.0.rc3 → 5.4.0.rc4.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1ca74c8ed8e383bcc1bd52d20db41e88aa9924a62305219e34af249b307d832d
4
- data.tar.gz: f7e712fe81c3d2a56cf1c0407755878feead32a54a3bdfeb277581a95055249f
3
+ metadata.gz: 155efe978034445f003e603c616a55745cb7d3e465ed4e1e6fe0f2ee7066cff4
4
+ data.tar.gz: 78cd7484369236dbb81525b341e80fe245083c7b4e85f35a1feb3b10d3fdd30e
5
5
  SHA512:
6
- metadata.gz: 3d0d5c786e70948d127f38621773498ebdbad6bfba3e6951b32ba34e1572185c2d72277b6d1cdcd293dfaaef04107d9f72e3572e6cbc34907005531ef28692be
7
- data.tar.gz: 9158b307eaae7635cbdbc09e26ef622ef43077db911373f948966c6d104eb95f66ae845d0cd696ac6c317dc3dddfead396adffa78efad46f027b5e942bdc147b
6
+ metadata.gz: eefd3828d29707d5f46cf287241adbe931f29957a84e19f12d0bb74a62b262ddf381bccdb6c05cb0f3f4608a951b11ed90304ddf9fe118cbee857bf9d3983b1e
7
+ data.tar.gz: 3a4f00885e5a492bb1247d9655b1a50d3626afccc09d7f489866634a422139b93e10f2c212fb2dee7959033a9200afa88636f348db767111d8fba763c182641e
@@ -76,7 +76,12 @@
76
76
  @apply block mt-1 text-sm text-danger;
77
77
  }
78
78
 
79
- /* Select */
79
+ /* Select — ensure text doesn't overlap the dropdown arrow */
80
+ .form-select,
81
+ .custom-select {
82
+ @apply pr-10;
83
+ }
84
+
80
85
  .custom-select:disabled,
81
86
  .custom-select[readonly],
82
87
  .form-select:disabled,
@@ -95,6 +95,7 @@ module Spree
95
95
 
96
96
  def bulk_status_update
97
97
  bulk_collection.update_all(status: params[:status], updated_at: Time.current)
98
+ bulk_collection.each(&:enqueue_search_index) # reindex products
98
99
  invoke_callbacks(:bulk_status_update, :after)
99
100
 
100
101
  handle_bulk_operation_response
@@ -238,6 +239,7 @@ module Spree
238
239
 
239
240
  def after_bulk_tags_change
240
241
  Spree::Product.bulk_auto_match_taxons(current_store, bulk_collection.ids)
242
+ bulk_collection.each(&:enqueue_search_index) # reindex products
241
243
  end
242
244
 
243
245
  def variant_stock_includes
@@ -10,6 +10,14 @@ module Spree
10
10
 
11
11
  belongs_to 'spree/webhook_endpoint'
12
12
 
13
+ def redeliver
14
+ load_resource
15
+ authorize! :update, @object.webhook_endpoint
16
+ new_delivery = @object.redeliver!
17
+ flash[:success] = Spree.t('admin.webhook_deliveries.redelivered')
18
+ redirect_back(fallback_location: spree.admin_webhook_endpoint_webhook_delivery_path(@object.webhook_endpoint, new_delivery))
19
+ end
20
+
13
21
  private
14
22
 
15
23
  def collection_default_sort
@@ -8,6 +8,19 @@ module Spree
8
8
 
9
9
  helper 'spree/admin/webhook_endpoints'
10
10
 
11
+ def test
12
+ load_resource
13
+ authorize! :update, @object
14
+ begin
15
+ @object.send_test!
16
+ flash[:success] = Spree.t('admin.webhook_endpoints.test_sent')
17
+ rescue StandardError => e
18
+ Rails.error.report(e, context: { webhook_endpoint_id: @object.id, url: @object.url })
19
+ flash[:error] = Spree.t('admin.webhook_endpoints.test_failed')
20
+ end
21
+ redirect_back(fallback_location: spree.admin_webhook_endpoint_path(@object))
22
+ end
23
+
11
24
  private
12
25
 
13
26
  def permitted_resource_params
@@ -12,7 +12,7 @@ module Spree
12
12
  link_to_with_icon(
13
13
  'code',
14
14
  Spree.t('admin.show_json'),
15
- spree.admin_json_preview_resource_path(record.id, resource_type: record.class.to_s),
15
+ spree.admin_json_preview_resource_path(record.to_param, resource_type: record.class.to_s),
16
16
  options
17
17
  )
18
18
  end
@@ -10,7 +10,7 @@ module Spree
10
10
  options[:class] ||= 'dropdown-item'
11
11
  options[:data] ||= { action: 'drawer#open', turbo_frame: :drawer }
12
12
 
13
- link_to_with_icon 'edit', Spree.t(:metafields), spree.edit_admin_metafield_path(record.id, resource_type: record.class.name), options
13
+ link_to_with_icon 'edit', Spree.t(:metafields), spree.edit_admin_metafield_path(record.to_param, resource_type: record.class.name), options
14
14
  end
15
15
 
16
16
  def metafield_definition_resource_types
@@ -12,7 +12,7 @@ module Spree
12
12
  link_to_with_icon(
13
13
  'language',
14
14
  Spree.t(:translations),
15
- spree.edit_admin_translation_path(resource.id, resource_type: resource.class.to_s),
15
+ spree.edit_admin_translation_path(resource.to_param, resource_type: resource.class.to_s),
16
16
  options
17
17
  )
18
18
  end
@@ -66,15 +66,33 @@ module Spree
66
66
  end
67
67
 
68
68
  def webhook_endpoint_success_percentage(webhook_endpoint)
69
- return '' if webhook_endpoint.webhook_deliveries.none?
69
+ return nil if webhook_endpoint.webhook_deliveries.none?
70
70
 
71
71
  (webhook_endpoint.webhook_deliveries.successful.count / webhook_endpoint.webhook_deliveries.count.to_f * 100).round(2)
72
72
  end
73
73
 
74
+ def webhook_endpoint_health_badge(endpoint)
75
+ if endpoint.auto_disabled?
76
+ content_tag(:span, Spree.t('admin.webhook_endpoints.health.disabled'), class: 'badge badge-danger')
77
+ elsif endpoint.webhook_deliveries.none?
78
+ content_tag(:span, Spree.t('admin.webhook_endpoints.health.no_deliveries'), class: 'badge badge-light')
79
+ else
80
+ pct = webhook_endpoint_success_percentage(endpoint)
81
+ if pct >= 95
82
+ content_tag(:span, Spree.t('admin.webhook_endpoints.health.healthy', percentage: pct), class: 'badge badge-success')
83
+ elsif pct >= 80
84
+ content_tag(:span, Spree.t('admin.webhook_endpoints.health.degraded', percentage: pct), class: 'badge badge-warning')
85
+ else
86
+ content_tag(:span, Spree.t('admin.webhook_endpoints.health.failing', percentage: pct), class: 'badge badge-danger')
87
+ end
88
+ end
89
+ end
90
+
74
91
  private
75
92
 
76
93
  def custom_webhook_events
77
94
  %w[
95
+ customer.password_reset_requested
78
96
  order.completed
79
97
  order.paid
80
98
  order.canceled
@@ -1,7 +1,7 @@
1
1
  <%= turbo_frame_tag :drawer do %>
2
2
  <%= drawer_header(Spree.t(:metafields)) %>
3
3
  <% if @metafields.present? %>
4
- <%= form_for @object, url: spree.admin_metafield_path(@object.id, resource_type: model_class.to_s), method: :put do |f| %>
4
+ <%= form_for @object, url: spree.admin_metafield_path(@object.to_param, resource_type: model_class.to_s), method: :put do |f| %>
5
5
  <div class="drawer-body">
6
6
  <%= f.fields_for :metafields, @metafields do |metafield_form| %>
7
7
  <%= metafield_form.hidden_field :id %>
@@ -3,7 +3,7 @@
3
3
  <div data-replace-target="from">
4
4
  <div readonly class="input-group bg-gray-25 border border-gray-100">
5
5
  <span class="text-gray-600 py-2 grow pl-2">
6
- <%= form.object.send(field).length.times do %>&bull; <% end %>
6
+ <%= 16.times do %>&bull; <% end %>
7
7
  <%= form.object.send(field)&.last(4) %>
8
8
  </span>
9
9
  <button class="btn btn-sm btn-light mr-1" type="button" data-action="click->replace#replace">
@@ -7,6 +7,16 @@
7
7
  <%= link_to_with_icon 'plus', Spree.t(:new_price_list), new_object_url, class: 'btn btn-primary' if can?(:create, Spree::PriceList) %>
8
8
  <% end %>
9
9
 
10
+ <% content_for :page_alerts do %>
11
+ <div class="alert alert-info">
12
+ Price lists are a powerful tool for managing pricing strategies based on customer groups, products, or other criteria.
13
+ </div>
14
+ <% end %>
15
+
10
16
  <%= render_admin_partials(:price_lists_header_partials) %>
11
17
 
12
18
  <%= render_table @collection, :price_lists, sortable: true %>
19
+
20
+ <p class="documentation-link-container">
21
+ <%= external_link_to "Learn more about price lists", "https://spreecommerce.org/docs/user/manage-products/price-lists" %>
22
+ </p>
@@ -0,0 +1,2 @@
1
+ <%# locals: (record:, column:, value:) %>
2
+ <%= webhook_endpoint_health_badge(record) %>
@@ -1,7 +1,7 @@
1
1
  <%= turbo_frame_tag :drawer do %>
2
2
  <%= drawer_header(Spree.t(:translations)) %>
3
3
  <% if @locales.any? %>
4
- <%= form_for @object, url: spree.admin_translation_path(@object.id, resource_type: model_class.to_s), method: :put do |f| %>
4
+ <%= form_for @object, url: spree.admin_translation_path(@object.to_param, resource_type: model_class.to_s), method: :put do |f| %>
5
5
  <div class="drawer-body">
6
6
  <ul class="nav nav-pills mb-3">
7
7
  <% @locales.each do |locale| %>
@@ -32,7 +32,7 @@
32
32
  <p class="text-center mb-3"><%= Spree.t('admin.translations.no_translations_configured') %></p>
33
33
 
34
34
  <% if can?(:edit, current_store) %>
35
- <%= link_to_with_icon 'settings', Spree.t('admin.translations.configure_store'), spree.edit_admin_store_path(section: 'general-settings'), class: 'btn btn-primary', data: { 'turbo-frame': '_top' } %>
35
+ <%= link_to_with_icon 'world', Spree.t('admin.translations.manage_markets'), spree.edit_admin_store_path(section: 'general-settings'), class: 'btn btn-primary', data: { 'turbo-frame': '_top' } %>
36
36
  <% end %>
37
37
  </div>
38
38
  </div>
@@ -57,5 +57,15 @@
57
57
  <%= code_block @webhook_delivery.response_body.truncate(2000) %>
58
58
  <% end %>
59
59
 
60
+ <% if @webhook_delivery.failed? %>
61
+ <div class="pt-2">
62
+ <%= button_to Spree.t('admin.webhook_deliveries.redeliver_button'),
63
+ spree.redeliver_admin_webhook_endpoint_webhook_delivery_path(@webhook_delivery.webhook_endpoint, @webhook_delivery),
64
+ method: :post,
65
+ class: 'btn btn-primary w-full',
66
+ data: { turbo: false } %>
67
+ </div>
68
+ <% end %>
69
+
60
70
  </div>
61
71
  <% end %>
@@ -3,7 +3,8 @@
3
3
  <h5 class="card-title"><%= Spree.t('admin.webhook_endpoints.endpoint_settings') %></h5>
4
4
  </div>
5
5
  <div class="card-body">
6
- <%= f.spree_text_field :url, required: true, autofocus: f.object.new_record?, placeholder: 'https://example.com/webhooks', disabled: f.object.persisted? %>
6
+ <%= f.spree_text_field :name, placeholder: 'e.g. Storefront emails, Fulfillment service' %>
7
+ <%= f.spree_text_field :url, required: true, autofocus: f.object.new_record?, placeholder: 'https://example.com/webhooks' %>
7
8
  <%= f.spree_check_box :active %>
8
9
  </div>
9
10
  </div>
@@ -1,6 +1,21 @@
1
+ <% if @webhook_endpoint.auto_disabled? %>
2
+ <div class="alert alert-danger mb-6">
3
+ <%= Spree.t('admin.webhook_endpoints.auto_disabled') %>
4
+ <%= button_to Spree.t('admin.webhook_endpoints.re_enable'), spree.admin_webhook_endpoint_path(@webhook_endpoint), method: :patch,
5
+ params: { webhook_endpoint: { active: true } }, class: 'btn btn-sm btn-outline-danger ms-2', data: { turbo: false } %>
6
+ </div>
7
+ <% end %>
8
+
1
9
  <div class="card mb-6">
2
10
  <div class="card-body">
3
- <div class="grid grid-cols-2 lg:grid-cols-3 gap-6">
11
+ <div class="grid grid-cols-2 lg:grid-cols-4 gap-6">
12
+ <div class="flex flex-col mb-6 lg:mb-0 border-r gap-2">
13
+ <span class="text-sm text-gray-500"><%= Spree.t('admin.webhook_endpoints.health_label') %></span>
14
+ <span class="text-lg">
15
+ <%= webhook_endpoint_health_badge(@webhook_endpoint) %>
16
+ </span>
17
+ </div>
18
+
4
19
  <div class="flex flex-col mb-6 lg:mb-0 border-r gap-2">
5
20
  <span class="text-sm text-gray-500"><%= Spree.t('admin.webhook_endpoints.deliveries') %></span>
6
21
  <span class="text-lg text-gray-900 font-bold">
@@ -1,6 +1,14 @@
1
1
  <%= content_for :page_title do %>
2
2
  <%= page_header_back_button(collection_url) %>
3
- <%= @webhook_endpoint.url %>
3
+ <%= @webhook_endpoint.name.presence || @webhook_endpoint.url %>
4
+ <% end %>
5
+
6
+ <%= content_for :page_actions do %>
7
+ <%= button_to Spree.t('admin.webhook_endpoints.send_test'),
8
+ spree.test_admin_webhook_endpoint_path(@webhook_endpoint),
9
+ method: :post,
10
+ class: 'btn btn-light',
11
+ data: { turbo: false } %>
4
12
  <% end %>
5
13
 
6
14
  <div class="grid grid-cols-12 gap-6">
@@ -1178,11 +1178,20 @@ Rails.application.config.after_initialize do
1178
1178
  # ==========================================
1179
1179
  # Webhook Endpoints Table
1180
1180
  # ==========================================
1181
- Spree.admin.tables.register(:webhook_endpoints, model_class: Spree::WebhookEndpoint, search_param: :url_cont, row_actions: false, link_to_action: :show)
1181
+ Spree.admin.tables.register(:webhook_endpoints, model_class: Spree::WebhookEndpoint, search_param: :name_or_url_cont, row_actions: false, link_to_action: :show)
1182
+
1183
+ Spree.admin.tables.webhook_endpoints.add :name,
1184
+ label: :name,
1185
+ type: :link,
1186
+ sortable: true,
1187
+ filterable: true,
1188
+ default: true,
1189
+ position: 5,
1190
+ method: ->(endpoint) { endpoint.name.presence || endpoint.url }
1182
1191
 
1183
1192
  Spree.admin.tables.webhook_endpoints.add :url,
1184
1193
  label: :url,
1185
- type: :link,
1194
+ type: :string,
1186
1195
  sortable: true,
1187
1196
  filterable: true,
1188
1197
  default: true,
@@ -1201,6 +1210,15 @@ Rails.application.config.after_initialize do
1201
1210
  { value: 'false', label: 'Inactive' }
1202
1211
  ]
1203
1212
 
1213
+ Spree.admin.tables.webhook_endpoints.add :health,
1214
+ label: 'admin.webhook_endpoints.health_label',
1215
+ type: :custom,
1216
+ sortable: false,
1217
+ filterable: false,
1218
+ default: true,
1219
+ position: 25,
1220
+ partial: 'spree/admin/tables/columns/webhook_endpoint_health'
1221
+
1204
1222
  Spree.admin.tables.webhook_endpoints.add :subscriptions_count,
1205
1223
  label: 'admin.webhook_endpoints.events',
1206
1224
  type: :string,
@@ -52,19 +52,16 @@ en:
52
52
  products:
53
53
  body:
54
54
  add_tags: 'Select tags to add to the products:'
55
- add_to_brand: 'Select which brand to add the products to:'
56
- add_to_taxons: 'Select which taxons to add the products to:'
57
- remove_from_taxons: 'Select which taxons to remove the products from:'
55
+ add_to_taxons: 'Select which categories to add the products to:'
56
+ remove_from_taxons: 'Select which categories to remove the products from:'
58
57
  remove_tags: 'Select tags to remove from the products:'
59
58
  set_active: Setting products to active will make those products available on the storefront.
60
59
  set_archived: Setting products to archived will hide them from storefront.
61
60
  set_draft: Setting products to draft will hide them from storefront.
62
61
  title:
63
62
  add_tags: Add tags
64
- add_to_brand: Add to brand
65
- add_to_taxons: Add to taxons
66
- remove_from_brand: Remove from brand
67
- remove_from_taxons: Remove from taxons
63
+ add_to_taxons: Add to categories
64
+ remove_from_taxons: Remove from categories
68
65
  remove_tags: Remove tags
69
66
  set_active: Set as Active
70
67
  set_archived: Set as Archived
@@ -149,7 +146,7 @@ en:
149
146
  manage_currencies: Manage Currencies
150
147
  manage_properties: Manage Properties
151
148
  manage_stock_locations: Manage Stock Locations
152
- manage_taxons: Manage Taxons
149
+ manage_taxons: Manage Categories
153
150
  manage_zones: Manage Zones
154
151
  markets:
155
152
  edit: Edit Market
@@ -227,7 +224,7 @@ en:
227
224
  not_set: Not set
228
225
  separated: Separated
229
226
  show_more_button: Show explore category button
230
- show_taxon_image: Show taxon image
227
+ show_taxon_image: Show category image
231
228
  text_color: Text color
232
229
  title: Title
233
230
  top_padding: Top padding
@@ -362,15 +359,15 @@ en:
362
359
  on_sale: On sale
363
360
  products_must_match: 'Products must match:'
364
361
  tag: Product tag
365
- taxon_type: Taxon type
362
+ taxon_type: Category type
366
363
  taxon_types:
367
364
  automatic: Automatic
368
- automatic_info: Automatically add products to this taxon if they match the rules you set.
365
+ automatic_info: Automatically add products to this category if they match the rules you set.
369
366
  manual: Manual
370
367
  manual_info: Curate products manually. You can add or remove them in bulk.
371
368
  translations:
372
- configure_store: Configure store
373
- no_translations_configured: No translations configured. Please configure more than one locale for the store to use translations.
369
+ manage_markets: Manage Markets
370
+ no_translations_configured: No translations configured. Please setup Markets to use translations.
374
371
  upload_new_asset: Upload new asset
375
372
  user:
376
373
  last_order_placed: Last order placed
@@ -402,11 +399,14 @@ en:
402
399
  execution_time: Execution Time
403
400
  failed: Failed
404
401
  pending: Pending
402
+ redeliver_button: Redeliver
403
+ redelivered: Webhook redelivered successfully.
405
404
  request_errors: Request Errors
406
405
  request_payload: Request Payload
407
406
  response_body: Response Body
408
407
  response_code: Response Code
409
408
  webhook_endpoints:
409
+ auto_disabled: This endpoint was automatically disabled after repeated delivery failures.
410
410
  back_to_endpoint: Back to endpoint
411
411
  deliveries: Deliveries
412
412
  endpoint_settings: Endpoint Settings
@@ -414,11 +414,22 @@ en:
414
414
  event_subscriptions_help: Select which events should trigger a webhook delivery to this endpoint.
415
415
  events: events
416
416
  failed_deliveries: Failed Deliveries
417
+ health:
418
+ degraded: "%{percentage}% success"
419
+ disabled: Disabled
420
+ failing: "%{percentage}% success"
421
+ healthy: "%{percentage}% success"
422
+ no_deliveries: No data
423
+ health_label: Health
417
424
  new: New Webhook Endpoint
425
+ re_enable: Re-enable
418
426
  secret_key: Secret Key
419
427
  secret_key_help: Use this key to verify webhook signatures. Keep it secure and do not share it publicly.
428
+ send_test: Send Test
420
429
  subscriptions: Subscriptions
421
430
  successful_deliveries: Successful Deliveries
431
+ test_failed: Failed to send test webhook. Please check the endpoint configuration.
432
+ test_sent: Test webhook sent. Check deliveries for the result.
422
433
  webhooks_subscribers:
423
434
  all_events: All Events
424
435
  new_webhooks_subscriber: New Webhooks Subscriber
data/config/routes.rb CHANGED
@@ -256,7 +256,14 @@ Spree::Core::Engine.add_routes do
256
256
  end
257
257
  end
258
258
  resources :webhook_endpoints do
259
- resources :webhook_deliveries, only: [:index, :show]
259
+ member do
260
+ post :test
261
+ end
262
+ resources :webhook_deliveries, only: [:index, :show] do
263
+ member do
264
+ post :redeliver
265
+ end
266
+ end
260
267
  end
261
268
  resources :allowed_origins, except: :show
262
269
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: spree_admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.4.0.rc3
4
+ version: 5.4.0.rc4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vendo Connect Inc.
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-03-25 00:00:00.000000000 Z
11
+ date: 2026-03-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: spree
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 5.4.0.rc3
19
+ version: 5.4.0.rc4.1
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
- version: 5.4.0.rc3
26
+ version: 5.4.0.rc4.1
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: active_link_to
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -997,6 +997,7 @@ files:
997
997
  - app/views/spree/admin/tables/columns/_webhook_deliveries_stats.html.erb
998
998
  - app/views/spree/admin/tables/columns/_webhook_delivery_actions.html.erb
999
999
  - app/views/spree/admin/tables/columns/_webhook_delivery_status.html.erb
1000
+ - app/views/spree/admin/tables/columns/_webhook_endpoint_health.html.erb
1000
1001
  - app/views/spree/admin/tax_categories/_form.html.erb
1001
1002
  - app/views/spree/admin/tax_categories/edit.html.erb
1002
1003
  - app/views/spree/admin/tax_categories/index.html.erb
@@ -1169,9 +1170,9 @@ licenses:
1169
1170
  - BSD-3-Clause
1170
1171
  metadata:
1171
1172
  bug_tracker_uri: https://github.com/spree/spree/issues
1172
- changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.0.rc3
1173
+ changelog_uri: https://github.com/spree/spree/releases/tag/v5.4.0.rc4.1
1173
1174
  documentation_uri: https://docs.spreecommerce.org/
1174
- source_code_uri: https://github.com/spree/spree/tree/v5.4.0.rc3
1175
+ source_code_uri: https://github.com/spree/spree/tree/v5.4.0.rc4.1
1175
1176
  post_install_message:
1176
1177
  rdoc_options: []
1177
1178
  require_paths: