spree_admin 5.3.3 → 5.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/helpers/spree/admin/table_helper.rb +1 -1
- data/app/javascript/spree/admin/controllers/bulk_editor_controller.js +0 -86
- data/app/javascript/spree/admin/controllers/money_field_controller.js +1 -23
- data/app/javascript/spree/admin/controllers/variants_form_controller.js +26 -88
- data/app/models/spree/admin/table/column.rb +1 -1
- data/app/models/spree/admin/table/query_builder.rb +7 -2
- data/app/views/spree/admin/products/form/_variants.html.erb +0 -10
- data/app/views/spree/admin/products/form/variants/_variant_template.html.erb +1 -1
- data/app/views/spree/admin/tables/_table.html.erb +3 -4
- data/config/initializers/spree_admin_tables.rb +18 -18
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 50a1165ee32d40280a53a301cc00059012380a2c0fd27e5ef6933ee074bd50b8
|
|
4
|
+
data.tar.gz: 4282e3887a4f1a32e13ec9611cf9d02377c5fd98ec153361d0f635bbd25e64b0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 74520ef7ba4d6f284ecf05f024bdfb835ccfa27b91fb564330bd5d45c42c857527d24adc0aa76e54403685d3387280ebfc431205544f59e34cc1318575ad3adc
|
|
7
|
+
data.tar.gz: d1fc1d04175d7baed961400407b43a9efa040a79f7e94d3902597bce0712258df8418737a4ba9539409350ed73933e9d435c4c65f6339c50a2a68df727a7c660
|
|
@@ -230,7 +230,7 @@ module Spree
|
|
|
230
230
|
# @return [String] JSON string
|
|
231
231
|
def query_builder_fields_json(table)
|
|
232
232
|
query_builder = Spree::Admin::Table::QueryBuilder.new(table)
|
|
233
|
-
query_builder.available_fields.to_json
|
|
233
|
+
query_builder.available_fields(self).to_json
|
|
234
234
|
end
|
|
235
235
|
|
|
236
236
|
# Build available operators JSON for Stimulus controller
|
|
@@ -79,21 +79,16 @@ export default class extends Controller {
|
|
|
79
79
|
this.boundHandleBeforeUnload = this.handleBeforeUnload.bind(this)
|
|
80
80
|
this.boundHandleMouseUp = this.handleMouseUp.bind(this)
|
|
81
81
|
this.boundHandleMouseMove = this.handleMouseMove.bind(this)
|
|
82
|
-
this.boundNormalizeBeforeSubmit = this.normalizeBeforeSubmit.bind(this)
|
|
83
82
|
|
|
84
83
|
window.addEventListener('beforeunload', this.boundHandleBeforeUnload)
|
|
85
84
|
document.addEventListener('mouseup', this.boundHandleMouseUp)
|
|
86
85
|
document.addEventListener('mousemove', this.boundHandleMouseMove)
|
|
87
|
-
|
|
88
|
-
// Listen for form submission to normalize values
|
|
89
|
-
this.element.addEventListener('submit', this.boundNormalizeBeforeSubmit)
|
|
90
86
|
}
|
|
91
87
|
|
|
92
88
|
disconnect() {
|
|
93
89
|
window.removeEventListener('beforeunload', this.boundHandleBeforeUnload)
|
|
94
90
|
document.removeEventListener('mouseup', this.boundHandleMouseUp)
|
|
95
91
|
document.removeEventListener('mousemove', this.boundHandleMouseMove)
|
|
96
|
-
this.element.removeEventListener('submit', this.boundNormalizeBeforeSubmit)
|
|
97
92
|
}
|
|
98
93
|
|
|
99
94
|
// ==================== Fill Handle ====================
|
|
@@ -783,85 +778,4 @@ export default class extends Controller {
|
|
|
783
778
|
return this.dirtyInputs.size > 0
|
|
784
779
|
}
|
|
785
780
|
|
|
786
|
-
// ==================== Locale-aware Number Handling ====================
|
|
787
|
-
|
|
788
|
-
/**
|
|
789
|
-
* Normalizes a locale-formatted number string to standard decimal format
|
|
790
|
-
* e.g., "1.234,56" (German) -> "1234.56"
|
|
791
|
-
* e.g., "1,234.56" (English) -> "1234.56"
|
|
792
|
-
* @param {string} value - The locale-formatted number string
|
|
793
|
-
* @returns {string} The normalized number string with "." as decimal separator
|
|
794
|
-
*/
|
|
795
|
-
normalizeNumber(value) {
|
|
796
|
-
if (value === null || value === undefined) return ''
|
|
797
|
-
|
|
798
|
-
let stringValue = String(value).trim()
|
|
799
|
-
if (stringValue === '') return ''
|
|
800
|
-
|
|
801
|
-
// Detect the decimal separator by finding the last separator character
|
|
802
|
-
// This handles both "1,234.56" (en) and "1.234,56" (de/pl) formats
|
|
803
|
-
const lastComma = stringValue.lastIndexOf(',')
|
|
804
|
-
const lastDot = stringValue.lastIndexOf('.')
|
|
805
|
-
|
|
806
|
-
let decimalSeparator = '.'
|
|
807
|
-
let thousandsSeparator = ','
|
|
808
|
-
|
|
809
|
-
// If comma comes after dot, comma is the decimal separator (European format)
|
|
810
|
-
// Also treat comma as decimal if there's no dot and comma has 1-2 digits after it
|
|
811
|
-
if (lastComma > lastDot) {
|
|
812
|
-
decimalSeparator = ','
|
|
813
|
-
thousandsSeparator = '.'
|
|
814
|
-
} else if (lastDot === -1 && lastComma !== -1) {
|
|
815
|
-
// No dot present, check if comma looks like a decimal separator
|
|
816
|
-
// (has 1-3 digits after it, typical for currency)
|
|
817
|
-
const afterComma = stringValue.substring(lastComma + 1)
|
|
818
|
-
if (/^\d{1,3}$/.test(afterComma)) {
|
|
819
|
-
decimalSeparator = ','
|
|
820
|
-
thousandsSeparator = '.'
|
|
821
|
-
}
|
|
822
|
-
}
|
|
823
|
-
|
|
824
|
-
// Remove thousands separators
|
|
825
|
-
stringValue = stringValue.split(thousandsSeparator).join('')
|
|
826
|
-
|
|
827
|
-
// Replace decimal separator with standard "."
|
|
828
|
-
if (decimalSeparator !== '.') {
|
|
829
|
-
stringValue = stringValue.replace(decimalSeparator, '.')
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
// Remove any non-numeric characters except "." and "-"
|
|
833
|
-
stringValue = stringValue.replace(/[^0-9.\-]/g, '')
|
|
834
|
-
|
|
835
|
-
return stringValue
|
|
836
|
-
}
|
|
837
|
-
|
|
838
|
-
/**
|
|
839
|
-
* Formats a number for display using the configured locale
|
|
840
|
-
* @param {number|string} value - The number to format
|
|
841
|
-
* @returns {string} The formatted number string
|
|
842
|
-
*/
|
|
843
|
-
formatNumber(value) {
|
|
844
|
-
if (value === null || value === undefined || value === '') return ''
|
|
845
|
-
|
|
846
|
-
const number = parseFloat(value)
|
|
847
|
-
if (!Number.isFinite(number)) return ''
|
|
848
|
-
|
|
849
|
-
return number.toLocaleString(this.localeValue, {
|
|
850
|
-
minimumFractionDigits: 2,
|
|
851
|
-
maximumFractionDigits: 2,
|
|
852
|
-
useGrouping: false
|
|
853
|
-
})
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
/**
|
|
857
|
-
* Normalizes all cell values before form submission
|
|
858
|
-
* @param {Event} event - The form submit event
|
|
859
|
-
*/
|
|
860
|
-
normalizeBeforeSubmit(event) {
|
|
861
|
-
this.cellTargets.forEach((cell) => {
|
|
862
|
-
if (cell.value) {
|
|
863
|
-
cell.value = this.normalizeNumber(cell.value)
|
|
864
|
-
}
|
|
865
|
-
})
|
|
866
|
-
}
|
|
867
781
|
}
|
|
@@ -4,11 +4,10 @@ import { Controller } from '@hotwired/stimulus'
|
|
|
4
4
|
* MoneyFieldController
|
|
5
5
|
*
|
|
6
6
|
* A Stimulus controller for locale-aware money/price input fields.
|
|
7
|
-
* Handles formatting for display
|
|
7
|
+
* Handles formatting values for display in the user's locale format.
|
|
8
8
|
*
|
|
9
9
|
* Features:
|
|
10
10
|
* - Displays amounts in the user's locale format (e.g., "1.234,56" for German, "1,234.56" for English)
|
|
11
|
-
* - Normalizes values to standard decimal format (with "." as decimal separator) before form submission
|
|
12
11
|
* - Supports optional currency symbol display
|
|
13
12
|
*
|
|
14
13
|
* Usage:
|
|
@@ -32,23 +31,10 @@ export default class extends Controller {
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
connect() {
|
|
35
|
-
this.form = this.element.closest('form')
|
|
36
|
-
|
|
37
|
-
if (this.form) {
|
|
38
|
-
this.boundNormalizeBeforeSubmit = this.normalizeBeforeSubmit.bind(this)
|
|
39
|
-
this.form.addEventListener('submit', this.boundNormalizeBeforeSubmit)
|
|
40
|
-
}
|
|
41
|
-
|
|
42
34
|
// Format the initial value for display
|
|
43
35
|
this.formatForDisplay()
|
|
44
36
|
}
|
|
45
37
|
|
|
46
|
-
disconnect() {
|
|
47
|
-
if (this.form && this.boundNormalizeBeforeSubmit) {
|
|
48
|
-
this.form.removeEventListener('submit', this.boundNormalizeBeforeSubmit)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
38
|
/**
|
|
53
39
|
* Called on blur to format the value for display
|
|
54
40
|
*/
|
|
@@ -139,12 +125,4 @@ export default class extends Controller {
|
|
|
139
125
|
return stringValue
|
|
140
126
|
}
|
|
141
127
|
|
|
142
|
-
/**
|
|
143
|
-
* Normalizes the value before form submission
|
|
144
|
-
* @param {Event} event - The form submit event
|
|
145
|
-
*/
|
|
146
|
-
normalizeBeforeSubmit(event) {
|
|
147
|
-
const normalizedValue = this.normalizeValue(this.element.value)
|
|
148
|
-
this.element.value = normalizedValue
|
|
149
|
-
}
|
|
150
128
|
}
|
|
@@ -33,7 +33,6 @@ export default class extends CheckboxSelectAll {
|
|
|
33
33
|
prices: Object,
|
|
34
34
|
currentCurrency: String,
|
|
35
35
|
currencies: Array,
|
|
36
|
-
currencyFormats: Object,
|
|
37
36
|
variantIds: Object,
|
|
38
37
|
currentStockLocationId: String,
|
|
39
38
|
stockLocations: Array,
|
|
@@ -71,19 +70,6 @@ export default class extends CheckboxSelectAll {
|
|
|
71
70
|
}
|
|
72
71
|
|
|
73
72
|
this.inventoryFormTarget = document.querySelector('.inventory-form');
|
|
74
|
-
|
|
75
|
-
// Add form submit listener to normalize price inputs before submission
|
|
76
|
-
this.form = this.element.closest('form')
|
|
77
|
-
if (this.form) {
|
|
78
|
-
this.boundNormalizePricesBeforeSubmit = this.normalizePricesBeforeSubmit.bind(this)
|
|
79
|
-
this.form.addEventListener('submit', this.boundNormalizePricesBeforeSubmit)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
disconnect() {
|
|
84
|
-
if (this.form && this.boundNormalizePricesBeforeSubmit) {
|
|
85
|
-
this.form.removeEventListener('submit', this.boundNormalizePricesBeforeSubmit)
|
|
86
|
-
}
|
|
87
73
|
}
|
|
88
74
|
|
|
89
75
|
toggleQuantityTracked() {
|
|
@@ -387,6 +373,16 @@ export default class extends CheckboxSelectAll {
|
|
|
387
373
|
}
|
|
388
374
|
}
|
|
389
375
|
|
|
376
|
+
formatPrice(event) {
|
|
377
|
+
const value = event.target.value
|
|
378
|
+
if (value === '' || value === null) return
|
|
379
|
+
|
|
380
|
+
const number = this.parseLocaleNumber(value)
|
|
381
|
+
if (!Number.isFinite(number)) return
|
|
382
|
+
|
|
383
|
+
event.target.value = this.formatNumber(number)
|
|
384
|
+
}
|
|
385
|
+
|
|
390
386
|
replaceBlankWithZero(event) {
|
|
391
387
|
if (event.target.value === '') {
|
|
392
388
|
event.target.value = 0
|
|
@@ -1100,13 +1096,13 @@ export default class extends CheckboxSelectAll {
|
|
|
1100
1096
|
if (existingPrice) {
|
|
1101
1097
|
return {
|
|
1102
1098
|
...existingPrice,
|
|
1103
|
-
amount: existingPrice.amount ?
|
|
1099
|
+
amount: existingPrice.amount ? this.parseLocaleNumber(existingPrice.amount) : existingPrice.amount
|
|
1104
1100
|
}
|
|
1105
1101
|
} else {
|
|
1106
1102
|
const parentName = variantName.split('/')[0]
|
|
1107
1103
|
const parentPrices = Object.entries(this.pricesValue)
|
|
1108
1104
|
.filter(([internalName, prices]) => internalName.startsWith(parentName) && prices[currency.toLowerCase()] !== undefined)
|
|
1109
|
-
.map(([_key, prices]) =>
|
|
1105
|
+
.map(([_key, prices]) => this.parseLocaleNumber(prices[currency.toLowerCase()].amount))
|
|
1110
1106
|
.sort((priceAmountA, priceAmountB) => priceAmountA - priceAmountB)
|
|
1111
1107
|
|
|
1112
1108
|
return {
|
|
@@ -1124,7 +1120,7 @@ export default class extends CheckboxSelectAll {
|
|
|
1124
1120
|
...this.pricesValue[variantName],
|
|
1125
1121
|
[currency.toLowerCase()]: {
|
|
1126
1122
|
...existingPrice,
|
|
1127
|
-
amount:
|
|
1123
|
+
amount: this.parseLocaleNumber(newPrice)
|
|
1128
1124
|
}
|
|
1129
1125
|
}
|
|
1130
1126
|
}
|
|
@@ -1148,23 +1144,13 @@ export default class extends CheckboxSelectAll {
|
|
|
1148
1144
|
}
|
|
1149
1145
|
}
|
|
1150
1146
|
|
|
1151
|
-
formatNumber(value
|
|
1147
|
+
formatNumber(value) {
|
|
1152
1148
|
if (value === null) return ''
|
|
1153
1149
|
if (typeof value === 'string' && value.trim() === '') return ''
|
|
1154
1150
|
|
|
1155
1151
|
const number = Number(value)
|
|
1156
1152
|
if (!Number.isFinite(number)) return ''
|
|
1157
1153
|
|
|
1158
|
-
// Use currency-specific decimal mark if available
|
|
1159
|
-
const currencyCode = currency || this.currentCurrencyValue
|
|
1160
|
-
const currencyFormat = this.currencyFormatsValue?.[currencyCode]
|
|
1161
|
-
|
|
1162
|
-
if (currencyFormat?.decimal_mark) {
|
|
1163
|
-
// Format with 2 decimal places and replace . with currency's decimal mark
|
|
1164
|
-
return number.toFixed(2).replace('.', currencyFormat.decimal_mark)
|
|
1165
|
-
}
|
|
1166
|
-
|
|
1167
|
-
// Fallback to locale-based formatting
|
|
1168
1154
|
return number.toLocaleString(this.localeValue, {
|
|
1169
1155
|
minimumFractionDigits: 2,
|
|
1170
1156
|
maximumFractionDigits: 2,
|
|
@@ -1172,70 +1158,22 @@ export default class extends CheckboxSelectAll {
|
|
|
1172
1158
|
})
|
|
1173
1159
|
}
|
|
1174
1160
|
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
* e.g., "1.234,56" (German) -> "1234.56"
|
|
1178
|
-
* e.g., "30,99" (Polish) -> "30.99"
|
|
1179
|
-
* @param {string} value - The locale-formatted number string
|
|
1180
|
-
* @returns {string} The normalized number string with "." as decimal separator
|
|
1181
|
-
*/
|
|
1182
|
-
normalizeNumber(value) {
|
|
1183
|
-
if (value === null || value === undefined) return ''
|
|
1184
|
-
|
|
1185
|
-
let stringValue = String(value).trim()
|
|
1186
|
-
if (stringValue === '') return ''
|
|
1187
|
-
|
|
1188
|
-
// Detect the decimal separator by finding the last separator character
|
|
1189
|
-
// This handles both "1,234.56" (en) and "1.234,56" (de/pl) formats
|
|
1190
|
-
const lastComma = stringValue.lastIndexOf(',')
|
|
1191
|
-
const lastDot = stringValue.lastIndexOf('.')
|
|
1192
|
-
|
|
1193
|
-
let decimalSeparator = '.'
|
|
1194
|
-
let thousandsSeparator = ','
|
|
1195
|
-
|
|
1196
|
-
// If comma comes after dot, comma is the decimal separator (European format)
|
|
1197
|
-
// Also treat comma as decimal if there's no dot and comma has 1-3 digits after it
|
|
1198
|
-
if (lastComma > lastDot) {
|
|
1199
|
-
decimalSeparator = ','
|
|
1200
|
-
thousandsSeparator = '.'
|
|
1201
|
-
} else if (lastDot === -1 && lastComma !== -1) {
|
|
1202
|
-
// No dot present, check if comma looks like a decimal separator
|
|
1203
|
-
// (has 1-3 digits after it, typical for currency)
|
|
1204
|
-
const afterComma = stringValue.substring(lastComma + 1)
|
|
1205
|
-
if (/^\d{1,3}$/.test(afterComma)) {
|
|
1206
|
-
decimalSeparator = ','
|
|
1207
|
-
thousandsSeparator = '.'
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1161
|
+
parseLocaleNumber(value) {
|
|
1162
|
+
if (value === null || value === undefined) return NaN
|
|
1210
1163
|
|
|
1211
|
-
|
|
1212
|
-
|
|
1164
|
+
let str = String(value).trim()
|
|
1165
|
+
if (str === '') return NaN
|
|
1213
1166
|
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
stringValue = stringValue.replace(decimalSeparator, '.')
|
|
1217
|
-
}
|
|
1167
|
+
const lastComma = str.lastIndexOf(',')
|
|
1168
|
+
const lastDot = str.lastIndexOf('.')
|
|
1218
1169
|
|
|
1219
|
-
|
|
1220
|
-
|
|
1170
|
+
if (lastComma > lastDot) {
|
|
1171
|
+
str = str.replace(/\./g, '').replace(',', '.')
|
|
1172
|
+
} else if (lastDot === -1 && lastComma !== -1 && /^\d{1,3}$/.test(str.substring(lastComma + 1))) {
|
|
1173
|
+
str = str.replace(',', '.')
|
|
1174
|
+
}
|
|
1221
1175
|
|
|
1222
|
-
return
|
|
1176
|
+
return parseFloat(str)
|
|
1223
1177
|
}
|
|
1224
1178
|
|
|
1225
|
-
/**
|
|
1226
|
-
* Normalizes all price inputs in the variants form before submission
|
|
1227
|
-
* @param {Event} event - The form submit event
|
|
1228
|
-
*/
|
|
1229
|
-
normalizePricesBeforeSubmit(event) {
|
|
1230
|
-
// Find all price inputs in the variants container
|
|
1231
|
-
const priceInputs = this.variantsContainerTarget.querySelectorAll(
|
|
1232
|
-
'input[data-slot*="[prices_attributes]"][data-slot*="[amount]_input"]'
|
|
1233
|
-
)
|
|
1234
|
-
|
|
1235
|
-
priceInputs.forEach((input) => {
|
|
1236
|
-
if (input.value) {
|
|
1237
|
-
input.value = this.normalizeNumber(input.value)
|
|
1238
|
-
}
|
|
1239
|
-
})
|
|
1240
|
-
}
|
|
1241
1179
|
}
|
|
@@ -70,8 +70,9 @@ module Spree
|
|
|
70
70
|
end
|
|
71
71
|
|
|
72
72
|
# Get available fields for filtering based on table configuration
|
|
73
|
+
# @param view_context [ActionView::Base] optional view context for resolving dynamic URLs
|
|
73
74
|
# @return [Array<Hash>]
|
|
74
|
-
def available_fields
|
|
75
|
+
def available_fields(view_context = nil)
|
|
75
76
|
@table.filterable_columns.map do |column|
|
|
76
77
|
{
|
|
77
78
|
key: column.ransack_attribute,
|
|
@@ -79,7 +80,7 @@ module Spree
|
|
|
79
80
|
type: column.filter_type.to_s,
|
|
80
81
|
operators: column.operators.map(&:to_s),
|
|
81
82
|
value_options: format_value_options(column.value_options),
|
|
82
|
-
search_url: column.search_url
|
|
83
|
+
search_url: resolve_search_url(column.search_url, view_context)
|
|
83
84
|
}
|
|
84
85
|
end
|
|
85
86
|
end
|
|
@@ -92,6 +93,10 @@ module Spree
|
|
|
92
93
|
|
|
93
94
|
private
|
|
94
95
|
|
|
96
|
+
def resolve_search_url(search_url, view_context)
|
|
97
|
+
search_url.is_a?(Proc) ? search_url.call(view_context) : search_url
|
|
98
|
+
end
|
|
99
|
+
|
|
95
100
|
def format_value_options(options)
|
|
96
101
|
return nil if options.blank?
|
|
97
102
|
|
|
@@ -5,21 +5,11 @@
|
|
|
5
5
|
</div>
|
|
6
6
|
<% option_types_for_select = @option_types.pluck(:presentation, :id) %>
|
|
7
7
|
<div class="card-body p-0">
|
|
8
|
-
<%# Build currency format info for JavaScript %>
|
|
9
|
-
<% currency_formats = supported_currencies.each_with_object({}) do |currency, hash|
|
|
10
|
-
currency_obj = ::Money::Currency.find(currency)
|
|
11
|
-
hash[currency.to_s] = {
|
|
12
|
-
decimal_mark: currency_obj.decimal_mark,
|
|
13
|
-
thousands_separator: currency_obj.thousands_separator,
|
|
14
|
-
symbol: currency_obj.symbol
|
|
15
|
-
}
|
|
16
|
-
end %>
|
|
17
8
|
<div
|
|
18
9
|
data-controller="variants-form"
|
|
19
10
|
class="variants-form"
|
|
20
11
|
data-action="product-form:toggle-quantity-tracked@window->variants-form#toggleQuantityTracked"
|
|
21
12
|
data-variants-form-locale-value="<%= I18n.locale %>"
|
|
22
|
-
data-variants-form-currency-formats-value="<%= currency_formats.to_json %>"
|
|
23
13
|
<% if @product.persisted? %> data-variants-form-product-id-value="<%= @product.slug %>" <% end %>
|
|
24
14
|
data-variants-form-current-currency-value="<%= current_currency %>"
|
|
25
15
|
data-variants-form-currencies-value="<%= supported_currencies.map(&:to_s).to_json %>"
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
<div class="variants-table__body__cell column-price mr-2">
|
|
19
19
|
<% supported_currencies.each_with_index do |currency, i| %>
|
|
20
20
|
<div class="input-group price-input-container <%= current_currency != currency ? 'hidden' : 'flex' %>" <%= !can_manage_prices ? 'readonly' : '' %>>
|
|
21
|
-
<%= text_field_tag "product[variants_attributes][prices_attributes][#{i}][amount]", '', class: 'border-0 focus:ring-0 focus:outline-none', data: { slot: "[prices_attributes][#{currency}][amount]_input", action: 'variants-form#updatePrice', currency: currency.to_s }, readonly: !can_manage_prices %>
|
|
21
|
+
<%= text_field_tag "product[variants_attributes][prices_attributes][#{i}][amount]", '', class: 'border-0 focus:ring-0 focus:outline-none', data: { slot: "[prices_attributes][#{currency}][amount]_input", action: 'variants-form#updatePrice blur->variants-form#formatPrice', currency: currency.to_s }, readonly: !can_manage_prices %>
|
|
22
22
|
<span class="px-3"><%= currency_symbol(currency) %></span>
|
|
23
23
|
</div>
|
|
24
24
|
<%= hidden_field_tag "product[variants_attributes][prices_attributes][#{i}][currency]", currency, data: {slot: "[prices_attributes][#{currency}][currency]_input"} %>
|
|
@@ -6,11 +6,10 @@
|
|
|
6
6
|
<% search_placeholder = (table.respond_to?(:search_placeholder) && table.search_placeholder) || [Spree.t(:search), controller_name.humanize.downcase].join(' ') %>
|
|
7
7
|
<% date_range_param = table.date_range_param %>
|
|
8
8
|
|
|
9
|
-
<% if export_type.present? %>
|
|
10
|
-
<%= render 'spree/admin/shared/export_modal', export_type: export_type %>
|
|
11
|
-
<% end %>
|
|
12
|
-
|
|
13
9
|
<%= turbo_frame_tag frame_name, data: { turbo_action: 'advance' } do %>
|
|
10
|
+
<% if export_type.present? %>
|
|
11
|
+
<%= render 'spree/admin/shared/export_modal', export_type: export_type %>
|
|
12
|
+
<% end %>
|
|
14
13
|
<div class="<%= local_assigns[:container_class] || 'card-lg' %>" data-controller="table" data-table-url-value="<%= request.path %>">
|
|
15
14
|
<div class="p-3 border-b border-gray-200">
|
|
16
15
|
<div class="flex flex-col lg:flex-row gap-3 items-start lg:items-center justify-between">
|
|
@@ -111,7 +111,7 @@ Rails.application.config.after_initialize do
|
|
|
111
111
|
position: 80,
|
|
112
112
|
ransack_attribute: 'taxons_id',
|
|
113
113
|
operators: %i[in],
|
|
114
|
-
search_url:
|
|
114
|
+
search_url: ->(view_context) { view_context.spree.admin_taxons_select_options_path(format: :json) },
|
|
115
115
|
method: ->(product) { product.taxons.pluck(:pretty_name).to_sentence if product.classification_count.positive? }
|
|
116
116
|
|
|
117
117
|
# Tags - displayed as comma-separated list, filtered via autocomplete
|
|
@@ -125,14 +125,14 @@ Rails.application.config.after_initialize do
|
|
|
125
125
|
position: 85,
|
|
126
126
|
ransack_attribute: 'tags_name',
|
|
127
127
|
operators: %i[in],
|
|
128
|
-
search_url:
|
|
128
|
+
search_url: ->(view_context) { view_context.spree.admin_tags_select_options_path(format: :json, taggable_type: 'Spree::Product') },
|
|
129
129
|
method: ->(product) { product.tag_list.to_sentence }
|
|
130
130
|
|
|
131
131
|
# Products bulk actions
|
|
132
132
|
Spree.admin.tables.products.add_bulk_action :set_active,
|
|
133
133
|
label: 'admin.bulk_ops.products.title.set_active',
|
|
134
134
|
icon: 'circle-check',
|
|
135
|
-
action_path: '
|
|
135
|
+
action_path: ->(view_context) { view_context.spree.bulk_status_update_admin_products_path(status: 'active') },
|
|
136
136
|
body: 'admin.bulk_ops.products.body.set_active',
|
|
137
137
|
position: 10,
|
|
138
138
|
condition: -> { can?(:activate, Spree::Product) }
|
|
@@ -140,21 +140,21 @@ Rails.application.config.after_initialize do
|
|
|
140
140
|
Spree.admin.tables.products.add_bulk_action :set_draft,
|
|
141
141
|
label: 'admin.bulk_ops.products.title.set_draft',
|
|
142
142
|
icon: 'circle-dotted',
|
|
143
|
-
action_path: '
|
|
143
|
+
action_path: ->(view_context) { view_context.spree.bulk_status_update_admin_products_path(status: 'draft') },
|
|
144
144
|
body: 'admin.bulk_ops.products.body.set_draft',
|
|
145
145
|
position: 20
|
|
146
146
|
|
|
147
147
|
Spree.admin.tables.products.add_bulk_action :set_archived,
|
|
148
148
|
label: 'admin.bulk_ops.products.title.set_archived',
|
|
149
149
|
icon: 'archive',
|
|
150
|
-
action_path: '
|
|
150
|
+
action_path: ->(view_context) { view_context.spree.bulk_status_update_admin_products_path(status: 'archived') },
|
|
151
151
|
body: 'admin.bulk_ops.products.body.set_archived',
|
|
152
152
|
position: 30
|
|
153
153
|
|
|
154
154
|
Spree.admin.tables.products.add_bulk_action :add_to_taxons,
|
|
155
155
|
label: 'admin.bulk_ops.products.title.add_to_taxons',
|
|
156
156
|
icon: 'category-plus',
|
|
157
|
-
action_path:
|
|
157
|
+
action_path: ->(view_context) { view_context.spree.bulk_add_to_taxons_admin_products_path },
|
|
158
158
|
body: 'admin.bulk_ops.products.body.add_to_taxons',
|
|
159
159
|
form_partial: 'spree/admin/bulk_operations/forms/taxon_picker',
|
|
160
160
|
position: 40,
|
|
@@ -163,7 +163,7 @@ Rails.application.config.after_initialize do
|
|
|
163
163
|
Spree.admin.tables.products.add_bulk_action :remove_from_taxons,
|
|
164
164
|
label: 'admin.bulk_ops.products.title.remove_from_taxons',
|
|
165
165
|
icon: 'category-minus',
|
|
166
|
-
action_path:
|
|
166
|
+
action_path: ->(view_context) { view_context.spree.bulk_remove_from_taxons_admin_products_path },
|
|
167
167
|
body: 'admin.bulk_ops.products.body.remove_from_taxons',
|
|
168
168
|
form_partial: 'spree/admin/bulk_operations/forms/taxon_picker',
|
|
169
169
|
position: 50,
|
|
@@ -172,7 +172,7 @@ Rails.application.config.after_initialize do
|
|
|
172
172
|
Spree.admin.tables.products.add_bulk_action :add_tags,
|
|
173
173
|
label: 'admin.bulk_ops.products.title.add_tags',
|
|
174
174
|
icon: 'tag-plus',
|
|
175
|
-
action_path:
|
|
175
|
+
action_path: ->(view_context) { view_context.spree.bulk_add_tags_admin_products_path },
|
|
176
176
|
body: 'admin.bulk_ops.products.body.add_tags',
|
|
177
177
|
form_partial: 'spree/admin/bulk_operations/forms/tag_picker',
|
|
178
178
|
form_partial_locals: { allow_create: true },
|
|
@@ -182,7 +182,7 @@ Rails.application.config.after_initialize do
|
|
|
182
182
|
Spree.admin.tables.products.add_bulk_action :remove_tags,
|
|
183
183
|
label: 'admin.bulk_ops.products.title.remove_tags',
|
|
184
184
|
icon: 'tag-minus',
|
|
185
|
-
action_path:
|
|
185
|
+
action_path: ->(view_context) { view_context.spree.bulk_remove_tags_admin_products_path },
|
|
186
186
|
body: 'admin.bulk_ops.products.body.remove_tags',
|
|
187
187
|
form_partial: 'spree/admin/bulk_operations/forms/tag_picker',
|
|
188
188
|
form_partial_locals: { allow_create: false },
|
|
@@ -348,7 +348,7 @@ Rails.application.config.after_initialize do
|
|
|
348
348
|
position: 150,
|
|
349
349
|
ransack_attribute: 'promotions_id',
|
|
350
350
|
operators: %i[in],
|
|
351
|
-
search_url:
|
|
351
|
+
search_url: ->(view_context) { view_context.spree.select_options_admin_promotions_path(format: :json) }
|
|
352
352
|
|
|
353
353
|
# Register Checkouts table (draft orders)
|
|
354
354
|
Spree.admin.tables.register(:checkouts, model_class: Spree::Order, search_param: :multi_search, date_range_param: :created_at, new_resource: false)
|
|
@@ -462,7 +462,7 @@ Rails.application.config.after_initialize do
|
|
|
462
462
|
position: 30,
|
|
463
463
|
ransack_attribute: 'addresses_country_name',
|
|
464
464
|
operators: %i[eq],
|
|
465
|
-
search_url:
|
|
465
|
+
search_url: ->(view_context) { view_context.spree.admin_countries_select_options_path(format: :json) },
|
|
466
466
|
partial: 'spree/admin/tables/columns/user_location'
|
|
467
467
|
|
|
468
468
|
# Number of orders
|
|
@@ -533,13 +533,13 @@ Rails.application.config.after_initialize do
|
|
|
533
533
|
position: 90,
|
|
534
534
|
ransack_attribute: 'tags_name',
|
|
535
535
|
operators: %i[in],
|
|
536
|
-
search_url:
|
|
536
|
+
search_url: ->(view_context) { view_context.spree.admin_tags_select_options_path(format: :json, taggable_type: 'Spree::User') }
|
|
537
537
|
|
|
538
538
|
# Users bulk actions
|
|
539
539
|
Spree.admin.tables.users.add_bulk_action :add_tags,
|
|
540
540
|
label: 'admin.bulk_ops.users.title.add_tags',
|
|
541
541
|
icon: 'tag-plus',
|
|
542
|
-
action_path:
|
|
542
|
+
action_path: ->(view_context) { view_context.spree.bulk_add_tags_admin_users_path },
|
|
543
543
|
body: 'admin.bulk_ops.users.body.add_tags',
|
|
544
544
|
form_partial: 'spree/admin/bulk_operations/forms/tag_picker',
|
|
545
545
|
form_partial_locals: { allow_create: true },
|
|
@@ -550,7 +550,7 @@ Rails.application.config.after_initialize do
|
|
|
550
550
|
Spree.admin.tables.users.add_bulk_action :remove_tags,
|
|
551
551
|
label: 'admin.bulk_ops.users.title.remove_tags',
|
|
552
552
|
icon: 'tag-minus',
|
|
553
|
-
action_path:
|
|
553
|
+
action_path: ->(view_context) { view_context.spree.bulk_remove_tags_admin_users_path },
|
|
554
554
|
body: 'admin.bulk_ops.users.body.remove_tags',
|
|
555
555
|
form_partial: 'spree/admin/bulk_operations/forms/tag_picker',
|
|
556
556
|
form_partial_locals: { allow_create: false },
|
|
@@ -1080,7 +1080,7 @@ Rails.application.config.after_initialize do
|
|
|
1080
1080
|
position: 70,
|
|
1081
1081
|
ransack_attribute: 'user_id',
|
|
1082
1082
|
operators: %i[eq],
|
|
1083
|
-
search_url:
|
|
1083
|
+
search_url: ->(view_context) { view_context.spree.admin_users_select_options_path(format: :json) },
|
|
1084
1084
|
method: ->(gc) { gc.user&.email }
|
|
1085
1085
|
|
|
1086
1086
|
Spree.admin.tables.gift_cards.add :created_at,
|
|
@@ -1125,7 +1125,7 @@ Rails.application.config.after_initialize do
|
|
|
1125
1125
|
position: 20,
|
|
1126
1126
|
ransack_attribute: 'stock_location_id',
|
|
1127
1127
|
operators: %i[eq],
|
|
1128
|
-
search_url:
|
|
1128
|
+
search_url: ->(view_context) { view_context.spree.admin_stock_locations_select_options_path(format: :json) },
|
|
1129
1129
|
partial: 'spree/admin/tables/columns/stock_item_location'
|
|
1130
1130
|
|
|
1131
1131
|
# Backorderable (inline editable checkbox)
|
|
@@ -1198,7 +1198,7 @@ Rails.application.config.after_initialize do
|
|
|
1198
1198
|
position: 20,
|
|
1199
1199
|
method: ->(post) { post.post_category_title },
|
|
1200
1200
|
ransack_attribute: 'post_category_id',
|
|
1201
|
-
search_url:
|
|
1201
|
+
search_url: ->(view_context) { view_context.spree.select_options_admin_post_categories_path(format: :json) }
|
|
1202
1202
|
|
|
1203
1203
|
Spree.admin.tables.posts.add :author,
|
|
1204
1204
|
label: :author,
|
|
@@ -1210,7 +1210,7 @@ Rails.application.config.after_initialize do
|
|
|
1210
1210
|
position: 30,
|
|
1211
1211
|
method: ->(post) { post.author_name },
|
|
1212
1212
|
ransack_attribute: 'author_id',
|
|
1213
|
-
search_url:
|
|
1213
|
+
search_url: ->(view_context) { view_context.spree.select_options_admin_admin_users_path(format: :json) }
|
|
1214
1214
|
|
|
1215
1215
|
Spree.admin.tables.posts.add :published_at,
|
|
1216
1216
|
label: :published_at,
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spree_admin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.3.
|
|
4
|
+
version: 5.3.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Vendo Connect Inc.
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: 5.3.
|
|
18
|
+
version: 5.3.4
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: 5.3.
|
|
25
|
+
version: 5.3.4
|
|
26
26
|
- !ruby/object:Gem::Dependency
|
|
27
27
|
name: active_link_to
|
|
28
28
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -1257,9 +1257,9 @@ licenses:
|
|
|
1257
1257
|
- AGPL-3.0-or-later
|
|
1258
1258
|
metadata:
|
|
1259
1259
|
bug_tracker_uri: https://github.com/spree/spree/issues
|
|
1260
|
-
changelog_uri: https://github.com/spree/spree/releases/tag/v5.3.
|
|
1260
|
+
changelog_uri: https://github.com/spree/spree/releases/tag/v5.3.4
|
|
1261
1261
|
documentation_uri: https://docs.spreecommerce.org/
|
|
1262
|
-
source_code_uri: https://github.com/spree/spree/tree/v5.3.
|
|
1262
|
+
source_code_uri: https://github.com/spree/spree/tree/v5.3.4
|
|
1263
1263
|
rdoc_options: []
|
|
1264
1264
|
require_paths:
|
|
1265
1265
|
- lib
|