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.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/spree/admin/components/_alerts.scss +6 -3
- data/app/assets/stylesheets/spree/admin/components/_bulk_panel.scss +11 -1
- data/app/assets/stylesheets/spree/admin/components/_cards.scss +3 -4
- data/app/assets/stylesheets/spree/admin/components/_dropdowns.scss +1 -1
- data/app/assets/stylesheets/spree/admin/components/_main.scss +8 -1
- data/app/assets/stylesheets/spree/admin/components/_modals.scss +1 -1
- data/app/assets/stylesheets/spree/admin/global/_variables.scss +12 -6
- data/app/assets/stylesheets/spree/admin/shared/_base.scss +3 -5
- data/app/controllers/spree/admin/posts_controller.rb +6 -0
- data/app/controllers/spree/admin/products_controller.rb +7 -8
- data/app/controllers/spree/admin/storefront_controller.rb +1 -1
- data/app/controllers/spree/admin/translations_controller.rb +1 -1
- data/app/controllers/spree/admin/users_controller.rb +1 -1
- data/app/helpers/spree/admin/base_helper.rb +49 -57
- data/app/helpers/spree/admin/bulk_operations_helper.rb +86 -0
- data/app/helpers/spree/admin/modal_helper.rb +29 -0
- data/app/helpers/spree/admin/navigation_helper.rb +76 -1
- data/app/helpers/spree/admin/orders_helper.rb +0 -19
- data/app/helpers/spree/admin/stores_helper.rb +5 -34
- data/app/javascript/spree/admin/controllers/slug_form_controller.js +0 -3
- data/app/javascript/spree/admin/controllers/variants_form_controller.js +6 -0
- data/app/javascript/spree/admin/helpers/bootstrap.js +3 -3
- data/app/views/active_storage/_upload_form.html.erb +4 -8
- data/app/views/spree/admin/assets/edit.html.erb +3 -8
- data/app/views/spree/admin/coupon_codes/index.html.erb +4 -6
- data/app/views/spree/admin/custom_domains/_custom_domains.html.erb +1 -1
- data/app/views/spree/admin/custom_domains/index.html.erb +1 -1
- data/app/views/spree/admin/customer_returns/index.html.erb +4 -17
- data/app/views/spree/admin/dashboard/_setup_progress.html.erb +4 -2
- data/app/views/spree/admin/dashboard/show.html.erb +1 -1
- data/app/views/spree/admin/digital_assets/_table.html.erb +1 -1
- data/app/views/spree/admin/digital_assets/edit.html.erb +3 -11
- data/app/views/spree/admin/digital_assets/new.html.erb +3 -11
- data/app/views/spree/admin/errors/forbidden.html.erb +13 -0
- data/app/views/spree/admin/exports/index.html.erb +22 -24
- data/app/views/spree/admin/exports/new.html.erb +3 -9
- data/app/views/spree/admin/line_items/new.html.erb +2 -5
- data/app/views/spree/admin/oauth_applications/index.html.erb +57 -58
- data/app/views/spree/admin/option_types/_filter.html.erb +1 -1
- data/app/views/spree/admin/option_types/index.html.erb +7 -11
- data/app/views/spree/admin/orders/_filters.html.erb +2 -7
- data/app/views/spree/admin/orders/_list.html.erb +2 -4
- data/app/views/spree/admin/orders/billing_address/create.turbo_stream.erb +3 -6
- data/app/views/spree/admin/orders/billing_address/edit.html.erb +3 -6
- data/app/views/spree/admin/orders/billing_address/new.html.erb +3 -6
- data/app/views/spree/admin/orders/billing_address/update.turbo_stream.erb +3 -6
- data/app/views/spree/admin/orders/contact_information/edit.html.erb +3 -6
- data/app/views/spree/admin/orders/customer_returns/edit.html.erb +1 -10
- data/app/views/spree/admin/orders/index.html.erb +1 -1
- data/app/views/spree/admin/orders/return_authorizations/_form.html.erb +1 -1
- data/app/views/spree/admin/orders/return_authorizations/show.html.erb +45 -43
- data/app/views/spree/admin/orders/shipping_address/create.turbo_stream.erb +3 -6
- data/app/views/spree/admin/orders/shipping_address/edit.html.erb +3 -6
- data/app/views/spree/admin/orders/shipping_address/new.html.erb +3 -6
- data/app/views/spree/admin/orders/shipping_address/update.turbo_stream.erb +3 -6
- data/app/views/spree/admin/pages/_filters.html.erb +1 -1
- data/app/views/spree/admin/pages/_page.html.erb +26 -0
- data/app/views/spree/admin/pages/edit.html.erb +2 -5
- data/app/views/spree/admin/pages/index.html.erb +9 -7
- data/app/views/spree/admin/payment_methods/index.html.erb +10 -8
- data/app/views/spree/admin/post_categories/_post_category.html.erb +5 -2
- data/app/views/spree/admin/post_categories/index.html.erb +6 -7
- data/app/views/spree/admin/posts/_filters.html.erb +4 -9
- data/app/views/spree/admin/posts/_form.html.erb +2 -2
- data/app/views/spree/admin/posts/_post.html.erb +1 -11
- data/app/views/spree/admin/posts/index.html.erb +7 -11
- data/app/views/spree/admin/products/_bulk_operations.html.erb +59 -94
- data/app/views/spree/admin/products/_filters.html.erb +12 -7
- data/app/views/spree/admin/products/_list.html.erb +2 -10
- data/app/views/spree/admin/products/_product.html.erb +1 -4
- data/app/views/spree/admin/products/bulk_modal.html.erb +3 -8
- data/app/views/spree/admin/products/index.html.erb +5 -5
- data/app/views/spree/admin/promotion_actions/new.html.erb +7 -12
- data/app/views/spree/admin/promotion_rules/new.html.erb +7 -12
- data/app/views/spree/admin/promotions/_filters.html.erb +27 -0
- data/app/views/spree/admin/promotions/index.html.erb +7 -35
- data/app/views/spree/admin/properties/index.html.erb +10 -9
- data/app/views/spree/admin/refund_reasons/index.html.erb +37 -35
- data/app/views/spree/admin/refunds/edit.html.erb +3 -8
- data/app/views/spree/admin/reimbursement_types/index.html.erb +42 -40
- data/app/views/spree/admin/reports/_report.html.erb +1 -1
- data/app/views/spree/admin/return_authorization_reasons/index.html.erb +41 -41
- data/app/views/spree/admin/return_authorizations/_filters.html.erb +1 -1
- data/app/views/spree/admin/return_authorizations/_list.html.erb +1 -10
- data/app/views/spree/admin/return_authorizations/index.html.erb +1 -1
- data/app/views/spree/admin/roles/_form.html.erb +1 -1
- data/app/views/spree/admin/roles/index.html.erb +26 -24
- data/app/views/spree/admin/shared/_bulk_modal.html.erb +6 -7
- data/app/views/spree/admin/shared/_filter_submit.html.erb +6 -0
- data/app/views/spree/admin/shared/_modal.html.erb +2 -8
- data/app/views/spree/admin/shared/_multi_product_picker.html.erb +2 -4
- data/app/views/spree/admin/shared/_no_resource_found.html.erb +1 -1
- data/app/views/spree/admin/shared/_product_image.html.erb +1 -10
- data/app/views/spree/admin/shared/_refunds.html.erb +1 -1
- data/app/views/spree/admin/shared/sidebar/_orders_nav.html.erb +1 -1
- data/app/views/spree/admin/shared/sidebar/_store_dropdown.html.erb +36 -7
- data/app/views/spree/admin/shared/sidebar/_store_nav.html.erb +4 -0
- data/app/views/spree/admin/shared/sortable_tree/_taxonomy.html.erb +3 -23
- data/app/views/spree/admin/shipping_categories/index.html.erb +28 -26
- data/app/views/spree/admin/shipping_methods/_actions.html.erb +1 -1
- data/app/views/spree/admin/shipping_methods/index.html.erb +23 -21
- data/app/views/spree/admin/stock_items/_filters.html.erb +2 -7
- data/app/views/spree/admin/stock_items/index.html.erb +5 -8
- data/app/views/spree/admin/stock_locations/_stock_location.html.erb +16 -13
- data/app/views/spree/admin/stock_locations/index.html.erb +24 -21
- data/app/views/spree/admin/stock_transfers/_filters.html.erb +1 -1
- data/app/views/spree/admin/stock_transfers/_new_variant_modal.html.erb +3 -5
- data/app/views/spree/admin/stock_transfers/index.html.erb +6 -6
- data/app/views/spree/admin/store_credit_categories/_form.html.erb +1 -1
- data/app/views/spree/admin/store_credit_categories/edit.html.erb +6 -4
- data/app/views/spree/admin/store_credit_categories/index.html.erb +28 -24
- data/app/views/spree/admin/store_credits/index.html.erb +2 -2
- data/app/views/spree/admin/storefront/edit.html.erb +7 -9
- data/app/views/spree/admin/stores/form/_policies.html.erb +1 -1
- data/app/views/spree/admin/stores/new.html.erb +9 -6
- data/app/views/spree/admin/tax_categories/index.html.erb +24 -22
- data/app/views/spree/admin/tax_rates/index.html.erb +26 -24
- data/app/views/spree/admin/taxonomies/index.html.erb +4 -4
- data/app/views/spree/admin/taxonomies/show.html.erb +2 -2
- data/app/views/spree/admin/themes/_theme_preview_image.html.erb +1 -10
- data/app/views/spree/admin/themes/index.html.erb +2 -2
- data/app/views/spree/admin/translations/_translations_unavailable.html.erb +6 -8
- data/app/views/spree/admin/users/_filters.html.erb +2 -7
- data/app/views/spree/admin/users/_lifetime_stats.html.erb +1 -1
- data/app/views/spree/admin/users/_tabs.html.erb +4 -4
- data/app/views/spree/admin/users/_user.html.erb +1 -4
- data/app/views/spree/admin/users/bulk_modal.html.erb +3 -8
- data/app/views/spree/admin/users/index.html.erb +25 -58
- data/app/views/spree/admin/variants/form/_media_asset.html.erb +1 -7
- data/app/views/spree/admin/variants/form/_pricing.html.erb +1 -1
- data/app/views/spree/admin/webhooks_subscribers/_form.html.erb +1 -1
- data/app/views/spree/admin/webhooks_subscribers/index.html.erb +25 -22
- data/app/views/spree/admin/webhooks_subscribers/show.html.erb +3 -3
- data/app/views/spree/admin/zones/index.html.erb +34 -32
- data/config/initializers/chartkick.rb +1 -1
- data/config/locales/en.yml +3 -7
- metadata +14 -10
- data/app/views/spree/admin/pages/_page.erb +0 -8
- 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:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1fb2e27934e0ce22324b5a7c032fbeb7d0abf76d3512f726dd0acddc30a217dc
|
4
|
+
data.tar.gz: 3caabc53934c4c0bdbd2b70bfea5dcaa9685eb3acb9a2d2bcebcc362c4807e73
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ffb8d7703b134adf2439b7f035557930448883896f6e4a07daea768de52847d13dc0ed7ca8cb37fc1e38e0df637b7fcbfb54cc3d7e13fdf03adc23493714e33a
|
7
|
+
data.tar.gz: 88f4985f3985761932f2e341ed62085658c925a18244718bb14ffc729b3074cc9d726fa8419c70af12a3da77e9a624f39d3bba5841b4d759a03a1cb8abaad994
|
@@ -31,13 +31,16 @@
|
|
31
31
|
}
|
32
32
|
|
33
33
|
.alert-danger {
|
34
|
-
background-color: #
|
35
|
-
border-color:
|
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
|
-
|
64
|
-
|
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:
|
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
|
+
}
|
@@ -18,16 +18,19 @@ $light: $gray-50 !default;
|
|
18
18
|
|
19
19
|
$primary: #061932 !default;
|
20
20
|
$black: #000000 !default;
|
21
|
-
$blue: #
|
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":
|
30
|
-
"action-border":
|
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
|
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: .
|
105
|
-
$tooltip-padding-x: .
|
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
|
-
|
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
|
-
|
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
|
-
|
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(
|
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] =
|
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
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
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
|
-
|
235
|
-
|
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
|