spree_admin 5.0.0 → 5.0.2

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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/stylesheets/spree/admin/components/_alerts.scss +6 -3
  3. data/app/assets/stylesheets/spree/admin/components/_bulk_panel.scss +11 -1
  4. data/app/assets/stylesheets/spree/admin/components/_cards.scss +3 -4
  5. data/app/assets/stylesheets/spree/admin/components/_dropdowns.scss +1 -1
  6. data/app/assets/stylesheets/spree/admin/components/_main.scss +8 -1
  7. data/app/assets/stylesheets/spree/admin/components/_modals.scss +1 -1
  8. data/app/assets/stylesheets/spree/admin/global/_variables.scss +12 -6
  9. data/app/assets/stylesheets/spree/admin/shared/_base.scss +3 -5
  10. data/app/controllers/spree/admin/posts_controller.rb +6 -0
  11. data/app/controllers/spree/admin/products_controller.rb +7 -8
  12. data/app/controllers/spree/admin/storefront_controller.rb +1 -1
  13. data/app/controllers/spree/admin/translations_controller.rb +1 -1
  14. data/app/controllers/spree/admin/users_controller.rb +1 -1
  15. data/app/helpers/spree/admin/base_helper.rb +49 -57
  16. data/app/helpers/spree/admin/bulk_operations_helper.rb +86 -0
  17. data/app/helpers/spree/admin/modal_helper.rb +29 -0
  18. data/app/helpers/spree/admin/navigation_helper.rb +76 -1
  19. data/app/helpers/spree/admin/orders_helper.rb +0 -19
  20. data/app/helpers/spree/admin/stores_helper.rb +5 -34
  21. data/app/javascript/spree/admin/controllers/slug_form_controller.js +0 -3
  22. data/app/javascript/spree/admin/controllers/variants_form_controller.js +6 -0
  23. data/app/javascript/spree/admin/helpers/bootstrap.js +3 -3
  24. data/app/views/active_storage/_upload_form.html.erb +4 -8
  25. data/app/views/spree/admin/assets/edit.html.erb +3 -8
  26. data/app/views/spree/admin/coupon_codes/index.html.erb +4 -6
  27. data/app/views/spree/admin/custom_domains/_custom_domains.html.erb +1 -1
  28. data/app/views/spree/admin/custom_domains/index.html.erb +1 -1
  29. data/app/views/spree/admin/customer_returns/index.html.erb +4 -17
  30. data/app/views/spree/admin/dashboard/_setup_progress.html.erb +4 -2
  31. data/app/views/spree/admin/dashboard/show.html.erb +1 -1
  32. data/app/views/spree/admin/digital_assets/_table.html.erb +1 -1
  33. data/app/views/spree/admin/digital_assets/edit.html.erb +3 -11
  34. data/app/views/spree/admin/digital_assets/new.html.erb +3 -11
  35. data/app/views/spree/admin/errors/forbidden.html.erb +13 -0
  36. data/app/views/spree/admin/exports/index.html.erb +22 -24
  37. data/app/views/spree/admin/exports/new.html.erb +3 -9
  38. data/app/views/spree/admin/line_items/new.html.erb +2 -5
  39. data/app/views/spree/admin/oauth_applications/index.html.erb +57 -58
  40. data/app/views/spree/admin/option_types/_filter.html.erb +1 -1
  41. data/app/views/spree/admin/option_types/index.html.erb +7 -11
  42. data/app/views/spree/admin/orders/_filters.html.erb +2 -7
  43. data/app/views/spree/admin/orders/_list.html.erb +2 -4
  44. data/app/views/spree/admin/orders/billing_address/create.turbo_stream.erb +3 -6
  45. data/app/views/spree/admin/orders/billing_address/edit.html.erb +3 -6
  46. data/app/views/spree/admin/orders/billing_address/new.html.erb +3 -6
  47. data/app/views/spree/admin/orders/billing_address/update.turbo_stream.erb +3 -6
  48. data/app/views/spree/admin/orders/contact_information/edit.html.erb +3 -6
  49. data/app/views/spree/admin/orders/customer_returns/edit.html.erb +1 -10
  50. data/app/views/spree/admin/orders/index.html.erb +1 -1
  51. data/app/views/spree/admin/orders/return_authorizations/_form.html.erb +1 -1
  52. data/app/views/spree/admin/orders/return_authorizations/show.html.erb +45 -43
  53. data/app/views/spree/admin/orders/shipping_address/create.turbo_stream.erb +3 -6
  54. data/app/views/spree/admin/orders/shipping_address/edit.html.erb +3 -6
  55. data/app/views/spree/admin/orders/shipping_address/new.html.erb +3 -6
  56. data/app/views/spree/admin/orders/shipping_address/update.turbo_stream.erb +3 -6
  57. data/app/views/spree/admin/pages/_filters.html.erb +1 -1
  58. data/app/views/spree/admin/pages/_page.html.erb +26 -0
  59. data/app/views/spree/admin/pages/edit.html.erb +2 -5
  60. data/app/views/spree/admin/pages/index.html.erb +9 -7
  61. data/app/views/spree/admin/payment_methods/index.html.erb +10 -8
  62. data/app/views/spree/admin/post_categories/_post_category.html.erb +5 -2
  63. data/app/views/spree/admin/post_categories/index.html.erb +6 -7
  64. data/app/views/spree/admin/posts/_filters.html.erb +4 -9
  65. data/app/views/spree/admin/posts/_form.html.erb +2 -2
  66. data/app/views/spree/admin/posts/_post.html.erb +1 -11
  67. data/app/views/spree/admin/posts/index.html.erb +7 -11
  68. data/app/views/spree/admin/products/_bulk_operations.html.erb +59 -94
  69. data/app/views/spree/admin/products/_filters.html.erb +12 -7
  70. data/app/views/spree/admin/products/_list.html.erb +2 -10
  71. data/app/views/spree/admin/products/_product.html.erb +1 -4
  72. data/app/views/spree/admin/products/bulk_modal.html.erb +3 -8
  73. data/app/views/spree/admin/products/index.html.erb +5 -5
  74. data/app/views/spree/admin/promotion_actions/new.html.erb +7 -12
  75. data/app/views/spree/admin/promotion_rules/new.html.erb +7 -12
  76. data/app/views/spree/admin/promotions/_filters.html.erb +27 -0
  77. data/app/views/spree/admin/promotions/index.html.erb +7 -35
  78. data/app/views/spree/admin/properties/index.html.erb +10 -9
  79. data/app/views/spree/admin/refund_reasons/index.html.erb +37 -35
  80. data/app/views/spree/admin/refunds/edit.html.erb +3 -8
  81. data/app/views/spree/admin/reimbursement_types/index.html.erb +42 -40
  82. data/app/views/spree/admin/reports/_report.html.erb +1 -1
  83. data/app/views/spree/admin/return_authorization_reasons/index.html.erb +41 -41
  84. data/app/views/spree/admin/return_authorizations/_filters.html.erb +1 -1
  85. data/app/views/spree/admin/return_authorizations/_list.html.erb +1 -10
  86. data/app/views/spree/admin/return_authorizations/index.html.erb +1 -1
  87. data/app/views/spree/admin/roles/_form.html.erb +1 -1
  88. data/app/views/spree/admin/roles/index.html.erb +26 -24
  89. data/app/views/spree/admin/shared/_bulk_modal.html.erb +6 -7
  90. data/app/views/spree/admin/shared/_filter_submit.html.erb +6 -0
  91. data/app/views/spree/admin/shared/_modal.html.erb +2 -8
  92. data/app/views/spree/admin/shared/_multi_product_picker.html.erb +2 -4
  93. data/app/views/spree/admin/shared/_no_resource_found.html.erb +1 -1
  94. data/app/views/spree/admin/shared/_product_image.html.erb +1 -10
  95. data/app/views/spree/admin/shared/_refunds.html.erb +1 -1
  96. data/app/views/spree/admin/shared/sidebar/_orders_nav.html.erb +1 -1
  97. data/app/views/spree/admin/shared/sidebar/_store_dropdown.html.erb +36 -7
  98. data/app/views/spree/admin/shared/sidebar/_store_nav.html.erb +4 -0
  99. data/app/views/spree/admin/shared/sortable_tree/_taxonomy.html.erb +3 -23
  100. data/app/views/spree/admin/shipping_categories/index.html.erb +28 -26
  101. data/app/views/spree/admin/shipping_methods/_actions.html.erb +1 -1
  102. data/app/views/spree/admin/shipping_methods/index.html.erb +23 -21
  103. data/app/views/spree/admin/stock_items/_filters.html.erb +2 -7
  104. data/app/views/spree/admin/stock_items/index.html.erb +5 -8
  105. data/app/views/spree/admin/stock_locations/_stock_location.html.erb +16 -13
  106. data/app/views/spree/admin/stock_locations/index.html.erb +24 -21
  107. data/app/views/spree/admin/stock_transfers/_filters.html.erb +1 -1
  108. data/app/views/spree/admin/stock_transfers/_new_variant_modal.html.erb +3 -5
  109. data/app/views/spree/admin/stock_transfers/index.html.erb +6 -6
  110. data/app/views/spree/admin/store_credit_categories/_form.html.erb +1 -1
  111. data/app/views/spree/admin/store_credit_categories/edit.html.erb +6 -4
  112. data/app/views/spree/admin/store_credit_categories/index.html.erb +28 -24
  113. data/app/views/spree/admin/store_credits/index.html.erb +2 -2
  114. data/app/views/spree/admin/storefront/edit.html.erb +7 -9
  115. data/app/views/spree/admin/stores/form/_policies.html.erb +1 -1
  116. data/app/views/spree/admin/stores/new.html.erb +9 -6
  117. data/app/views/spree/admin/tax_categories/index.html.erb +24 -22
  118. data/app/views/spree/admin/tax_rates/index.html.erb +26 -24
  119. data/app/views/spree/admin/taxonomies/index.html.erb +4 -4
  120. data/app/views/spree/admin/taxonomies/show.html.erb +2 -2
  121. data/app/views/spree/admin/themes/_theme_preview_image.html.erb +1 -10
  122. data/app/views/spree/admin/themes/index.html.erb +2 -2
  123. data/app/views/spree/admin/translations/_translations_unavailable.html.erb +6 -8
  124. data/app/views/spree/admin/users/_filters.html.erb +2 -7
  125. data/app/views/spree/admin/users/_lifetime_stats.html.erb +1 -1
  126. data/app/views/spree/admin/users/_tabs.html.erb +4 -4
  127. data/app/views/spree/admin/users/_user.html.erb +1 -4
  128. data/app/views/spree/admin/users/bulk_modal.html.erb +3 -8
  129. data/app/views/spree/admin/users/index.html.erb +25 -58
  130. data/app/views/spree/admin/variants/form/_media_asset.html.erb +1 -7
  131. data/app/views/spree/admin/variants/form/_pricing.html.erb +1 -1
  132. data/app/views/spree/admin/webhooks_subscribers/_form.html.erb +1 -1
  133. data/app/views/spree/admin/webhooks_subscribers/index.html.erb +25 -22
  134. data/app/views/spree/admin/webhooks_subscribers/show.html.erb +3 -3
  135. data/app/views/spree/admin/zones/index.html.erb +34 -32
  136. data/config/initializers/chartkick.rb +1 -1
  137. data/config/locales/en.yml +3 -7
  138. metadata +14 -10
  139. data/app/views/spree/admin/pages/_page.erb +0 -8
  140. 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: 1fb2e27934e0ce22324b5a7c032fbeb7d0abf76d3512f726dd0acddc30a217dc
4
+ data.tar.gz: 3caabc53934c4c0bdbd2b70bfea5dcaa9685eb3acb9a2d2bcebcc362c4807e73
5
5
  SHA512:
6
- metadata.gz: 42d85993653cd2792a7ee9bb052da3a5dfab181415fb2362c73fd09f33acc46a4ed6253d81fcdbb3d61320ca14ca4d5fa5eb92f5080e292a179f397778dcfc1a
7
- data.tar.gz: cadca2e5fa570bf58c8de527f4702e9623e0ad3a3861a030404838a9ae3e1186d23cdd071dea58d3fe5222faf5a3d90f49cd095e767ea08b870f28cb21921944
6
+ metadata.gz: ffb8d7703b134adf2439b7f035557930448883896f6e4a07daea768de52847d13dc0ed7ca8cb37fc1e38e0df637b7fcbfb54cc3d7e13fdf03adc23493714e33a
7
+ data.tar.gz: 88f4985f3985761932f2e341ed62085658c925a18244718bb14ffc729b3074cc9d726fa8419c70af12a3da77e9a624f39d3bba5841b4d759a03a1cb8abaad994
@@ -31,13 +31,16 @@
31
31
  }
32
32
 
33
33
  .alert-danger {
34
- background-color: #f8d7da;
35
- border-color: rgba($danger, 0.3) !important;
36
-
34
+ background-color: #FEF2F2;
35
+ border-color: #FBE3E3;
36
+ color: #450A09;
37
37
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23dc2626' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='icon icon-tabler icons-tabler-outline icon-tabler-exclamation-circle'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0' /%3E%3Cpath d='M12 9v4' /%3E%3Cpath d='M12 16v.01' /%3E%3C/svg%3E");
38
38
  }
39
39
 
40
40
  .alert-success {
41
+ background-color: #ECFDF5;
42
+ color: #092E26;
43
+ border-color: #D5F9E6;
41
44
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%2310b981' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' class='icon icon-tabler icons-tabler-outline icon-tabler-check-circle'%3E%3Cpath stroke='none' d='M0 0h24v24H0z' fill='none'/%3E%3Cpath d='M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0' /%3E%3Cpath d='M9 12l2 2l4 -4' /%3E%3C/svg%3E");
42
45
  }
43
46
 
@@ -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;
@@ -18,16 +18,19 @@ $light: $gray-50 !default;
18
18
 
19
19
  $primary: #061932 !default;
20
20
  $black: #000000 !default;
21
- $blue: #0077ff !default;
21
+ $blue: #0090FE !default;
22
22
  $white: #FFFFFF !default;
23
23
 
24
+ $action: #F4F9FF !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;
@@ -98,11 +104,11 @@ $box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1),0 2px 4px -1px rgba(0, 0, 0, 0.06
98
104
  $box-shadow-xs: rgba(43, 34, 51, 0.04) 0px 1px 2px !default;
99
105
  $box-shadow-lg: rgba(0, 5, 13, 0.5) 0px 4px 8px 2px;
100
106
 
101
- $tooltip-border-radius: $border-radius-sm !default;
107
+ $tooltip-border-radius: $border-radius !default;
102
108
  $tooltip-opacity: 1 !default;
103
109
  $tooltip-margin: 0.25rem 0 !default;
104
- $tooltip-padding-y: .5rem !default;
105
- $tooltip-padding-x: .75rem !default;
110
+ $tooltip-padding-y: .25rem !default;
111
+ $tooltip-padding-x: .5rem !default;
106
112
  $tooltip-bg: $white !default;
107
113
  $tooltip-color: $body-color !default;
108
114
  $tooltip-arrow-color: transparent !default;
@@ -1,10 +1,7 @@
1
1
  // https://twitter.com/NatalieMarleny/status/1662402066365526016
2
2
  html {
3
3
  min-height: 100%;
4
- font-feature-settings: "kern";
5
- font-optical-sizing: auto;
6
- font-style: normal;
7
- font-variation-settings: "slnt" 0;
4
+ letter-spacing: normal;
8
5
  }
9
6
  body {
10
7
  @extend .h-100;
@@ -670,7 +667,8 @@ div.uppy-Root {
670
667
  }
671
668
 
672
669
  .tooltip-inner {
673
- box-shadow: $dropdown-box-shadow;
670
+ border: 1px solid $gray-100;
671
+ box-shadow: $box-shadow-xs;
674
672
  }
675
673
 
676
674
  .avatar {
@@ -1,6 +1,8 @@
1
1
  module Spree
2
2
  module Admin
3
3
  class PostsController < ResourceController
4
+ before_action :load_post_categories
5
+
4
6
  def select_options
5
7
  render json: current_store.posts.published.to_tom_select_json
6
8
  end
@@ -18,6 +20,10 @@ module Spree
18
20
  @search = @collection.ransack(params[:q])
19
21
  @collection = @search.result.page(params[:page]).per(params[:per_page])
20
22
  end
23
+
24
+ def load_post_categories
25
+ @post_categories = current_store.post_categories.accessible_by(current_ability).order(:title)
26
+ end
21
27
  end
22
28
  end
23
29
  end
@@ -15,6 +15,7 @@ module Spree
15
15
  before_action :prepare_product_params, only: [:create, :update]
16
16
  before_action :strip_stock_items_param, only: [:create, :update]
17
17
  before_action :ensure_session_uploaded_assets_uuid, only: :new
18
+ before_action :check_slug_availability, only: [:create, :update]
18
19
 
19
20
  new_action.before :build_master_prices
20
21
  new_action.before :build_master_stock_items
@@ -68,10 +69,7 @@ module Spree
68
69
  # update the product again
69
70
  @product.slug = @product.slug_was if @product.slug.blank?
70
71
  invoke_callbacks(:update, :fails)
71
- respond_to do |format|
72
- format.html { render :edit, status: :unprocessable_entity }
73
- format.turbo_stream
74
- end
72
+ render :edit, status: :unprocessable_entity
75
73
  end
76
74
  end
77
75
 
@@ -294,10 +292,6 @@ module Spree
294
292
 
295
293
  private
296
294
 
297
- def update_turbo_stream_enabled?
298
- true
299
- end
300
-
301
295
  def variant_stock_includes
302
296
  [:images, { stock_items: :stock_location, option_values: :option_type }]
303
297
  end
@@ -361,6 +355,11 @@ module Spree
361
355
  variant_images: [],
362
356
  }
363
357
  end
358
+
359
+ def check_slug_availability
360
+ new_slug = permitted_resource_params[:slug]
361
+ permitted_resource_params[:slug] = @product.ensure_slug_is_unique(new_slug)
362
+ end
364
363
  end
365
364
  end
366
365
  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
@@ -27,7 +27,7 @@ module Spree
27
27
 
28
28
  def update
29
29
  if @user.update(user_params)
30
- flash[:success] = Spree.t(:account_updated)
30
+ flash[:success] = flash_message_for(@user, :successfully_updated)
31
31
  redirect_to spree.admin_user_path(@user)
32
32
  else
33
33
  render :edit, status: :unprocessable_entity
@@ -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