spree_admin 5.0.0 → 5.0.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.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/spree/admin/components/_bulk_panel.scss +11 -1
  3. data/app/assets/stylesheets/spree/admin/components/_cards.scss +3 -4
  4. data/app/assets/stylesheets/spree/admin/components/_dropdowns.scss +1 -1
  5. data/app/assets/stylesheets/spree/admin/components/_main.scss +8 -1
  6. data/app/assets/stylesheets/spree/admin/components/_modals.scss +1 -1
  7. data/app/assets/stylesheets/spree/admin/global/_variables.scss +8 -2
  8. data/app/controllers/spree/admin/products_controller.rb +1 -8
  9. data/app/controllers/spree/admin/storefront_controller.rb +1 -1
  10. data/app/controllers/spree/admin/translations_controller.rb +1 -1
  11. data/app/helpers/spree/admin/base_helper.rb +49 -57
  12. data/app/helpers/spree/admin/bulk_operations_helper.rb +86 -0
  13. data/app/helpers/spree/admin/modal_helper.rb +29 -0
  14. data/app/helpers/spree/admin/navigation_helper.rb +76 -1
  15. data/app/helpers/spree/admin/orders_helper.rb +0 -19
  16. data/app/helpers/spree/admin/stores_helper.rb +5 -34
  17. data/app/javascript/spree/admin/controllers/variants_form_controller.js +6 -0
  18. data/app/views/active_storage/_upload_form.html.erb +4 -8
  19. data/app/views/spree/admin/assets/edit.html.erb +3 -8
  20. data/app/views/spree/admin/coupon_codes/index.html.erb +4 -6
  21. data/app/views/spree/admin/custom_domains/_custom_domains.html.erb +1 -1
  22. data/app/views/spree/admin/custom_domains/index.html.erb +1 -1
  23. data/app/views/spree/admin/customer_returns/index.html.erb +4 -17
  24. data/app/views/spree/admin/dashboard/_setup_progress.html.erb +4 -2
  25. data/app/views/spree/admin/dashboard/show.html.erb +1 -1
  26. data/app/views/spree/admin/digital_assets/_table.html.erb +1 -1
  27. data/app/views/spree/admin/digital_assets/edit.html.erb +3 -11
  28. data/app/views/spree/admin/digital_assets/new.html.erb +3 -11
  29. data/app/views/spree/admin/exports/index.html.erb +22 -24
  30. data/app/views/spree/admin/exports/new.html.erb +3 -9
  31. data/app/views/spree/admin/line_items/new.html.erb +2 -5
  32. data/app/views/spree/admin/oauth_applications/index.html.erb +57 -58
  33. data/app/views/spree/admin/option_types/_filter.html.erb +1 -1
  34. data/app/views/spree/admin/option_types/index.html.erb +7 -11
  35. data/app/views/spree/admin/orders/_filters.html.erb +2 -7
  36. data/app/views/spree/admin/orders/_list.html.erb +2 -4
  37. data/app/views/spree/admin/orders/billing_address/create.turbo_stream.erb +3 -6
  38. data/app/views/spree/admin/orders/billing_address/edit.html.erb +3 -6
  39. data/app/views/spree/admin/orders/billing_address/new.html.erb +3 -6
  40. data/app/views/spree/admin/orders/billing_address/update.turbo_stream.erb +3 -6
  41. data/app/views/spree/admin/orders/contact_information/edit.html.erb +3 -6
  42. data/app/views/spree/admin/orders/customer_returns/edit.html.erb +1 -10
  43. data/app/views/spree/admin/orders/index.html.erb +1 -1
  44. data/app/views/spree/admin/orders/return_authorizations/_form.html.erb +1 -1
  45. data/app/views/spree/admin/orders/return_authorizations/show.html.erb +45 -43
  46. data/app/views/spree/admin/orders/shipping_address/create.turbo_stream.erb +3 -6
  47. data/app/views/spree/admin/orders/shipping_address/edit.html.erb +3 -6
  48. data/app/views/spree/admin/orders/shipping_address/new.html.erb +3 -6
  49. data/app/views/spree/admin/orders/shipping_address/update.turbo_stream.erb +3 -6
  50. data/app/views/spree/admin/pages/_filters.html.erb +1 -1
  51. data/app/views/spree/admin/pages/edit.html.erb +2 -5
  52. data/app/views/spree/admin/pages/index.html.erb +4 -4
  53. data/app/views/spree/admin/payment_methods/index.html.erb +10 -8
  54. data/app/views/spree/admin/post_categories/index.html.erb +4 -6
  55. data/app/views/spree/admin/posts/_filters.html.erb +2 -7
  56. data/app/views/spree/admin/posts/_post.html.erb +1 -11
  57. data/app/views/spree/admin/posts/index.html.erb +5 -9
  58. data/app/views/spree/admin/products/_bulk_operations.html.erb +59 -94
  59. data/app/views/spree/admin/products/_filters.html.erb +12 -7
  60. data/app/views/spree/admin/products/_list.html.erb +2 -10
  61. data/app/views/spree/admin/products/_product.html.erb +1 -4
  62. data/app/views/spree/admin/products/bulk_modal.html.erb +3 -8
  63. data/app/views/spree/admin/products/index.html.erb +5 -5
  64. data/app/views/spree/admin/promotion_actions/new.html.erb +7 -12
  65. data/app/views/spree/admin/promotion_rules/new.html.erb +7 -12
  66. data/app/views/spree/admin/promotions/_filters.html.erb +27 -0
  67. data/app/views/spree/admin/promotions/index.html.erb +7 -35
  68. data/app/views/spree/admin/properties/index.html.erb +10 -9
  69. data/app/views/spree/admin/refund_reasons/index.html.erb +37 -35
  70. data/app/views/spree/admin/refunds/edit.html.erb +3 -8
  71. data/app/views/spree/admin/reimbursement_types/index.html.erb +42 -40
  72. data/app/views/spree/admin/reports/_report.html.erb +1 -1
  73. data/app/views/spree/admin/return_authorization_reasons/index.html.erb +41 -41
  74. data/app/views/spree/admin/return_authorizations/_filters.html.erb +1 -1
  75. data/app/views/spree/admin/return_authorizations/_list.html.erb +1 -10
  76. data/app/views/spree/admin/return_authorizations/index.html.erb +1 -1
  77. data/app/views/spree/admin/roles/_form.html.erb +1 -1
  78. data/app/views/spree/admin/roles/index.html.erb +26 -24
  79. data/app/views/spree/admin/shared/_bulk_modal.html.erb +6 -7
  80. data/app/views/spree/admin/shared/_filter_submit.html.erb +6 -0
  81. data/app/views/spree/admin/shared/_modal.html.erb +2 -8
  82. data/app/views/spree/admin/shared/_multi_product_picker.html.erb +2 -4
  83. data/app/views/spree/admin/shared/_no_resource_found.html.erb +1 -1
  84. data/app/views/spree/admin/shared/_product_image.html.erb +1 -10
  85. data/app/views/spree/admin/shared/_refunds.html.erb +1 -1
  86. data/app/views/spree/admin/shared/sidebar/_orders_nav.html.erb +1 -1
  87. data/app/views/spree/admin/shared/sidebar/_store_dropdown.html.erb +36 -7
  88. data/app/views/spree/admin/shared/sidebar/_store_nav.html.erb +4 -0
  89. data/app/views/spree/admin/shared/sortable_tree/_taxonomy.html.erb +3 -23
  90. data/app/views/spree/admin/shipping_categories/index.html.erb +28 -26
  91. data/app/views/spree/admin/shipping_methods/_actions.html.erb +1 -1
  92. data/app/views/spree/admin/shipping_methods/index.html.erb +23 -21
  93. data/app/views/spree/admin/stock_items/_filters.html.erb +2 -7
  94. data/app/views/spree/admin/stock_items/index.html.erb +5 -8
  95. data/app/views/spree/admin/stock_locations/_stock_location.html.erb +16 -13
  96. data/app/views/spree/admin/stock_locations/index.html.erb +24 -21
  97. data/app/views/spree/admin/stock_transfers/_filters.html.erb +1 -1
  98. data/app/views/spree/admin/stock_transfers/_new_variant_modal.html.erb +3 -5
  99. data/app/views/spree/admin/stock_transfers/index.html.erb +6 -6
  100. data/app/views/spree/admin/store_credit_categories/_form.html.erb +1 -1
  101. data/app/views/spree/admin/store_credit_categories/edit.html.erb +6 -4
  102. data/app/views/spree/admin/store_credit_categories/index.html.erb +28 -24
  103. data/app/views/spree/admin/store_credits/index.html.erb +2 -2
  104. data/app/views/spree/admin/storefront/edit.html.erb +7 -9
  105. data/app/views/spree/admin/stores/form/_policies.html.erb +1 -1
  106. data/app/views/spree/admin/stores/new.html.erb +8 -6
  107. data/app/views/spree/admin/tax_categories/index.html.erb +24 -22
  108. data/app/views/spree/admin/tax_rates/index.html.erb +26 -24
  109. data/app/views/spree/admin/taxonomies/index.html.erb +4 -4
  110. data/app/views/spree/admin/taxonomies/show.html.erb +2 -2
  111. data/app/views/spree/admin/themes/_theme_preview_image.html.erb +1 -10
  112. data/app/views/spree/admin/themes/index.html.erb +2 -2
  113. data/app/views/spree/admin/translations/_translations_unavailable.html.erb +6 -8
  114. data/app/views/spree/admin/users/_filters.html.erb +2 -7
  115. data/app/views/spree/admin/users/_tabs.html.erb +4 -4
  116. data/app/views/spree/admin/users/_user.html.erb +1 -4
  117. data/app/views/spree/admin/users/bulk_modal.html.erb +3 -8
  118. data/app/views/spree/admin/users/index.html.erb +25 -58
  119. data/app/views/spree/admin/variants/form/_media_asset.html.erb +1 -7
  120. data/app/views/spree/admin/variants/form/_pricing.html.erb +1 -1
  121. data/app/views/spree/admin/webhooks_subscribers/_form.html.erb +1 -1
  122. data/app/views/spree/admin/webhooks_subscribers/index.html.erb +25 -22
  123. data/app/views/spree/admin/webhooks_subscribers/show.html.erb +3 -3
  124. data/app/views/spree/admin/zones/index.html.erb +34 -32
  125. data/config/locales/en.yml +1 -3
  126. metadata +12 -9
  127. data/app/views/spree/admin/products/_empty_list.html.erb +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a3f2875dd028cc2a4d3dc3fb9933583918ff856afe242193a4c784bae6af84f
4
- data.tar.gz: 9b3ec33e0fbc122fa9915fb5f0199c2ec79e249f9291429713c6d7e5dd89e2b8
3
+ metadata.gz: d55b4e39523cee4652dddb953445f27d15190d2cff8e40d3f012329c3e3612ec
4
+ data.tar.gz: e919c13188d0b35f8c17afaa52fd6e26ea2eae5713e2f5c7d2abb81ea7b7cb9e
5
5
  SHA512:
6
- metadata.gz: 42d85993653cd2792a7ee9bb052da3a5dfab181415fb2362c73fd09f33acc46a4ed6253d81fcdbb3d61320ca14ca4d5fa5eb92f5080e292a179f397778dcfc1a
7
- data.tar.gz: cadca2e5fa570bf58c8de527f4702e9623e0ad3a3861a030404838a9ae3e1186d23cdd071dea58d3fe5222faf5a3d90f49cd095e767ea08b870f28cb21921944
6
+ metadata.gz: f7534f9a249beb83294f14d274920f12d7eb55504951365b0511e1efd980040a4811ffb9261af1aaf8074a60afb564176aa654c321bf771da211f629862e1281
7
+ data.tar.gz: 50b9265c84d615cade73af58b1af47ff41c043394ac10f9475d1a5cfdaf1398cf3bd274be2880264d846ad15e0ff9701e7b883cf1839b99eef34e198779db873
@@ -5,6 +5,9 @@
5
5
  background-color: $white;
6
6
  padding: 0.5rem;
7
7
  box-shadow: $dropdown-box-shadow;
8
+ animation: bounceInUp;
9
+ animation-duration: 0.5s;
10
+ gap: 0.75rem;
8
11
  }
9
12
 
10
13
  #bulk-panel {
@@ -28,4 +31,11 @@
28
31
  left: 16.66666667%;
29
32
  width: 83.33333333%;
30
33
  }
31
- }
34
+ }
35
+
36
+ .bulk-operations-counter {
37
+ display: inline-flex;
38
+ align-items: center;
39
+ justify-content: center;
40
+ gap: 0.25rem;
41
+ }
@@ -60,12 +60,11 @@
60
60
  }
61
61
 
62
62
  .card-lg {
63
- @extend .mb-3;
64
- @extend .bg-white;
65
-
63
+ margin-bottom: 1rem;
64
+ background-color: $white;
66
65
  border-radius: $border-radius-lg;
67
66
  border: 1px solid $card-border-color;
68
- padding: 1rem;
67
+ padding: 0;
69
68
  }
70
69
 
71
70
  .card-text {
@@ -26,7 +26,6 @@
26
26
  box-shadow: $dropdown-box-shadow;
27
27
 
28
28
  .dropdown-item, .dropdown-header {
29
- margin-bottom: 0.25rem;
30
29
  padding-left: $input-btn-padding-x;
31
30
  padding-right: $input-btn-padding-x;
32
31
  padding-top: $input-btn-padding-y;
@@ -34,6 +33,7 @@
34
33
  }
35
34
 
36
35
  .dropdown-item {
36
+ margin-bottom: 0.25rem;
37
37
  border-radius: $border-radius;
38
38
  display: flex;
39
39
  align-items: center;
@@ -82,7 +82,7 @@ turbo-frame[loading] .spinner-border, turbo-frame[busy] .spinner-border {
82
82
  }
83
83
  }
84
84
 
85
- .badge {
85
+ .badge:not(.badge-info) {
86
86
  @extend .badge-light;
87
87
  }
88
88
  }
@@ -156,3 +156,10 @@ turbo-frame[loading] .spinner-border, turbo-frame[busy] .spinner-border {
156
156
  top: 0.5rem;
157
157
  }
158
158
  }
159
+
160
+ .documentation-link-container {
161
+ font-size: $font-size-sm;
162
+ text-align: center;
163
+ margin-top: 2rem;
164
+ color: $gray-400;
165
+ }
@@ -25,7 +25,7 @@ body.modal-open {
25
25
  }
26
26
  .modal-footer {
27
27
  display: flex;
28
- justify-content: flex-end;
28
+ justify-content: space-between;
29
29
  padding: $modal-inner-padding;
30
30
  background-color: #FAFAFA;
31
31
  border-top: 1px solid $gray-50;
@@ -21,13 +21,16 @@ $black: #000000 !default;
21
21
  $blue: #0077ff !default;
22
22
  $white: #FFFFFF !default;
23
23
 
24
+ $action: #f1faff !default;
25
+ $action-border: #e2ecff !default;
26
+
24
27
  $theme-colors: (
25
28
  "white": $white,
26
29
  "black": $black,
27
30
  "primary": $primary,
28
31
  "secondary": rgba($blue, 0.1),
29
- "action": #f1faff,
30
- "action-border": #e2ecff,
32
+ "action": $action,
33
+ "action-border": $action-border,
31
34
  "active": $gray-25,
32
35
  "partial": #E2E8F0,
33
36
  "warning": #ffe17d,
@@ -67,6 +70,9 @@ $border-color: $gray-100 !default;
67
70
  $input-border-color: $gray-100 !default;
68
71
  $list-group-border-color: $border-color !default;
69
72
  $list-group-hover-bg: $gray-25 !default;
73
+ $list-group-active-bg: $action !default;
74
+ $list-group-active-border-color: $action-border !default;
75
+
70
76
  $thumbnail-border-color: $gray-100 !default;
71
77
  $hr-border-color: $border-color !default;
72
78
  $table-border-color: $gray-50 !default;
@@ -68,10 +68,7 @@ module Spree
68
68
  # update the product again
69
69
  @product.slug = @product.slug_was if @product.slug.blank?
70
70
  invoke_callbacks(:update, :fails)
71
- respond_to do |format|
72
- format.html { render :edit, status: :unprocessable_entity }
73
- format.turbo_stream
74
- end
71
+ render :edit, status: :unprocessable_entity
75
72
  end
76
73
  end
77
74
 
@@ -294,10 +291,6 @@ module Spree
294
291
 
295
292
  private
296
293
 
297
- def update_turbo_stream_enabled?
298
- true
299
- end
300
-
301
294
  def variant_stock_includes
302
295
  [:images, { stock_items: :stock_location, option_values: :option_type }]
303
296
  end
@@ -26,7 +26,7 @@ module Spree
26
26
  :meta_description, :meta_title, :meta_keywords, :seo_robots,
27
27
  :facebook, :twitter, :instagram, :linkedin, :youtube, :tiktok, :pinterest,
28
28
  :storefront_custom_code_head, :storefront_custom_code_body_start,
29
- :storefront_custom_code_body_end
29
+ :storefront_custom_code_body_end, :storefront_password
30
30
  )
31
31
  end
32
32
 
@@ -66,7 +66,7 @@ module Spree
66
66
  @back_path = spree.edit_admin_taxonomy_path(@resource)
67
67
  when Spree::Store
68
68
  @resource_name = @resource.name
69
- @back_path = spree.edit_admin_store_path(@resource, section: "general-settings")
69
+ @back_path = spree.edit_admin_store_path(section: "general-settings")
70
70
  end
71
71
  end
72
72
  end
@@ -21,6 +21,9 @@ module Spree
21
21
  @spree_update_available ||= !Rails.env.test? && spree_updater.update_available?
22
22
  end
23
23
 
24
+ # check if the current controller is a settings controller
25
+ # this is used to display different sidebar navigation for settings pages
26
+ # @return [Boolean]
24
27
  def settings_active?
25
28
  @settings_active || %w[stores zones shipping_methods oauth_applications
26
29
  payment_methods refund_reasons reimbursement_types
@@ -30,10 +33,19 @@ module Spree
30
33
  documents stripe_tax_registrations members subscriptions stock_locations webhooks_subscribers].include?(controller_name)
31
34
  end
32
35
 
36
+ # @return [Array<String>] the available countries for checkout
33
37
  def available_countries_iso
34
38
  @available_countries_iso ||= current_store.countries_available_for_checkout.pluck(:iso)
35
39
  end
36
40
 
41
+ # render an avatar for a user
42
+ # if user doesn't have an avatar, the user's initials will be displayed on a rounded background
43
+ # @param user [Spree::User] the user to render the avatar for
44
+ # @param options [Hash] the options for the avatar
45
+ # @option options [Integer] :width the width of the avatar, default: 128
46
+ # @option options [Integer] :height the height of the avatar, default: 128
47
+ # @option options [String] :class the CSS class(es) of the avatar, default: 'avatar'
48
+ # @return [String] the avatar
37
49
  def render_avatar(user, options = {})
38
50
  return unless user.present?
39
51
 
@@ -42,10 +54,10 @@ module Spree
42
54
  options[:class] ||= 'avatar'
43
55
 
44
56
  if user.respond_to?(:avatar) && user.avatar.attached? && user.avatar.variable?
45
- image_tag(
46
- main_app.cdn_image_url(
47
- user.avatar.variant(spree_image_variant_options(resize_to_fill: [options[:width] * 2, options[:height] * 2]))
48
- ),
57
+ spree_image_tag(
58
+ user.avatar,
59
+ width: options[:width],
60
+ height: options[:height],
49
61
  class: options[:class],
50
62
  style: "width: #{options[:width]}px; height: #{options[:height]}px;"
51
63
  )
@@ -54,12 +66,19 @@ module Spree
54
66
  end
55
67
  end
56
68
 
69
+ # returns the available display on options, eg backend, frontend, both
70
+ # @return [Array<Array<String, String>>] the available display on options
57
71
  def display_on_options
58
72
  Spree::DisplayOn::DISPLAY.map do |display_on|
59
73
  [Spree.t("admin.display_on_options.#{display_on}"), display_on]
60
74
  end
61
75
  end
62
76
 
77
+ # render an error message for a form field
78
+ # @param object [Spree::Model] the object to render the error message for
79
+ # @param method [String] the method to render the error message for
80
+ # @param options [Hash] the options for the error message
81
+ # @return [String] the error message
63
82
  def error_message_on(object, method, _options = {})
64
83
  object = convert_to_model(object)
65
84
  obj = object.respond_to?(:errors) ? object : instance_variable_get("@#{object}")
@@ -72,6 +91,10 @@ module Spree
72
91
  end
73
92
  end
74
93
 
94
+ # render an icon, using the tabler icons library
95
+ # @param icon_name [String] the name of the icon, eg: 'pencil', see: https://tabler.io/icons
96
+ # @param options [Hash] the options for the icon
97
+ # @return [String] the icon
75
98
  def icon(icon_name, options = {})
76
99
  if icon_name.ends_with?('.svg')
77
100
  icon_name = File.basename(icon_name, File.extname(icon_name))
@@ -91,42 +114,19 @@ module Spree
91
114
  content_tag :i, nil, class: "ti ti-#{icon_name} #{options[:class]}", style: styles
92
115
  end
93
116
 
117
+ # returns the flag emoji for a country
118
+ # @param iso [String] the ISO code of the country
119
+ # @return [String] the flag emoji
94
120
  def flag_emoji(iso)
95
121
  ::Country.new(iso).emoji_flag
96
122
  end
97
123
 
98
- def preference_field_tag(name, value, options)
99
- if options[:key] == :currency
100
- return select_tag(
101
- name,
102
- currency_options_for_select(
103
- value,
104
- current_store.supported_currencies.split(',')
105
- ),
106
- class: 'custom-select',
107
- disabled: current_store.supported_currencies.split(',').count == 1
108
- )
109
- end
110
-
111
- case options[:type]
112
- when :integer
113
- number_field_tag(name, value, preference_field_options(options))
114
- when :decimal
115
- number_field_tag(name, value, preference_field_options(options))
116
- when :boolean
117
- hidden_field_tag(name, 0, id: "#{name}_hidden") +
118
- check_box_tag(name, 1, value, preference_field_options(options))
119
- when :string
120
- text_field_tag(name, value, preference_field_options(options))
121
- when :password
122
- password_field_tag(name, value, preference_field_options(options))
123
- when :text
124
- text_area_tag(name, value, preference_field_options(options))
125
- else
126
- text_field_tag(name, value, preference_field_options(options))
127
- end
128
- end
129
-
124
+ # render a form field for a preference, according to the type of the preference (number, decimal, boolean, string, password, text)
125
+ # see https://spreecommerce.org/docs/developer/customization/model-preferences
126
+ # @param form [ActionView::Helpers::FormBuilder] the form builder
127
+ # @param field [String] the name of the field
128
+ # @param options [Hash] the options for the field
129
+ # @return [String] the preference field
130
130
  def preference_field_for(form, field, options)
131
131
  case options[:type]
132
132
  when :integer
@@ -146,6 +146,11 @@ module Spree
146
146
  end
147
147
  end
148
148
 
149
+ # returns the options for a preference field, according to the type of the preference (number, decimal, boolean, string, password, text)
150
+ # @param options [Hash] the options for the field
151
+ # @option options [Symbol] :type the type of the preference, eg. :integer, :decimal, :boolean, :string, :password, :text
152
+ # @option options [Boolean] :disabled whether the field is disabled
153
+ # @return [Hash] the options for the field
149
154
  def preference_field_options(options)
150
155
  field_options = case options[:type]
151
156
  when :integer
@@ -191,6 +196,10 @@ module Spree
191
196
  size: options[:size])
192
197
  end
193
198
 
199
+ # renders all the preference fields for an object
200
+ # @param object [Spree::TaxRate, Spree::Calculator, Spree::PaymentMethod, Spree::ShippingMethod, Spree::Store] the object to render the preference fields for
201
+ # @param form [ActionView::Helpers::FormBuilder] the form builder
202
+ # @return [String] the preference fields
194
203
  def preference_fields(object, form)
195
204
  return unless object.respond_to?(:preferences)
196
205
 
@@ -227,31 +236,14 @@ module Spree
227
236
  dom_id(record, 'spree')
228
237
  end
229
238
 
239
+ # renders a red dot with a * to indicate that a field is required
240
+ # @return [String] the required span tag
230
241
  def required_span_tag
231
242
  content_tag(:span, ' *', class: 'required font-weight-bold text-danger')
232
243
  end
233
244
 
234
- def external_page_preview_link(resource, options = {})
235
- resource_name = options[:name] || resource.class.name.demodulize
236
-
237
- url = if [Spree::Product, Spree::Post].include?(resource.class)
238
- spree_storefront_resource_url(resource, preview_id: resource.id)
239
- else
240
- spree_storefront_resource_url(resource)
241
- end
242
-
243
- link_to_with_icon(
244
- 'eye',
245
- Spree.t('admin.utilities.preview', name: resource_name),
246
- url,
247
- class: 'text-left dropdown-item', id: "adminPreview#{resource_name}", target: :blank, data: { turbo: false }
248
- )
249
- end
250
-
251
- def path_from_url(url)
252
- url.to_s.gsub('https://', '').gsub('http://', '')
253
- end
254
-
245
+ # returns the allowed file types for upload, according to the active storage configuration
246
+ # @return [Array<String>] the allowed file types for upload, eg. ['image/png', 'image/jpeg', 'image/gif', 'image/webp']
255
247
  def allowed_file_types_for_upload
256
248
  Rails.application.config.active_storage.web_image_content_types
257
249
  end
@@ -0,0 +1,86 @@
1
+ module Spree
2
+ module Admin
3
+ module BulkOperationsHelper
4
+ # render a checkbox to select all items for bulk operations
5
+ # @return [String]
6
+ def bulk_operations_select_all_checkbox
7
+ content_tag :div, class: "custom-control custom-checkbox ml-1" do
8
+ check_box_tag(
9
+ nil,
10
+ nil,
11
+ false,
12
+ id: "checkAllMasterCheckbox",
13
+ class: "custom-control-input",
14
+ data: { bulk_operation_target: "checkboxAll" }
15
+ ) +
16
+ content_tag(:label, content_tag(:span, ""), class: "custom-control-label", for: "checkAllMasterCheckbox")
17
+ end
18
+ end
19
+
20
+ # render a checkbox to select an item for bulk operations
21
+ # @param object [Spree::Product, Spree::User, Spree::Order]
22
+ # @return [String]
23
+ def bulk_operations_checkbox(object)
24
+ content_tag :div, class: "custom-control custom-checkbox ml-1" do
25
+ check_box_tag(
26
+ "ids[]",
27
+ object.id,
28
+ false,
29
+ class: "custom-control-input",
30
+ id: "ids_#{object.id}",
31
+ data: { bulk_operation_target: "checkbox" }
32
+ ) +
33
+ content_tag(:label, content_tag(:span, ""), class: "custom-control-label", for: "ids_#{object.id}")
34
+ end
35
+ end
36
+
37
+ # render a link to perform a bulk action
38
+ # @param text [String] the text of the link
39
+ # @param path [String] the path of the link
40
+ # @param options [Hash] the options of the link
41
+ # @option options [String] :icon the icon of the link
42
+ # @option options [String] :url the url to perform the bulk action to be set for the form in bulk modal
43
+ # @option options [String] :class the class of the link
44
+ # @option options [String] :data the data of the link
45
+ # @return [String]
46
+ def bulk_action_link(text, path, options = {})
47
+ options[:data] ||= {}
48
+ options[:data][:action] ||= 'click->bulk-operation#setBulkAction'
49
+ options[:data][:turbo_frame] ||= :bulk_modal
50
+ options[:data][:url] ||= options[:url]
51
+ options[:class] ||= 'btn btn-light'
52
+
53
+ if options[:icon]
54
+ text = icon(options[:icon]) + ' ' + text
55
+ end
56
+
57
+ content_tag :span, data: { toggle: 'modal', target: '#bulk-modal' } do
58
+ link_to text, path, options
59
+ end
60
+ end
61
+
62
+ # render a close button for the bulk modal
63
+ def bulk_operations_close_button
64
+ button_tag(
65
+ '',
66
+ type: 'button',
67
+ class: 'btn-close',
68
+ data: {
69
+ dismiss: 'modal',
70
+ aria_label: Spree.t(:close),
71
+ action: 'bulk-operation#cancel'
72
+ }
73
+ )
74
+ end
75
+
76
+ # render a counter for the bulk operations
77
+ # @return [String]
78
+ def bulk_operations_counter
79
+ content_tag(:span, class: 'bulk-operations-counter ml-1') do
80
+ content_tag(:strong, '', data: { bulk_operation_target: 'counter' }) +
81
+ Spree.t("admin.selected")
82
+ end
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,29 @@
1
+ module Spree
2
+ module Admin
3
+ module ModalHelper
4
+ # render a header for the modal
5
+ # @param title [String, Proc] the title of the modal
6
+ # @return [String]
7
+ def modal_header(title)
8
+ title = capture(&title) if block_given?
9
+ content_tag(:div, class: 'modal-header') do
10
+ content_tag(:h5, title, class: 'modal-title') + modal_close_button
11
+ end.html_safe
12
+ end
13
+
14
+ # render a close button for the modal
15
+ # @return [String]
16
+ def modal_close_button
17
+ button_tag('', type: 'button', class: 'btn-close', data: { dismiss: 'modal', aria_label: Spree.t(:close) }).html_safe
18
+ end
19
+
20
+ # render a discard button for the modal
21
+ # @return [String]
22
+ def modal_discard_button
23
+ button_tag(type: 'button', class: 'btn btn-light', data: { dismiss: 'modal' }) do
24
+ Spree.t('actions.discard')
25
+ end.html_safe
26
+ end
27
+ end
28
+ end
29
+ end
@@ -16,6 +16,7 @@ module Spree
16
16
 
17
17
  # the per_page_dropdown is used on index pages like orders, products, promotions etc.
18
18
  # this method generates the select_tag
19
+ # @return [String]
19
20
  def per_page_dropdown
20
21
  per_page_default = if @products
21
22
  Spree::Admin::RuntimeConfig.admin_products_per_page
@@ -48,6 +49,8 @@ module Spree
48
49
 
49
50
  # helper method to create proper url to apply per page ing
50
51
  # fixes https://github.com/spree/spree/issues/6888
52
+ # @param per_page [Integer] the number of items per page
53
+ # @return [Hash] the params to apply per page
51
54
  def per_page_dropdown_params(per_page)
52
55
  args = params.permit!.to_h.clone
53
56
  args.delete(:page)
@@ -56,6 +59,12 @@ module Spree
56
59
  args
57
60
  end
58
61
 
62
+ # render a button link to edit a resource
63
+ # if the current user doesn't have permission to update the resource, the button will not be rendered
64
+ # @param resource [Spree::Product, Spree::User, Spree::Order] the resource to edit
65
+ # @param options [Hash] the options for the link
66
+ # @option options [String] :url the url to edit the resource (optional)
67
+ # @return [String] the link to edit the resource
59
68
  def link_to_edit(resource, options = {})
60
69
  url = options[:url] || edit_object_url(resource)
61
70
  options[:data] ||= {}
@@ -64,6 +73,12 @@ module Spree
64
73
  link_to_with_icon('pencil', Spree.t(:edit), url, options) if can?(:update, resource)
65
74
  end
66
75
 
76
+ # render a button to delete a resource with a confirmation modal
77
+ # if the current user doesn't have permission to destroy the resource, the button will not be rendered
78
+ # @param resource [Spree::Product, Spree::User, Spree::Order] the resource to delete
79
+ # @param options [Hash] the options for the link
80
+ # @option options [String] :url the url to delete the resource (optional)
81
+ # @return [String] the link to delete the resource
67
82
  def link_to_delete(resource, options = {})
68
83
  url = options[:url] || object_url(resource)
69
84
  name = options[:name] || Spree.t('actions.destroy')
@@ -81,6 +96,12 @@ module Spree
81
96
  end
82
97
  end
83
98
 
99
+ # renders a link with an icon
100
+ # @param icon_name [String] the name of the icon, eg: 'pencil', see: https://tabler.io/icons
101
+ # @param text [String] the text of the link
102
+ # @param url [String] the url of the link
103
+ # @param options [Hash] the options for the link
104
+ # @return [String] the link with the icon
84
105
  def link_to_with_icon(icon_name, text, url, options = {})
85
106
  options[:class] ||= (options[:class].to_s + " with-tip").strip
86
107
  options[:title] ||= text if options[:no_text]
@@ -95,6 +116,12 @@ module Spree
95
116
  link_to(text.html_safe, url, options)
96
117
  end
97
118
 
119
+ # renders an active link with an icon, using the active_link_to method from https://github.com/comfy/active_link_to gem
120
+ # @param icon_name [String] the name of the icon, eg: 'pencil', see: https://tabler.io/icons
121
+ # @param text [String] the text of the link
122
+ # @param url [String] the url of the link
123
+ # @param options [Hash] the options for the link
124
+ # @return [String] the active link with the icon
98
125
  def active_link_to_with_icon(icon_name, text, url, options = {})
99
126
  options[:class] = (options[:class].to_s + " with-tip").strip
100
127
  options[:title] = text if options[:no_text]
@@ -109,7 +136,13 @@ module Spree
109
136
  active_link_to(text.html_safe, url, options)
110
137
  end
111
138
 
139
+ # renders a button with an icon (optional)
112
140
  # Override: Add disable_with option to prevent multiple request on consecutive clicks
141
+ # @param text [String] the text of the button
142
+ # @param icon_name [String] the name of the icon, eg: 'pencil', see: https://tabler.io/icons
143
+ # @param button_type [String] the type of the button, eg: 'submit', 'button'
144
+ # @param options [Hash] the options for the button
145
+ # @return [String] the button with the icon
113
146
  def button(text, icon_name = nil, button_type = 'submit', options = {})
114
147
  if icon_name
115
148
  text = "#{icon(icon_name, class: "icon icon-#{icon_name}")} #{text}"
@@ -128,6 +161,8 @@ module Spree
128
161
  end
129
162
 
130
163
  def button_link_to(text, url, html_options = {})
164
+ Spree::Deprecation.warn("button_link_to is deprecated. Use standard link_to instead.")
165
+
131
166
  if html_options[:method] &&
132
167
  !html_options[:method].to_s.casecmp('get').zero? &&
133
168
  !html_options[:remote]
@@ -149,6 +184,10 @@ module Spree
149
184
  end
150
185
  end
151
186
 
187
+ # renders a badge (active/inactive)
188
+ # @param condition [Boolean] the condition to check
189
+ # @param options [Hash] the options for the badge
190
+ # @return [String] the badge with the icon
152
191
  def active_badge(condition, options = {})
153
192
  label = options[:label]
154
193
  label ||= condition ? Spree.t(:say_yes) : Spree.t(:say_no)
@@ -161,6 +200,11 @@ module Spree
161
200
  end
162
201
  end
163
202
 
203
+ # renders a back button to the previous page
204
+ # @param default_url [String] the default url to go back to
205
+ # @param object [Spree::Product, Spree::User, Spree::Order] the object list to go back to
206
+ # @param label [String] the label of the back button (optional)
207
+ # @return [String] the back button
164
208
  def page_header_back_button(default_url, object = nil, label = nil)
165
209
  url = default_url
166
210
 
@@ -175,10 +219,15 @@ module Spree
175
219
  end
176
220
  end
177
221
 
222
+ # renders an external link with an icon (eg. spree documentation website)
223
+ # @param label [String] the label of the link
224
+ # @param url [String] the url of the link
225
+ # @param opts [Hash] the options for the link
226
+ # @return [String] the external link with the icon
178
227
  def external_link_to(label, url, opts = {}, &block)
179
228
  opts[:target] ||= :blank
180
229
  opts[:rel] ||= :nofollow
181
- opts[:class] ||= "d-inline-flex align-items-center text-blue"
230
+ opts[:class] ||= "d-inline-flex align-items-center text-blue text-decoration-none"
182
231
 
183
232
  if block_given?
184
233
  link_to url, opts, &block
@@ -189,6 +238,32 @@ module Spree
189
238
  end
190
239
  end
191
240
 
241
+ # renders a link to preview a resource on the storefront using the spree_storefront_resource_url helper
242
+ # @param resource [Spree::Product, Spree::Post] the resource to preview
243
+ # @param options [Hash] the options for the link
244
+ # @return [String] the link to preview the resource
245
+ def external_page_preview_link(resource, options = {})
246
+ resource_name = options[:name] || resource.class.name.demodulize
247
+
248
+ url = if [Spree::Product, Spree::Post].include?(resource.class)
249
+ spree_storefront_resource_url(resource, preview_id: resource.id)
250
+ else
251
+ spree_storefront_resource_url(resource)
252
+ end
253
+
254
+ link_to_with_icon(
255
+ 'eye',
256
+ Spree.t('admin.utilities.preview', name: resource_name),
257
+ url,
258
+ class: 'text-left dropdown-item', id: "adminPreview#{resource_name}", target: :blank, data: { turbo: false }
259
+ )
260
+ end
261
+
262
+ # renders a help bubble with an icon
263
+ # @param text [String] the text of the help bubble
264
+ # @param placement [String] the placement of the help bubble
265
+ # @param css [String] the css class of the help bubble
266
+ # @return [String] the help bubble with the icon
192
267
  def help_bubble(text = '', placement = 'bottom', css: nil)
193
268
  css ||= 'text-muted'
194
269
  content_tag :small, icon('info-square-rounded', class: css), data: { placement: placement }, class: "with-tip #{css}", title: text
@@ -69,25 +69,6 @@ module Spree
69
69
  end
70
70
  end
71
71
 
72
- # Renders all the extension partials that may have been specified in the extensions
73
- def event_links(order, events)
74
- links = []
75
- events.each do |event|
76
- next unless order.send("can_#{event}?")
77
-
78
- label = Spree.t(event, scope: 'admin.order.events', default: Spree.t(event))
79
- links << button_link_to(
80
- label.capitalize,
81
- [event.to_sym, :admin, order],
82
- method: :put,
83
- icon: event.to_s + '.svg',
84
- data: { turbo_confirm: Spree.t(:order_sure_want_to, event: label) },
85
- class: 'btn-light'
86
- )
87
- end
88
- safe_join(links, ''.html_safe)
89
- end
90
-
91
72
  def line_item_shipment_price(line_item, quantity)
92
73
  Spree::Money.new(line_item.price * quantity, currency: line_item.currency)
93
74
  end