Compare commits

...

40 Commits

Author SHA1 Message Date
Gaetan Craig-Riou
dd5db396b4 Merge pull request #13828 from rioug/10298-upgrade-to-shakapaker
Upgrade to shakapaker
2026-01-21 16:17:50 +11:00
Gaetan Craig-Riou
315d52961a Add "v1" to locale cache key
This is to invalidate existing locale cache key, so it will pick up
image path changes in cached fragment with locale
2026-01-21 14:29:46 +11:00
David Cook
c0bcf177e7 Merge pull request #13861 from mkllnk/bump-ruby
Bump Ruby from 3.3.10 to 3.4.8
2026-01-20 16:34:31 +11:00
David Cook
8dfede11c6 Merge pull request #13862 from mkllnk/allow_checkout_on_gateway_error
Remove unused switch to allow checkout on failures
2026-01-20 12:25:03 +11:00
Maikel Linke
bac123f223 Remove unused switch to allow checkout on failures
The inherited payment logic is complicated enough. Removing this dead
code makes it slightly simpler.
2026-01-19 14:35:54 +11:00
Maikel Linke
fdc775ae6d Style arguments forwarding 2026-01-19 10:55:24 +11:00
Maikel Linke
26b39d6626 Add convenience script to bump ruby version 2026-01-19 10:40:01 +11:00
Maikel Linke
8953e8481d Remove unnecessary bundler install script
Bundler does the same already.
2026-01-19 10:40:01 +11:00
Maikel Linke
1ce76a3166 Bump Ruby from 3.3.10p183 to 3.4.8p72 2026-01-19 10:34:34 +11:00
Maikel Linke
1c703905fe Remove now redundant install of bundler 2026-01-19 10:34:34 +11:00
David Cook
feed223ab4 Merge pull request #13528 from dacook/vine-expiry-message-13495
[VINE] Show helpful message if voucher expired
2026-01-19 09:20:18 +11:00
Gaetan Craig-Riou
90f962a886 Use compiler_strategy mtime for test environment
It fixes the issue for CI as it's faster than the digest strategy:
https://github.com/shakacode/shakapacker/blob/main/docs/configuration.md#compiler_strategy
2026-01-16 13:47:23 +11:00
Gaetan Craig-Riou
82f6484031 Add comment explaning why defer loading is disabled 2026-01-16 12:30:57 +11:00
Gaetan Craig-Riou
8cd9e94148 Use a separate config for webpacker on CI
For some reason having webpack compile turned on for the test
environment makes system test slow, resulting in lots of failure. Assets
are precompiled for system test, so there isn't any compilation on each
request, but still test are slow.
To fix the issue, we use a separate config file for CI where webpack
compile is set turned off.
2026-01-13 14:35:36 +11:00
Gaetan Craig-Riou
a934b60f67 Make sure shipping modal gets closed
Also check the modal is not showing instead of checking it's hidden
2026-01-13 14:34:50 +11:00
David Cook
368da19993 Display more specific invalid_voucher message to customer
It was implemented with error code  409 in https://github.com/openfoodfoundation/vine/pull/112
2026-01-12 17:14:57 +11:00
David Cook
419f4490d6 Recognise certain voucher errors
I considered using the vine error message as the translation key (ie I18n.t(vine_voucher_validator_service.errors.#{message.parameterize.underscore}), but thought it might be more predictable to have keys explicitly defined and whitelisted like this.

These error message are still squashed by the controller, we'll deal with that next.
2026-01-12 16:25:57 +11:00
Gaetan Craig-Riou
39245d55e2 Turn defer off when loading javascript script
It seems that we have functionality that depends on the order the
scripts are executed. Using defer breaks that.
Using defer is better performance wise so we should try to address this
eventually, might need to wait till we get rid of angular.
2026-01-12 15:56:03 +11:00
Gaetan Craig-Riou
fe8200b7e8 Move babel config back to it's own file
It's need for jest to work properly.
2026-01-12 15:56:03 +11:00
Gaetan Craig-Riou
3676acf244 Fix font link 2026-01-06 14:31:44 +11:00
Gaetan Craig-Riou
caf6b087c1 Clean up wepacker config
Disable overlayi, it covers the whole page as we have lots of warning
2026-01-06 14:31:44 +11:00
Gaetan Craig-Riou
24d6c1e386 Remove support for IE 11
Stimulus doesn't support IE 11 : https://stimulus.hotwired.dev/handbook/installing#browser-support
2026-01-06 14:31:44 +11:00
Gaetan Craig-Riou
a120e390d0 Remove added config, not needed anymore 2026-01-06 14:31:44 +11:00
Gaetan Craig-Riou
98a2bf5d47 image_pack_path is now available from Shackapaker 2026-01-06 14:31:44 +11:00
Gaetan Craig-Riou
bb0c1e7a0f Quiet sass deprecations warning for dependencies
We are not planning to upgrade foundation-sites
2026-01-06 14:31:44 +11:00
Gaetan Craig-Riou
55a15b914c Upgrade to shakapacker 6.6.0 2026-01-06 14:31:44 +11:00
Gaetan Craig-Riou
8ce14a55c8 Fix dependencies version, and update config
Trying to stay as close as possible to the default config
2026-01-06 14:31:43 +11:00
Gaetan Craig-Riou
d1f47f6956 Rename bin scripts to match new name 2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
2d50dace20 Move to shakapacker 6 and install dependencies 2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
bbbbe71bc4 Remove deprecated ~prefix
https://github.com/webpack/sass-loader/blob/main/README.md#the-style-new-api-by-default-since-16-version-and-outputstyle-old-api-options-in-production-mode
2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
b3dc76b8cf Fix configuration and scss to get webpack to compile
Move the Postcss config hack to postcss.config.js
2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
ad4b26e86d Add missing dependency for asset compilation 2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
c2a7a89381 Move extensions configuration to webpack.config.js 2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
68e3623861 Use default babel config, set up on package.json 2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
577aa55f98 Move browserlist settings to package.json 2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
b8e62b3d84 Add coffeeScript dependency 2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
dbb8e07b9a Add Sass integration
We are still using the old `ruby-sass` because it's a dependency from
`rails-sass` which is a dependcy from `select2`. It looks like the
master branch on the ofn fork get rid of the dependency, so we should
upgrading.
2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
19550ed4fe Add postcss integration 2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
4d0c710e3b Add css integration 2026-01-06 14:31:32 +11:00
Gaetan Craig-Riou
fccde70690 Upgrading to webpacker v6.0.0.rc.6
Migration guide : https://github.com/shakacode/shakapacker/blob/main/docs/v6_upgrade.md#how-to-upgrade-to-webpacker-v600rc6-from-v5
Setp 1,2,3,4
2026-01-06 14:31:25 +11:00
51 changed files with 3583 additions and 6303 deletions

View File

@@ -1,2 +0,0 @@
defaults
IE 11

1
.gitattributes vendored
View File

@@ -8,4 +8,3 @@
# Same thing for following files, but they don't have an sh extension
pre-commit eol=lf
webpack-dev-server eol=lf
install-bundler eol=lf

View File

@@ -1 +1 @@
3.3.10
3.4.8

View File

@@ -1,4 +1,4 @@
FROM ruby:3.3.10-alpine3.19 AS base
FROM ruby:3.4.8-alpine3.19 AS base
ENV LANG=C.UTF-8 \
LC_ALL=C.UTF-8 \
TZ=Europe/London \

View File

@@ -83,11 +83,8 @@ RUN wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.z
# Copy code and install app dependencies
COPY . /usr/src/app/
# Install Bundler
RUN ./script/install-bundler
# Install front-end dependencies
RUN yarn install
# Run bundler install in parallel with the amount of available CPUs
RUN bundle install --jobs="$(nproc)"
RUN bundle install --jobs="$(nproc)"

View File

@@ -18,7 +18,7 @@ gem 'activemerchant'
gem 'angular-rails-templates'
gem 'ransack', '~> 4.1.0'
gem 'responders'
gem 'webpacker', '~> 5'
gem 'shakapacker', '6.6.0'
# Indirect dependency but we access it directly in JS specs.
# It turns out to be hard to upgrade but please do if you can.
@@ -126,6 +126,8 @@ gem 'angular_rails_csrf'
gem 'jquery-rails', '4.4.0'
gem 'jquery-ui-rails', '~> 4.2'
# TODO move away from sass-rails, master branch will get rid of dependency, so we can move to
# https://github.com/sass/embedded-host-node
gem "select2-rails", github: "openfoodfoundation/select2-rails", branch: "v349_with_thor_v1"
gem 'good_migrations'

View File

@@ -615,7 +615,7 @@ GEM
rack-protection (3.2.0)
base64 (>= 0.1.0)
rack (~> 2.2, >= 2.2.4)
rack-proxy (0.7.6)
rack-proxy (0.7.7)
rack
rack-rewrite (1.5.1)
rack-session (1.0.2)
@@ -814,7 +814,12 @@ GEM
tilt (>= 1.1, < 3)
sd_notify (0.1.1)
securerandom (0.4.1)
semantic_range (3.0.0)
semantic_range (3.1.0)
shakapacker (6.6.0)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
shoulda-matchers (7.0.1)
activesupport (>= 7.1)
sidekiq (7.2.4)
@@ -942,11 +947,6 @@ GEM
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webpacker (5.4.4)
activesupport (>= 5.2)
rack-proxy (>= 0.6.1)
railties (>= 5.2)
semantic_range (>= 2.3.0)
webrick (1.9.2)
websocket-driver (0.7.7)
base64
@@ -1083,6 +1083,7 @@ DEPENDENCIES
rubocop-rspec_rails
sd_notify
select2-rails!
shakapacker (= 6.6.0)
shoulda-matchers
sidekiq
sidekiq-scheduler
@@ -1108,13 +1109,12 @@ DEPENDENCIES
web!
web-console
webmock
webpacker (~> 5)
whenever
wicked_pdf
wkhtmltopdf-binary
RUBY VERSION
ruby 3.3.10p183
ruby 3.4.8p72
BUNDLED WITH
2.5.22
4.0.3

View File

@@ -1,5 +1,5 @@
# Foreman Procfile. Start all dev server processes with: `foreman start`
rails: DEV_CACHING=true bundle exec rails s -p 3000
webpack: ./bin/webpack-dev-server
webpack: ./bin/webpacker-dev-server
sidekiq: DEV_CACHING=true bundle exec sidekiq -q mailers -q default

View File

@@ -1,5 +1,5 @@
# Foreman Procfile for Docker env. Start all dev server processes with: `bundle exec foreman start -f Procfile.docker`
webpack: WEBPACKER_DEV_SERVER_HOST=0.0.0.0 ./bin/webpack-dev-server
webpack: WEBPACKER_DEV_SERVER_HOST=0.0.0.0 ./bin/webpacker-dev-server
sidekiq: DEV_CACHING=true bundle exec sidekiq -q mailers -q default
rails: WEBPACKER_DEV_SERVER_HOST=0.0.0.0 DEV_CACHING=true bundle exec rails s -p 3000 -b 0.0.0.0

View File

@@ -1,4 +1,4 @@
= render ConfirmModalComponent.new(id: dom_id(@order, :ship), confirm_reflexes: "click->Admin::OrdersReflex#ship", controller: "orders", reflex: "Admin::Orders#ship") do
= render ConfirmModalComponent.new(id: dom_id(@order, :ship), confirm_actions: "click->modal#close", confirm_reflexes: "click->Admin::OrdersReflex#ship", controller: "orders", reflex: "Admin::Orders#ship") do
%div{class: "margin-bottom-30"}
%p= t('spree.admin.orders.shipment.mark_as_shipped_message_html')
%div{class: "margin-bottom-30"}

View File

@@ -90,11 +90,13 @@ class VoucherAdjustmentsController < BaseController
voucher_code: voucher_params[:voucher_code], enterprise: @order.distributor
)
voucher = vine_voucher_validator.validate
errors = vine_voucher_validator.errors
return nil if vine_voucher_validator.errors[:not_found_voucher].present?
return nil if errors[:not_found_voucher].present?
if vine_voucher_validator.errors.present?
@order.errors.add(:voucher_code, I18n.t('checkout.errors.add_voucher_error'))
if errors.present?
message = errors[:invalid_voucher] || I18n.t('checkout.errors.add_voucher_error')
@order.errors.add(:voucher_code, message)
return nil
end

View File

@@ -72,7 +72,8 @@ module ApplicationHelper
end
end
# Update "v1" to invalidate existing cache key
def cache_key_with_locale(key, locale)
Array.wrap(key) + [locale.to_s, I18nDigests.for_locale(locale)]
Array.wrap(key) + ["v1", locale.to_s, I18nDigests.for_locale(locale)]
end
end

View File

@@ -31,7 +31,6 @@ module Spree
preference :admin_products_per_page, :integer, default: 10
# Should only be true if you don't need to track inventory
preference :allow_backorder_shipping, :boolean, default: false
preference :allow_checkout_on_gateway_error, :boolean, default: false
preference :allow_guest_checkout, :boolean, default: true
preference :currency_decimal_mark, :string, default: "."
preference :currency_symbol_position, :string, default: "before"

View File

@@ -437,18 +437,13 @@ module Spree
#
# Returns:
# - true if all pending_payments processed successfully
# - true if a payment failed, ie. raised a GatewayError
# which gets rescued and converted to TRUE when
# :allow_checkout_gateway_error is set to true
# - false if a payment failed, ie. raised a GatewayError
# which gets rescued and converted to FALSE when
# :allow_checkout_on_gateway_error is set to false
# which gets rescued and converted to FALSE
#
def process_payments!
process_each_payment(&:process!)
rescue Core::GatewayError => e
result = !!Spree::Config[:allow_checkout_on_gateway_error]
errors.add(:base, e.message) && (return result)
errors.add(:base, e.message) && (return false)
end
def process_payments_offline!

View File

@@ -93,8 +93,8 @@ module Spree
type.demodulize.downcase
end
def self.find_with_destroyed(*args)
unscoped { find(*args) }
def self.find_with_destroyed(*)
unscoped { find(*) }
end
def payment_profiles_supported?

View File

@@ -2,6 +2,11 @@
module Vine
class VoucherValidatorService
VINE_ERRORS = {
# https://github.com/openfoodfoundation/vine/blob/main/app/Enums/ApiResponse.php
"This voucher has expired." => :expired,
}.freeze
attr_reader :voucher_code, :errors
def initialize(voucher_code:, enterprise:)
@@ -42,8 +47,10 @@ module Vine
end
def handle_errors(response)
if response[:status] == 400
errors[:invalid_voucher] = I18n.t("vine_voucher_validator_service.errors.invalid_voucher")
if [400, 409].include?(response[:status])
message = response[:body] && JSON.parse(response[:body]).dig("meta", "message")
key = VINE_ERRORS.fetch(message, :invalid_voucher)
errors[:invalid_voucher] = I18n.t("vine_voucher_validator_service.errors.#{key}")
elsif response[:status] == 404
errors[:not_found_voucher] =
I18n.t("vine_voucher_validator_service.errors.not_found_voucher")

View File

@@ -13,12 +13,12 @@
- else
= favicon_link_tag "/favicon-staging.ico"
%link{href: "https://fonts.googleapis.com/css?family=Roboto:400,300italic,400italic,300,700,700italic|Oswald:300,400,700", rel: "stylesheet", type: "text/css"}
%link{href: asset_pack_path("media/fonts/OFN-v2.woff"), rel: "preload", as: "font", crossorigin: "anonymous"}
%link{href: asset_pack_path("static/OFN-v2.woff"), rel: "preload", as: "font", crossorigin: "anonymous"}
= render "layouts/matomo_tag"
= language_meta_tags
= stylesheet_pack_tag "darkswarm", "data-turbo-track": "reload", media: "screen"
= javascript_pack_tag "application", "data-turbo-track": "reload"
= javascript_pack_tag "application", "data-turbo-track": "reload", defer: false # do not use defer because our javascript currently depend on order of execution of loaded script.
= render "layouts/shopfront_script" if @shopfront_layout
= render "layouts/bugsnag_js"

View File

@@ -16,7 +16,7 @@
= stylesheet_pack_tag "darkswarm", media: "screen"
= javascript_include_tag "darkswarm/all"
= javascript_pack_tag "application"
= javascript_pack_tag "application", defer: false # do not use defer because our javascript currently depend on order of execution of loaded script.
= csrf_meta_tags

View File

@@ -25,7 +25,7 @@
= render "spree/admin/shared/translations"
= render "spree/admin/shared/routes"
= javascript_pack_tag "admin", "data-turbo-track": "reload"
= javascript_pack_tag "admin", "data-turbo-track": "reload", defer: false # do not use defer because our javascript currently depend on order of execution of loaded script.
%script
= raw "var AUTH_TOKEN = \"#{form_authenticity_token}\";"

View File

@@ -2,19 +2,19 @@
// While in feature-toggle, we inherit all files from old admin design.
// Individual files may be copied in order to replace the old files.
@import "vendor/assets/stylesheets/normalize";
@import "vendor/assets/stylesheets/responsive-tables";
@import "vendor/assets/stylesheets/jquery.powertip";
@import "~jquery-ui/themes/base/core";
@import "~jquery-ui/themes/base/button";
@import "~jquery-ui/themes/base/resizable";
@import "vendor/assets/stylesheets/jquery-ui-theme";
@import "~jquery-ui/themes/base/dialog";
@import "assets/stylesheets/normalize";
@import "assets/stylesheets/responsive-tables";
@import "assets/stylesheets/jquery.powertip";
@import "jquery-ui/themes/base/core";
@import "jquery-ui/themes/base/button";
@import "jquery-ui/themes/base/resizable";
@import "assets/stylesheets/jquery-ui-theme";
@import "jquery-ui/themes/base/dialog";
@import "../shared/ng-tags-input.min";
@import "vendor/assets/stylesheets/select2.css.scss";
@import "~flatpickr/dist/flatpickr";
@import "~flatpickr/dist/themes/material_blue";
@import "~shortcut-buttons-flatpickr/dist/themes/light";
@import "assets/stylesheets/select2";
@import "flatpickr/dist/flatpickr";
@import "flatpickr/dist/themes/material_blue";
@import "shortcut-buttons-flatpickr/dist/themes/light";
@import "../admin/globals/functions";
@import "globals/palette"; // admin_v3
@@ -123,13 +123,13 @@
@import "shared/question-mark-icon";
@import "../admin/question-mark-tooltip";
@import "~tom-select/src/scss/tom-select.default";
@import "tom-select/src/scss/tom-select.default";
@import "components/tom_select"; // admin_v3
@import "app/components/modal_component/modal_component";
@import "app/components/vertical_ellipsis_menu_component/vertical_ellipsis_menu_component"; // admin_v3 and only V3
@import "app/components/tag_list_input_component/tag_list_input_component";
@import "app/webpacker/css/admin/trix.scss";
@import "modal_component/modal_component";
@import "vertical_ellipsis_menu_component/vertical_ellipsis_menu_component"; // admin_v3 and only V3
@import "tag_list_input_component/tag_list_input_component";
@import "admin/trix";
@import "terms_of_service_banner"; // admin_v3

View File

@@ -1,10 +1,10 @@
@import 'vendor/assets/stylesheets/autocomplete';
@import 'vendor/assets/stylesheets/leaflet';
@import 'assets/stylesheets/autocomplete';
@import 'assets/stylesheets/leaflet';
@import 'variables';
@import '../shared/variables/layout';
@import '../shared/utilities';
@import '~foundation-sites/scss/foundation';
@import 'foundation-sites/scss/foundation';
@import 'big-input';
@import 'branding';
@@ -77,4 +77,4 @@ ofn-modal {
@import "../shared/question-mark-icon";
@import '../admin/shared/scroll_bar';
@import 'app/components/modal_component/modal_component';
@import 'modal_component/modal_component';

View File

@@ -1,4 +1,4 @@
@import "~foundation-sites/scss/foundation/components/global";
@import "foundation-sites/scss/foundation/components/global";
// Brand guide colours:
// International: #81c26e

View File

@@ -1,72 +1,6 @@
module.exports = function(api) {
var validEnv = ['development', 'test', 'production']
var currentEnv = api.env()
var isDevelopmentEnv = api.env('development')
var isProductionEnv = api.env('production')
var isTestEnv = api.env('test')
module.exports = function (api) {
const defaultConfigFunc = require("shakapacker/package/babel/preset.js");
const resultConfig = defaultConfigFunc(api);
if (!validEnv.includes(currentEnv)) {
throw new Error(
'Please specify a valid `NODE_ENV` or ' +
'`BABEL_ENV` environment variables. Valid values are "development", ' +
'"test", and "production". Instead, received: ' +
JSON.stringify(currentEnv) +
'.'
)
}
return {
presets: [
isTestEnv && [
'@babel/preset-env',
{
targets: {
node: 'current'
}
}
],
(isProductionEnv || isDevelopmentEnv) && [
'@babel/preset-env',
{
forceAllTransforms: true,
useBuiltIns: 'entry',
corejs: 3,
modules: false,
exclude: ['transform-typeof-symbol']
}
]
].filter(Boolean),
plugins: [
'babel-plugin-macros',
'@babel/plugin-syntax-dynamic-import',
isTestEnv && 'babel-plugin-dynamic-import-node',
'@babel/plugin-transform-destructuring',
[
'@babel/plugin-proposal-class-properties',
{
loose: true
}
],
[
'@babel/plugin-proposal-object-rest-spread',
{
useBuiltIns: true
}
],
[
'@babel/plugin-transform-runtime',
{
helpers: false
}
],
[
'@babel/plugin-transform-regenerator',
{
async: false
}
],
["@babel/plugin-proposal-private-property-in-object", { "loose": true }],
["@babel/plugin-proposal-private-methods", { "loose": true }]
].filter(Boolean)
}
}
return resultConfig;
};

View File

@@ -16,7 +16,7 @@ FileUtils.chdir APP_ROOT do
# Add necessary setup steps to this file.
puts "== Installing dependencies =="
system! "script/install-bundler"
# Check first (it's quicker), then install new gems if necessary
system("bundle check 2> /dev/null") || system!(BUNDLE_ENV, "bundle install")

View File

@@ -1,18 +1,13 @@
#!/usr/bin/env ruby
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
ENV["NODE_ENV"] ||= "development"
ENV["NODE_OPTIONS"] ||= "--openssl-legacy-provider"
require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
Pathname.new(__FILE__).realpath)
require "bundler/setup"
require "webpacker"
require "webpacker/webpack_runner"
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", Pathname.new(__FILE__).realpath)
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
Webpacker::WebpackRunner.run(ARGV)

View File

@@ -1,8 +1,6 @@
#!/usr/bin/env ruby
ENV["RAILS_ENV"] ||= ENV["RACK_ENV"] || "development"
ENV["NODE_ENV"] ||= "development"
ENV["NODE_OPTIONS"] ||= "--openssl-legacy-provider"
require "pathname"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",

View File

@@ -1,9 +1,16 @@
#!/usr/bin/env ruby
APP_ROOT = File.expand_path('..', __dir__)
APP_ROOT = File.expand_path("..", __dir__)
Dir.chdir(APP_ROOT) do
begin
exec "yarnpkg", *ARGV
rescue Errno::ENOENT
yarn = ENV["PATH"].split(File::PATH_SEPARATOR).
select { |dir| File.expand_path(dir) != __dir__ }.
product(["yarn", "yarnpkg", "yarn.cmd", "yarn.ps1"]).
map { |dir, file| File.expand_path(file, dir) }.
find { |file| File.executable?(file) }
if yarn
exec yarn, *ARGV
else
$stderr.puts "Yarn executable was not detected in the system."
$stderr.puts "Download Yarn at https://yarnpkg.com/en/docs/install"
exit 1

View File

@@ -89,7 +89,7 @@ services:
build: .
command: >
sh -lc 'until [ -f /bundles/.Gemfile.lock.sha ] && sha256sum -c /bundles/.Gemfile.lock.sha >/dev/null 2>&1; do sleep 0.5; done;
exec ./bin/webpack-dev-server'
exec ./bin/webpacker-dev-server'
ports:
- "3035:3035"
volumes:

View File

@@ -1,10 +0,0 @@
module WebpackImageExtension
def image_pack_path(image)
# The Webpacker::Helper#resolve_path_to_image method is incredibly useful
# for nicely fetching Webpacker image paths, but it's private.
resolve_path_to_image(image)
end
end
Webpacker::Helper.include WebpackImageExtension

View File

@@ -627,6 +627,7 @@ en:
errors:
vine_api: "There was an error communicating with the API, please try again later."
invalid_voucher: "The voucher is not valid"
expired: "The voucher has expired"
not_found_voucher: "Sorry, we couldn't find that voucher, please check the code."
vine_voucher_redeemer_service:
errors:

View File

@@ -1,5 +0,0 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()

View File

@@ -1,35 +0,0 @@
const { environment } = require('@rails/webpacker')
module.exports = environment
function hotfixPostcssLoaderConfig (subloader) {
const subloaderName = subloader.loader
if (subloaderName === 'postcss-loader') {
if (subloader.options.postcssOptions) {
console.log(
'\x1b[31m%s\x1b[0m',
'Remove postcssOptions workaround in config/webpack/environment.js'
)
} else {
subloader.options.postcssOptions = subloader.options.config;
delete subloader.options.config;
}
}
}
function addQuietDepsToSassLoader (subloader) {
if (subloader.loader === 'sass-loader') {
subloader.options.sassOptions = {
...subloader.options.sassOptions,
quietDeps: true
}
}
}
environment.loaders.keys().forEach(loaderName => {
const loader = environment.loaders.get(loaderName);
if (loaderName === 'sass') {
loader.use.forEach(addQuietDepsToSassLoader);
}
loader.use.forEach(hotfixPostcssLoaderConfig);
});

View File

@@ -1,5 +0,0 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()

View File

@@ -1,5 +0,0 @@
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()

View File

@@ -0,0 +1,20 @@
const { webpackConfig, merge } = require("shakapacker")
const options = {
resolve: {
extensions: [".mjs", ".js", ".sass",".scss", ".css", ".module.sass", ".module.scss", ".module.css", ".png", ".svg", ".gif", ".jpeg", ".jpg", ".eot", ".ttf", ".woff"]
}
}
const OFNwebpackConfig = merge(webpackConfig, options)
// quiet deprecations in dependencies, notably foundation-sites
const scssRule = OFNwebpackConfig.module.rules.find((rule) => rule.test.test(".scss"))
const sassDefaultOptions = scssRule.use[3].options.sassOptions
scssRule.use[3].options.sassOptions = {
...sassDefaultOptions,
quietDeps: true
}
// This results in a new object copied from the mutable global
module.exports = OFNwebpackConfig

View File

@@ -8,7 +8,7 @@ default: &default
cache_path: tmp/cache/webpacker
webpack_compile_output: true
# Additional paths webpack should lookup modules
# Additional paths webpack should look up modules
# ['app/assets', 'engine/foo/app/assets']
additional_paths: [
'vendor',
@@ -25,37 +25,6 @@ default: &default
# Extract and emit a css file
extract_css: true
static_assets_extensions:
- .jpg
- .jpeg
- .png
- .gif
- .tiff
- .ico
- .svg
- .eot
- .otf
- .ttf
- .woff
- .woff2
extensions:
- .mjs
- .js
- .sass
- .scss
- .css
- .module.sass
- .module.scss
- .module.css
- .png
- .svg
- .gif
- .jpeg
- .jpg
- .eot
- .ttf
- .woff
development:
<<: *default
@@ -66,22 +35,40 @@ development:
https: false
host: localhost
port: 3035
public: localhost:3035
# Hot Module Replacement updates modules while the application is running without a full reload
hmr: false
# Inline should be set to true if using HMR
inline: true
overlay: true
# Defaults to the inverse of hmr. Uncomment to manually set this.
# live_reload: true
client:
# Should we show a full-screen overlay in the browser when there are compiler errors or warnings?
overlay: false
# May also be a string
# webSocketURL:
# hostname: "0.0.0.0"
# pathname: "/ws"
# port: 8080
# Should we use gzip compression?
compress: true
disable_host_check: true
use_local_ip: false
quiet: false
pretty: false
# Note that apps that do not check the host are vulnerable to DNS rebinding attacks
allowed_hosts: "all"
#TODO Old config
#pretty: false
pretty: true
headers:
'Access-Control-Allow-Origin': '*'
watch_options:
ignored:
- '**/node_modules/**'
- '**/*.swp'
static:
watch:
ignored:
- '**/node_modules/**'
- '**/*.swp'
test:
<<: *default
compile: true
compiler_strategy: mtime
# Compile test packs to a separate directory
public_output_path: packs-test
production: &production
<<: *default
@@ -91,9 +78,3 @@ production: &production
# Cache manifest.json for performance
cache_manifest: true
test:
<<: *default
# Compile test packs to a separate directory
public_output_path: packs-test

View File

@@ -179,7 +179,7 @@ module.exports = {
// transform: { "\\.[jt]sx?$": "babel-jest" },
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation
transformIgnorePatterns: ["/node_modules/(?!(stimulus.+)/)"],
transformIgnorePatterns: ["/node_modules/(?!stimulus)/"],
// An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them
// unmockedModulePathPatterns: undefined,

View File

@@ -392,9 +392,9 @@ module Reporting
end
end
def filter_scope(*args)
def filter_scope(*)
chain_to_scope do
where(*args)
where(*)
end
end
end

View File

@@ -7,12 +7,21 @@
},
"license": "AGPL-3.0",
"dependencies": {
"@babel/core": "^7.28.5",
"@babel/plugin-transform-runtime": "^7.28.5",
"@babel/preset-env": "^7.28.5",
"@babel/runtime": "^7.28.4",
"@floating-ui/dom": "*",
"@hotwired/stimulus": "*",
"@hotwired/turbo": "*",
"@rails/webpacker": "5.4.4",
"@stimulus-components/rails-nested-form": "*",
"babel-loader": "^8.2.2",
"cable_ready": "5.0.6",
"coffee-loader": "^5.0.0",
"coffeescript": "^2.7.0",
"compression-webpack-plugin": "^9.0.0",
"css-loader": "^7.1.2",
"css-minimizer-webpack-plugin": "^7.0.4",
"flatpickr": "*",
"foundation-sites": "5.5.3",
"hotkeys-js": "*",
@@ -21,19 +30,40 @@
"leaflet": "1.9.4",
"leaflet-geosearch": "4.2.2",
"leaflet-providers": "3.0.0",
"mini-css-extract-plugin": "^2.9.4",
"moment": "*",
"mrujs": "*",
"pnp-webpack-plugin": "^1.7.0",
"postcss": "^8.5.6",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-import": "^16.1.1",
"postcss-loader": "^8.2.0",
"postcss-preset-env": "^10.5.0",
"regenerator-transform": "^0.15.2",
"sass-embedded": "^1.96.0",
"sass-loader": "^16.0.6",
"select2": "*",
"shakapacker": "6.6.0",
"shortcut-buttons-flatpickr": "*",
"stimulus": "*",
"stimulus-autocomplete": "*",
"stimulus-flatpickr": "*",
"stimulus_reflex": "3.5.5",
"style-loader": "^4.0.0",
"terser-webpack-plugin": "^5.3.16",
"tom-select": "*",
"trix": "*",
"turbo_power": "*",
"webpack": "~4"
"webpack": "^5.104.0",
"webpack-assets-manifest": "^5.0.6",
"webpack-cli": "^4.9.2",
"webpack-merge": "^5.8.0",
"webpack-sources": "^3.3.3"
},
"browserslist": [
"defaults",
"not IE 11"
],
"devDependencies": {
"@testing-library/dom": "<11.0.0",
"jasmine-core": "~5.12.1",
@@ -44,6 +74,6 @@
"karma-coffee-preprocessor": "~1.0.1",
"karma-jasmine": "~0.3.8",
"prettier": "*",
"webpack-dev-server": "~3"
"webpack-dev-server": "^4.9.0"
}
}

22
script/bump-ruby.sh Executable file
View File

@@ -0,0 +1,22 @@
#!/usr/bin/env sh
if [ "$#" -lt 1 ]; then
echo "Usage: $0 <new-version>"
echo "Example: $0 3.4.8"
exit 1
fi
set -ex
OLD_VERSION=$(cat .ruby-version)
NEW_VERSION=$1
PATTERN="$(echo "$OLD_VERSION" | sed 's:[]\[^$.*/]:\\&:g')"
sed -i "s/\<$PATTERN\>/$NEW_VERSION/" .ruby-version Dockerfile
script/rbenv-install.sh
# Update bundler to the version shipped with Ruby:
bundle update --bundler
git commit -a -m "Bump Ruby from $OLD_VERSION to $NEW_VERSION"

View File

@@ -1,42 +0,0 @@
#!/bin/sh
# This shell script looks for the last used Bundler version in Gemfile.lock and
# installs exactly that version, removing all other versions.
# Command line arguments are passed on to `gem install`. So you can call this
# script with with arguments:
#
# ./script/install-bundler --no-ri --no-rdoc
# This script is used by ofn-install and can by handy in your development
# environment.
# Fail if a single command fails.
set -e
# `grep`: find the occurrences of "BUNDLED WITH" (-m is unnecessary and behaves different on macOS)
# `-A`: print the next line after "BUNDLED WITH" as well
# `-F`: find exactly that string
# `tail -n 1`: take the last line, the version line
# `tr -d`: delete all spaces, the indent before the version
version="$(grep -A 1 -F "BUNDLED WITH" Gemfile.lock | tail -n 1 | tr -d '[:space:]')"
# if the length of $version is zero
if [ -z "$version" ]; then
echo >&2 "No bundler version in Gemfile.lock."
exit 1
fi
# Get the currently used bundler version.
# We ignore all errors with `2>/dev/null || true` in case there is no bundler
# or only an orphaned shim installed.
current="$(bundler --version 2>/dev/null || true)"
if [ "$current" = "Bundler version $version" ]; then
echo >&2 "Already up-to-date: $current"
exit 0
fi
# Passing on all arguments of this script with "$@".
gem install bundler -v "$version" "$@"
gem uninstall bundler -v "!= $version" 2>/dev/null || true

View File

@@ -89,13 +89,13 @@ RSpec.describe ApplicationHelper do
it "appends locale and digest to a single key" do
expect(
helper.cache_key_with_locale("single-key", "en")
).to eq(["single-key", "en", en_digest])
).to eq(["single-key", "v1", "en", en_digest])
end
it "appends locale and digest to multiple keys" do
expect(
helper.cache_key_with_locale(["array", "of", "keys"], "es")
).to eq(["array", "of", "keys", "es", es_digest])
).to eq(["array", "of", "keys", "v1", "es", es_digest])
end
end
end

View File

@@ -299,13 +299,7 @@ RSpec.describe Spree::Order do
context "when a payment raises a GatewayError" do
before { expect(payment).to receive(:process!).and_raise(Spree::Core::GatewayError) }
it "returns true when configured to allow checkout on gateway failures" do
Spree::Config.set allow_checkout_on_gateway_error: true
expect(order.process_payments!).to be_truthy
end
it "returns false when not configured to allow checkout on gateway failures" do
Spree::Config.set allow_checkout_on_gateway_error: false
it "returns false" do
expect(order.process_payments!).to be_falsy
end
end

View File

@@ -161,7 +161,19 @@ RSpec.describe VoucherAdjustmentsController do
post("/voucher_adjustments", params:)
expect(response).to be_unprocessable
expect(flash[:error]).to match "There was an error while adding the voucher"
expect(flash[:error]).to match "The voucher is not valid"
end
end
context "when voucher has expired" do
it "returns 422 and an error message" do
mock_vine_voucher_validator(voucher: nil,
errors: { invalid_voucher: "The voucher has expired" })
post("/voucher_adjustments", params:)
expect(response).to be_unprocessable
expect(flash[:error]).to match "The voucher has expired"
end
end
@@ -219,6 +231,20 @@ RSpec.describe VoucherAdjustmentsController do
)
end
end
context "when voucher has expired" do
it "returns 422 and an error message" do
vine_voucher = build(:vine_voucher, code: vine_voucher_code,
enterprise: distributor)
mock_vine_voucher_validator(voucher: vine_voucher,
errors: { invalid_voucher: "The voucher has expired" })
post("/voucher_adjustments", params:)
expect(response).to be_unprocessable
expect(flash[:error]).to match "The voucher has expired"
end
end
end
end
end

View File

@@ -270,11 +270,12 @@ RSpec.describe Vine::VoucherValidatorService, feature: :connected_apps do
enterprise: distributor, data: { api_key: "1234568", secret: "my_secret" }
)
}
# Faraday returns un-parsed json
let(:data) {
{
meta: { responseCode: 400, limit: 50, offset: 0, message: "Invalid merchant team." },
data: []
}.deep_stringify_keys
}.to_json
}
before do
@@ -285,7 +286,7 @@ RSpec.describe Vine::VoucherValidatorService, feature: :connected_apps do
expect_validate_to_be_nil
end
it "adds an error message" do
it "adds a general error message" do
validate_voucher_service.validate
expect(validate_voucher_service.errors).to include(
@@ -293,6 +294,23 @@ RSpec.describe Vine::VoucherValidatorService, feature: :connected_apps do
)
end
context "it is expired" do
let(:data) {
{
meta: { responseCode: 400, limit: 50, offset: 0, message: "This voucher has expired." },
data: []
}.to_json
}
it "adds a specific error message" do
validate_voucher_service.validate
expect(validate_voucher_service.errors).to include(
{ invalid_voucher: "The voucher has expired" }
)
end
end
it "doesn't creates a new VINE voucher" do
expect_voucher_count_not_to_change
end
@@ -420,6 +438,25 @@ RSpec.describe Vine::VoucherValidatorService, feature: :connected_apps do
}.not_to change { voucher.reload.amount }
end
end
context "it is expired" do
let(:data) {
{
meta: { responseCode: 400, limit: 50, offset: 0, message: "This voucher has expired." },
data: []
}.to_json
}
it "adds a specific error message" do
mock_api_exception(type: Faraday::BadRequestError, status: 409, body: data)
validate_voucher_service.validate
expect(validate_voucher_service.errors).to include(
{ invalid_voucher: "The voucher has expired" }
)
end
end
end
end

View File

@@ -2,12 +2,12 @@
module OpenFoodNetwork
module PerformanceHelper
def multi_benchmark(num_samples, cache_key_patterns: [], &block)
def multi_benchmark(num_samples, cache_key_patterns: [], &)
results = (0..num_samples).map do |_i|
ActiveRecord::Base.connection.query_cache.clear
delete_cache_keys(cache_key_patterns)
result = Benchmark.measure(&block)
result = Benchmark.measure(&)
puts result

View File

@@ -68,9 +68,9 @@ RSpec.describe "DFC Permissions", feature: "cqcm-dev", vcr: true do
end
end
def within_platform_list(variant, &block)
def within_platform_list(variant, &)
retry_expectations(on: Ferrum::JavaScriptError) do
within(platform_list(variant), &block)
within(platform_list(variant), &)
end
end

View File

@@ -555,7 +555,7 @@ RSpec.describe '
find_button("Confirm").click
end
expect(page).to have_selector('.reveal-modal', visible: false)
expect(page).not_to have_content("This will mark the order as Shipped.")
expect(page).to have_content "SHIPPED"
click_link('Order Details') unless subpage == 'Order Details'
@@ -578,7 +578,7 @@ RSpec.describe '
find_button("Confirm").click
end
expect(page).to have_selector('.reveal-modal', visible: false)
expect(page).not_to have_content("This will mark the order as Shipped.")
click_link('Order Details') unless subpage == 'Order Details'
expect(page).to have_content "SHIPPED"

View File

@@ -198,7 +198,7 @@ RSpec.describe "As a consumer, I want to checkout my order" do
fill_in "Enter voucher code", with: "KM1891"
click_button("Apply")
expect(page).to have_content("There was an error while adding the voucher")
expect(page).to have_content("The voucher is not valid")
expect(Vouchers::Vine.find_by(code: "KM1891", enterprise: distributor)).to be_nil
end
end

9285
yarn.lock

File diff suppressed because it is too large Load Diff