spree_admin 5.0.2 → 5.0.4

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/spree/admin/dashboard_controller.rb +11 -12
  3. data/app/controllers/spree/admin/page_blocks_controller.rb +10 -2
  4. data/app/controllers/spree/admin/page_sections_controller.rb +13 -1
  5. data/app/controllers/spree/admin/webhooks_subscribers_controller.rb +32 -13
  6. data/app/helpers/spree/admin/base_helper.rb +1 -1
  7. data/app/helpers/spree/admin/navigation_helper.rb +1 -1
  8. data/app/helpers/spree/admin/orders_helper.rb +3 -1
  9. data/app/helpers/spree/admin/products_helper.rb +4 -0
  10. data/app/helpers/spree/admin/tags_helper.rb +1 -1
  11. data/app/javascript/spree/admin/application.js +0 -2
  12. data/app/javascript/spree/admin/controllers/asset_uploader_controller.js +3 -2
  13. data/app/javascript/spree/admin/controllers/variants_form_controller.js +22 -2
  14. data/app/javascript/spree/admin/helpers/trix/video_embed.js +2 -2
  15. data/app/views/spree/admin/dashboard/_top_products.html.erb +1 -1
  16. data/app/views/spree/admin/orders/_filters.html.erb +11 -1
  17. data/app/views/spree/admin/orders/_summary.html.erb +1 -1
  18. data/app/views/spree/admin/page_blocks/forms/_image.html.erb +9 -0
  19. data/app/views/spree/admin/page_builder/_sidebar_block.html.erb +10 -9
  20. data/app/views/spree/admin/page_builder/_sidebar_sections_toolbar.html.erb +152 -39
  21. data/app/views/spree/admin/payment_methods/_form.html.erb +1 -1
  22. data/app/views/spree/admin/products/form/_inventory.html.erb +1 -1
  23. data/app/views/spree/admin/products/form/_properties.html.erb +1 -1
  24. data/app/views/spree/admin/products/form/_variants.html.erb +1 -0
  25. data/app/views/spree/admin/shared/_head.html.erb +6 -1
  26. data/app/views/spree/admin/shared/_tax_nav.html.erb +1 -0
  27. data/app/views/spree/admin/shared/_user.html.erb +1 -1
  28. data/app/views/spree/admin/shared/sidebar/_store_nav.html.erb +3 -2
  29. data/app/views/spree/admin/shared/sidebar/_storefront_nav.html.erb +2 -0
  30. data/app/views/spree/admin/stores/form/_basic.html.erb +1 -1
  31. data/app/views/spree/admin/taxons/_form.html.erb +2 -2
  32. data/app/views/spree/admin/users/_form.html.erb +1 -1
  33. data/app/views/spree/admin/users/_user.html.erb +7 -6
  34. data/app/views/spree/admin/users/index.html.erb +6 -5
  35. data/app/views/spree/admin/variants/form/_media.html.erb +1 -0
  36. data/app/views/spree/admin/webhooks_subscribers/_form.html.erb +37 -19
  37. data/app/views/spree/admin/webhooks_subscribers/_webhooks_subscriber.html.erb +12 -6
  38. data/app/views/spree/admin/webhooks_subscribers/edit.html.erb +2 -2
  39. data/app/views/spree/admin/webhooks_subscribers/show.html.erb +58 -47
  40. data/config/importmap.rb +2 -2
  41. data/config/locales/en.yml +1 -1
  42. data/lib/spree/admin/engine.rb +9 -1
  43. data/vendor/javascript/bootstrap--dist--js--bootstrap.bundle.min.js.js +4 -4
  44. data/vendor/javascript/dompurify.js +24 -24
  45. metadata +8 -9
  46. data/app/javascript/spree/admin/controllers/webhook_subscriber_events_controller.js +0 -19
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1fb2e27934e0ce22324b5a7c032fbeb7d0abf76d3512f726dd0acddc30a217dc
4
- data.tar.gz: 3caabc53934c4c0bdbd2b70bfea5dcaa9685eb3acb9a2d2bcebcc362c4807e73
3
+ metadata.gz: 896d26ce5c5cefb448bf77753fbb39af32b548d26aad748b20eae32ac51f1972
4
+ data.tar.gz: c51934c9b3763132ad0978789d770645819016286aa505a065e0257a1bbb517d
5
5
  SHA512:
6
- metadata.gz: ffb8d7703b134adf2439b7f035557930448883896f6e4a07daea768de52847d13dc0ed7ca8cb37fc1e38e0df637b7fcbfb54cc3d7e13fdf03adc23493714e33a
7
- data.tar.gz: 88f4985f3985761932f2e341ed62085658c925a18244718bb14ffc729b3074cc9d726fa8419c70af12a3da77e9a624f39d3bba5841b4d759a03a1cb8abaad994
6
+ metadata.gz: 3e4045b8196f7e9d3464942a40d5d8875ee37b0511df0e41a91876f83f052ea84ac94623ead5f91eff08fb1be514cb268894af96cd1b678045fb2f21ab6d26b6
7
+ data.tar.gz: 2845718bc86d3007d26c8482fe14b566d72a51b5b0159557969ce53c42cc2ddba9abd853da9458ee3914901cdce1341212babe1010e7b8dab81109d6cc0cf090
@@ -111,9 +111,11 @@ module Spree
111
111
  @audience_growth_rate = calc_growth_rate(@audience_total, previous_audience_total)
112
112
 
113
113
  @audience = if same_day?
114
- @audience_scope.group_by_hour(:created_at, range: analytics_time_range, time_zone: current_store.preferred_timezone, default_value: 0)
114
+ @audience_scope.group_by_hour(:created_at, range: analytics_time_range, time_zone: current_store.preferred_timezone,
115
+ default_value: 0)
115
116
  else
116
- @audience_scope.group_by_day(:created_at, range: analytics_time_range, time_zone: current_store.preferred_timezone, default_value: 0)
117
+ @audience_scope.group_by_day(:created_at, range: analytics_time_range, time_zone: current_store.preferred_timezone,
118
+ default_value: 0)
117
119
  end
118
120
 
119
121
  return unless defined?(Ahoy)
@@ -123,25 +125,22 @@ module Spree
123
125
  previous_visits_total = Ahoy::Visit.where(started_at: previous_analytics_time_range).count
124
126
  @visits_growth_rate = calc_growth_rate(@visits_total, previous_visits_total)
125
127
 
126
- @visits_scope = Ahoy::Visit.where(started_at: analytics_time_range)
127
- @visits_total = @visits_scope.count
128
- previous_visits_total = Ahoy::Visit.where(started_at: previous_analytics_time_range).count
129
- @visits_growth_rate = calc_growth_rate(@visits_total, previous_visits_total)
130
-
131
128
  @visits = if same_day?
132
- @visits_scope.group_by_hour(:started_at, range: analytics_time_range, time_zone: current_store.preferred_timezone, default_value: 0)
129
+ @visits_scope.group_by_hour(:started_at, range: analytics_time_range, time_zone: current_store.preferred_timezone,
130
+ default_value: 0)
133
131
  else
134
- @visits_scope.group_by_day(:started_at, range: analytics_time_range, time_zone: current_store.preferred_timezone, default_value: 0)
132
+ @visits_scope.group_by_day(:started_at, range: analytics_time_range, time_zone: current_store.preferred_timezone,
133
+ default_value: 0)
135
134
  end
136
135
 
137
- @top_landing_pages = @visits_scope.where.not(landing_page_title: [nil, '']).top(:landing_page_title, 10)
136
+ @top_landing_pages = @visits_scope.where.not(landing_page: [nil, '']).top(:landing_page, 10)
138
137
  @top_referrers = @visits_scope.where.not(referring_domain: current_store.custom_domains.pluck(:url) << current_store.url).top(
139
138
  :referring_domain, 10
140
139
  )
141
140
  @top_locations = @visits_scope.top(:country, 10)
142
141
  @top_devices = @visits_scope.group(:device_type).count.transform_keys do |device|
143
- device.nil? ? 'N/A' : device
144
- end.map { |series| [series.first, (series.second.to_f / @visits_scope.count) * 100] }
142
+ device.nil? ? 'N/A' : device
143
+ end.map { |series| [series.first, (series.second.to_f / @visits_scope.count) * 100] }
145
144
  end
146
145
  end
147
146
  end
@@ -26,15 +26,23 @@ module Spree
26
26
  end
27
27
 
28
28
  def create
29
- allowed_types = Rails.application.config.spree.page_blocks.map(&:to_s)
30
29
  page_block_type = params.dig(:page_block, :type)
31
30
 
32
- if allowed_types.include?(page_block_type) && page_block_type.safe_constantize.present?
31
+ if allowed_types.map(&:to_s).include?(page_block_type) && page_block_type.safe_constantize.present?
33
32
  @page_block = page_block_type.constantize.new
34
33
  @page_block.section = @page_section
35
34
  @page_block.save!
36
35
  end
37
36
  end
37
+
38
+ private
39
+
40
+ def allowed_types
41
+ [
42
+ *Rails.application.config.spree.page_blocks,
43
+ *parent&.available_blocks_to_add
44
+ ].uniq.sort_by(&:name)
45
+ end
38
46
  end
39
47
  end
40
48
  end
@@ -7,7 +7,7 @@ module Spree
7
7
 
8
8
  def create
9
9
  page_section_type = params.dig(:page_section, :type)
10
- allowed_types = Rails.application.config.spree.page_sections.map(&:to_s)
10
+ allowed_types = available_page_section_types.map(&:to_s)
11
11
 
12
12
  if allowed_types.include?(page_section_type) && page_section_type.safe_constantize.present?
13
13
  @page_section = page_section_type.constantize.new(permitted_resource_params)
@@ -52,6 +52,18 @@ module Spree
52
52
  current_store.theme_previews.find(params[:theme_id])
53
53
  end
54
54
  end
55
+
56
+ def available_page_section_types
57
+ return [] unless @pageable.present?
58
+
59
+ if @pageable.is_a?(Spree::Theme)
60
+ @pageable.available_page_sections
61
+ elsif @pageable.respond_to?(:theme)
62
+ @pageable.theme.available_page_sections
63
+ else
64
+ []
65
+ end
66
+ end
55
67
  end
56
68
  end
57
69
  end
@@ -1,20 +1,11 @@
1
1
  module Spree
2
2
  module Admin
3
3
  class WebhooksSubscribersController < ResourceController
4
+ before_action :set_supported_events, except: [:index, :show]
5
+
4
6
  create.before :process_subscriptions
5
7
  update.before :process_subscriptions
6
8
 
7
- def index
8
- params[:q] ||= {}
9
- params[:q][:s] ||= 'created_at desc'
10
-
11
- search = Webhooks::Subscriber.accessible_by(current_ability).ransack(params[:q])
12
- @webhooks_subscribers = search.result.
13
- includes(:events).
14
- page(params[:page]).
15
- per(params[:per_page])
16
- end
17
-
18
9
  def show
19
10
  @webhooks_subscriber = Webhooks::Subscriber.find(params[:id])
20
11
  @events = @webhooks_subscriber.events.order(created_at: :desc).page(params[:page]).per(params[:per_page])
@@ -26,7 +17,19 @@ module Spree
26
17
  @resource ||= Spree::Admin::Resource.new 'spree/admin/webhooks/subscribers', 'subscribers', nil
27
18
  end
28
19
 
20
+ def collection
21
+ params[:q] ||= {}
22
+ params[:q][:s] ||= 'created_at desc'
23
+
24
+ @search = Webhooks::Subscriber.accessible_by(current_ability).ransack(params[:q])
25
+ @collection = @search.result.
26
+ page(params[:page]).
27
+ per(params[:per_page])
28
+ end
29
+
29
30
  def process_subscriptions
31
+ return if params[:webhooks_subscriber].blank?
32
+
30
33
  params[:webhooks_subscriber][:subscriptions] = if params[:subscribe_to_all_events] == 'true'
31
34
  ['*']
32
35
  else
@@ -37,12 +40,28 @@ module Spree
37
40
  end
38
41
 
39
42
  def selected_events
40
- supported_events.select { |resource, _events| params[:webhooks_subscriber][resource] == 'true' }.values.flatten
43
+ @supported_events.select { |resource, _events| params[:webhooks_subscriber][resource] == 'true' }.values.flatten
41
44
  end
42
45
 
43
- def supported_events
46
+ def set_supported_events
44
47
  @supported_events ||= Spree::Webhooks::Subscriber.supported_events
45
48
  end
49
+
50
+ def supported_events
51
+ @supported_events
52
+ end
53
+
54
+ def permitted_resource_params
55
+ params.require(:webhooks_subscriber).permit(:url, :active, subscriptions: [])
56
+ end
57
+
58
+ def location_after_create
59
+ location_after_save
60
+ end
61
+
62
+ def location_after_save
63
+ spree.admin_webhooks_subscriber_path(@object)
64
+ end
46
65
  end
47
66
  end
48
67
  end
@@ -10,7 +10,7 @@ module Spree
10
10
  end
11
11
 
12
12
  def enterprise_edition?
13
- defined?(Vendo)
13
+ defined?(SpreeEnterprise)
14
14
  end
15
15
 
16
16
  def spree_updater
@@ -190,7 +190,7 @@ module Spree
190
190
  # @return [String] the badge with the icon
191
191
  def active_badge(condition, options = {})
192
192
  label = options[:label]
193
- label ||= condition ? Spree.t(:say_yes) : Spree.t(:say_no)
193
+ label ||= condition ? Spree.t(:say_yes).to_s : Spree.t(:say_no).to_s
194
194
  label = icon('check') + label if condition
195
195
 
196
196
  css_class = condition ? 'badge-active' : 'badge-inactive'
@@ -25,8 +25,10 @@ module Spree
25
25
  icon('credit-card-refund') + Spree.t('payment_states.refunded')
26
26
  elsif order.partially_refunded?
27
27
  icon('credit-card-refund') + Spree.t('payment_states.partially_refunded')
28
- elsif order.payment_state == 'failed' || order.payment_state == 'void'
28
+ elsif order.payment_state == 'failed'
29
29
  icon('cancel') + Spree.t('payment_states.failed')
30
+ elsif order.payment_state == 'void'
31
+ icon('cancel') + Spree.t('payment_states.void')
30
32
  elsif order.payment_state == 'paid'
31
33
  icon('check') + Spree.t('payment_states.paid')
32
34
  else
@@ -122,6 +122,10 @@ module Spree
122
122
  def product_list_filters_search_form_path
123
123
  [:admin, @search]
124
124
  end
125
+
126
+ def sorted_product_properties(product)
127
+ product.product_properties.sort_by { |product_property| product_property.property.position }
128
+ end
125
129
  end
126
130
  end
127
131
  end
@@ -13,7 +13,7 @@ module Spree
13
13
  @post_tags_scope ||= ActsAsTaggableOn::Tag.
14
14
  joins(:taggings).
15
15
  where("#{ActsAsTaggableOn.taggings_table}.taggable_type = ?", 'Spree::Post').
16
- for_context(:tags)
16
+ for_context(:tags).for_tenant(current_store.id)
17
17
  end
18
18
 
19
19
  def post_tags_json_array
@@ -78,7 +78,6 @@ import StockTransferController from 'spree/admin/controllers/stock_transfer_cont
78
78
  import StoreFormController from 'spree/admin/controllers/store_form_controller'
79
79
  import UnitSystemController from 'spree/admin/controllers/unit_system_controller'
80
80
  import VariantsFormController from 'spree/admin/controllers/variants_form_controller'
81
- import WebhooksSubscriberEventsController from 'spree/admin/controllers/webhook_subscriber_events_controller'
82
81
  import AddressAutocompleteController from 'spree/core/controllers/address_autocomplete_controller'
83
82
  import AddressFormController from 'spree/core/controllers/address_form_controller'
84
83
  import EnableButtonController from 'spree/core/controllers/enable_button_controller'
@@ -131,7 +130,6 @@ application.register('tabs', Tabs)
131
130
  application.register('textarea-autogrow', TextareaAutogrow)
132
131
  application.register('unit-system', UnitSystemController)
133
132
  application.register('variants-form', VariantsFormController)
134
- application.register('webhooks-subscriber-events', WebhooksSubscriberEventsController)
135
133
 
136
134
  LocalTime.start()
137
135
 
@@ -11,7 +11,8 @@ export default class extends Controller {
11
11
  viewableType: String,
12
12
  multiple: { type: Boolean, default: false },
13
13
  type: { type: String, default: 'image' },
14
- allowedFileTypes: { type: Array, default: [] }
14
+ allowedFileTypes: { type: Array, default: [] },
15
+ adminAssetsPath: String
15
16
  }
16
17
 
17
18
  connect() {
@@ -43,7 +44,7 @@ export default class extends Controller {
43
44
  }
44
45
 
45
46
  handleSuccessResult(response) {
46
- post('/admin/assets', {
47
+ post(this.adminAssetsPathValue, {
47
48
  body: JSON.stringify({
48
49
  asset: {
49
50
  type: this.assetClassValue,
@@ -37,7 +37,8 @@ export default class extends CheckboxSelectAll {
37
37
  currentStockLocationId: String,
38
38
  stockLocations: Array,
39
39
  optionValuesSelectOptions: Array,
40
- locale: String
40
+ locale: String,
41
+ adminPath: String
41
42
  }
42
43
 
43
44
  connect() {
@@ -67,6 +68,8 @@ export default class extends CheckboxSelectAll {
67
68
  .filter((internalName) => !existingVariantsOnServer.includes(internalName))
68
69
  )
69
70
  }
71
+
72
+ this.inventoryFormTarget = document.querySelector('.inventory-form');
70
73
  }
71
74
 
72
75
  toggleQuantityTracked() {
@@ -236,11 +239,14 @@ export default class extends CheckboxSelectAll {
236
239
  }
237
240
 
238
241
  optionsValueChanged(value, previousValue) {
242
+ let hasNoOptions = true
243
+
239
244
  if (this.hasNewOptionButtonTarget) {
240
245
  const label = this.newOptionButtonLabelTarget
241
246
 
242
247
  if (Object.values(value).filter(Boolean).length) {
243
248
  label.textContent = label.dataset.hasOptionsText
249
+ hasNoOptions = false
244
250
  } else {
245
251
  label.textContent = label.dataset.noOptionsText
246
252
  }
@@ -248,6 +254,8 @@ export default class extends CheckboxSelectAll {
248
254
  this.refreshOptionNameSelect()
249
255
  this.variantsValue = this.generateVariants(value)
250
256
 
257
+ this.toggleInventoryForm(hasNoOptions)
258
+
251
259
  // We want to clear the ignoredVariants when the options change
252
260
  if (previousValue && Object.keys(previousValue).length === 0) return
253
261
  this.ignoredVariants = new Set()
@@ -717,7 +725,7 @@ export default class extends CheckboxSelectAll {
717
725
  this.lastOptionNameId = targetInput.value
718
726
 
719
727
  if (this.lastOptionNameId) {
720
- const response = await get(`/admin/option_types/${this.lastOptionNameId}/option_values/select_options`)
728
+ const response = await get(`${this.adminPathValue}/option_types/${this.lastOptionNameId}/option_values/select_options`)
721
729
 
722
730
  if (response.ok) {
723
731
  this.currentOptionValues[this.lastOptionNameId] = await response.json
@@ -765,6 +773,8 @@ export default class extends CheckboxSelectAll {
765
773
  this.addOption(newOptionName, newOptionValues, newOptionId)
766
774
 
767
775
  this.hideNewOptionForm()
776
+
777
+ this.toggleInventoryForm(false)
768
778
  }
769
779
 
770
780
  hideNewOptionForm() {
@@ -1052,4 +1062,14 @@ export default class extends CheckboxSelectAll {
1052
1062
  }
1053
1063
  }
1054
1064
  }
1065
+
1066
+ toggleInventoryForm(value) {
1067
+ if (!this.inventoryFormTarget) return
1068
+
1069
+ if (value) {
1070
+ this.inventoryFormTarget.classList.remove('d-none')
1071
+ } else {
1072
+ this.inventoryFormTarget.classList.add('d-none')
1073
+ }
1074
+ }
1055
1075
  }
@@ -90,7 +90,7 @@ document.addEventListener("trix-attachment-remove", async function(event) {
90
90
  const { attachment } = event
91
91
  const { sgid } = attachment.attachment.attributes.values
92
92
 
93
- destroy(`/admin/action_text/video_embeds/${sgid}`, { responseKind: 'json' })
93
+ destroy(`${Spree.adminPath}/action_text/video_embeds/${sgid}`, { responseKind: 'json' })
94
94
  })
95
95
 
96
96
  function initializeTrixEditor(editor) {
@@ -129,7 +129,7 @@ function initializeTrixEditor(editor) {
129
129
 
130
130
  errorMessage.innerHTML = ''
131
131
 
132
- const response = await post('/admin/action_text/video_embeds', { body: JSON.stringify({ url: input.value }), responseKind: 'json' })
132
+ const response = await post(`${Spree.adminPath}/action_text/video_embeds`, { body: JSON.stringify({ url: input.value }), responseKind: 'json' })
133
133
 
134
134
  if (response.ok) {
135
135
  const { sgid, content } = await response.json
@@ -45,7 +45,7 @@
45
45
  <%= product.name %>
46
46
  <% end %>
47
47
  </td>
48
- <% if enterprise_edition? && defined?(vendor_logo_link) && !@vendor %>
48
+ <% if defined?(vendor_logo_link) && !@vendor %>
49
49
  <td>
50
50
  <%= vendor_logo_link(product.vendor) if product.vendor.present? %>
51
51
  </td>
@@ -1,7 +1,17 @@
1
1
  <% frame_name ||= nil %>
2
2
 
3
+ <% search_form_path = if @user.present?
4
+ spree.admin_user_orders_path(@user)
5
+ elsif @vendor.present? && spree.respond_to?(:admin_vendor_orders_path)
6
+ spree.admin_vendor_orders_path(@vendor)
7
+ elsif controller_name == 'checkouts'
8
+ spree.admin_checkouts_path
9
+ else
10
+ spree.admin_orders_path
11
+ end %>
12
+
3
13
  <%= search_form_for [:admin, @vendor || @user, @search],
4
- url: controller_name == 'checkouts' ? spree.admin_checkouts_path : nil,
14
+ url: search_form_path,
5
15
  class: "filter-wrap",
6
16
  data: {
7
17
  controller: "filters reveal",
@@ -74,7 +74,7 @@
74
74
  <%= render 'tax_lines', tax_lines: tax_lines, id: 'tax-lines-additional' %>
75
75
  </li>
76
76
 
77
- <%= render_admin_partials(:order_page_body_partials, order: @order) %>
77
+ <%= render_admin_partials(:order_page_summary_partials, order: @order) %>
78
78
 
79
79
  <li class="list-group-item d-flex justify-content-between align-items-center border-0">
80
80
  <span data-hook='admin_order_tab_total_title'><%= Spree.t(:total) %></span>
@@ -1 +1,10 @@
1
1
  <%= render 'active_storage/upload_form', form: f, field_name: :asset, width: 512, height: 512, auto_submit: true %>
2
+
3
+ <% content_for(:design_tab) do %>
4
+ <%= render 'spree/admin/page_builder/labeled_range_input',
5
+ f: f, field: :preferred_height, min: 1, max: 1024, unit: 'px', _label: 'Max image height on desktop'
6
+ %>
7
+ <%= render 'spree/admin/page_builder/labeled_range_input',
8
+ f: f, field: :preferred_mobile_height, min: 1, max: 512, unit: 'px', _label: 'Max image height on mobile'
9
+ %>
10
+ <% end %>
@@ -7,15 +7,16 @@
7
7
  } do %>
8
8
  <div class="d-flex align-items-center justify-content-between sidebar-block-title p-1 rounded-sm">
9
9
  <div class="d-flex align-items-center flex-fill">
10
- <%= icon "#{block.icon_name}", class: 'mr-2' if block.icon_name.present? %>
11
- <%= link_to block.display_name, edit_admin_page_section_block_path(block.section, block),
12
- class: 'block-edit-link flex-fill text-dark',
13
- data: {
14
- turbo_frame: :page_sidebar,
15
- action: 'click->page-builder#makeOverlayActive',
16
- page_builder_editor_id_param: "block-#{block.id}"
17
- }
18
- %>
10
+ <%= link_to(edit_admin_page_section_block_path(block.section, block),
11
+ class: 'block-edit-link flex-fill text-dark',
12
+ data: {
13
+ turbo_frame: :page_sidebar,
14
+ action: 'click->page-builder#makeOverlayActive',
15
+ page_builder_editor_id_param: "block-#{block.id}"
16
+ }) do %>
17
+ <%= icon "#{block.icon_name}", class: 'mr-2' if block.icon_name.present? %>
18
+ <%= block.display_name %>
19
+ <% end %>
19
20
  </div>
20
21
  <div class="d-flex align-items-center d-none">
21
22
  <% if block.section.can_sort_blocks? %>