Compare commits

..

133 Commits

Author SHA1 Message Date
Maikel
f7f7a5738a Merge pull request #13895 from cillian/remove-angular-from-enterprise-settings-users
Remove Angular from Enterprise > Settings > Users section
2026-03-06 14:05:13 +11:00
Gaetan Craig-Riou
da912f21b3 Merge pull request #14003 from openfoodfoundation/dependabot/npm_and_yarn/dompurify-3.3.2
Bump dompurify from 3.3.1 to 3.3.2
2026-03-06 11:29:51 +11:00
dependabot[bot]
e2146eb1a3 Bump dompurify from 3.3.1 to 3.3.2
Bumps [dompurify](https://github.com/cure53/DOMPurify) from 3.3.1 to 3.3.2.
- [Release notes](https://github.com/cure53/DOMPurify/releases)
- [Commits](https://github.com/cure53/DOMPurify/compare/3.3.1...3.3.2)

---
updated-dependencies:
- dependency-name: dompurify
  dependency-version: 3.3.2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-05 23:10:00 +00:00
Gaetan Craig-Riou
8e19bfca3c Merge pull request #13991 from openfoodfoundation/dependabot/npm_and_yarn/immutable-5.1.5
Bump immutable from 5.1.4 to 5.1.5
2026-03-06 09:59:29 +11:00
Gaetan Craig-Riou
255836b4d2 Merge pull request #13990 from openfoodfoundation/dependabot/npm_and_yarn/svgo-4.0.1
Bump svgo from 4.0.0 to 4.0.1
2026-03-06 09:54:52 +11:00
Gaetan Craig-Riou
fcd7b457e6 Merge pull request #13989 from openfoodfoundation/dependabot/bundler/vcr-6.4.0
Bump vcr from 6.3.1 to 6.4.0
2026-03-06 09:53:05 +11:00
Gaetan Craig-Riou
eb1daf425a Merge pull request #13988 from openfoodfoundation/dependabot/npm_and_yarn/hotkeys-js-4.0.2
Bump hotkeys-js from 4.0.1 to 4.0.2
2026-03-06 09:51:44 +11:00
Gaetan Craig-Riou
06bc6c276a Merge pull request #13987 from mkllnk/spring-watch
Add gem for spring to listen to filesystem changes efficiently
2026-03-06 09:50:32 +11:00
Gaetan Craig-Riou
6854a53bd1 Merge pull request #13785 from pacodelaluna/repair-rounding-issue-on-totals-in-reports
Repair rounding issue on totals in reports
2026-03-06 09:34:39 +11:00
Rachel Arnould
57186a74a8 Merge pull request #13958 from arunguleria/13864-remove-variants-dead-features
13864-Remove dead feature to re-arrange variants
2026-03-05 12:44:05 +01:00
dependabot[bot]
3575952d4b Bump immutable from 5.1.4 to 5.1.5
Bumps [immutable](https://github.com/immutable-js/immutable-js) from 5.1.4 to 5.1.5.
- [Release notes](https://github.com/immutable-js/immutable-js/releases)
- [Changelog](https://github.com/immutable-js/immutable-js/blob/main/CHANGELOG.md)
- [Commits](https://github.com/immutable-js/immutable-js/compare/v5.1.4...v5.1.5)

---
updated-dependencies:
- dependency-name: immutable
  dependency-version: 5.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 23:24:58 +00:00
dependabot[bot]
11203da5ca Bump svgo from 4.0.0 to 4.0.1
Bumps [svgo](https://github.com/svg/svgo) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/svg/svgo/releases)
- [Commits](https://github.com/svg/svgo/compare/v4.0.0...v4.0.1)

---
updated-dependencies:
- dependency-name: svgo
  dependency-version: 4.0.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 23:08:16 +00:00
dependabot[bot]
86091a5a79 Bump vcr from 6.3.1 to 6.4.0
Bumps [vcr](https://github.com/vcr/vcr) from 6.3.1 to 6.4.0.
- [Release notes](https://github.com/vcr/vcr/releases)
- [Changelog](https://github.com/vcr/vcr/blob/master/CHANGELOG.md)
- [Commits](https://github.com/vcr/vcr/compare/v6.3.1...v6.4.0)

---
updated-dependencies:
- dependency-name: vcr
  dependency-version: 6.4.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 09:35:06 +00:00
dependabot[bot]
f4328f1d18 Bump hotkeys-js from 4.0.1 to 4.0.2
Bumps [hotkeys-js](https://github.com/jaywcjlove/hotkeys-js) from 4.0.1 to 4.0.2.
- [Release notes](https://github.com/jaywcjlove/hotkeys-js/releases)
- [Commits](https://github.com/jaywcjlove/hotkeys-js/compare/v4.0.1...v4.0.2)

---
updated-dependencies:
- dependency-name: hotkeys-js
  dependency-version: 4.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-04 09:34:51 +00:00
Maikel Linke
1bec028a09 Add gem for spring to listen to filesystem changes efficiently
I found that each spring process was using around 3% CPU in the
background just scanning for file changes. By default, spring polls the
file system every 0.2 seconds.

With the added gem, I can't see any CPU use of spring in the background.
2026-03-04 14:43:18 +11:00
David Cook
59547ba9e4 Merge pull request #13964 from mkllnk/flaky-spec
Stabilise actions_spec
2026-03-04 13:06:08 +11:00
Maikel
9fb8bb15e8 Merge pull request #13951 from zilton7/fix/spree-credit-card-brand-deprecation
Fix Spree::CreditCard#brand= deprecation for Rails 7.2 compatibility
2026-03-04 11:01:10 +11:00
Maikel
8aa89c0bf7 Merge pull request #13669 from pacodelaluna/repair-proxy-order-to-support-order-cycle-without-closing-time
Repair ProxyOrder to support order cycle without closing time
2026-03-04 10:59:21 +11:00
Cillian O'Ruanaidh
447d80c960 Fix spec due to switch to email type field 2026-03-04 10:28:40 +11:00
Cillian O'Ruanaidh
67853bb976 Use guard 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
d57274fc4c Manager invitation email is only for new users 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
f063e2e8c6 Change to email field 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
d3eb887664 Align button 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
efae11e2af Change assertion for flakey test failure 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
1554459eb9 Display a JS alert if /admin/search/known_users returns an error 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
50265780cf Call AdminTooltipComponent directly and remove unnecessary partial 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
7433f6d183 Rename :save to save! on UserInvitation because it possibly could raise an exception 2026-03-04 10:28:39 +11:00
Cillian O'Ruanaidh
f1071575cd Remove Angular from Enterprise > Settings > Users section 2026-03-04 10:28:36 +11:00
Maikel
7a4beb8b22 Merge pull request #13982 from openfoodfoundation/dependabot/npm_and_yarn/tom-select-2.5.2
Bump tom-select from 2.5.1 to 2.5.2
2026-03-04 09:49:28 +11:00
Maikel
9a48ee16cc Merge pull request #13983 from openfoodfoundation/dependabot/npm_and_yarn/hotkeys-js-4.0.1
Bump hotkeys-js from 4.0.0 to 4.0.1
2026-03-04 09:48:23 +11:00
Maikel
50c0e8af7d Merge pull request #13984 from openfoodfoundation/dependabot/bundler/pdf-reader-2.15.1
Bump pdf-reader from 2.15.0 to 2.15.1
2026-03-04 09:47:35 +11:00
David Cook
1cf2928f9f Merge pull request #13979 from openfoodfoundation/RachL-patch-1
Update release issue template
2026-03-04 09:10:24 +11:00
François Turbelin
6cacde837d Remove duplicated test 2026-03-03 14:27:20 +01:00
dependabot[bot]
1d2d661675 Bump pdf-reader from 2.15.0 to 2.15.1
Bumps [pdf-reader](https://github.com/yob/pdf-reader) from 2.15.0 to 2.15.1.
- [Changelog](https://github.com/yob/pdf-reader/blob/main/CHANGELOG)
- [Commits](https://github.com/yob/pdf-reader/compare/v2.15.0...v2.15.1)

---
updated-dependencies:
- dependency-name: pdf-reader
  dependency-version: 2.15.1
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-03 09:33:47 +00:00
dependabot[bot]
5029c03205 Bump hotkeys-js from 4.0.0 to 4.0.1
Bumps [hotkeys-js](https://github.com/jaywcjlove/hotkeys-js) from 4.0.0 to 4.0.1.
- [Release notes](https://github.com/jaywcjlove/hotkeys-js/releases)
- [Commits](https://github.com/jaywcjlove/hotkeys-js/compare/v4.0.0...v4.0.1)

---
updated-dependencies:
- dependency-name: hotkeys-js
  dependency-version: 4.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-03 09:33:32 +00:00
dependabot[bot]
2b648f3f3c Bump tom-select from 2.5.1 to 2.5.2
Bumps [tom-select](https://github.com/orchidjs/tom-select) from 2.5.1 to 2.5.2.
- [Release notes](https://github.com/orchidjs/tom-select/releases)
- [Commits](https://github.com/orchidjs/tom-select/compare/v2.5.1...2.5.2)

---
updated-dependencies:
- dependency-name: tom-select
  dependency-version: 2.5.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-03 09:33:16 +00:00
David Cook
b2e847b551 Merge pull request #13957 from openfoodfoundation/dependabot/bundler/i18n-1.14.8
Bump i18n from 1.14.7 to 1.14.8
2026-03-03 17:16:58 +11:00
Maikel Linke
4873fd3275 Remove non-task item 2026-03-03 16:16:57 +11:00
Maikel Linke
e0ad4363a9 Fix formatting 2026-03-03 16:12:47 +11:00
David Cook
46de21ea2b Restore required expectation
It is the whole purpose of the spec.
2026-03-03 11:06:10 +11:00
Gaetan Craig-Riou
efdbf25f86 Merge pull request #13248 from drummer83/email_whitelabel
White labelling all customer facing emails
2026-03-03 09:40:47 +11:00
François Turbelin
a069e4247f Remove helper method to use direct logic 2026-03-02 22:43:18 +01:00
François Turbelin
7010cda9f7 Tidy up the tests 2026-03-02 22:07:45 +01:00
Konrad
498ed5a3ec Resolve conflicts 2026-03-02 22:05:29 +01:00
Rachel Arnould
c7d4c6f3c4 Merge pull request #13835 from prikeshsavla/13569-remove-v3-admin-styles
Refactor admin CSS: Promote v3 to canonical admin styles
2026-03-02 12:29:33 +01:00
Rachel Arnould
70b2a6d999 Update release template
Currently testers are using google docs to store release tests. This is maybe overkill.

I've documented the steps here and the proposal is for testers to document their test in the release issue.
2026-03-02 12:22:11 +01:00
dependabot[bot]
36e3e16ba0 Bump i18n from 1.14.7 to 1.14.8
Bumps [i18n](https://github.com/ruby-i18n/i18n) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/ruby-i18n/i18n/releases)
- [Changelog](https://github.com/ruby-i18n/i18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/ruby-i18n/i18n/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: i18n
  dependency-version: 1.14.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-02 02:36:18 +00:00
Gaetan Craig-Riou
0f047e2c25 Merge pull request #13977 from openfoodfoundation/dependabot/npm_and_yarn/minimatch-3.1.5
Bump minimatch from 3.1.2 to 3.1.5
2026-03-02 12:00:02 +11:00
dependabot[bot]
ef7bd083ed Bump minimatch from 3.1.2 to 3.1.5
Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.1.2 to 3.1.5.
- [Changelog](https://github.com/isaacs/minimatch/blob/main/changelog.md)
- [Commits](https://github.com/isaacs/minimatch/compare/v3.1.2...v3.1.5)

---
updated-dependencies:
- dependency-name: minimatch
  dependency-version: 3.1.5
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-28 03:02:06 +00:00
Rachel Arnould
c13785f2e3 Merge pull request #13943 from pavelk-lab/replace-brand-story-angular-with-details
Replace Angular expand/collapse with native HTML <details>/<summary> for brand story
2026-02-27 15:37:00 +01:00
François Turbelin
28dde86960 Repair ProxyOrder to support order cycle without closing time 2026-02-27 14:36:20 +01:00
François Turbelin
08691f81a1 Adjust logic and specs 2026-02-27 14:09:44 +01:00
Gaetan Craig-Riou
0c0304b1c1 Merge pull request #13976 from openfoodfoundation/revert-13973-fix-rubocop-violations
Revert "Fix 9 Rubocop violations (Rails/Presence and Rails/RedirectBackOrTo)Fix rubocop violations"
2026-02-27 10:06:29 +11:00
David-OFN-CA
7922bf7b65 Revert "Fix 9 Rubocop violations (Rails/Presence and Rails/RedirectBackOrTo)Fix rubocop violations" 2026-02-26 17:04:21 -05:00
David-OFN-CA
2d46676bb4 Merge pull request #13973 from David-OFN-CA/fix-rubocop-violations
Fix 9 Rubocop violations (Rails/Presence and Rails/RedirectBackOrTo)Fix rubocop violations
2026-02-26 16:01:15 -05:00
David Thomas
2808a41f0d Safely autocorrect Rails/RedirectBackOrTo
Inspecting 1721 files
........................................W...................................................................W................W..W.......W................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

Offenses:

app/controllers/admin/order_cycles_controller.rb:212:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back(fallback_location: root_path)
        ^^^^^^^^^^^^^
app/controllers/locales_controller.rb:6:5: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
    redirect_back fallback_location: main_app.root_url
    ^^^^^^^^^^^^^
app/controllers/spree/admin/invoices_controller.rb:31:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back(fallback_location: spree.admin_dashboard_path)
        ^^^^^^^^^^^^^
app/controllers/spree/admin/orders_controller.rb:83:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back fallback_location: spree.admin_dashboard_path
        ^^^^^^^^^^^^^
app/controllers/spree/admin/orders_controller.rb:91:25: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
          format.html { redirect_back(fallback_location: spree.admin_dashboard_path) }
                        ^^^^^^^^^^^^^
app/controllers/spree/admin/return_authorizations_controller.rb:13:9: W: [Corrected] Rails/RedirectBackOrTo: Use redirect_back_or_to instead of redirect_back with :fallback_location keyword argument.
        redirect_back fallback_location: spree.admin_dashboard_path
        ^^^^^^^^^^^^^

1721 files inspected, 6 offenses detected, 6 offenses corrected
2026-02-26 15:35:55 -05:00
David Thomas
18869979db Safely autocorrect Rails/Presence
Inspecting 1721 files
...................................C.................................................................................................................................................................................................................................................................................................................................................C...................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................................

Offenses:

app/controllers/admin/enterprises_controller.rb:180:7: C: [Corrected] Rails/Presence: Use @object.custom_tab.presence&.destroy instead of @object.custom_tab.destroy if @object.custom_tab.present?.
      @object.custom_tab.destroy if @object.custom_tab.present?
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/controllers/admin/enterprises_controller.rb:243:9: C: [Corrected] Rails/Presence: Use (enterprises.presence&.includes(supplied_products: [:variants, :image])) instead of if enterprises.present? ... end.
        if enterprises.present? ...
        ^^^^^^^^^^^^^^^^^^^^^^^
app/controllers/admin/enterprises_controller.rb:243:9: C: [Corrected] Style/RedundantParentheses: Don't use parentheses around a method call.
        (enterprises.presence&.includes(supplied_products: [:variants, :image]))
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/spree/product.rb:298:7: C: [Corrected] Rails/Presence: Use (first_variant.supplier.presence&.touch) instead of first_variant.supplier.touch if first_variant.supplier.present?.
      first_variant.supplier.touch if first_variant.supplier.present?
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
app/models/spree/product.rb:298:7: C: [Corrected] Style/RedundantParentheses: Don't use parentheses around a method call.
      (first_variant.supplier.presence&.touch)
      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

1721 files inspected, 5 offenses detected, 5 offenses corrected
2026-02-26 15:34:45 -05:00
David Thomas
708dbb2270 Regenerate Rubocop's TODO file 2026-02-26 15:33:37 -05:00
François Turbelin
de52e21ee9 Remove floating point overkill for prices sum 2026-02-26 18:04:02 +01:00
Zil Norvilis
9488e9b459 feat: display credit card brand instead of card type in the saved cards list. 2026-02-26 15:52:45 +02:00
Zil Norvilis
503429960a Reverse credit_card_serializer changes 2026-02-26 15:10:21 +02:00
Rachel Arnould
83ec97e720 Merge pull request #13944 from pavelk-lab/fix/rails-7-serialize-deprecation
Fix Rails 7.2 serialize deprecation warnings
2026-02-26 11:29:27 +01:00
Maikel Linke
c0b6f26338 Update all locales with the latest Transifex translations 2026-02-26 12:43:07 +11:00
Maikel Linke
fd178ee80b Use unique categories to avoid flakiness 2026-02-26 11:42:46 +11:00
Maikel Linke
e4db20f86e Remove unncessary expectation
This assertion was confusing me. It was quite complex and the only thing
it was asserting was the placeholder via a CSS selector. I don't think
it's worth keeping.
2026-02-26 11:37:30 +11:00
Zil Norvilis
58520a0c4c test: Add specs for the stripe_card_options helper method, verifying card formatting and month padding. 2026-02-25 19:49:10 +02:00
Zil Norvilis
0bc4b1c885 refactor: Standardize credit card type attribute to cc_type across the application, removing the brand alias and related methods. 2026-02-25 19:35:53 +02:00
Arun Guleria
b7a1754879 13864 - remove unnecessary routes for update positions 2026-02-25 16:29:20 +05:30
Maikel Linke
560348722c Revert "Test current flakiness of spec"
This reverts commit 7b715bf6c7.
2026-02-25 15:18:39 +11:00
Maikel Linke
6d17cf50fb Test impact of longer wait time on flakiness 2026-02-25 15:08:50 +11:00
Maikel Linke
7b715bf6c7 Test current flakiness of spec 2026-02-25 15:07:52 +11:00
Gaetan Craig-Riou
f6c426ef17 Merge pull request #13956 from openfoodfoundation/dependabot/npm_and_yarn/css-loader-7.1.4
Bump css-loader from 7.1.3 to 7.1.4
2026-02-25 10:24:55 +11:00
Ahmed Ejaz
0a42f15c25 Merge pull request #13960 from chahmedejaz/bugfix/13776-datetime-format-for-finnish
Update Finnish date and datetime formats in locale file
2026-02-25 04:19:08 +05:00
Ahmed Ejaz
95412bd203 Update Finnish date and datetime formats in locale file 2026-02-24 20:27:14 +05:00
Arun Guleria
ab811b2c83 13864-Remove dead feature to re-arrange variants 2026-02-24 18:16:34 +05:30
Rachel Arnould
81aac877a5 Merge pull request #13945 from mkllnk/taler-refund
Add "void" action to Taler payment admin page
2026-02-24 11:23:07 +01:00
dependabot[bot]
2330c7cfc2 Bump css-loader from 7.1.3 to 7.1.4
Bumps [css-loader](https://github.com/webpack/css-loader) from 7.1.3 to 7.1.4.
- [Release notes](https://github.com/webpack/css-loader/releases)
- [Changelog](https://github.com/webpack/css-loader/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/css-loader/compare/v7.1.3...v7.1.4)

---
updated-dependencies:
- dependency-name: css-loader
  dependency-version: 7.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-24 09:31:34 +00:00
Rachel Arnould
68c7d8f9f5 Merge pull request #13934 from chahmedejaz/bugfix/13827-tag-filters-reset-upon-product-update
Tag filters are reset after updating a product
2026-02-24 10:20:11 +01:00
Maikel
cf3175c16e Merge pull request #13709 from openfoodfoundation/dependabot/bundler/cuprite-0.17
Bump cuprite from 0.15 to 0.17
2026-02-24 12:05:17 +11:00
Pavel
85c903cb7f Remove fixed serialize deprecation from allowed warnings
The "Passing the class as positional argument" warning was suppressed
while serialize calls were being updated to use the keyword argument
form. Now that the fix is applied, the suppression is no longer needed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-23 23:30:48 +00:00
Gaetan Craig-Riou
ebd7b0b24d Merge pull request #13952 from openfoodfoundation/dependabot/npm_and_yarn/postcss-loader-8.2.1
Bump postcss-loader from 8.2.0 to 8.2.1
2026-02-24 10:11:42 +11:00
Gaetan Craig-Riou
78cf0434d6 Merge pull request #13953 from openfoodfoundation/dependabot/npm_and_yarn/webpack-sources-3.3.4
Bump webpack-sources from 3.3.3 to 3.3.4
2026-02-24 10:11:23 +11:00
dependabot[bot]
74e7e9b17b Bump webpack-sources from 3.3.3 to 3.3.4
Bumps [webpack-sources](https://github.com/webpack/webpack-sources) from 3.3.3 to 3.3.4.
- [Release notes](https://github.com/webpack/webpack-sources/releases)
- [Commits](https://github.com/webpack/webpack-sources/compare/v3.3.3...v3.3.4)

---
updated-dependencies:
- dependency-name: webpack-sources
  dependency-version: 3.3.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-23 10:24:42 +00:00
dependabot[bot]
2b32d53911 Bump postcss-loader from 8.2.0 to 8.2.1
Bumps [postcss-loader](https://github.com/webpack/postcss-loader) from 8.2.0 to 8.2.1.
- [Release notes](https://github.com/webpack/postcss-loader/releases)
- [Changelog](https://github.com/webpack/postcss-loader/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/postcss-loader/compare/v8.2.0...v8.2.1)

---
updated-dependencies:
- dependency-name: postcss-loader
  dependency-version: 8.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-23 10:24:16 +00:00
Maikel Linke
2cff5bc4df Style helper code 2026-02-23 13:08:56 +11:00
Maikel Linke
1dbcddf799 Select found option after search to fix spec
Selecting the tom select option in the dropdown often happened quicker
than the search finished. In that case we selected the option from the
list of all options and then the search would present the found option
again and leave the dropdown open.

This didn't cause any trouble in the past because any other action would
close the dropdown again. But the new cuprite version didn't trigger the
next click on the target element. It would just close the dropdown on
the next click without further action. That would then break the next
assertion looking for the next open dropdown, which didn't open with the
click.

Selecting the "active" option means that we wait for the search to
finish and present an option as active. Clicking that option closes the
dropdown without opening it again.
2026-02-23 13:08:55 +11:00
Maikel Linke
702db32595 Connect unit label to input
And replace redundant spec helper method.
2026-02-23 13:08:55 +11:00
Maikel Linke
d770049d2d Replace redundant spec helper method 2026-02-23 13:08:55 +11:00
Maikel Linke
424e25f83e Merge mostly duplicate Tom Select helpers 2026-02-23 13:08:55 +11:00
dependabot[bot]
ce12bc4dbc Bump cuprite from 0.15 to 0.17
Bumps [cuprite](https://github.com/rubycdp/cuprite) from 0.15 to 0.17.
- [Release notes](https://github.com/rubycdp/cuprite/releases)
- [Changelog](https://github.com/rubycdp/cuprite/blob/main/CHANGELOG.md)
- [Commits](https://github.com/rubycdp/cuprite/compare/v0.15...v0.17)

---
updated-dependencies:
- dependency-name: cuprite
  dependency-version: '0.17'
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-23 13:08:53 +11:00
Maikel Linke
9d79119eb0 Link to payment action with title
The custom helper was adding a PowerTip which replaced the title
attribute with its own display. I removed the PowerTip and use a simple
title attribute. This should have several benefits:

- Capybara can find the link by the title.
- Screenreaders should be able read the title.
- Browser can show the title in the best position.
- Using the browser feature is more consistent and efficient.
2026-02-23 13:00:02 +11:00
Maikel Linke
f2eec5685e Include amount in refund email 2026-02-23 13:00:02 +11:00
Gaetan Craig-Riou
8aac400c14 Merge pull request #13948 from openfoodfoundation/dependabot/bundler/sidekiq-scheduler-6.0.1
Bump sidekiq-scheduler from 5.0.3 to 6.0.1
2026-02-23 10:03:50 +11:00
Gaetan Craig-Riou
f31976a3a4 Merge pull request #13950 from openfoodfoundation/dependabot/npm_and_yarn/ajv-6.14.0
Bump ajv from 6.12.6 to 6.14.0
2026-02-23 09:58:17 +11:00
Gaetan Craig-Riou
0bb2c867e0 Merge pull request #13947 from openfoodfoundation/dependabot/npm_and_yarn/webpack-5.105.2
Bump webpack from 5.105.1 to 5.105.2
2026-02-23 09:45:01 +11:00
Gaetan Craig-Riou
cd68ddc34f Merge pull request #13946 from mkllnk/erb
Remove unnecessary erb compilation on JS file
2026-02-23 09:43:11 +11:00
Zil Norvilis
2cfd386ad7 test: add spec for Spree::CreditCard#brand= setter to verify card type reformatting 2026-02-22 22:28:40 +02:00
Zil Norvilis
ce94b394b2 feat: Add brand= setter to Spree::CreditCard for cc_type assignment. 2026-02-22 22:01:54 +02:00
Pavel
98775bfdb8 Pass type as keyword argument in migration serialize call
Same fix as applied to Invoice and ReportRenderingOptions models in
the parent PR: Rails 7.2 requires the type class to be passed as a
keyword argument to serialize.

  serialize :options, Hash, coder: YAML
  ->
  serialize :options, type: Hash, coder: YAML

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-21 23:23:12 +00:00
pavelk-lab
47ef21deb3 Merge branch 'master' into fix/rails-7-serialize-deprecation 2026-02-21 23:19:58 +00:00
dependabot[bot]
f80b484b12 Bump ajv from 6.12.6 to 6.14.0
Bumps [ajv](https://github.com/ajv-validator/ajv) from 6.12.6 to 6.14.0.
- [Release notes](https://github.com/ajv-validator/ajv/releases)
- [Commits](https://github.com/ajv-validator/ajv/compare/v6.12.6...v6.14.0)

---
updated-dependencies:
- dependency-name: ajv
  dependency-version: 6.14.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-21 16:39:48 +00:00
dependabot[bot]
1f7c08bbb0 Bump sidekiq-scheduler from 5.0.3 to 6.0.1
Bumps [sidekiq-scheduler](https://github.com/moove-it/sidekiq-scheduler) from 5.0.3 to 6.0.1.
- [Release notes](https://github.com/moove-it/sidekiq-scheduler/releases)
- [Changelog](https://github.com/sidekiq-scheduler/sidekiq-scheduler/blob/master/CHANGELOG.md)
- [Commits](https://github.com/moove-it/sidekiq-scheduler/compare/v5.0.3...v6.0.1)

---
updated-dependencies:
- dependency-name: sidekiq-scheduler
  dependency-version: 6.0.1
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-20 09:33:43 +00:00
dependabot[bot]
fcb9439cd2 Bump webpack from 5.105.1 to 5.105.2
Bumps [webpack](https://github.com/webpack/webpack) from 5.105.1 to 5.105.2.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Changelog](https://github.com/webpack/webpack/blob/main/CHANGELOG.md)
- [Commits](https://github.com/webpack/webpack/compare/v5.105.1...v5.105.2)

---
updated-dependencies:
- dependency-name: webpack
  dependency-version: 5.105.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-20 09:33:13 +00:00
Maikel Linke
96c2b75a0a Spec admin display of Taler payment actions
This should satisfy code coverage.
2026-02-20 13:43:09 +11:00
Maikel Linke
b6438992b9 Speed up spec by not saving to database 2026-02-20 13:43:09 +11:00
Maikel Linke
69108df206 Use Rails to translate email subject
And translate the subject with the user's locale.
If the subject doesn't need parameters, you don't need to supply it.
Rails finds the translation automatically.
2026-02-20 13:43:09 +11:00
Maikel Linke
c66b9611b6 Move PaymentMailer translations out of Spree namespace
The mailer is not in the Spree namespace and we don't need to keep the
clutter.
2026-02-20 13:43:09 +11:00
Maikel Linke
de873ae42c Add void action to Taler for refunds 2026-02-20 13:43:09 +11:00
Maikel Linke
ed701b00dc Stop storing now redundant redirect URL
The Taler gem now computes it from the order id. No need to store it.
2026-02-20 13:43:04 +11:00
Maikel Linke
52e2fb923e Update Taler calls for new v0.2.0 2026-02-20 13:37:46 +11:00
Maikel Linke
a2a9d32c5b Bump taler from 0.1.0 to 0.2.0 2026-02-20 13:37:45 +11:00
Pavel
e98244fe63 Fix Rails 7.2 serialize deprecation warnings
Pass type as keyword argument in serialize calls, as required from Rails 7.2 onwards.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 21:55:13 +00:00
Pavel
b348536d12 Clean up dead code after Angular brand story removal
- Delete HomeCtrl controller file (nothing references it anymore)
- Remove misplaced .text-vbig class from <details> (was on the old <a> toggle; summary has no visible text)
- Remove redundant cursor: pointer on #brand-story-text (<summary> already sets it)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-19 21:39:32 +00:00
Pavel
b528bb47a0 Replace Angular expand/collapse with native HTML details/summary for brand story
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-19 21:23:09 +00:00
Ahmed Ejaz
1d4bbfa506 Supports tag filters persistence during product updates
Adds functionality to retain tag filters applied in the admin product interface after bulk updates. Updates controller parameters to include tags_name_in, adds hidden fields for tag persistence in the view, and includes specs to verify filter state retention across update operations.
2026-02-18 01:37:41 +05:00
Maikel Linke
4b689d00a4 Remove unnecessary erb compilation on JS file 2026-02-17 13:56:30 +11:00
Prikesh Savla
5a9aa87831 Rename admin-style-v3 to admin-style and remove the admin_legacy styles folder that has no references 2026-01-25 21:15:40 +05:30
Prikesh Savla
8cfab08f9e Refactor admin CSS: Promote v3 to canonical admin styles
The Admin V3 styles are now the primary styles for the application. This change promotes the `admin_v3` directory to `admin` and archives the old styles.

Changes:
- Renamed `app/webpacker/css/admin_v3` to `app/webpacker/css/admin`.
- Renamed the previous `app/webpacker/css/admin` to `app/webpacker/css/admin_legacy`.
- Moved all files referenced by V3 styles from the legacy directory to the new `admin` directory.
- Updated imports in `all.scss` to distinct local files instead of relative paths.
- Cleaned up `admin_legacy` by removing files that are duplicates (by name or content) of the new admin styles.
- Updated `admin-style-v3` pack to point to the new location.
2026-01-25 21:05:38 +05:30
Konrad
e814fdd447 Remove test for active white labeling in test email as proposed by David 2025-12-29 12:36:50 +01:00
David Cook
4d6231105f Assign attribute directly instead of mocking
It's better to set a variable the same way the real code would

Co-authored-by: Maikel <maikel@email.org.au>
2025-12-29 12:18:55 +01:00
Konrad
3a75c3446e Update backorder mailer specs to check that these hub facing emails remain unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
29a76fd721 Update report mailer specs to check that this enterprise facing email remains unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
593bd89095 Update test mailer specs to check that this super admin facing email remains unaffected by white labelling (there are no user or customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
0079ed219b Update producer mailer specs to check that this producer facing email remains unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
5957d99812 Update enterprise mailer specs to check that enterprise facing emails remain unaffected by white labelling (there are no customer facing emails here)
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
89453ec758 Update subscription mailer specs to check that customer facing emails are white labelled, while shop facing emails are not
Also make use of the newly separated shared_examples

Made the check for link to order page more general, because on my system a double quote was expected but a single quote was generated
2025-12-29 12:18:55 +01:00
Konrad
0de4f2f596 Update payment mailer specs to check that customer facing emails are white labelled, while shop facing emails are not
Also make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
183cbecef6 Update shipment mailer specs to check that customer facing emails are white labelled (there are no shop facing emails here)
Make use of the newly separated shared_examples
2025-12-29 12:18:55 +01:00
Konrad
ab6a49e568 Update order mailer specs to check that customer facing emails are white labelled, while shop facing emails are not
Also make use of the newly separated shared_examples

Including the invoice email was too tricky for me for now, sorry
2025-12-29 12:18:55 +01:00
Konrad
52ddb29dc7 Update user mailer specs to check that white labelling does not affect these emails
Move tests to separate file for reuse in other emails

Pass on :mail symbol and obtain the mail-object using public_send() to call it with different names
2025-12-29 12:18:54 +01:00
drummer83
5ce7905a33 White labelling ALL customer facing emails
White labelling added for Order: cancellation email, Order: invoice email, Shipment: shipped email, Subscriptions: authorize payment email, Subscriptions: placement email, Subscriptions: empty order email, Subscriptions: failed payment email

White labelling existed already for Order: confirmation email, Subscriptions: order confirmation email
2025-12-29 12:18:54 +01:00
François Turbelin
8748bd76e2 Introduce a prices_sum helper to factorize the calculation on reports 2025-12-18 18:00:23 +01:00
François Turbelin
30f702ea96 Repair rounding issue on totals in reports 2025-12-04 16:14:04 +01:00
192 changed files with 1664 additions and 2714 deletions

View File

@@ -27,7 +27,12 @@ assignees: ''
- [ ] Move this issue to Test Ready.
- [ ] Notify `@testers` in [#testing].
- [ ] Test build: [Deploy to Staging] with release tag.
- [ ] Notify a deployer to deploy it
- [ ] Map is displayed correctly. Address changes are reflected in the map.
- [ ] Stripe with no authentication card: `4242424242424242` as shopper and as Admin. Order confirmation displays order as "Paid".
- [ ] Stripe with Authentication required card: `4000002760003184` as shopper and as Admin. As admin, check authorization through customer account `/account#/transactions` and email.
- [ ] Pay with Paypal.
- [ ] Order on mobile.
- [ ] Notify a deployer to deploy it.
## 3. Deployment at beginning of week
@@ -57,4 +62,4 @@ The full process is described at https://github.com/openfoodfoundation/openfoodn
[Create issue]: https://github.com/openfoodfoundation/openfoodnetwork/issues/new?assignees=&labels=&projects=&template=release.md&title=Release
[#delivery-circle]: https://openfoodnetwork.slack.com/archives/C01T75H6G0Z
[Transifex Client]: https://developers.transifex.com/docs/cli
[minor or major breaking changes]: https://github.com/openfoodfoundation/openfoodnetwork/pulls?q=label%3A%22breaking+change%22%2C%22major+breaking+change%22
[minor or major breaking changes]: https://github.com/openfoodfoundation/openfoodnetwork/pulls?q=label%3A%22breaking+change%22%2C%22major+breaking+change%22

View File

@@ -203,6 +203,7 @@ group :development do
gem 'spring'
gem 'spring-commands-rspec'
gem 'spring-commands-rubocop'
gem 'spring-watcher-listen'
gem 'web-console'
gem 'rack-mini-profiler', '< 3.0.0'

View File

@@ -170,7 +170,7 @@ GEM
addressable (2.8.8)
public_suffix (>= 2.0.2, < 8.0)
aes_key_wrap (1.1.0)
afm (0.2.2)
afm (1.0.0)
angular-rails-templates (1.4.0)
railties (>= 5.0, < 8.2)
sprockets (>= 3.0, < 5)
@@ -267,9 +267,9 @@ GEM
css_parser (1.21.1)
addressable
csv (3.3.5)
cuprite (0.15)
cuprite (0.17)
capybara (~> 3.0)
ferrum (~> 0.14.0)
ferrum (~> 0.17.0)
database_cleaner (2.1.0)
database_cleaner-active_record (>= 2, < 3)
database_cleaner-active_record (2.2.2)
@@ -315,7 +315,7 @@ GEM
activemodel
erb (6.0.1)
erubi (1.13.1)
et-orbi (1.3.0)
et-orbi (1.4.0)
tzinfo
eventmachine (1.2.7)
eventmachine_httpserver (0.2.1)
@@ -334,11 +334,12 @@ GEM
faraday (>= 1, < 3)
faraday-net_http (3.4.2)
net-http (~> 0.5)
ferrum (0.14)
ferrum (0.17.1)
addressable (~> 2.5)
base64 (~> 0.2)
concurrent-ruby (~> 1.1)
webrick (~> 1.7)
websocket-driver (>= 0.6, < 0.8)
websocket-driver (~> 0.7)
ffaker (2.25.0)
ffi (1.17.3)
flipper (1.3.6)
@@ -371,8 +372,8 @@ GEM
foreman (0.90.0)
thor (~> 1.4)
formatador (0.2.5)
fugit (1.11.1)
et-orbi (~> 1, >= 1.2.11)
fugit (1.12.1)
et-orbi (~> 1.4)
raabro (~> 1.4)
fuubar (2.5.1)
rspec-core (~> 3.0)
@@ -404,7 +405,7 @@ GEM
reline
htmlentities (4.4.2)
http_parser.rb (0.8.0)
i18n (1.14.7)
i18n (1.14.8)
concurrent-ruby (~> 1.0)
i18n-js (3.9.2)
i18n (>= 0.6.6)
@@ -529,7 +530,7 @@ GEM
net-protocol
newrelic_rpm (9.24.0)
nio4r (2.7.5)
nokogiri (1.19.0)
nokogiri (1.19.1)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
nokogiri-html5-inference (0.3.0)
@@ -583,7 +584,7 @@ GEM
xml-simple
paypal-sdk-merchant (1.117.2)
paypal-sdk-core (~> 0.3.0)
pdf-reader (2.15.0)
pdf-reader (2.15.1)
Ascii85 (>= 1.0, < 3.0, != 2.0.0)
afm (>= 0.2.1, < 2)
hashery (~> 2.0)
@@ -602,7 +603,7 @@ GEM
psych (5.3.1)
date
stringio
public_suffix (7.0.0)
public_suffix (7.0.2)
puffing-billy (4.0.2)
addressable (~> 2.5)
em-http-request (~> 1.1, >= 1.1.0)
@@ -710,7 +711,7 @@ GEM
redcarpet (3.6.1)
redis (5.4.1)
redis-client (>= 0.22.0)
redis-client (0.26.1)
redis-client (0.26.4)
connection_pool
regexp_parser (2.11.3)
reline (0.6.3)
@@ -815,8 +816,8 @@ GEM
ffi (~> 1.12)
logger
rubyzip (2.4.1)
rufus-scheduler (3.8.2)
fugit (~> 1.1, >= 1.1.6)
rufus-scheduler (3.9.2)
fugit (~> 1.1, >= 1.11.1)
rugged (1.9.0)
sanitize (7.0.0)
crass (~> 1.0.2)
@@ -838,10 +839,9 @@ GEM
logger
rack (>= 2.2.4, < 3.3)
redis-client (>= 0.23.0, < 1)
sidekiq-scheduler (5.0.3)
sidekiq-scheduler (6.0.1)
rufus-scheduler (~> 3.2)
sidekiq (>= 6, < 8)
tilt (>= 1.4.0)
sidekiq (>= 7.3, < 9)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
@@ -857,6 +857,9 @@ GEM
spring (>= 0.9.1)
spring-commands-rubocop (0.4.0)
spring (>= 1.0)
spring-watcher-listen (2.1.0)
listen (>= 2.7, < 4.0)
spring (>= 4)
sprockets (3.7.5)
base64
concurrent-ruby (~> 1.0)
@@ -893,13 +896,13 @@ GEM
faraday (~> 2.0)
faraday-follow_redirects
sysexits (1.2.0)
taler (0.1.0)
taler (0.2.0)
temple (0.10.4)
terminal-table (4.0.0)
unicode-display_width (>= 1.1.1, < 4)
thor (1.5.0)
thread-local (1.1.0)
tilt (2.6.1)
tilt (2.7.0)
timeout (0.6.0)
tsort (0.2.0)
ttfunk (1.8.0)
@@ -932,8 +935,7 @@ GEM
public_suffix
validates_lengths_from_database (0.8.0)
activerecord (>= 4)
vcr (6.3.1)
base64
vcr (6.4.0)
view_component (4.1.1)
actionview (>= 7.1.0, < 8.2)
activesupport (>= 7.1.0, < 8.2)
@@ -960,7 +962,7 @@ GEM
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
webrick (1.9.2)
websocket-driver (0.7.7)
websocket-driver (0.8.0)
base64
websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5)
@@ -1101,6 +1103,7 @@ DEPENDENCIES
spring
spring-commands-rspec
spring-commands-rubocop
spring-watcher-listen
sprockets (~> 3.7)
state_machines-activerecord
stimulus_reflex

View File

@@ -4,16 +4,12 @@ angular.module("admin.enterprises")
$scope.Enterprises = Enterprises
$scope.navClear = NavigationCheck.clear
$scope.menu = SideMenu
$scope.newManager = { id: null, email: (t('add_manager')) }
$scope.StatusMessage = StatusMessage
$scope.RequestMonitor = RequestMonitor
$scope.$watch 'enterprise_form.$dirty', (newValue) ->
StatusMessage.display 'notice', t('admin.unsaved_changes') if newValue
$scope.$watch 'newManager', (newValue) ->
$scope.addManager($scope.newManager) if newValue
$scope.setFormDirty = ->
$scope.$apply ->
$scope.enterprise_form.$setDirty()
@@ -35,26 +31,6 @@ angular.module("admin.enterprises")
# Register the NavigationCheck callback
NavigationCheck.register(enterpriseNavCallback)
$scope.removeManager = (manager) ->
if manager.id?
if manager.id == $scope.Enterprise.owner.id or manager.id == parseInt($scope.receivesNotifications)
return
for i, user of $scope.Enterprise.users when user.id == manager.id
$scope.Enterprise.users.splice i, 1
$scope.enterprise_form?.$setDirty()
$scope.addManager = (manager) ->
if manager.id? and angular.isNumber(manager.id) and manager.email?
manager =
id: manager.id
email: manager.email
confirmed: manager.confirmed
if (user for user in $scope.Enterprise.users when user.id == manager.id).length == 0
$scope.Enterprise.users.unshift(manager)
$scope.enterprise_form?.$setDirty()
else
alert ("#{manager.email}" + " " + t("is_already_manager"))
$scope.performEnterpriseAction = (enterpriseActionName, warning_message_key, success_message_key) ->
return unless confirm($scope.translation(warning_message_key))

View File

@@ -1,5 +0,0 @@
angular.module('Darkswarm').controller "HomeCtrl", ($scope) ->
$scope.brandStoryExpanded = false
$scope.toggleBrandStory = ->
$scope.brandStoryExpanded = !$scope.brandStoryExpanded

View File

@@ -67,7 +67,6 @@ module Admin
def update
tag_rules_attributes = params[object_name].delete :tag_rules_attributes
update_tag_rules(tag_rules_attributes) if tag_rules_attributes.present?
update_enterprise_notifications
update_vouchers
delete_custom_tab if params[:custom_tab] == 'false'
@@ -314,14 +313,6 @@ module Admin
end
end
def update_enterprise_notifications
user_id = params[:receives_notifications].to_i
return unless user_id.positive? && @enterprise.user_ids.include?(user_id)
@enterprise.update_contact(user_id)
end
def update_vouchers
params_voucher_ids = params[:enterprise][:voucher_ids].to_a.map(&:to_i)
voucher_ids = @enterprise.vouchers.map(&:id)

View File

@@ -28,7 +28,7 @@ module Admin
flash[:success] = I18n.t('admin.products_v3.bulk_update.success')
redirect_to [:index,
{ page: @page, per_page: @per_page, search_term: @search_term,
producer_id: @producer_id, category_id: @category_id }]
producer_id: @producer_id, category_id: @category_id, tags_name_in: @tags }]
elsif product_set.errors.present?
@error_counts = { saved: product_set.saved_count, invalid: product_set.invalid.count }
@@ -120,7 +120,7 @@ module Admin
@search_term = params[:search_term] || params[:_search_term]
@producer_id = params[:producer_id] || params[:_producer_id]
@category_id = params[:category_id] || params[:_category_id]
@tags = params[:tags_name_in] || params[:_tags_name_in]
@tags = params[:tags_name_in] || []
end
def init_pagination_params

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
module Admin
class UserInvitationsController < ResourceController
before_action :load_enterprise
def new; end
def create
@user_invitation.attributes = permitted_resource_params
if @user_invitation.save!
flash[:success] = I18n.t(:user_invited, email: @user_invitation.email)
else
render :new
end
end
private
def load_enterprise
@enterprise = OpenFoodNetwork::Permissions
.new(spree_current_user)
.editable_enterprises
.find_by(permalink: params[:enterprise_id])
end
def permitted_resource_params
params.require(:user_invitation).permit(:email).merge(enterprise: @enterprise)
end
end
end

View File

@@ -1,19 +0,0 @@
# frozen_string_literal: true
module ManagerInvitations
extend ActiveSupport::Concern
def create_new_manager(email, enterprise)
password = SecureRandom.base58(64)
new_user = Spree::User.create(email:, unconfirmed_email: email, password:)
new_user.reset_password_token = Devise.friendly_token
# Same time as used in Devise's lib/devise/models/recoverable.rb.
new_user.reset_password_sent_at = Time.now.utc
if new_user.save
enterprise.users << new_user
EnterpriseMailer.manager_invitation(enterprise, new_user).deliver_later
end
new_user
end
end

View File

@@ -0,0 +1,50 @@
# frozen_string_literal: true
class UserInvitation
include ActiveModel::Model
include ActiveModel::Attributes
include ActiveModel::Validations::Callbacks
attribute :enterprise
attribute :email
before_validation :normalize_email
validates :email, presence: true, 'valid_email_2/email': { mx: true }
validates :enterprise, presence: true
validate :not_existing_enterprise_user
def save!
return unless valid?
user = find_or_create_user!
enterprise.users << user
return unless user.previously_new_record?
EnterpriseMailer.manager_invitation(enterprise, user).deliver_later
end
private
def find_or_create_user!
Spree::User.find_or_create_by!(email: email) do |user|
user.email = email
user.password = SecureRandom.base58(64)
user.unconfirmed_email = email
user.reset_password_token = Devise.friendly_token
# Same time as used in Devise's lib/devise/models/recoverable.rb.
user.reset_password_sent_at = Time.now.utc
end
end
def normalize_email
self.email = email.strip if email.present?
end
def not_existing_enterprise_user
return unless email.present? && enterprise.users.where(email: email).exists?
errors.add(:email, :is_already_manager)
end
end

View File

@@ -139,7 +139,7 @@ module CheckoutHelper
def stripe_card_options(cards)
cards.map do |cc|
[
"#{cc.brand} #{cc.last_digits} #{I18n.t(:card_expiry_abbreviation)}:" \
"#{cc.cc_type} #{cc.last_digits} #{I18n.t(:card_expiry_abbreviation)}:" \
"#{cc.month.to_s.rjust(2, '0')}/#{cc.year}", cc.id
]
end

View File

@@ -6,11 +6,10 @@ class PaymentMailer < ApplicationMailer
def authorize_payment(payment)
@payment = payment
@order = @payment.order
subject = I18n.t('spree.payment_mailer.authorize_payment.subject',
distributor: @order.distributor.name)
@hide_ofn_navigation = @payment.order.distributor.hide_ofn_navigation
I18n.with_locale valid_locale(@order.user) do
mail(to: @order.email,
subject:,
subject: default_i18n_subject(distributor: @order.distributor.name),
reply_to: @order.distributor.contact.email)
end
end
@@ -18,11 +17,20 @@ class PaymentMailer < ApplicationMailer
def authorization_required(payment)
@order = payment.order
shop_owner = @order.distributor.owner
subject = I18n.t('spree.payment_mailer.authorization_required.subject',
order: @order)
I18n.with_locale valid_locale(shop_owner) do
mail(to: shop_owner.email,
subject:,
mail(to: shop_owner.email, reply_to: @order.email)
end
end
def refund_available(payment, taler_order_status_url)
@order = payment.order
@shop = @order.distributor.name
@amount = payment.display_amount
@taler_order_status_url = taler_order_status_url
I18n.with_locale valid_locale(@order.user) do
mail(to: @order.email,
subject: default_i18n_subject(shop: @shop),
reply_to: @order.email)
end
end

View File

@@ -11,6 +11,7 @@ module Spree
def cancel_email(order_or_order_id, resend = false)
@order = find_order(order_or_order_id)
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
I18n.with_locale valid_locale(@order.user) do
mail(to: @order.email,
subject: mail_subject(t('spree.order_mailer.cancel_email.subject'), resend),
@@ -51,6 +52,7 @@ module Spree
def invoice_email(order_or_order_id, options = {})
@order = find_order(order_or_order_id)
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
current_user = if options[:current_user_id].present?
find_user(options[:current_user_id])
end

View File

@@ -4,6 +4,7 @@ module Spree
class ShipmentMailer < ApplicationMailer
def shipped_email(shipment, delivery:)
@shipment = shipment.respond_to?(:id) ? shipment : Spree::Shipment.find(shipment)
@hide_ofn_navigation = @shipment.order.distributor.hide_ofn_navigation
@delivery = delivery
@order = @shipment.order
subject = base_subject

View File

@@ -19,6 +19,7 @@ class SubscriptionMailer < ApplicationMailer
@type = 'empty'
@changes = changes
@order = order
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
send_mail(order)
end
@@ -26,11 +27,13 @@ class SubscriptionMailer < ApplicationMailer
@type = 'placement'
@changes = changes
@order = order
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
send_mail(order)
end
def failed_payment_email(order)
@order = order
@hide_ofn_navigation = @order.distributor.hide_ofn_navigation
send_mail(order)
end

View File

@@ -294,7 +294,13 @@ class Enterprise < ApplicationRecord
contact || owner
end
def update_contact(user_id)
def contact_id
contact&.id
end
def contact_id=(user_id)
return unless user_id.to_i.positive? && users.confirmed.exists?(user_id.to_i)
enterprise_roles.update_all(["receives_notifications=(user_id=?)", user_id])
end
@@ -576,7 +582,7 @@ class Enterprise < ApplicationRecord
end
def set_default_contact
update_contact owner_id
self.contact_id = owner_id
end
def relate_to_owners_enterprises

View File

@@ -4,7 +4,7 @@ class Invoice < ApplicationRecord
self.belongs_to_required_by_default = false
belongs_to :order, class_name: 'Spree::Order'
serialize :data, Hash, coder: YAML
serialize :data, type: Hash, coder: YAML
before_validation :serialize_order
after_create :cancel_previous_invoices
default_scope { order(created_at: :desc) }

View File

@@ -76,6 +76,7 @@ class ProxyOrder < ApplicationRecord
def cart?
order&.state == 'complete' &&
order_cycle.orders_close_at.present? &&
order_cycle.orders_close_at > Time.zone.now
end

View File

@@ -4,5 +4,5 @@ class ReportRenderingOptions < ApplicationRecord
self.belongs_to_required_by_default = false
belongs_to :user, class_name: "Spree::User"
serialize :options, Hash, coder: YAML
serialize :options, type: Hash, coder: YAML
end

View File

@@ -191,7 +191,7 @@ module Spree
user.enterprises.include? stripe_account.enterprise
end
can [:admin, :create], :manager_invitation
can [:admin, :create], UserInvitation
can [:admin, :index, :destroy], :oidc_setting

View File

@@ -25,9 +25,6 @@ module Spree
scope :with_payment_profile, -> { where.not(gateway_customer_profile_id: nil) }
# needed for some of the ActiveMerchant gateways (eg. SagePay)
alias_attribute :brand, :cc_type
def expiry=(expiry)
self[:month], self[:year] = expiry.split(" / ")
self[:year] = "20#{self[:year]}"

View File

@@ -52,9 +52,9 @@ module Spree
def supports?(source)
return true unless provider_class.respond_to? :supports?
return false unless source.brand
return false unless source.cc_type
provider_class.supports?(source.brand)
provider_class.supports?(source.cc_type)
end
end
end

View File

@@ -21,6 +21,14 @@ module Spree
preference :backend_url, :string
preference :api_key, :password
def actions
%w{void}
end
def can_void?(payment)
payment.state == "completed"
end
# Name of the view to display during checkout
def method_type
"check" # empty view
@@ -38,10 +46,9 @@ module Spree
payment.source ||= self
payment.response_code ||= create_taler_order(payment)
payment.redirect_auth_url ||= fetch_order_url(payment)
payment.save! if payment.changed?
payment.redirect_auth_url
taler_order.status_url
end
# Main method called by Spree::Payment::Processing during checkout
@@ -53,14 +60,33 @@ module Spree
return unless payment.response_code
taler_order = client.fetch_order(payment.response_code)
status = taler_order["order_status"]
taler_order = taler_order(id: payment.response_code)
status = taler_order.fetch("order_status")
success = (status == "paid")
message = I18n.t(status, default: status, scope: "taler.order_status")
ActiveMerchant::Billing::Response.new(success, message)
end
def void(response_code, gateway_options)
payment = gateway_options[:payment]
taler_order = taler_order(id: response_code)
status = taler_order.fetch("order_status")
if status == "claimed"
return ActiveMerchant::Billing::Response.new(true, "Already expired")
end
raise "Unsupported action" if status != "paid"
amount = taler_order.fetch("contract_terms")["amount"]
taler_order.refund(refund: amount, reason: "void")
PaymentMailer.refund_available(payment, taler_order.status_url).deliver_later
ActiveMerchant::Billing::Response.new(true, "Refund initiated")
end
private
def load_payment(order)
@@ -72,22 +98,20 @@ module Spree
# current demo backend only working with the KUDOS currency.
taler_amount = "KUDOS:#{payment.amount}"
urls = Rails.application.routes.url_helpers
new_order = client.create_order(
taler_amount,
I18n.t("payment_method_taler.order_summary"),
urls.payment_gateways_confirm_taler_url(payment_id: payment.id),
fulfillment_url = urls.payment_gateways_confirm_taler_url(payment_id: payment.id)
taler_order.create(
amount: taler_amount,
summary: I18n.t("payment_method_taler.order_summary"),
fulfillment_url:,
)
new_order["order_id"]
end
def fetch_order_url(payment)
order = client.fetch_order(payment.response_code)
order["order_status_url"]
end
def client
@client ||= ::Taler::Client.new(preferred_backend_url, preferred_api_key)
def taler_order(id: nil)
@taler_order ||= ::Taler::Order.new(
backend_url: preferred_backend_url,
password: preferred_api_key,
id:,
)
end
end
end

View File

@@ -23,6 +23,7 @@ module Spree
before_destroy :check_completed_orders
scope :admin, -> { where(admin: true) }
scope :confirmed, -> { where.not(confirmed_at: nil) }
has_many :enterprise_roles, dependent: :destroy
has_many :enterprises, through: :enterprise_roles

View File

@@ -1,40 +0,0 @@
# frozen_string_literal: true
class InviteManagerReflex < ApplicationReflex
include ManagerInvitations
def invite
email = params[:email]
enterprise = Enterprise.find(params[:enterprise_id])
authorize! :edit, enterprise
existing_user = Spree::User.find_by(email:)
locals = { error: nil, success: nil, email:, enterprise: }
if existing_user
locals[:error] = I18n.t('admin.enterprises.invite_manager.user_already_exists')
return_morph(locals)
return
end
new_user = create_new_manager(email, enterprise)
if new_user.errors.empty?
locals[:success] = true
else
locals[:error] = new_user.errors.full_messages.to_sentence
end
return_morph(locals)
end
private
def return_morph(locals)
morph "#add_manager_modal",
render(partial: "admin/enterprises/form/add_new_unregistered_manager", locals:)
end
end

View File

@@ -40,7 +40,7 @@ module PermittedAttributes
:hide_ofn_navigation, :white_label_logo, :white_label_logo_link,
:hide_groups_tab, :external_billing_id,
:enable_producers_to_edit_orders,
:remove_logo, :remove_promo_image, :remove_white_label_logo
:remove_logo, :remove_promo_image, :remove_white_label_logo, :contact_id
]
end
end

View File

@@ -1,21 +0,0 @@
%form#add_manager_modal{ 'data-reflex': 'submit->InviteManager#invite', 'data-reflex-serialize-form': true }
.margin-bottom-30.text-center
.text-big
= t('js.admin.modals.invite_title')
- if success
%p.alert-box.ok= t('user_invited', email: email)
- if error
%p.alert-box.error= error
= text_field_tag :email, nil, class: 'fullwidth margin-bottom-20'
= hidden_field_tag :enterprise_id, @enterprise&.id || enterprise.id
.modal-actions
- if success
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->help-modal#close" }
- else
%input{ class: "button icon-plus secondary", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->help-modal#close" }
= submit_tag "#{t('js.admin.modals.invite')}"

View File

@@ -1,75 +1,54 @@
- owner_email = @enterprise&.owner&.email || ""
- full_permissions = (spree_current_user.admin? || spree_current_user == @enterprise&.owner)
.row
.three.columns.alpha
=f.label :owner_id, t('.owner')
- if full_permissions
%span.required *
= render partial: 'admin/shared/whats_this_tooltip', locals: {tooltip_text: t('.owner_tip')}
.eight.columns.omega
- if full_permissions
= f.hidden_field :owner_id, class: "select2 fullwidth", 'user-select' => 'Enterprise.owner', 'ng-model' => 'Enterprise.owner'
- else
= owner_email
= t '.description'
.row
.three.columns.alpha
=f.label :user_ids, t('.notifications')
- if full_permissions
%span.required *
= render partial: 'admin/shared/whats_this_tooltip', locals: {tooltip_text: t('.contact_tip')}
.eight.columns.omega
- if full_permissions
%select.select2.fullwidth{ id: 'receives_notifications_dropdown', name: 'receives_notifications', "ng-model": 'receivesNotifications', "ng-init": "receivesNotifications = '#{@enterprise.contact.id}'" }
%option{ value: '{{user.id}}', "ng-repeat": 'user in Enterprise.users', "ng-selected": "user.id == #{@enterprise.contact.id}", "ng-hide": '!user.confirmed' }
{{user.email}}
- else
= @enterprise.contact.email
- if full_permissions && @enterprise.users.count > 0
- enterprise_role_ids_by_user_id = @enterprise.enterprise_roles.pluck(:user_id, :id).to_h
.row
.three.columns.alpha
=f.label :user_ids, t('.managers')
- if full_permissions
%span.required *
= render partial: 'admin/shared/whats_this_tooltip', locals: {tooltip_text: t('.managers_tip')}
.eight.columns.omega
- if full_permissions
%table.managers
%tr
%table.managers
%thead
%tr
%th= t('.manager')
%th.center
= t('.owner')
= render AdminTooltipComponent.new(text: t('.owner_tip'), link_text: %[<i class="fa fa-question-circle"></i>].html_safe, link: nil)
%th.center
= t('.contact')
= render AdminTooltipComponent.new(text: t('.contact_tip'), link_text: %[<i class="fa fa-question-circle"></i>].html_safe, link: nil)
%tbody
- @enterprise.users.each do |user|
- contact = user.id == @enterprise.contact&.id
- owner = user.id == @enterprise.owner&.id
%tr{ id: "manager-#{user.id}" }
%td
- # Ignore this input in the submit
= hidden_field_tag :ignored, nil, class: "select2 fullwidth", 'user-select' => 'newManager', 'ng-model' => 'newManager'
= user.email
- if user.confirmed?
%i.confirmation.confirmed.fa.fa-check-circle{ "ofn-with-tip": t('.email_confirmed') }
- else
%i.confirmation.unconfirmed.fa.fa-exclamation-triangle{ "ofn-with-tip": t('.email_not_confirmed') }
%td.center
- if user.confirmed?
= f.label :owner_id, t(".set_as_owner", email: user.email), class: "sr-only", value: user.id
= f.radio_button :owner_id, user.id
%td.center
- if user.confirmed?
= f.label :owner_id, t(".set_as_contact", email: user.email), class: "sr-only", value: user.id
= f.radio_button :contact_id, user.id
%td.actions
%tr.animate-repeat{ id: "manager-{{manager.id}}", "ng-repeat": 'manager in Enterprise.users' }
%td
= hidden_field_tag "enterprise[user_ids][]", nil, multiple: true, 'ng-value' => 'manager.id'
{{ manager.email }}
%i.confirmation.confirmed.fa.fa-check-circle{ "ofn-with-tip": t('.email_confirmed'), "ng-show": 'manager.confirmed' }
%i.confirmation.unconfirmed.fa.fa-exclamation-triangle{ "ofn-with-tip": t('.email_not_confirmed'), "ng-show": '!manager.confirmed' }
%i.role.contact.fa.fa-envelope-o{ "ofn-with-tip": t('.contact'), "ng-show": 'manager.id == receivesNotifications' }
%i.role.owner.fa.fa-star{ "ofn-with-tip": t('.owner'), "ng-show": 'manager.id == Enterprise.owner.id' }
%td.actions
%a{ class: "icon-trash no-text", "ng-click": 'removeManager(manager)', "ng-class": "{disabled: manager.id == Enterprise.owner.id || manager.id == receivesNotifications}" }
- if !owner && !contact
= link_to_delete user, no_text: true, url: admin_enterprise_role_path(id: enterprise_role_ids_by_user_id[user.id])
- else
%a{ class: "icon-trash no-text disabled" }
- else
- @enterprise.users.each do |manager|
= manager.email
%br
%a.button{ href: "#{new_admin_enterprise_user_invitation_path(@enterprise)}", data: { turbo_stream: true, turbo: true } }
%i.icon-plus
= t('.invite_manager')
%br
- if full_permissions
%form
.row
.three.columns.alpha
%label
= t('.invite_manager')
= render partial: 'admin/shared/whats_this_tooltip', locals: {tooltip_text: t('.invite_manager_tip')}
.eight.columns.omega
.row
%a.button{ "data-controller": "help-modal-link", "data-action": "click->help-modal-link#open", "data-help-modal-link-target-value": "invite-manager-modal" }
= t('.add_unregistered_user')
-# add to admin footer to avoid nesting invitation form inside enterprise form
- content_for :admin_footer do
= render HelpModalComponent.new(id: "invite-manager-modal", close_button: false) do
= render partial: 'admin/enterprises/form/add_new_unregistered_manager', locals: { error: nil, success: nil }
- else
- @enterprise.users.each do |manager|
= manager.email
%br

View File

@@ -13,6 +13,8 @@
= hidden_field_tag :search_term, @search_term
= hidden_field_tag :producer_id, @producer_id
= hidden_field_tag :category_id, @category_id
- @tags.each do |tag|
= hidden_field_tag 'tags_name_in[]', tag
%table.products{ 'data-column-preferences-target': "table", class: (hide_producer_column?(producer_options) ? 'hide-producer' : '') }
%colgroup

View File

@@ -0,0 +1,5 @@
= turbo_stream.update "remote_modal", ""
= turbo_stream.update "users_panel" do
= render partial: "admin/enterprises/form/users", locals: { f: ActionView::Helpers::FormBuilder.new(:enterprise, @enterprise, self, {}) }
= turbo_stream.append "flashes" do
= render partial: 'admin/shared/flashes', locals: { flashes: flash }

View File

@@ -0,0 +1,17 @@
= turbo_stream.update "remote_modal" do
= render ModalComponent.new id: "#modal_new_user_invitation", instant: true, close_button: false, modal_class: :fit do
= form_with model: @user_invitation, url: admin_enterprise_user_invitations_path(@enterprise), html: { name: "user_invitation", data: { turbo: true } } do |f|
%h2= t ".invite_new_user"
%p= t ".description"
%fieldset.no-border-top.no-border-bottom
.row
= f.label :email, t(:email)
= f.email_field :email, placeholder: t('.eg_email_address'), data: { controller: "select-user" }, inputmode: "email", autocomplete: "off"
= f.error_message_on :email
.modal-actions.justify-end.filter-actions
%input{ class: "secondary relaxed", type: 'button', value: t('.back'), "data-action": "click->modal#close" }
%button.button.primary.relaxed.icon-envelope{ type: "submit" }
= t(".invite")

View File

@@ -6,21 +6,21 @@
%p
= t :brandstory_intro
#brand-story-text.hide-show.slideable
%p
= t :brandstory_part1
%p
= t :brandstory_part2
%p
= t :brandstory_part3
%p
= t :brandstory_part4
%p
%strong
= t :brandstory_part5_strong
%p
= t :brandstory_part6
%a.text-vbig{"slide-toggle" => "#brand-story-text", "ng-click" => "toggleBrandStory()"}
%i.ofn-i_005-caret-down{"ng-hide" => "brandStoryExpanded"}
%i.ofn-i_006-caret-up{ "ng-show" => "brandStoryExpanded"}
%details#brand-story-text
%summary
%i.ofn-i_005-caret-down
%i.ofn-i_006-caret-up
.brand-story-content
%p
= t :brandstory_part1
%p
= t :brandstory_part2
%p
= t :brandstory_part3
%p
= t :brandstory_part4
%p
%strong
= t :brandstory_part5_strong
%p
= t :brandstory_part6

View File

@@ -5,7 +5,7 @@
- content_for :page_alert do
= render "shared/menu/alert"
%div{"ng-controller" => "HomeCtrl"}
%div
= render "home/tagline"
#panes

View File

@@ -1,2 +1,2 @@
= t('spree.payment_mailer.authorization_required.message', order_number: @order.number)
= t(".message", order_number: @order.number)
= link_to spree.edit_admin_order_url(@order), spree.edit_admin_order_url(@order)

View File

@@ -1,2 +1,2 @@
= t('spree.payment_mailer.authorize_payment.instructions', distributor: @payment.order.distributor.name, amount: @payment.display_amount)
= t(".instructions", distributor: @payment.order.distributor.name, amount: @payment.display_amount)
= link_to main_app.authorize_payment_url(@payment), main_app.authorize_payment_url(@payment)

View File

@@ -0,0 +1,2 @@
%p= t(".message", shop: @shop, amount: @amount)
%p= link_to @taler_order_status_url, @taler_order_status_url

View File

@@ -18,5 +18,5 @@
%span{class: "state #{payment.state}"}= t(payment.state, scope: "spree.payment_states", default: payment.state.capitalize)
%td.actions
- payment.actions.each do |action|
= link_to_with_icon "icon-#{action}", Spree.t(action), fire_admin_order_payment_path(@order, payment, e: action),
no_text: true, data: { method: :put, action: action, disable_with: "" }
= link_to "", fire_admin_order_payment_path(@order, payment, e: action),
class: "icon_link icon-#{action} no-text", data: { method: :put, action: action, disable_with: "" }, title: Spree.t(action)

View File

@@ -29,7 +29,7 @@
.sixteen.columns.alpha
.eight.columns.alpha
= f.field_container :variant_unit do
= f.label :variant_unit, t(".units")
= f.label :variant_unit_with_scale, t(".units")
%span.required *
= f.select 'variant_unit', [],
{ include_blank: true },

View File

@@ -14,7 +14,7 @@
= " - OFN #{t(:administration)}"
%link{:href => "https://fonts.googleapis.com/css?family=Open+Sans:400italic,600italic,400,600&subset=latin,cyrillic,greek,vietnamese", :rel => "stylesheet", :type => "text/css"}
= stylesheet_pack_tag 'admin-style-v3', media: "screen, print"
= stylesheet_pack_tag 'admin-style', media: "screen, print"
= render "layouts/bugsnag_js"
- if content_for? :minimal_js

View File

@@ -4,25 +4,21 @@
#new_variant
%table.index.sortable{"data-sortable-link" => update_positions_admin_product_variants_path(@product)}
%table.index
%colgroup
%col{style: "width: 5%"}/
%col{style: "width: 25%"}/
%col{style: "width: 20%"}/
%col{style: "width: 20%"}/
%col{style: "width: 15%"}/
%col{style: "width: 15%"}/
%col{style: "width: 25%"}/
%col{style: "width: 25%"}/
%col{style: "width: 25%"}/
%thead
%tr
%th{colspan: "2"}= t('.options')
%th= t('.price')
%th= t('.sku')
%th= t('.options')
%th{ style: 'text-align: center;' }= t('.price')
%th{ style: 'text-align: center;' }= t('.sku')
%th.actions
%tbody
- @variants.each do |variant|
%tr{id: spree_dom_id(variant), class: cycle('odd', 'even'), style: "#{"color:red;" if variant.deleted? }" }
%td.no-border
%span.handle
%td= variant.full_name
%td.align-center= variant.display_price.to_html
%td.align-center= variant.sku

View File

@@ -60,10 +60,12 @@
= yield :sidebar
= render "admin/terms_of_service_banner" if tos_need_accepting?
%script
= raw "Spree.api_key = \"#{spree_current_user.try(:spree_api_key).to_s}\";"
= render "layouts/matomo_tag"
= yield :admin_footer
#remote_modal

View File

@@ -0,0 +1,44 @@
import { Controller } from "stimulus";
import TomSelect from "tom-select/dist/esm/tom-select.complete";
import showHttpError from "js/services/show_http_error";
export default class extends Controller {
connect() {
this.control = new TomSelect(this.element, {
create: true,
plugins: ["dropdown_input"],
labelField: "email",
load: this.#load.bind(this),
maxItems: 1,
persist: false,
searchField: ["email"],
shouldLoad: (query) => query.length > 2,
valueField: "email",
});
}
disconnect() {
if (this.control) this.control.destroy();
}
// private
#load(query, callback) {
const url = "/admin/search/known_users.json?q=" + encodeURIComponent(query);
fetch(url)
.then((response) => {
if (!response.ok) {
showHttpError(response.status);
throw response;
}
return response.json();
})
.then((json) => {
callback({ items: json });
})
.catch((error) => {
console.log(error);
callback();
});
}
}

View File

@@ -16,13 +16,13 @@
@import "flatpickr/dist/themes/material_blue";
@import "shortcut-buttons-flatpickr/dist/themes/light";
@import "../admin/globals/functions";
@import "globals/functions";
@import "globals/palette"; // admin_v3
@import "globals/variables"; // admin_v3
@import "../admin/globals/mixins";
@import "globals/mixins";
@import "mixins"; // admin_v3
@import "../admin/plugins/font-awesome";
@import "plugins/font-awesome";
@import "../shared/variables/layout";
@import "../shared/variables/variables";
@@ -32,7 +32,7 @@
@import "shared/icons"; // admin_v3
@import "shared/forms"; // admin_v3
@import "shared/layout"; // admin_v3
@import "../admin/shared/scroll_bar";
@import "shared/scroll_bar";
@import "../shared/trix";
@@ -40,96 +40,94 @@
@import "plugins/powertip"; // admin_v3
@import "sections/orders"; // admin_v3
@import "../admin/sections/products";
@import "sections/products";
@import "../admin/hacks/mozilla";
@import "../admin/hacks/opera";
@import "../admin/hacks/ie";
@import "hacks/mozilla";
@import "hacks/opera";
@import "hacks/ie";
@import "components/actions"; // admin_v3
@import "../admin/components/alert-box";
@import "../admin/components/alert_row";
@import "components/alert-box";
@import "components/alert_row";
@import "components/buttons"; // admin_v3
@import "components/date-picker"; // admin_v3
@import "../admin/components/dialogs";
@import "../admin/components/input";
@import "../admin/components/jquery_dialog";
@import "components/dialogs";
@import "components/input";
@import "components/jquery_dialog";
@import "components/messages"; // admin_v3
@import "components/navigation"; // admin_v3
@import "../admin/components/ng-cloak";
@import "../admin/components/page_actions";
@import "components/ng-cloak";
@import "components/page_actions";
@import "components/pagination"; // admin_v3
@import "../admin/components/per_page_controls";
@import "../admin/components/product_autocomplete";
@import "../admin/components/progress";
@import "../admin/components/save_bar";
@import "components/per_page_controls";
@import "components/product_autocomplete";
@import "components/progress";
@import "components/save_bar";
@import "components/sidebar"; // admin_v3
@import "../admin/components/simple_modal";
@import "../admin/components/states";
@import "../admin/components/stripe_connect_button";
@import "../admin/components/subscriptions_states";
@import "../admin/components/table-filter";
@import "../admin/components/table_loading";
@import "../admin/components/timepicker";
@import "../admin/components/todo";
@import "../admin/components/tooltip";
@import "../admin/components/wizard_progress";
@import "components/simple_modal";
@import "components/states";
@import "components/stripe_connect_button";
@import "components/subscriptions_states";
@import "components/table-filter";
@import "components/table_loading";
@import "components/timepicker";
@import "components/todo";
@import "components/tooltip";
@import "components/wizard_progress";
@import "../admin/pages/enterprise_form";
@import "../admin/pages/subscription_form";
@import "../admin/pages/subscription_line_items";
@import "../admin/pages/subscription_review";
@import "pages/enterprise_form";
@import "pages/subscription_form";
@import "pages/subscription_line_items";
@import "pages/subscription_review";
@import "../admin/advanced_settings";
@import "../admin/alert";
@import "../admin/animations";
@import "advanced_settings";
@import "alert";
@import "animations";
@import "pages/change_type_form"; // admin_v3
@import "../admin/connected_apps";
@import "../admin/customers";
@import "connected_apps";
@import "customers";
@import "dashboard/dashboard_item"; // admin_v3
@import "pages/dashboard-single-ent"; // admin_v3
@import "../admin/dialog";
@import "../admin/disabled";
@import "dialog";
@import "disabled";
@import "components/dropdown"; // admin_v3
@import "pages/edit_variant"; // admin_v3
@import "pages/enterprise_index_panels"; // admin_v3
@import "../admin/enterprises";
@import "../admin/filters_and_controls";
@import "../admin/grid";
@import "../admin/icons";
@import "../admin/index_panel_buttons";
@import "../admin/index_panels";
@import "../admin/modals";
@import "../admin/offsets";
@import "../admin/openfoodnetwork";
@import "../admin/order_cycles";
@import "../admin/orders";
@import "enterprises";
@import "filters_and_controls";
@import "grid";
@import "icons";
@import "index_panel_buttons";
@import "index_panels";
@import "modals";
@import "offsets";
@import "openfoodnetwork";
@import "order_cycles";
@import "orders";
@import "pages/product_import"; // admin_v3
@import "../admin/products";
@import "../admin/products_v3";
@import "../admin/question-mark-tooltip";
@import "../admin/relationships";
@import "../admin/reports";
@import "products";
@import "products_v3";
@import "question-mark-tooltip";
@import "relationships";
@import "reports";
@import "components/select2"; // admin_v3
@import "components/sidebar-item"; // admin_v3
@import "../admin/side_menu";
@import "../admin/tables";
@import "../admin/tag_rules";
@import "../admin/terms_of_service_files";
@import "../admin/validation";
@import "../admin/variant_overrides";
@import "../admin/welcome";
@import "side_menu";
@import "tables";
@import "tag_rules";
@import "terms_of_service_files";
@import "validation";
@import "variant_overrides";
@import "welcome";
@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 "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 "trix";
@import "terms_of_service_banner"; // admin_v3

View File

@@ -1,110 +0,0 @@
#change_type {
section {
margin: 2em 0 0 0;
&,
& * {
color: $spree-blue;
}
}
.description {
background-color: $spree-light-blue;
margin-top: -2em;
padding: 4em 2em 2em 1em;
@media all and (max-width: 786px) {
margin-bottom: 2em;
}
}
.admin-cta {
border: 1px solid $spree-blue;
@include border-radius(3px);
text-align: center;
padding: 1em;
}
.error {
display: block;
color: #f57e80;
border: 1px solid #f57e80;
background-color: #fde6e7;
@include border-radius(3px);
margin-bottom: 1em;
padding: 0.5em;
}
a.selector {
position: relative;
border: 2px solid black;
text-align: center;
width: 100%;
cursor: pointer;
&,
& * {
color: white;
}
&:after,
&:before {
top: 100%;
left: 50%;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
}
&:after {
border-color: rgba(136, 183, 213, 0);
border-top-color: $spree-blue;
border-width: 12px;
margin-left: -12px;
}
&:hover {
&:after {
border-top-color: $spree-green;
}
}
&:before {
border-color: rgba(84, 152, 218, 0);
border-top-color: black;
border-width: 15px;
margin-left: -15px;
}
.bottom {
background: repeating-linear-gradient(
60deg,
rgba(84, 152, 218, 0),
rgba(84, 152, 218, 0) 5px,
rgba(255, 255, 255, 0.25) 5px,
rgba(255, 255, 255, 0.25) 10px
);
margin-top: 1em;
margin-left: -15px;
margin-right: -15px;
padding: 5px;
text-transform: uppercase;
}
&.selected {
background-color: black;
&:after,
&:hover &:after {
border-top-color: black;
}
}
}
}

View File

@@ -1,21 +0,0 @@
.dashboard_item.single-ent {
.header {
padding: 0.77778em 1.33333em 0.77778em 0.77778em;
height: auto !important;
}
.list {
.button.bottom {
width: 100%;
}
}
}
.button.big {
width: 100%;
font-size: 1rem;
@include border-radius(25px);
padding: 15px;
}

View File

@@ -1,244 +0,0 @@
div.dashboard_item {
margin-bottom: 30px;
.centered {
text-align: center;
}
.text-icon {
margin-top: 8px;
display: block;
font-size: 16px;
font-weight: bold;
color: #fff;
padding: 0px 6px;
border-radius: 10px;
&.green {
background-color: $spree-green;
}
&.warning {
background-color: $color-warning;
}
&.orange {
background-color: $color-warning;
}
}
div.header {
height: 50px;
border-radius: 6px 6px 0px 0px;
border: 1px solid $spree-blue;
position: relative;
a[ofn-with-tip] {
position: absolute;
right: 5px;
bottom: 5px;
}
&.warning {
border-color: $color-warning;
border-width: 3px;
h3 {
color: $color-warning;
}
}
&.orange {
border-color: $color-warning;
border-width: 3px;
h3 {
color: $color-warning;
}
}
h3.alpha {
height: 100%;
padding: 10px 5px 0px 3%;
}
a {
border-radius: 0px 4px 0px 0px;
height: 100%;
padding: 15px 2px 0px 2px;
}
}
.tabs {
height: 30px;
border: solid $spree-blue;
border-width: 0px 0px 1px 0px;
margin-top: 3px;
div.dashboard_tab {
cursor: pointer;
height: 30px;
color: #fff;
background-color: $spree-blue;
padding: 5px 5px 0px 5px;
text-align: center;
font-weight: bold;
border: solid $spree-blue;
border-width: 1px 1px 0px 1px;
&:hover {
background-color: $spree-green;
}
&.selected {
color: $spree-blue;
background-color: #fff;
}
}
}
.list {
max-height: 250px;
overflow-y: auto;
overflow-x: hidden;
&:focus {
outline: none;
}
}
.list-title {
border: solid $spree-blue;
border-width: 0px 1px 0px 1px;
span {
font-size: 105%;
padding: 10px 0px;
font-weight: bold;
}
span.alpha {
padding: 10px 2px 10px 5%;
}
}
.list-item {
border: solid $spree-blue;
border-width: 0px 1px 0px 1px;
height: 41px;
span.alpha {
font-weight: bold;
margin-left: -3px;
padding: 10px 2px 0px 5%;
}
span.omega {
padding-right: 13px;
margin-right: -3px;
text-align: right;
}
.icon-arrow-right {
padding-top: 6px;
font-size: 20px;
}
.icon-warning-sign {
color: $color-warning;
font-size: 30px;
}
.icon-remove-sign {
color: $color-warning;
font-size: 30px;
}
.icon-ok-sign {
color: $spree-green;
font-size: 30px;
}
&.orange {
color: $color-warning;
border: solid $color-warning;
}
&.warning {
color: $color-warning;
border: solid $color-warning;
}
&.orange,
&.warning {
border-width: 0px 3px 0px 3px;
}
&.even {
background-color: #fff;
}
&.odd {
background-color: $spree-light-blue;
}
&.even,
&.odd {
&:hover {
color: #ffffff;
background-color: $spree-green;
.icon-arrow-right {
color: #fff;
}
.icon-remove-sign {
color: #fff;
}
.icon-warning-sign {
color: #fff;
}
.icon-ok-sign {
color: #fff;
}
.text-icon {
&.green {
color: $spree-green;
background-color: #fff;
}
}
}
}
}
a.button {
color: #fff;
font-size: 110%;
font-weight: bold;
text-align: center;
&.orange {
background-color: $color-warning;
}
&.blue {
background-color: $spree-blue;
}
&.warning {
background-color: $color-warning;
}
&:hover {
background-color: $spree-green;
}
&.bottom {
border-radius: 0px 0px 6px 6px;
padding: 15px 15px;
}
}
}

View File

@@ -1,271 +0,0 @@
#content-header .ofn-drop-down {
border: none;
background-color: $spree-blue;
color: #fff;
float: none;
margin-left: 3px;
}
.ofn-drop-down {
.dropdown-content {
display: none;
}
.toggle-off {
display: none;
}
&:active:not(.disabled),
&:focus:not(.disabled) {
.dropdown-content {
display: inline-block;
}
}
}
.ofn-drop-down:hover,
.ofn-drop-down.expanded {
border: 1px solid #adadad;
color: #575757;
}
@mixin ofn-drop-down-style {
padding: 7px 15px;
border-radius: 3px;
border: 1px solid #d4d4d4;
background-color: #f5f5f5;
display: block;
color: #828282;
cursor: pointer;
-moz-user-select: none;
-khtml-user-select: none;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
text-align: center;
margin-right: 10px;
&.disabled {
opacity: 0.5;
pointer-events: none;
&:hover {
cursor: default;
border-color: #d4d4d4;
color: #828282;
}
}
}
.ofn-drop-down-with-prepend {
display: flex;
&.right {
float: right;
}
.ofn-drop-down {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.ofn-drop-down-prepend {
@include ofn-drop-down-style;
border-right: none;
margin-left: 0;
margin-right: 0;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
cursor: default;
}
}
.ofn-drop-down {
@include ofn-drop-down-style;
position: relative;
float: left;
&.right {
float: right;
margin-right: 0px;
margin-left: 10px;
}
&:hover,
&.expanded {
border: 1px solid #adadad;
color: #575757;
}
> span {
width: auto;
text-transform: uppercase;
font-size: 85%;
font-weight: 600;
}
.menu {
margin-top: 1px;
position: absolute;
float: none;
top: 100%;
left: 0px;
padding: 5px 0px;
border: 1px solid #adadad;
background-color: #ffffff;
box-shadow: 1px 3px 10px #888888;
z-index: 100;
white-space: nowrap;
.filter {
padding-left: 5px;
padding-right: 5px;
position: relative;
> input[type="text"] {
border: 1px solid rgba(18, 18, 18, 0.1);
width: 100%;
padding-left: 30px;
padding-top: 10px;
padding-bottom: 10px;
font-size: 13px;
color: #454545;
}
&:after {
content: "\f002";
font-family: FontAwesome;
position: absolute;
left: 15px;
top: 13px;
color: #454545;
}
}
.menu_item {
margin: 0px;
padding: 2px 10px;
color: #454545;
text-align: left;
display: block;
.check {
display: inline-block;
text-align: center;
width: 40px;
&:before {
content: "\00a0";
}
}
.name {
display: inline-block;
padding: 0px 15px 0px 0px;
}
&.selected {
.check:before {
content: "\2713";
}
}
&.hidden {
display: none;
}
}
.menu_item:hover {
background-color: #ededed;
}
}
> details {
// Override padding on ofn-drop-down-style
margin: -7px -15px;
padding: 7px 15px;
}
> details > summary {
display: inline-block;
list-style: none;
width: auto;
text-transform: uppercase;
font-size: 85%;
font-weight: 600;
// Override padding on ofn-drop-down-style to increase clickable area
margin: -8px -15px;
padding: 8px 15px;
}
> details > summary:after {
content: "\f0d7";
font-family: FontAwesome;
}
> details[open] > summary:after {
content: "\f0d8";
font-family: FontAwesome;
}
}
.ofn-drop-down-v2 {
border: 1px solid $pale-blue;
background-color: white;
padding: 0px;
&:hover {
border-color: $spree-blue;
}
.ofn-drop-down-label {
color: $color-3;
padding: 10px;
width: 235px;
display: flex;
justify-content: space-between;
&:hover {
color: $color-3;
}
.label {
padding-right: 10px;
}
.icon-caret-down,
.icon-caret-up {
padding-right: 0px;
}
}
.menu {
width: 100%;
}
.menu_items {
max-height: 200px;
overflow-y: scroll;
.menu_item {
margin-bottom: 5px;
color: #454545;
font-weight: 400;
cursor: pointer;
padding-top: 4px;
padding-bottom: 5px;
text-transform: uppercase;
font-size: 85%;
}
}
}
.ofn-drop-down.ofn-drop-down-v2 {
// Add very specific styling here for components that are in transition:
// ie. the ones using the two classes above
.ofn-drop-down-label {
padding-top: 7px;
padding-bottom: 7px;
}
}

View File

@@ -1,120 +0,0 @@
.enterprise_package_panel,
.enterprise_producer_panel {
.info {
p {
font-size: 1rem;
margin: 10px 0px;
}
}
a.selector {
display: block;
position: relative;
margin-bottom: 20px;
border: 2px solid black;
text-align: center;
// width: 100%;
cursor: pointer;
&,
& * {
color: white;
}
&:hover {
&:after {
border-top-color: $spree-green;
}
}
&.disabled {
background-color: #c1c1c1;
}
.bottom {
background: repeating-linear-gradient(
60deg,
rgba(84, 152, 218, 0),
rgba(84, 152, 218, 0) 5px,
rgba(255, 255, 255, 0.25) 5px,
rgba(255, 255, 255, 0.25) 10px
);
margin-top: 1em;
margin-left: -15px;
margin-right: -15px;
padding: 5px;
text-transform: uppercase;
}
&.selected {
background-color: #000000;
&:after {
top: 50%;
left: 0;
border: solid transparent;
content: " ";
height: 0;
width: 0;
position: absolute;
pointer-events: none;
border-top: 20px solid transparent;
border-bottom: 20px solid transparent;
border-right: 20px solid #000000;
margin-top: -20px;
margin-left: -20px;
}
}
}
}
.enterprise_status_panel {
.status-ok {
margin: 30px 0px;
i.icon-ok-sign {
color: $spree-green;
font-size: 1.5rem;
}
}
td.description {
font-size: 0.9rem;
}
td.severity {
text-align: center;
i {
font-size: 1.5rem;
&.issue {
color: $color-warning;
}
&.warning {
color: #ff9848;
}
}
}
}
tags-input .tags li.tag-item {
-webkit-border-radius: 3px;
-moz-border-radius: 3px;
-ms-border-radius: 3px;
-o-border-radius: 3px;
border-radius: 3px;
margin: 2px 0 2px 3px;
background-image: none;
background-color: #5fa5e8;
border: none;
box-shadow: none;
color: white !important;
font-size: 85%;
height: 25px;
}
tags-input .tags .tag-item .remove-button {
color: white;
}
table th.actions .no-text[class*="icon-"],
table td.actions .no-text[class*="icon-"] {
cursor: pointer;
}

View File

@@ -4,8 +4,17 @@ form[name="enterprise_form"] {
}
table.managers {
th {
div[data-controller="tooltip"] {
display: inline-block;
}
}
.center {
text-align: center;
}
i.role {
float: right;
margin-left: 0.5em;
font-size: 1.5em;
cursor: pointer;

View File

@@ -1,20 +1,38 @@
// Basic color palette for admin
$spree-green: #9fc820;
$spree-blue: #5498da;
// Basic color palette for admin styles v3
$white: #ffffff !default; // White
$green: #9fc820 !default; // Green
$teal: #008397 !default; // Teal (Allports)
$orient: #006878 !default; // Orient (Cerulean)
$dark-blue: #004e5b !default; // Dark Blue (Sherpa)
$pale-blue: #cee1f4; // Pale blue
$red: #c85136 !default; // Red/Orange (Mojo)
$bright-orange: #ffa92e; // Bright orange
$yellow: #ff9300 !default; // Yellow
$mystic: #d9e8eb !default; // Mystic
$lighter-grey: #f8f9fa !default; // Lighter grey
$light-grey: #eff1f2 !default; // Light grey (Porcelain)
$medium-light-grey: #babdbe !default; // Silver Sand
$medium-grey: #919191 !default; // Medium grey
$dark-grey: #2e3132 !default; // Dark Grey
$near-black: #191c1d !default; // Near-black (Shark)
$fair-pink: #ffefeb !default; // Fair Pink
$roof-terracotta: #b83b1f !default; // Roof Terracotta
// Old colour variables for backwards compatibility
$spree-green: $green;
$spree-blue: $teal;
$spree-light-blue: #eff5fc;
$pale-blue: #cee1f4;
$bright-orange: #ffa92e;
$medium-grey: #919191;
$light-grey: #ccc;
$color-1: #ffffff !default; // White
$color-2: $spree-green !default; // Green
$color-3: $spree-blue !default; // Light Blue
$color-4: #6788a2 !default; // Dark Blue
$color-5: #c60f13 !default; // Red
$color-6: #ff9300 !default; // Yellow
$color-14: #f8f9fa !default; // Lighter grey
$dark-grey: #333;
$light-grey: #ddd;
$near-black: #222;
$color-1: $white;
$color-2: $green;
$color-3: $teal;
$color-4: $dark-blue;
$color-5: $red;
$color-6: $yellow;
$color-7: $light-grey;
$color-8: $near-black;
$color-9: $dark-grey;
$color-10: $orient;
$color-11: $mystic;
$color-12: $fair-pink;
$color-13: $roof-terracotta;
$color-14: $lighter-grey;

View File

@@ -1,189 +0,0 @@
.select2-container {
&:hover .select2-choice,
&.select2-container-active .select2-choice {
background-color: $color-sel-hover-bg !important;
border-color: $color-sel-hover-bg !important;
}
.select2-choice {
background-image: none !important;
background-color: $color-sel-bg;
border: none !important;
box-shadow: none !important;
@include border-radius($border-radius);
color: $color-1 !important;
font-size: 90%;
height: 31px;
line-height: inherit !important;
padding: 5px 15px 7px;
span {
display: block;
padding: 2px;
}
.select2-search-choice-close {
background-image: none !important;
font-size: 100% !important;
@extend .icon-remove;
@extend [class^="icon-"], :before;
margin-top: 2px;
}
}
&.select2-container-active {
.select2-choice {
box-shadow: none !important;
}
&.select2-dropdown-open .select2-choice div b {
@extend .icon-caret-up;
}
}
}
.select2-drop {
border-color: $color-sel-hover-bg;
box-shadow: none !important;
z-index: 1000000;
&.select2-drop-above {
border-color: $color-sel-hover-bg;
}
}
.select2-search {
@extend .icon-search;
font-size: 100%;
color: darken($color-border, 15);
padding: 0 9px 0 0;
&:before {
@extend [class^="icon-"], :before;
position: absolute;
top: 13px;
left: 13px;
}
input {
@extend input, [type="text"];
padding: 6px 0 6px 25px;
margin: 5px 0 0 5px;
font-family: $base-font-family;
font-size: 90%;
box-shadow: none;
background-image: none;
}
}
.select2-container .select2-choice .select2-arrow {
background-image: none;
background: transparent;
border: 0;
b {
padding-top: 7px;
display: block;
width: 100%;
height: 100%;
background: none;
font-family: FontAwesome;
font-weight: 200 !important;
&:before {
content: "\f0d7";
}
}
}
.select2-results {
padding-left: 0 !important;
li {
font-size: 85% !important;
&.select2-highlighted {
.select2-result-label {
&,
h6 {
color: $color-1 !important;
}
}
}
.select2-result-label {
color: $color-body-text;
min-height: 22px;
clear: both;
overflow: auto;
}
&.select2-no-results,
&.select2-searching {
padding: 5px;
background-color: transparent;
color: $color-body-text;
text-align: center;
font-weight: $font-weight-bold;
text-transform: uppercase;
}
}
.select2-highlighted {
background-color: $color-sel-bg;
}
}
.select2-container-multi {
&.select2-container-active,
&.select2-dropdown-open {
.select2-choices {
border-color: $color-sel-hover-bg !important;
box-shadow: none;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}
}
.select2-choices {
@extend input, [type="text"];
padding: 6px 3px 3px 3px;
box-shadow: none;
background-image: none !important;
.select2-search-choice {
@include border-radius($border-radius);
margin: 0 0 3px 3px;
background-image: none;
background-color: $color-sel-bg;
border: none;
box-shadow: none;
color: $color-1 !important;
font-size: 85%;
&:hover {
background-color: $color-sel-hover-bg;
}
.select2-search-choice-close {
background-image: none !important;
font-size: 85% !important;
@extend .icon-remove;
@extend [class^="icon-"], :before;
margin-left: 2px;
color: $color-1;
}
}
}
}
label .select2-container {
margin-top: -6px;
.select2-choice {
span {
text-transform: none;
font-weight: normal;
}
}
}

View File

@@ -1,299 +0,0 @@
$pi-red: $color-warning;
$pi-green: lighten($spree-green, 10%);
$pi-orange: $bright-orange;
$pi-blue: lighten($spree-blue, 10%);
$pi-light-yellow: #faffaf;
// scss-lint:disable NestingDepth
div.panel-section {
.error {
color: $pi-red;
}
.warning {
color: $bright-orange;
}
.success {
color: $pi-green;
}
.info {
color: #68b7c0;
}
div.panel-header {
width: 100%;
clear: both;
float: left;
padding: 0.5em;
div {
font-size: 1.25em;
float: left;
}
div.header-caret {
width: 2em;
text-align: center;
min-height: 0.1em; //Empty div fix
}
div.header-icon {
width: 2.5em;
text-align: center;
padding-top: 0.18em;
i {
font-size: 1.5em;
line-height: 0.9em;
}
}
div.header-count {
min-width: 2em;
text-align: right;
padding-right: 0.5em;
}
div.header-description {
width: auto;
}
}
div.panel-header:hover {
cursor: pointer;
background-color: #f7f7f7;
}
div.panel-header.active {
background-color: #efefef;
text-shadow: 1px 1px 0px rgba(255, 255, 255, 0.75);
}
div.panel-content {
width: 100%;
clear: both;
margin-bottom: 0.5em;
background-color: #f9f9f9;
padding: 1.5em;
div.table-wrap {
width: 100%;
overflow: auto;
border-right: 1px solid #ceede3;
max-height: 23em;
}
table {
background-color: white;
margin-bottom: 0;
td,
th {
white-space: nowrap;
}
tr {
&.error {
color: #c84c4c;
}
&:hover td.invalid {
background-color: darken(#f05c51, 5%);
}
i {
display: block;
margin-bottom: -0.2em;
font-size: 1.4em !important;
}
}
td {
&.invalid {
background-color: #f05c51;
box-shadow: inset 0px 0px 1px red;
color: white;
}
}
}
div.import-errors {
margin-bottom: 0.85em;
p.line {
font-size: 1.15em;
margin-bottom: 0.2em;
color: #577084;
}
p.error {
color: #cb1b1b;
margin-bottom: 0.2em;
}
}
}
}
br.panels.clearfix {
clear: both;
}
.panel-section.import-settings {
.header-description {
padding-left: 1em;
}
span.header-error {
font-size: 0.85em;
color: $pi-red;
}
.select2-search {
display: none;
}
.select2-results {
margin: 0;
}
}
.post-save-results {
p {
font-size: 1.25em;
margin-bottom: 0.5em;
strong {
margin-right: 0.2em;
min-width: 1.8em;
display: inline-block;
text-align: right;
}
i {
font-size: 1.4em;
vertical-align: middle;
position: relative;
}
i.fa-check-circle {
color: $pi-green;
}
i.fa-info-circle {
color: $pi-blue;
}
}
p.save-error {
color: #ee4728;
font-size: 1.05em;
margin-top: 0.4em;
}
}
form.product-import,
div.post-save-results,
div.import-wrapper {
input[type="submit"] {
margin-right: 0.5em;
}
input[type="submit"],
button,
a.button {
min-width: 8em;
text-align: center;
}
}
div.import-wrapper {
.alert-box {
margin: 0 0 1.75em;
}
.ng-hide:not(.ng-hide-animate) {
// We have to use !important here to override angular's display properties
// scss-lint:disable ImportantRule
display: block !important;
position: absolute;
opacity: 0;
top: -9999px;
left: -9999px;
}
.ng-hide-add,
.ng-hide-remove,
.ng-hide-animate {
transition: all 0.4s ease-in-out;
}
form.product-import,
div.save-results {
transition: all 0.4s ease-in-out;
}
div.progress-interface {
text-align: center;
transition: all 0.4s ease-in-out;
button:disabled {
background: #ccc !important;
}
}
.post-save-results {
a.button {
float: left;
margin-right: 0.5em;
}
}
}
div.progress-bar {
height: 25px;
width: 30em;
max-width: 90%;
margin: 1em auto;
background: #f7f7f7;
padding: 3px;
border-radius: 0.3em;
border: 1px solid #eee;
span.progress-track {
display: block;
background: lighten($pi-green, 10%);
height: 100%;
border-radius: 0.3em;
box-shadow: inset 0 0 3px rgba(0, 0, 0, 0.3);
transition: width 0.3s ease-in-out;
}
}
#upload-sidebar {
float: right;
background-color: lighten($spree-light-blue, 2.5%);
border: 1px solid lighten($pale-blue, 2.5%);
width: 50%;
padding: 0 1.5em 1.5em;
h4,
h5,
h6,
p {
margin: 1.25em 0 1em;
}
a.download {
display: block;
font-size: 1.05em;
margin-bottom: 0.5em;
i {
margin-right: 0.25em;
}
}
span.category {
display: inline-block;
background-color: $pi-blue;
color: white;
padding: 0.3em 0.6em;
margin: 0 0.4em 0.5em 0;
}
}

View File

@@ -1,6 +1,6 @@
// Customisations for the new Bulk Edit Products page only
// Scoped to containing div, because Turbo messes with body classes
@import "../admin_v3/pages/unit_popout";
@import "pages/unit_popout";
#products_v3_page {
#content > .row:first-child > .container:first-child {
@@ -59,6 +59,7 @@
overflow: visible;
background-color: white;
}
.form-actions-wrapper2 {
position: relative;
// Stretch to cover table side borders
@@ -157,6 +158,7 @@
tr:first-child td {
border-top: 4px solid $color-tbl-bg;
}
tr:last-child td {
border-bottom: 1px solid $color-tbl-cell-shadow;
}
@@ -187,6 +189,7 @@
$columns:
"image", "name", "sku", "unit_scale", "unit", "price", "on_hand", "producer", "category",
"tax_category", "tags", "inherits_properties";
@each $col in $columns {
&.hide-#{$col} {
.col-#{$col} {
@@ -237,6 +240,7 @@
align-items: center;
gap: 10px;
}
.per-page {
width: 9em;
}
@@ -286,6 +290,7 @@
.search-button {
position: relative;
> input {
padding-left: 30px;
}
@@ -295,6 +300,7 @@
// Blurred and non-clickable
$disabled-blur: 1.5px;
.disabled-section {
position: relative;
@@ -346,6 +352,7 @@
from {
transform: scaleY(1);
}
to {
transform: scaleY(0);
}
@@ -360,6 +367,7 @@
from {
transform: scaleY(0);
}
to {
transform: scaleY(1);
}

View File

@@ -1,63 +0,0 @@
.select2-container {
.select2-choice {
.select2-search-choice-close {
display: none !important;
}
.select2-arrow {
width: 22px;
border: none;
background-image: none;
background-color: transparent;
}
}
&.light {
.select2-choice {
background-color: #ffffff;
font-weight: normal;
color: $spree-blue !important;
border: 1px solid $color-border !important;
}
&:hover,
&.select2-container-active {
.select2-choice {
background-color: #ffffff !important;
border: 1px solid $spree-green !important;
.select2-arrow {
&:before {
color: $spree-blue;
}
}
}
}
}
&.select2-container-multi {
.select2-search-field {
max-height: 20px;
input {
padding: 0 !important;
margin: 0 0 0 5px !important;
}
}
.select2-search-choice {
display: flex;
align-items: center;
justify-content: center;
padding-left: 7px;
.select2-search-choice-close {
position: relative;
order: -1;
width: auto;
left: 0;
top: 0;
margin: 0;
padding: 0;
font-size: 100% !important;
}
}
}
}

View File

@@ -68,6 +68,18 @@
display: none;
}
// Only display for screen readers
.sr-only {
clip: rect(1px, 1px, 1px, 1px);
clip-path: inset(50%);
height: 1px;
width: 1px;
margin: -1px;
overflow: hidden;
padding: 0;
position: absolute;
}
.float-right {
float: right;
}

View File

@@ -1,124 +0,0 @@
div.sidebar_item {
margin-bottom: 30px;
.centered {
text-align: center;
}
div.header {
font-size: 105%;
color: #fff;
padding: 10px 0px;
position: relative;
&.blue {
background-color: $spree-blue;
}
&.red {
background-color: $color-warning;
}
}
.list {
max-height: 400px;
overflow-y: auto;
overflow-x: hidden;
&.red {
color: $color-warning;
.list-item {
border: solid $color-warning;
border-width: 0px 3px 0px 3px;
a.alpha,
span.alpha {
margin-left: -3px;
}
&.odd {
background-color: #fcf6ef;
&:hover {
background-color: $spree-green;
}
}
}
a {
color: $color-warning;
}
}
}
.list-item {
.icon-arrow-right {
padding-top: 6px;
font-size: 20px;
}
border: solid $spree-blue;
border-width: 0px 1px 0px 1px;
a.alpha,
span.alpha {
font-weight: bold;
margin-left: -1px;
padding: 10px 2px 10px 5%;
overflow: hidden;
text-overflow: ellipsis;
}
span.omega {
padding: 8px 18px 8px 0px;
margin-right: -3px;
text-align: right;
}
.icon-remove-sign {
color: $color-warning;
font-size: 18px;
}
&.even {
background-color: #fff;
}
&.odd {
background-color: $spree-light-blue;
}
&.even,
&.odd {
&:hover {
color: #ffffff;
background-color: $spree-green;
a {
color: #ffffff;
}
}
}
}
a.button {
color: #fff;
padding: 15px 15px;
font-weight: bold;
text-align: center;
border-radius: 0px;
&.blue {
background-color: $spree-blue;
}
&.red {
background-color: $color-warning;
}
&:hover {
background-color: $spree-green;
}
}
}

View File

@@ -1,38 +0,0 @@
// Basic color palette for admin styles v3
$white: #ffffff !default; // White
$green: #9fc820 !default; // Green
$teal: #008397 !default; // Teal (Allports)
$orient: #006878 !default; // Orient (Cerulean)
$dark-blue: #004e5b !default; // Dark Blue (Sherpa)
$pale-blue: #cee1f4; // Pale blue
$red: #c85136 !default; // Red/Orange (Mojo)
$bright-orange: #ffa92e; // Bright orange
$yellow: #ff9300 !default; // Yellow
$mystic: #d9e8eb !default; // Mystic
$lighter-grey: #f8f9fa !default; // Lighter grey
$light-grey: #eff1f2 !default; // Light grey (Porcelain)
$medium-light-grey: #babdbe !default; // Silver Sand
$medium-grey: #919191 !default; // Medium grey
$dark-grey: #2e3132 !default; // Dark Grey
$near-black: #191c1d !default; // Near-black (Shark)
$fair-pink: #ffefeb !default; // Fair Pink
$roof-terracotta: #b83b1f !default; // Roof Terracotta
// Old colour variables for backwards compatibility
$spree-green: $green;
$spree-blue: $teal;
$spree-light-blue: #eff5fc;
$color-1: $white;
$color-2: $green;
$color-3: $teal;
$color-4: $dark-blue;
$color-5: $red;
$color-6: $yellow;
$color-7: $light-grey;
$color-8: $near-black;
$color-9: $dark-grey;
$color-10: $orient;
$color-11: $mystic;
$color-12: $fair-pink;
$color-13: $roof-terracotta;
$color-14: $lighter-grey;

View File

@@ -71,8 +71,50 @@
}
}
a.text-vbig i {
font-size: 75px;
#brand-story-text {
text-align: center;
margin-top: 1rem;
summary {
list-style: none;
cursor: pointer;
display: inline-block;
&::-webkit-details-marker {
display: none;
}
&::marker {
display: none;
}
i {
font-size: 75px;
}
.ofn-i_005-caret-down {
display: inline-block;
}
.ofn-i_006-caret-up {
display: none;
}
}
&[open] summary {
.ofn-i_005-caret-down {
display: none;
}
.ofn-i_006-caret-up {
display: inline-block;
}
}
.brand-story-content {
margin-top: 1rem;
text-align: left;
}
}
}

View File

@@ -1,5 +0,0 @@
@import "../css/admin_v3/all.scss";
@import "../css/admin_v3/components/spinner.scss";
@import "../../../node_modules/trix/dist/trix.css";

View File

@@ -0,0 +1,5 @@
@import "../css/admin/all.scss";
@import "../css/admin/components/spinner.scss";
@import "../../../node_modules/trix/dist/trix.css";

View File

@@ -74,8 +74,6 @@ Rails.application.configure do
allowed_warnings = [
# List strings here to allow matching deprecations.
#
"Passing the class as positional argument",
# Spree::CreditCard model aliases `cc_type` and has a method called `cc_type=` defined. Starting in Rails 7.2 `brand=` will not be calling `cc_type=` anymore. You may want to additionally define `brand=` to preserve the current behavior.
"model aliases",

View File

@@ -273,6 +273,13 @@ ar:
join_community: "انظم إلى المجتمع"
invite_manager:
subject: "تلقيت دعوة من %{enterprise} لتصبح مديرًا"
payment_mailer:
authorize_payment:
subject: "يرجى تفويض الدفع الخاص بك إلى %{distributor} على OFN"
instructions: "يتطلب الدفع الخاص بك من %{amount} إلى %{distributor} مصادقة إضافية. الرجاء زيارة URL التالي لتفويض الدفع الخاص بك:"
authorization_required:
subject: "يتطلب الدفع إذنًا من العميل"
message: "يتطلب الدفع للطلب %{order_number} تفويضًا إضافيًا من العميل. تم إخطار العميل عبر البريد الإلكتروني وسيظهر الدفع على أنه معلق حتى يتم التصريح به."
producer_mailer:
order_cycle:
subject: "تقرير دورة الطلبية لـ %{producer}"
@@ -4289,13 +4296,6 @@ ar:
subject: "تعليمات إعادة تعيين كلمة المرور"
confirmation_instructions:
subject: "يرجى تأكيد حسابك OFN"
payment_mailer:
authorize_payment:
subject: "يرجى تفويض الدفع الخاص بك إلى %{distributor} على OFN"
instructions: "يتطلب الدفع الخاص بك من %{amount} إلى %{distributor} مصادقة إضافية. الرجاء زيارة URL التالي لتفويض الدفع الخاص بك:"
authorization_required:
subject: "يتطلب الدفع إذنًا من العميل"
message: "يتطلب الدفع للطلب %{order_number} تفويضًا إضافيًا من العميل. تم إخطار العميل عبر البريد الإلكتروني وسيظهر الدفع على أنه معلق حتى يتم التصريح به."
shipment_mailer:
shipped_email:
dear_customer: "عزيزي العميل،"

View File

@@ -283,6 +283,13 @@ ca:
join_community: "Uneix-te a la comunitat"
invite_manager:
subject: "%{enterprise} t'ha convidat a ser administrador"
payment_mailer:
authorize_payment:
subject: "Autoritzeu el vostre pagament a %{distributor} a OFN"
instructions: "El vostre pagament de %{amount} a %{distributor} requereix una autenticació addicional. Visiteu lURL següent per autoritzar el vostre pagament:"
authorization_required:
subject: "Un pagament requereix lautorització del client"
message: "El pagament de la comanda %{order_number} requereix una autorització addicional del client. El client ha rebut una notificació per correu electrònic i el pagament apareixerà pendent fins que no sautoritzi."
producer_mailer:
order_cycle:
subject: "Informe del cicle de comanda per %{producer}"
@@ -4170,13 +4177,6 @@ ca:
subject: "Instruccions per restablir la contrasenya"
confirmation_instructions:
subject: "Si us plau confirma el teu compte d'OFN"
payment_mailer:
authorize_payment:
subject: "Autoritzeu el vostre pagament a %{distributor} a OFN"
instructions: "El vostre pagament de %{amount} a %{distributor} requereix una autenticació addicional. Visiteu lURL següent per autoritzar el vostre pagament:"
authorization_required:
subject: "Un pagament requereix lautorització del client"
message: "El pagament de la comanda %{order_number} requereix una autorització addicional del client. El client ha rebut una notificació per correu electrònic i el pagament apareixerà pendent fins que no sautoritzi."
shipment_mailer:
shipped_email:
dear_customer: "Benvolguda consumidora:"

View File

@@ -348,6 +348,13 @@ cy:
join_community: "Ymunwch â'r gymuned"
invite_manager:
subject: "mae %{enterprise} wedi eich gwahodd i fod yn rheolwr"
payment_mailer:
authorize_payment:
subject: "Gofynnir ichi awdurdodi eich taliad i %{distributor} ar y Open Food Network"
instructions: "Mae angen dilysu ychwanegol ar gyfer eich taliad o %{amount} i %{distributor} . Dilynwch yr URL canlynol i awdurdodi eich taliad."
authorization_required:
subject: "Mae angen i gwsmer awdurdodi taliad."
message: "Mae angen awdurdod ychwanegol gan y cwsmer i dalu am archeb %{order_number} Hysbyswyd y cwsmer trwy ebost a bydd y taliad yn ymddangos fel taliad yn yr arfaeth nes ei awdurdodi."
producer_mailer:
order_cycle:
subject: "Adroddiad cylch archebu ar gyfer %{producer}"
@@ -4669,13 +4676,6 @@ cy:
subject: "Cyfarwyddiadau ailosod cyfrinair"
confirmation_instructions:
subject: "Gofynnir ichi gadarnhau eich cyfrif y Open Food Network os gwelwch yn dda"
payment_mailer:
authorize_payment:
subject: "Gofynnir ichi awdurdodi eich taliad i %{distributor} ar y Open Food Network"
instructions: "Mae angen dilysu ychwanegol ar gyfer eich taliad o %{amount} i %{distributor} . Dilynwch yr URL canlynol i awdurdodi eich taliad."
authorization_required:
subject: "Mae angen i gwsmer awdurdodi taliad."
message: "Mae angen awdurdod ychwanegol gan y cwsmer i dalu am archeb %{order_number} Hysbyswyd y cwsmer trwy ebost a bydd y taliad yn ymddangos fel taliad yn yr arfaeth nes ei awdurdodi."
shipment_mailer:
shipped_email:
dear_customer: "Annwyl Gwsmer,"

View File

@@ -273,6 +273,13 @@ de_CH:
join_community: "Jetzt Teil der Community werden!"
invite_manager:
subject: "%{enterprise} hat Sie eingeladen, ein Manager zu sein"
payment_mailer:
authorize_payment:
subject: "Bitte autorisieren Sie Ihre Zahlung an %{distributor} im Open Food Network"
instructions: "Ihre Zahlung in Höhe von %{amount} an %{distributor} erfordert Ihre zusätzliche Autorisierung. Bitte klicken Sie auf den folgenden Link, um Ihre Zahlung zu bestätigen:"
authorization_required:
subject: "Eine Zahlung muss durch den Kunden autorisiert werden"
message: "Die Zahlung der Bestellung %{order_number} erfordert eine zusätzliche Autorisierung durch den Kunden. Der Kunde wurde per E-Mail benachrichtigt und die Zahlung wird bis zur Bestätigung als ausstehend angezeigt."
producer_mailer:
order_cycle:
subject: "Bestellzyklusbericht für %{producer}"
@@ -4196,13 +4203,6 @@ de_CH:
subject: "Anweisungen zum Zurücksetzen des Passworts"
confirmation_instructions:
subject: "Bitte bestätigen Sie Ihre Registrierung im Open Food Network"
payment_mailer:
authorize_payment:
subject: "Bitte autorisieren Sie Ihre Zahlung an %{distributor} im Open Food Network"
instructions: "Ihre Zahlung in Höhe von %{amount} an %{distributor} erfordert Ihre zusätzliche Autorisierung. Bitte klicken Sie auf den folgenden Link, um Ihre Zahlung zu bestätigen:"
authorization_required:
subject: "Eine Zahlung muss durch den Kunden autorisiert werden"
message: "Die Zahlung der Bestellung %{order_number} erfordert eine zusätzliche Autorisierung durch den Kunden. Der Kunde wurde per E-Mail benachrichtigt und die Zahlung wird bis zur Bestätigung als ausstehend angezeigt."
shipment_mailer:
shipped_email:
dear_customer: "Liebe Kundin, lieber Kunde,"

View File

@@ -297,6 +297,13 @@ de_DE:
join_community: "Jetzt Teil der Community werden!"
invite_manager:
subject: "%{enterprise} hat Sie eingeladen, ein Manager zu sein"
payment_mailer:
authorize_payment:
subject: "Bitte autorisieren Sie Ihre Zahlung an %{distributor} im Open Food Network"
instructions: "Ihre Zahlung in Höhe von %{amount} an %{distributor} erfordert Ihre zusätzliche Autorisierung. Bitte klicken Sie auf den folgenden Link, um Ihre Zahlung zu bestätigen:"
authorization_required:
subject: "Eine Zahlung muss durch den Kunden autorisiert werden"
message: "Die Zahlung der Bestellung %{order_number} erfordert eine zusätzliche Autorisierung durch den Kunden. Der Kunde wurde per E-Mail benachrichtigt und die Zahlung wird bis zur Bestätigung als ausstehend angezeigt."
producer_mailer:
order_cycle:
subject: "Bestellzyklusbericht für %{producer}"
@@ -4419,13 +4426,6 @@ de_DE:
subject: "Anweisungen zum Zurücksetzen des Passworts"
confirmation_instructions:
subject: "Bitte bestätigen Sie Ihre Registrierung im Open Food Network"
payment_mailer:
authorize_payment:
subject: "Bitte autorisieren Sie Ihre Zahlung an %{distributor} im Open Food Network"
instructions: "Ihre Zahlung in Höhe von %{amount} an %{distributor} erfordert Ihre zusätzliche Autorisierung. Bitte klicken Sie auf den folgenden Link, um Ihre Zahlung zu bestätigen:"
authorization_required:
subject: "Eine Zahlung muss durch den Kunden autorisiert werden"
message: "Die Zahlung der Bestellung %{order_number} erfordert eine zusätzliche Autorisierung durch den Kunden. Der Kunde wurde per E-Mail benachrichtigt und die Zahlung wird bis zur Bestätigung als ausstehend angezeigt."
shipment_mailer:
shipped_email:
dear_customer: "Liebe Kundin, lieber Kunde,"

Some files were not shown because too many files have changed in this diff Show More