Merge branch 'master' into buu-dropdown-tweaks-11518

This commit is contained in:
Rachel Arnould
2024-01-12 10:40:19 +01:00
committed by GitHub
295 changed files with 16127 additions and 5078 deletions

View File

@@ -4,6 +4,9 @@
SECRET_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
STRIPE_SECRET_TEST_API_KEY="bogus_key"
STRIPE_CUSTOMER="bogus_customer"
STRIPE_ACCOUNT="bogus_account"
STRIPE_CLIENT_ID="bogus_client_id"
STRIPE_PUBLIC_TEST_API_KEY="bogus_stripe_publishable_key"
SITE_URL="test.host"

View File

@@ -1,6 +1,6 @@
# This configuration was generated by
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 1400 --no-auto-gen-timestamp`
# using RuboCop version 1.57.2.
# using RuboCop version 1.59.0.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
@@ -116,13 +116,18 @@ Lint/RedundantSafeNavigation:
Exclude:
- 'app/models/spree/payment.rb'
# Offense count: 1
Lint/SelfAssignment:
Exclude:
- 'app/models/spree/order/checkout.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
Lint/UselessMethodDefinition:
Exclude:
- 'app/models/spree/gateway.rb'
# Offense count: 27
# Offense count: 26
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
Metrics/AbcSize:
Exclude:
@@ -520,21 +525,7 @@ Rails/NegateInclude:
- 'lib/spree/localized_number.rb'
- 'spec/support/matchers/table_matchers.rb'
# Offense count: 16
Rails/OutputSafety:
Exclude:
- 'app/helpers/angular_form_helper.rb'
- 'app/helpers/application_helper.rb'
- 'app/helpers/reports_helper.rb'
- 'app/helpers/spree/admin/base_helper.rb'
- 'app/helpers/spree/admin/navigation_helper.rb'
- 'app/helpers/spree/admin/orders_helper.rb'
- 'app/helpers/spree/admin/zones_helper.rb'
- 'lib/reporting/queries/query_builder.rb'
- 'lib/reporting/queries/query_interface.rb'
- 'lib/spree/money.rb'
# Offense count: 31
# Offense count: 32
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/Pluck:
Exclude:
@@ -553,6 +544,7 @@ Rails/Pluck:
- 'spec/lib/reports/lettuce_share_report_spec.rb'
- 'spec/lib/reports/users_and_enterprises_report_spec.rb'
- 'spec/serializers/api/admin/for_order_cycle/supplied_product_serializer_spec.rb'
- 'spec/support/api_helper.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
@@ -620,13 +612,12 @@ Rails/ResponseParsedBody:
- 'spec/controllers/spree/credit_cards_controller_spec.rb'
- 'spec/controllers/user_registrations_controller_spec.rb'
# Offense count: 3
# Offense count: 2
# This cop supports unsafe autocorrection (--autocorrect-all).
Rails/RootPathnameMethods:
Exclude:
- 'spec/lib/reports/orders_and_fulfillment/order_cycle_customer_totals_report_spec.rb'
- 'spec/models/terms_of_service_file_spec.rb'
- 'spec/system/admin/configuration/terms_of_service_files_spec.rb'
# Offense count: 1
# This cop supports unsafe autocorrection (--autocorrect-all).
@@ -841,6 +832,22 @@ Style/HashConversion:
- 'spec/controllers/admin/inventory_items_controller_spec.rb'
- 'spec/controllers/admin/variant_overrides_controller_spec.rb'
# Offense count: 13
# This cop supports unsafe autocorrection (--autocorrect-all).
# Configuration parameters: AllowedReceivers.
# AllowedReceivers: Thread.current
Style/HashEachMethods:
Exclude:
- 'app/controllers/admin/enterprises_controller.rb'
- 'app/controllers/spree/admin/shipping_methods_controller.rb'
- 'app/forms/enterprise_fees_bulk_update.rb'
- 'app/models/product_import/entry_processor.rb'
- 'app/models/spree/preferences/configuration.rb'
- 'app/services/sets/model_set.rb'
- 'lib/reporting/reports/sales_tax/sales_tax_totals_by_producer.rb'
- 'spec/models/product_importer_spec.rb'
- 'spec/support/cancan_helper.rb'
# Offense count: 1
# Configuration parameters: MinBranchesCount.
Style/HashLikeCase:

View File

@@ -17,7 +17,7 @@ gem "image_processing"
gem 'activemerchant', '>= 1.78.0'
gem 'angular-rails-templates', '>= 0.3.0'
gem 'awesome_nested_set'
gem 'ransack', '~> 2.6.0'
gem 'ransack', '~> 4.1.0'
gem 'responders'
gem 'rexml'
gem 'webpacker', '~> 5'
@@ -93,7 +93,7 @@ gem 'bootsnap', require: false
gem 'geocoder'
gem 'gmaps4rails'
gem 'mimemagic', '> 0.3.5'
gem 'paper_trail', '~> 12.1'
gem 'paper_trail'
gem 'rack-rewrite'
gem 'rack-timeout'
gem 'roadie-rails'

View File

@@ -90,7 +90,7 @@ GEM
rails-html-sanitizer (~> 1.1, >= 1.2.0)
active_model_serializers (0.8.4)
activemodel (>= 3.0)
active_storage_validations (1.1.3)
active_storage_validations (1.1.4)
activejob (>= 5.2.0)
activemodel (>= 5.2.0)
activestorage (>= 5.2.0)
@@ -155,22 +155,21 @@ GEM
awesome_nested_set (3.6.0)
activerecord (>= 4.0.0, < 7.2)
aws-eventstream (1.3.0)
aws-partitions (1.860.0)
aws-sdk-core (3.189.0)
aws-partitions (1.877.0)
aws-sdk-core (3.190.1)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.651.0)
aws-sigv4 (~> 1.8)
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.74.0)
aws-sdk-kms (1.75.0)
aws-sdk-core (~> 3, >= 3.188.0)
aws-sigv4 (~> 1.1)
aws-sdk-s3 (1.141.0)
aws-sdk-s3 (1.142.0)
aws-sdk-core (~> 3, >= 3.189.0)
aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.8)
aws-sigv4 (1.8.0)
aws-eventstream (~> 1, >= 1.0.2)
base64 (0.2.0)
bcp47_spec (0.2.1)
bcrypt (3.1.19)
bigdecimal (3.0.2)
@@ -178,10 +177,10 @@ GEM
bindex (0.8.1)
bootsnap (1.17.0)
msgpack (~> 1.2)
bugsnag (6.26.0)
bugsnag (6.26.1)
concurrent-ruby (~> 1.0)
builder (3.2.4)
bullet (7.1.4)
bullet (7.1.5)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
cable_ready (5.0.1)
@@ -216,7 +215,7 @@ GEM
coffee-script-source
execjs
coffee-script-source (1.12.2)
combine_pdf (1.0.24)
combine_pdf (1.0.26)
matrix
ruby-rc4 (>= 0.1.5)
concurrent-ruby (1.2.2)
@@ -238,7 +237,7 @@ GEM
datafoodconsortium-connector (1.0.0.pre.alpha.9)
virtual_assembly-semantizer (~> 1.0, >= 1.0.5)
date (3.3.3)
debug (1.9.0)
debug (1.9.1)
irb (~> 1.10)
reline (>= 0.3.8)
debugger-linecache (1.2.0)
@@ -271,13 +270,12 @@ GEM
factory_bot_rails (6.2.0)
factory_bot (~> 6.2.0)
railties (>= 5.0.0)
faraday (2.7.12)
base64
faraday-net_http (>= 2.0, < 3.1)
ruby2_keywords (>= 0.0.4)
faraday (2.9.0)
faraday-net_http (>= 2.0, < 3.2)
faraday-follow_redirects (0.3.0)
faraday (>= 1, < 3)
faraday-net_http (3.0.2)
faraday-net_http (3.1.0)
net-http
ferrum (0.14)
addressable (~> 2.5)
concurrent-ruby (~> 1.1)
@@ -345,9 +343,9 @@ GEM
ruby-vips (>= 2.0.17, < 3)
immigrant (0.3.6)
activerecord (>= 3.0)
io-console (0.6.0)
io-console (0.7.1)
ipaddress (0.8.3)
irb (1.10.1)
irb (1.11.0)
rdoc
reline (>= 0.3.8)
jmespath (1.6.2)
@@ -380,7 +378,7 @@ GEM
jsonapi-serializer (2.2.0)
activesupport (>= 4.2)
jwt (2.7.1)
knapsack_pro (6.0.3)
knapsack_pro (6.0.4)
rake
language_server-protocol (3.17.0.3)
launchy (2.5.0)
@@ -402,9 +400,9 @@ GEM
marcel (1.0.2)
matrix (0.4.2)
method_source (1.0.0)
mime-types (3.5.1)
mime-types (3.5.2)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.0808)
mime-types-data (3.2023.1205)
mimemagic (0.4.3)
nokogiri (~> 1)
rake
@@ -419,6 +417,8 @@ GEM
msgpack (1.7.2)
multi_json (1.15.0)
multi_xml (0.6.0)
net-http (0.4.1)
uri
net-imap (0.4.2)
date
net-protocol
@@ -428,10 +428,9 @@ GEM
timeout
net-smtp (0.4.0)
net-protocol
newrelic_rpm (9.6.0)
base64
nio4r (2.5.9)
nokogiri (1.15.5)
newrelic_rpm (9.7.0)
nio4r (2.7.0)
nokogiri (1.16.0)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
oauth2 (1.4.11)
@@ -464,10 +463,10 @@ GEM
orm_adapter (0.5.0)
pagy (5.10.1)
activesupport
paper_trail (12.3.0)
activerecord (>= 5.2)
request_store (~> 1.1)
parallel (1.23.0)
paper_trail (15.1.0)
activerecord (>= 6.1)
request_store (~> 1.4)
parallel (1.24.0)
paranoia (2.6.3)
activerecord (>= 5.1, < 7.2)
parser (3.2.2.4)
@@ -478,7 +477,7 @@ GEM
xml-simple
paypal-sdk-merchant (1.117.2)
paypal-sdk-core (~> 0.3.0)
pdf-reader (2.11.0)
pdf-reader (2.12.0)
Ascii85 (~> 1.0)
afm (~> 0.2.1)
hashery (~> 2.0)
@@ -489,10 +488,10 @@ GEM
pry (0.13.1)
coderay (~> 1.1)
method_source (~> 1.0)
psych (5.1.1.1)
psych (5.1.2)
stringio
public_suffix (5.0.4)
puma (6.4.0)
puma (6.4.2)
nio4r (~> 2.0)
query_count (1.1.1)
activerecord (>= 4.2)
@@ -559,9 +558,9 @@ GEM
zeitwerk (~> 2.5)
rainbow (3.1.1)
rake (13.1.0)
ransack (2.6.0)
activerecord (>= 6.0.4)
activesupport (>= 6.0.4)
ransack (4.1.1)
activerecord (>= 6.1.5)
activesupport (>= 6.1.5)
i18n
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
@@ -569,13 +568,13 @@ GEM
rdf (3.3.1)
bcp47_spec (~> 0.2)
link_header (~> 0.0, >= 0.0.8)
rdoc (6.6.1)
rdoc (6.6.2)
psych (>= 4.0.0)
redcarpet (3.6.0)
redis (4.8.1)
redis-client (0.18.0)
connection_pool
regexp_parser (2.8.2)
regexp_parser (2.8.3)
reline (0.4.1)
io-console (~> 0.5)
request_store (1.5.1)
@@ -634,7 +633,7 @@ GEM
rswag-ui (2.13.0)
actionpack (>= 3.1, < 7.2)
railties (>= 3.1, < 7.2)
rubocop (1.58.0)
rubocop (1.59.0)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
@@ -647,7 +646,7 @@ GEM
unicode-display_width (>= 2.4.0, < 3.0)
rubocop-ast (1.30.0)
parser (>= 3.2.1.0)
rubocop-rails (2.22.2)
rubocop-rails (2.23.1)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 1.33.0, < 2.0)
@@ -658,7 +657,6 @@ GEM
ruby-rc4 (0.1.5)
ruby-vips (2.1.4)
ffi (~> 1.12)
ruby2_keywords (0.0.5)
rubyzip (2.3.2)
rufus-scheduler (3.8.2)
fugit (~> 1.1, >= 1.1.6)
@@ -674,7 +672,7 @@ GEM
tilt (>= 1.1, < 3)
sd_notify (0.1.1)
semantic_range (3.0.0)
shoulda-matchers (5.3.0)
shoulda-matchers (6.0.0)
activesupport (>= 5.2.0)
sidekiq (7.2.0)
concurrent-ruby (< 2)
@@ -725,7 +723,7 @@ GEM
stimulus_reflex (>= 3.3.0)
stringex (2.8.6)
stringio (3.1.0)
stripe (10.2.0)
stripe (10.3.0)
swd (1.3.0)
activesupport (>= 3)
attr_required (>= 0.0.5)
@@ -741,6 +739,7 @@ GEM
concurrent-ruby (~> 1.0)
unicode-display_width (2.5.0)
uniform_notifier (1.16.0)
uri (0.13.0)
valid_email2 (5.1.1)
activemodel (>= 3.2)
mail (~> 2.5)
@@ -753,7 +752,7 @@ GEM
validates_lengths_from_database (0.8.0)
activerecord (>= 4)
vcr (6.2.0)
view_component (3.8.0)
view_component (3.10.0)
activesupport (>= 5.2.0, < 8.0)
concurrent-ruby (~> 1.0)
method_source (~> 1.0)
@@ -878,7 +877,7 @@ DEPENDENCIES
openid_connect (~> 1.3)
order_management!
pagy (~> 5.1)
paper_trail (~> 12.1)
paper_trail
paranoia (~> 2.4)
paypal-sdk-merchant (= 1.117.2)
pdf-reader
@@ -895,7 +894,7 @@ DEPENDENCIES
rails-erd
rails-i18n
rails_safe_tasks (~> 1.0)
ransack (~> 2.6.0)
ransack (~> 4.1.0)
redcarpet
redis (>= 4.0)
responders

View File

@@ -44,7 +44,7 @@ We use [KnapsackPro](https://knapsackpro.com/) for optimal parallelisation of ou
## Licence
Copyright (c) 2012 - 2022 Open Food Foundation, released under the AGPL licence.
Copyright (c) 2012 - 2024 Open Food Foundation, released under the AGPL licence.
[survey]: https://docs.google.com/a/eaterprises.com.au/forms/d/1zxR5vSiU9CigJ9cEaC8-eJLgYid8CR8er7PPH9Mc-30/edit#
[slack-invite]: https://join.slack.com/t/openfoodnetwork/shared_invite/zt-9sjkjdlu-r02kUMP1zbrTgUhZhYPF~A

View File

@@ -43,7 +43,8 @@ angular.module('admin.payments').factory 'Payment', (AdminStripeElements, curren
submit: =>
munged = @preprocess()
PaymentResource.create({order_id: munged.order_id}, munged, (response, headers, status) ->
document.body.innerHTML = Object.values(response).join('')
rawHtml = Object.values(response).join('').replace('[object Object]true', '')
document.body.innerHTML = rawHtml
$window.history.pushState({}, '', "/admin/orders/" + munged.order_id + "/payments")
, (response) ->
StatusMessage.display 'error', t("spree.admin.payments.source_forms.stripe.error_saving_payment")

View File

@@ -14,7 +14,7 @@
{{'hubs_delivery' | t}}
.row
.columns.small-12
%a.cta-hub{"ng-href" => "{{::enterprise.path}}#/shop", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}",
%a.cta-hub{"ng-href" => "{{::enterprise.path}}#/shop_panel", "ng-attr-target" => "{{ embedded_layout ? '_blank' : undefined}}",
"ng-class" => "{primary: enterprise.active, secondary: !enterprise.active}",
"ng-click" => "$close()",
"ofn-change-hub" => "enterprise"}

View File

@@ -12,7 +12,7 @@
.row
.columns.small-12
%a.cta-hub{"ng-repeat" => "hub in enterprise.hubs | filter:{id: '!'+enterprise.id} | orderBy:'-active'",
"ng-href" => "{{::hub.path}}#/shop", "ofn-empties-cart" => "hub",
"ng-href" => "{{::hub.path}}#/shop_panel", "ofn-empties-cart" => "hub",
"ng-class" => "::{primary: hub.active, secondary: !hub.active}",
"ng-click" => "$close()",
"ofn-change-hub" => "hub"}

View File

@@ -1,14 +1,29 @@
# frozen_string_literal: true
class ConfirmModalComponent < ModalComponent
def initialize(id:, confirm_actions: nil, reflex: nil, controller: nil, message: nil,
confirm_reflexes: nil)
# @param actions_alignment_class [String] possible classes: 'justify-space-around', 'justify-end'
def initialize(
id:,
reflex: nil,
controller: nil,
message: nil,
confirm_actions: nil,
confirm_reflexes: nil,
confirm_button_class: :primary,
confirm_button_text: I18n.t('js.admin.modals.confirm'),
cancel_button_text: I18n.t('js.admin.modals.cancel'),
actions_alignment_class: 'justify-space-around'
)
super(id:, close_button: true)
@confirm_actions = confirm_actions
@reflex = reflex
@confirm_reflexes = confirm_reflexes
@controller = controller
@message = message
@confirm_button_class = confirm_button_class
@confirm_button_text = confirm_button_text
@cancel_button_text = cancel_button_text
@actions_alignment_class = actions_alignment_class
end
private

View File

@@ -5,6 +5,6 @@
= render @message if @message
.modal-actions
%input{ class: "button icon-plus #{close_button_class}", type: 'button', value: t('js.admin.modals.cancel'), "data-action": "click->modal#close" }
%input{ class: "button icon-plus primary", type: 'button', value: t('js.admin.modals.confirm'), "data-action": @confirm_actions, "data-reflex": @confirm_reflexes }
%div{ class: "modal-actions #{@actions_alignment_class}" }
%input{ class: "button icon-plus #{close_button_class}", type: 'button', value: @cancel_button_text, "data-action": "click->modal#close" }
%input{ id: 'modal-confirm-button', class: "button icon-plus #{@confirm_button_class}", type: 'button', value: @confirm_button_text, "data-action": @confirm_actions, "data-reflex": @confirm_reflexes }

View File

@@ -1,4 +1,22 @@
.modal-actions {
display: flex;
justify-content: space-around;
&.justify-space-around {
justify-content: space-around;
}
&.justify-end {
justify-content: flex-end;
input[type="button"] {
margin: 0 5px;
}
@media only screen and (max-width: 1024px) {
flex-direction: column;
justify-content: space-around;
input[type="button"] {
margin: 5px 0;
}
}
}
}

View File

@@ -2,6 +2,9 @@
visibility: visible;
position: fixed;
top: 3em;
&.in {
padding: 1.2rem;
}
}
/* prevent arrow on selected admin menu item appearing above modal */

View File

@@ -38,7 +38,8 @@ module Admin
@enterprise_fee_set = EnterpriseFeesBulkUpdate.new(params)
if @enterprise_fee_set.save
redirect_to redirect_path, notice: I18n.t(:enterprise_fees_update_notice)
flash[:success] = I18n.t(:enterprise_fees_update_notice)
redirect_to redirect_path
else
redirect_to redirect_path,
flash: { error: @enterprise_fee_set.errors.full_messages.to_sentence }

View File

@@ -3,9 +3,8 @@
module Admin
class EnterpriseRolesController < Admin::ResourceController
def index
@enterprise_roles = EnterpriseRole.by_user_email
@users = Spree::User.order('spree_users.email')
@my_enterprises = @all_enterprises = Enterprise.by_name
@enterprise_roles, @users, @all_enterprises = Admin::EnterpriseRolesQuery.query
@my_enterprises = @all_enterprises
end
def create

View File

@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'open_food_network/permissions'
require 'order_management/subscriptions/proxy_order_syncer'
module Admin
class SchedulesController < Admin::ResourceController

View File

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'api/admin/enterprise_serializer'
module Api
module V0
class EnterpriseAttachmentController < Api::V0::BaseController

View File

@@ -9,6 +9,7 @@ module Spree
helper 'admin/injection'
helper 'admin/orders'
helper 'admin/enterprises'
helper 'admin/terms_of_service'
helper 'enterprise_fees'
helper 'angular_form'

View File

@@ -21,15 +21,28 @@ module Admin
show_payment_methods = can?(:manage_payment_methods, enterprise) && is_shop
show_enterprise_fees = can?(:manage_enterprise_fees,
enterprise) && (is_shop || enterprise.is_primary_producer)
show_connected_apps = feature?(:connected_apps, spree_current_user, enterprise)
build_enterprise_side_menu_items(is_shop, show_properties, show_shipping_methods,
show_payment_methods, show_enterprise_fees)
build_enterprise_side_menu_items(
is_shop:,
show_properties:,
show_shipping_methods:,
show_payment_methods:,
show_enterprise_fees:,
show_connected_apps:,
)
end
private
def build_enterprise_side_menu_items(is_shop, show_properties, show_shipping_methods,
show_payment_methods, show_enterprise_fees)
def build_enterprise_side_menu_items(
is_shop:,
show_properties:,
show_shipping_methods:,
show_payment_methods:,
show_enterprise_fees:,
show_connected_apps:
)
[
{ name: 'primary_details', icon_class: "icon-home", show: true, selected: 'selected' },
{ name: 'address', icon_class: "icon-map-marker", show: true },
@@ -50,6 +63,7 @@ module Admin
{ name: 'shop_preferences', icon_class: "icon-shopping-cart", show: is_shop },
{ name: 'users', icon_class: "icon-user", show: true },
{ name: 'white_label', icon_class: "icon-leaf", show: true },
{ name: 'connected_apps', icon_class: "icon-puzzle-piece", show: show_connected_apps },
]
end
end

View File

@@ -27,13 +27,6 @@ module Admin
Api::Admin::EnterpriseRelationshipSerializer
end
def admin_inject_enterprise_roles(enterprise_roles)
admin_inject_json_ams_array "ofn.admin",
"enterpriseRoles",
enterprise_roles,
Api::Admin::EnterpriseRoleSerializer
end
def admin_inject_payment_methods(payment_methods)
admin_inject_json_ams_array "admin.paymentMethods",
"paymentMethods",
@@ -137,13 +130,6 @@ module Admin
Api::Admin::TaxonSerializer
end
def admin_inject_users(users)
admin_inject_json_ams_array "ofn.admin",
"users",
users,
Api::Admin::UserSerializer
end
def admin_inject_variant_overrides(variant_overrides)
admin_inject_json_ams_array "admin.variantOverrides",
"variantOverrides",

View File

@@ -0,0 +1,25 @@
# frozen_string_literal: true
module Admin
module TermsOfServiceHelper
def tos_need_accepting?
return false unless spree_user_signed_in?
return false if Spree::Config.enterprises_require_tos == false
return false if TermsOfServiceFile.current.nil?
!accepted_tos?
end
private
def accepted_tos?
file_uploaded_at = TermsOfServiceFile.updated_at
current_spree_user.terms_of_service_accepted_at.present? &&
current_spree_user.terms_of_service_accepted_at > file_uploaded_at &&
current_spree_user.terms_of_service_accepted_at < DateTime.now
end
end
end

View File

@@ -9,7 +9,7 @@ module AngularFormHelper
text, value = option_text_and_value(element).map(&:to_s)
%(<option value="#{ERB::Util.html_escape(value)}"\
#{html_attributes}>#{ERB::Util.html_escape(text)}</option>)
end.join("\n").html_safe
end.join("\n").html_safe # rubocop:disable Rails/OutputSafety
end
def ng_options_from_collection_for_select(collection, value_method, text_method, angular_field)

View File

@@ -10,7 +10,7 @@ module ApplicationHelper
return "" unless obj && obj.errors[method].present?
errors = obj.errors[method].map { |err| h(err) }.join('<br />').html_safe
errors = obj.errors[method].map { |err| h(err) }.join('<br />').html_safe # rubocop:disable Rails/OutputSafety
if options[:standalone]
content_tag(
@@ -36,7 +36,7 @@ module ApplicationHelper
hreflang: locale.to_s.gsub("_", "-").downcase,
href: "#{request.protocol}#{request.host_with_port}/locales/#{locale}"
)
end.join("\n").html_safe
end.join("\n").html_safe # rubocop:disable Rails/OutputSafety
end
def ng_form_for(name, *args, &)

View File

@@ -5,7 +5,9 @@ module ReportsHelper
order_cycles.map do |oc|
orders_open_at = oc.orders_open_at&.to_fs(:short) || 'NA'
orders_close_at = oc.orders_close_at&.to_fs(:short) || 'NA'
# rubocop:disable Rails/OutputSafety
["#{oc.name} &nbsp; (#{orders_open_at} - #{orders_close_at})".html_safe, oc.id]
# rubocop:enable Rails/OutputSafety
end
end

View File

@@ -20,6 +20,6 @@ module SharedHelper
end
def current_shop_products_path
"#{main_app.enterprise_shop_path(current_distributor)}#/shop"
"#{main_app.enterprise_shop_path(current_distributor)}#/shop_panel"
end
end

View File

@@ -45,7 +45,7 @@ module ShopHelper
end
def shopfront_closed_message?(order_cycles)
no_open_order_cycles?(order_cycles) && \
no_open_order_cycles?(order_cycles) &&
current_distributor.preferred_shopfront_closed_message.present?
end

View File

@@ -17,7 +17,9 @@ module Spree
obj = object.respond_to?(:errors) ? object : instance_variable_get("@#{object}")
if obj && obj.errors[method].present?
# rubocop:disable Rails/OutputSafety
errors = obj.errors[method].map { |err| h(err) }.join('<br />').html_safe
# rubocop:enable Rails/OutputSafety
content_tag(:span, errors, class: 'formError')
else
''
@@ -110,12 +112,12 @@ module Spree
object.preferences.keys.map { |key|
preference_label = form.label("preferred_#{key}",
Spree.t(key.to_s.gsub("_from_list", "")) + ": ").html_safe
Spree.t(key.to_s.gsub("_from_list", "")) + ": ")
preference_field = preference_field_for(
form,
"preferred_#{key}",
{ type: object.preference_type(key) }, object
).html_safe
)
{ label: preference_label, field: preference_field }
}
end

View File

@@ -98,7 +98,9 @@ module Spree
options[:class] = (options[:class].to_s + " icon_link with-tip #{icon_name}").strip
options[:class] += ' no-text' if options[:no_text]
options[:title] = text if options[:no_text]
# rubocop:disable Rails/OutputSafety
text = options[:no_text] ? '' : raw("<span class='text'>#{text}</span>")
# rubocop:enable Rails/OutputSafety
options.delete(:no_text)
link_to(text, url, options)
end
@@ -131,14 +133,14 @@ module Spree
if html_options[:icon]
html_options[:class] += " #{html_options[:icon]}"
end
link_to(text_for_button_link(text, html_options), url, html_options)
link_to(text, url, html_options)
end
end
def text_for_button_link(text, _html_options)
s = ''
s << text
raw(s)
raw(s) # rubocop:disable Rails/OutputSafety
end
def configurations_sidebar_menu_item(link_text, url, options = {})

View File

@@ -7,7 +7,7 @@ module Spree
links = []
links << cancel_event_link if @order.can_cancel?
links << resume_event_link if @order.can_resume?
links.join('&nbsp;').html_safe
links.join('&nbsp;').html_safe # rubocop:disable Rails/OutputSafety
end
def line_item_shipment_price(line_item, quantity)

View File

@@ -31,7 +31,7 @@ module Spree
out = ''
out << fields.hidden_field(:_destroy) unless fields.object.new_record?
out << (link_to icon('icon-remove'), "#", class: 'remove')
out.html_safe
out.html_safe # rubocop:disable Rails/OutputSafety
end
end
end

View File

@@ -0,0 +1,28 @@
# frozen_string_literal: true
class ConnectAppJob < ApplicationJob
include CableReady::Broadcaster
def perform(app, token, channel: nil)
url = "https://n8n.openfoodnetwork.org.uk/webhook/regen/connect-enterprise"
event = "connect-app"
enterprise = app.enterprise
payload = {
'@id': DfcBuilder.urls.enterprise_url(enterprise.id),
access_token: token,
}
response = WebhookDeliveryJob.perform_now(url, event, payload)
app.update!(data: JSON.parse(response))
return unless channel
selector = "#edit_enterprise_#{enterprise.id} #connected-app-discover-regen"
html = ApplicationController.render(
partial: "admin/enterprises/form/connected_apps",
locals: { enterprise: },
)
cable_ready[channel].morph(selector:, html:).broadcast
end
end

View File

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'order_management/subscriptions/summarizer'
# Confirms orders of unconfirmed proxy orders in recently closed Order Cycles
class SubscriptionConfirmJob < ApplicationJob
def perform

View File

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'order_management/subscriptions/summarizer'
class SubscriptionPlacementJob < ApplicationJob
def perform
proxy_orders.each do |proxy_order|

View File

@@ -46,5 +46,7 @@ class WebhookDeliveryJob < ApplicationJob
# Raise a failed request error and let job runner handle retrying.
# In theory, only 5xx errors should be retried, but who knows.
raise FailedWebhookRequestError, response.status.to_s unless response.success?
response.body
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
# An enterprise can be connected to other apps.
#
# Here we store keys and links to access the app.
class ConnectedApp < ApplicationRecord
belongs_to :enterprise
scope :connecting, -> { where(data: nil) }
scope :ready, -> { where.not(data: nil) }
end

View File

@@ -27,21 +27,24 @@ class ContentConfiguration < Spree::Preferences::Configuration
default: I18n.t(:content_configuration_pricing_table)
preference :producer_signup_case_studies_html, :text,
default: I18n.t(:content_configuration_case_studies)
preference :producer_signup_detail_html, :text, default: I18n.t(:content_configuration_detail)
preference :producer_signup_detail_html, :text,
default: I18n.t(:content_configuration_detail)
# Hubs sign-up page
preference :hub_signup_pricing_table_html, :text,
default: I18n.t(:content_configuration_pricing_table)
preference :hub_signup_case_studies_html, :text,
default: I18n.t(:content_configuration_case_studies)
preference :hub_signup_detail_html, :text, default: I18n.t(:content_configuration_detail)
preference :hub_signup_detail_html, :text,
default: I18n.t(:content_configuration_detail)
# Groups sign-up page
preference :group_signup_pricing_table_html, :text,
default: I18n.t(:content_configuration_pricing_table)
preference :group_signup_case_studies_html, :text,
default: I18n.t(:content_configuration_case_studies)
preference :group_signup_detail_html, :text, default: I18n.t(:content_configuration_detail)
preference :group_signup_detail_html, :text,
default: I18n.t(:content_configuration_detail)
# Main URLs
preference :menu_1, :boolean, default: true

View File

@@ -62,6 +62,7 @@ class Enterprise < ApplicationRecord
has_many :tag_rules, dependent: :destroy
has_one :stripe_account, dependent: :destroy
has_many :vouchers
has_many :connected_apps, dependent: :destroy
has_one :custom_tab, dependent: :destroy
delegate :latitude, :longitude, :city, :state_name, to: :address

View File

@@ -30,4 +30,8 @@ class Invoice < ApplicationRecord
def display_number
"#{order.distributor.id}-#{number}"
end
def previous_invoice
order.invoices.where("id < ?", id).first
end
end

View File

@@ -5,7 +5,7 @@ class Invoice
include ::ActionView::Helpers::NumberHelper
attr_reader :invoice
delegate :display_number, :data, to: :invoice
delegate :display_number, :data, :previous_invoice, to: :invoice
delegate :date, to: :invoice, prefix: true
FINALIZED_NON_SUCCESSFUL_STATES = %w(canceled returned).freeze

View File

@@ -5,6 +5,10 @@ class Invoice
class ShippingMethod < Invoice::DataPresenter::Base
attributes :id, :name, :require_ship_address
invoice_generation_attributes :id
def category
I18n.t "invoice_shipping_category_#{require_ship_address ? 'delivery' : 'pickup'}"
end
end
end
end

View File

@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'spree/localized_number'
require 'concerns/adjustment_scopes'
# Adjustments represent a change to the +item_total+ of an Order. Each adjustment
# has an +amount+ that can be either positive or negative.

View File

@@ -135,7 +135,7 @@ module Spree
# Enable cache
preference :enable_products_cache?, :boolean,
default: (Rails.env.production? || Rails.env.staging?)
default: Rails.env.production? || Rails.env.staging?
# Available units
preference :available_units, :string, default: "g,kg,T,mL,L,kL"

View File

@@ -6,12 +6,6 @@ module Spree
validates :name, :iso_name, presence: true
def self.cached_find_by(attrs)
Rails.cache.fetch("countries/#{attrs.hash}", expires_in: 1.hour) do
find_by(attrs)
end
end
def <=>(other)
name <=> other.name
end

View File

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'concerns/payment_method_distributors'
module Spree
class Gateway < PaymentMethod
acts_as_taggable

View File

@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'open_food_network/scope_variant_to_hub'
require 'variant_units/variant_and_line_item_naming'
module Spree
class LineItem < ApplicationRecord

View File

@@ -1,10 +1,5 @@
# frozen_string_literal: true
require 'spree/order/checkout'
require 'open_food_network/enterprise_fee_calculator'
require 'open_food_network/feature_toggle'
require 'open_food_network/tag_rule_applicator'
module Spree
class Order < ApplicationRecord
include OrderShipment

View File

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'concerns/payment_method_distributors'
module Spree
class PaymentMethod < ApplicationRecord
include CalculatedAdjustments

View File

@@ -70,31 +70,31 @@ module Spree
end
def preference_getter_method(name)
"preferred_#{name}".to_sym
:"preferred_#{name}"
end
def preference_setter_method(name)
"preferred_#{name}=".to_sym
:"preferred_#{name}="
end
def prefers_getter_method(name)
"prefers_#{name}?".to_sym
:"prefers_#{name}?"
end
def prefers_setter_method(name)
"prefers_#{name}=".to_sym
:"prefers_#{name}="
end
def preference_default_getter_method(name)
"preferred_#{name}_default".to_sym
:"preferred_#{name}_default"
end
def preference_type_getter_method(name)
"preferred_#{name}_type".to_sym
:"preferred_#{name}_type"
end
def preference_description_getter_method(name)
"preferred_#{name}_description".to_sym
:"preferred_#{name}_description"
end
end
end

View File

@@ -1,7 +1,6 @@
# frozen_string_literal: true
require 'open_food_network/property_merge'
require 'concerns/product_stock'
# PRODUCTS
# Products represent an entity for sale in a store.
@@ -189,7 +188,7 @@ module Spree
.with_permission(:add_to_order_cycle)
.where(enterprises: { is_primary_producer: true })
.pluck(:parent_id)
return where('spree_products.supplier_id IN (?)', [enterprise.id] | permitted_producer_ids)
where('spree_products.supplier_id IN (?)', [enterprise.id] | permitted_producer_ids)
}
scope :active, lambda { where("spree_products.deleted_at IS NULL") }

View File

@@ -1,8 +1,6 @@
# frozen_string_literal: true
require 'open_food_network/enterprise_fee_calculator'
require 'variant_units/variant_and_line_item_naming'
require 'concerns/variant_stock'
require 'spree/localized_number'
module Spree

View File

@@ -0,0 +1,43 @@
# frozen_string_literal: true
module Admin
class EnterpriseRolesQuery
class << self
def query
enterprise_roles = query_enterprise_roles
users = query_users
enterprises = query_enterprises
[enterprise_roles, users, enterprises]
end
private
def query_enterprise_roles
EnterpriseRole.joins(:user, :enterprise).order('spree_users.email ASC').
pluck(:id, :user_id, :enterprise_id, 'spree_users.email', 'enterprises.name').
map do |data|
id, user_id, enterprise_id, user_email, enterprise_name = data
{ id:, user_id:, enterprise_id:, user_email:, enterprise_name: }
end
end
def query_users
Spree::User.order(:email).pluck(:id, :email).map do |data|
id, email = data
{ id:, email: }
end
end
def query_enterprises
Enterprise.order(:name).pluck(:id, :name).map do |data|
id, name = data
{ id:, name: }
end
end
end
end
end

View File

@@ -0,0 +1,53 @@
# frozen_string_literal: true
module Admin
class ConnectedAppReflex < ApplicationReflex
def create
authorize! :admin, enterprise
app = ConnectedApp.create!(enterprise_id: enterprise.id)
# Avoid race condition by sending before enqueuing job:
broadcast_partial
ConnectAppJob.perform_later(
app, current_user.spree_api_key,
channel: SessionChannel.for_request(request),
)
morph :nothing
end
def destroy
authorize! :admin, enterprise
app = enterprise.connected_apps.first
app.destroy
broadcast_partial
WebhookDeliveryJob.perform_later(
app.data["destroy"],
"disconnect-app",
nil
)
morph :nothing
end
private
def enterprise
@enterprise ||= Enterprise.find(element.dataset.enterprise_id)
end
def broadcast_partial
selector = "#edit_enterprise_#{enterprise.id} #connected-app-discover-regen"
html = ApplicationController.render(
partial: "admin/enterprises/form/connected_apps",
locals: { enterprise: },
)
# Avoid race condition by sending before enqueuing job:
cable_ready.morph(selector:, html:).broadcast
end
end
end

View File

@@ -6,20 +6,20 @@ class ProductsReflex < ApplicationReflex
before_reflex :init_filters_params, :init_pagination_params
def fetch
fetch_and_render_products
fetch_and_render_products_with_flash
end
def change_per_page
@per_page = element.value.to_i
@page = 1
fetch_and_render_products
fetch_and_render_products_with_flash
end
def filter
@page = 1
fetch_and_render_products
fetch_and_render_products_with_flash
end
def clear_search
@@ -28,7 +28,7 @@ class ProductsReflex < ApplicationReflex
@category_id = nil
@page = 1
fetch_and_render_products
fetch_and_render_products_with_flash
end
def bulk_update
@@ -46,6 +46,34 @@ class ProductsReflex < ApplicationReflex
render_products_form_with_flash
end
def delete_product
id = current_id_from_element(element)
product = product_finder(id).find_product
authorize! :delete, product
if product.destroy
flash[:success] = I18n.t('admin.products_v3.delete_product.success')
else
flash[:error] = I18n.t('admin.products_v3.delete_product.error')
end
fetch_and_render_products_with_flash
end
def delete_variant
id = current_id_from_element(element)
variant = Spree::Variant.active.find(id)
authorize! :delete, variant
if VariantDeleter.new.delete(variant)
flash[:success] = I18n.t('admin.products_v3.delete_variant.success')
else
flash[:error] = I18n.t('admin.products_v3.delete_variant.error')
end
fetch_and_render_products_with_flash
end
private
def init_filters_params
@@ -63,7 +91,7 @@ class ProductsReflex < ApplicationReflex
@per_page = element.dataset.perpage || params[:_per_page] || 15
end
def fetch_and_render_products
def fetch_and_render_products_with_flash
fetch_products
render_products
end
@@ -74,7 +102,8 @@ class ProductsReflex < ApplicationReflex
html: render(partial: "admin/products_v3/content",
locals: { products: @products, pagy: @pagy, search_term: @search_term,
producer_options: producers, producer_id: @producer_id,
category_options: categories, category_id: @category_id })
category_options: categories, category_id: @category_id,
flashes: flash })
).broadcast
cable_ready.replace_state(
@@ -195,4 +224,12 @@ class ProductsReflex < ApplicationReflex
params.permit(products: ::PermittedAttributes::Product.attributes)
.to_h.with_indifferent_access
end
def product_finder(id)
ProductScopeQuery.new(current_user, { id: })
end
def current_id_from_element(element)
element.dataset.current_id
end
end

View File

@@ -0,0 +1,9 @@
# frozen_string_literal: true
class UserReflex < ApplicationReflex
def accept_terms_of_services
current_user.update(terms_of_service_accepted_at: DateTime.now)
morph "#banner-container", ""
end
end

View File

@@ -10,7 +10,10 @@ class DefaultCountry
end
def self.country
Spree::Country.cached_find_by(iso: ENV.fetch("DEFAULT_COUNTRY_CODE",
nil)) || Spree::Country.first
# Changing ENV requires restarting the process.
iso = ENV.fetch("DEFAULT_COUNTRY_CODE", nil)
# When ENV changes on restart, this cache will be reset as well.
@country ||= Spree::Country.find_by(iso:) || Spree::Country.first
end
end

View File

@@ -1,5 +1,7 @@
# frozen_string_literal: true
require 'open_food_network/tag_rule_applicator'
class OrderAvailablePaymentMethods
attr_reader :order, :customer

View File

@@ -1,5 +1,7 @@
# frozen_string_literal: true
require 'open_food_network/tag_rule_applicator'
class OrderAvailableShippingMethods
attr_reader :order, :customer

View File

@@ -1,7 +1,5 @@
# frozen_string_literal: true
require 'order_management/subscriptions/proxy_order_syncer'
class OrderCycleClone
def initialize(order_cycle)
@original_order_cycle = order_cycle

View File

@@ -2,7 +2,6 @@
require 'open_food_network/permissions'
require 'open_food_network/order_cycle_form_applicator'
require 'order_management/subscriptions/proxy_order_syncer'
class OrderCycleForm
def initialize(order_cycle, order_cycle_params, user)

View File

@@ -118,7 +118,7 @@ module Sets
# Copy any variant errors to product
variant&.errors&.each do |error|
# The name is namespaced to avoid confusion with product attrs of same name.
product.errors.add("variant_#{error.attribute}".to_sym, error.message)
product.errors.add(:"variant_#{error.attribute}", error.message)
end
variant&.errors.blank?
end

View File

@@ -1,5 +1,7 @@
# frozen_string_literal: true
require 'open_food_network/tag_rule_applicator'
# Lists available order cycles for a given customer in a given distributor
module Shop
class OrderCyclesList

View File

@@ -4,8 +4,6 @@
# It contains all of our logic for creating and naming option values (which are associated
# with both models) and methods for printing human readable "names" for instances of these models.
require 'variant_units/option_value_namer'
module VariantUnits
module VariantAndLineItemNaming
def options_text

View File

@@ -0,0 +1,8 @@
#banner-container
.terms-of-service-banner.form-actions
.column-left
%p= t("admin.terms_of_service_have_been_updated_html", tos_link: link_to(t("admin.terms_of_service"), TermsOfServiceFile.current_url, target: "_blank"))
.column-right
%button{ data: { reflex: "click->user#accept_terms_of_services" } }
= t("admin.accept_terms_of_service")

View File

@@ -1,4 +1,3 @@
= admin_inject_enterprise_roles(@enterprise_roles)
= admin_inject_users(@users)
= admin_inject_enterprises(@my_enterprises, @all_enterprises)
= admin_inject_json('ofn.admin', 'enterpriseRoles', @enterprise_roles)
= admin_inject_json('ofn.admin', 'users', @users)
= admin_inject_json('ofn.admin', 'my_enterprises', @my_enterprises) + admin_inject_json('ofn.admin', 'all_enterprises', @all_enterprises)

View File

@@ -9,12 +9,6 @@
%fieldset.alpha.no-border-bottom{ id: "#{item[:name]}_panel", data: { "tabs-and-panels-target": "panel" }}
%legend= t(".#{ item[:name] }.legend")
- when 'vouchers'
- if feature?(:vouchers, spree_current_user, @enterprise)
%fieldset.alpha.no-border-bottom{ id: "#{item[:name]}_panel", data: { "tabs-and-panels-target": "panel" }}
%legend= t(".#{ item[:form_name] || item[:name] }.legend")
= render "admin/enterprises/form/#{ item[:form_name] || item[:name] }", f: f
- else
%fieldset.alpha.no-border-bottom{ id: "#{item[:name]}_panel", data: { "tabs-and-panels-target": "panel" }}
%legend= t(".#{ item[:form_name] || item[:name] }.legend")

View File

@@ -0,0 +1,31 @@
- enterprise ||= f.object
#connected-app-discover-regen
.connected-app__head
%div
%h3= t ".title"
%p= t ".tagline"
%div
- if enterprise.connected_apps.empty?
%button{ data: {reflex: "click->Admin::ConnectedApp#create", enterprise_id: enterprise.id} }
= t ".enable"
- elsif enterprise.connected_apps.connecting.present?
%button{ disabled: true }
%i.spinner.fa.fa-spin.fa-circle-o-notch
&nbsp;
= t ".loading"
- else
%button{ data: {reflex: "click->Admin::ConnectedApp#destroy", enterprise_id: enterprise.id} }
= t ".disable"
.connected-app__connection
- if enterprise.connected_apps.ready.present?
.connected-app__note
- link = enterprise.connected_apps[0].data["link"]
%p= t ".note"
%div
%a{ href: link, target: "_blank", class: "button secondary" }
= t ".link_label"
%hr
.connected-app__description
= t ".description_html"

View File

@@ -2,7 +2,7 @@
.alpha.three.columns
= f.label :logo
%br
100 x 100 pixels
= t('.logo_size')
.omega.eight.columns
%img{ class: 'image-field-group__preview-image', ng: { src: '{{ Enterprise.logo.thumb }}', if: 'Enterprise.logo' } }
%br

View File

@@ -1,6 +1,7 @@
#products-content
.container
.sixteen.columns
= render partial: 'admin/shared/flashes', locals: { flashes: } if defined? flashes
= render partial: 'filters', locals: { search_term: search_term,
producer_id: producer_id,
producer_options: producer_options,

View File

@@ -0,0 +1,16 @@
-# object_type can be 'variant' or 'product'
- base_translation_key = ".delete_#{object_type}_modal"
- delete_modal = ConfirmModalComponent.new(id: "#{object_type}-delete-modal",
confirm_button_text: t("#{base_translation_key}.confirmation_text"),
cancel_button_text: t("#{base_translation_key}.cancellation_text"),
confirm_button_class: :red,
actions_alignment_class: 'justify-end',
confirm_reflexes: "click->products#delete_#{object_type}",
confirm_actions: "click->modal#close",
)
= render delete_modal do
%h2.margin-bottom-20.black-text
= t("#{base_translation_key}.heading")
%p
= t("#{base_translation_key}.prompt")
.margin-bottom-50

View File

@@ -5,17 +5,6 @@
'data-bulk-form-error-value': defined?(error_counts),
} do |form|
= render(partial: "admin/shared/flashes", locals: { flashes: }) if defined? flashes
%fieldset.form-actions{ class: ("hidden" unless defined?(error_counts)), 'data-bulk-form-target': "actions" }
.container
.status.eleven.columns
.modified_summary{ 'data-bulk-form-target': "changedSummary", 'data-translation-key': 'admin.products_v3.table.changed_summary'}
- if defined?(error_counts)
.error_summary
-# X products were saved correctly, but Y products could not be saved correctly. Please review errors and try again
= t('.error_summary.saved', count: error_counts[:saved]) + t('.error_summary.invalid', count: error_counts[:invalid])
.form-buttons.five.columns
= form.submit t('.reset'), type: :reset, class: "medium", 'data-reflex': 'click->products#fetch'
= form.submit t('.save'), class: "medium"
%table.products
%col{ width:"15%" }
%col{ width:"5%", style: "max-width:5em" }
@@ -28,6 +17,20 @@
%col{ width:"5%", style: "max-width:5em" }
%col{ width:"5%", style: "max-width:5em" }
%thead
%tr
%td.form-actions-wrapper{ colspan: 10 }
.form-actions-wrapper2
%fieldset.form-actions{ class: ("hidden" unless defined?(error_counts)), 'data-bulk-form-target': "actions" }
.container
.status
.modified_summary{ 'data-bulk-form-target': "changedSummary", 'data-translation-key': 'admin.products_v3.table.changed_summary'}
- if defined?(error_counts)
.error_summary
-# X products were saved correctly, but Y products could not be saved correctly. Please review errors and try again
= t('.error_summary.saved', count: error_counts[:saved]) + t('.error_summary.invalid', count: error_counts[:invalid])
.form-buttons
= form.submit t('.reset'), type: :reset, class: "medium", 'data-reflex': 'click->products#fetch'
= form.submit t('.save'), class: "medium"
%tr
%th.align-left.with-input= t('admin.products_page.columns.name')
%th.align-right= t('admin.products_page.columns.sku')
@@ -70,6 +73,10 @@
= render(VerticalEllipsisMenu::Component.new) do
= link_to t('admin.products_page.actions.edit'), edit_admin_product_path(product)
= link_to t('admin.products_page.actions.clone'), clone_admin_product_path(product)
%a{ "data-controller": "modal-link", "data-action": "click->modal-link#setModalDataSetOnConfirm click->modal-link#open",
"data-modal-link-target-value": "product-delete-modal", "class": "delete",
"data-modal-link-modal-dataset-value": {'data-current-id': product.id}.to_json }
= t('admin.products_page.actions.delete')
- product.variants.each_with_index do |variant, variant_index|
= form.fields_for("products][#{product_index}][variants_attributes][", variant, variant_index:) do |variant_form|
@@ -108,3 +115,8 @@
%td.align-right
= render(VerticalEllipsisMenu::Component.new) do
= link_to t('admin.products_page.actions.edit'), edit_admin_product_variant_path(product, variant)
- if product.variants.size > 1
%a{ "data-controller": "modal-link", "data-action": "click->modal-link#setModalDataSetOnConfirm click->modal-link#open",
"data-modal-link-target-value": "variant-delete-modal", "class": "delete",
"data-modal-link-modal-dataset-value": {'data-current-id': variant.id}.to_json }
= t('admin.products_page.actions.delete')

View File

@@ -17,3 +17,5 @@
.spinner
= t('.loading')
#products-content
- %w[product variant].each do |object_type|
= render partial: 'delete_modal', locals: { object_type: }

View File

@@ -28,4 +28,3 @@
.alpha.two.columns= label_tag nil, t(:report_columns)
.omega.fourteen.columns
= render MultipleCheckedSelectComponent.new(name: "fields_to_show", options: @report.available_headers, selected: @rendering_options.options[:fields_to_show])

View File

@@ -1,13 +1,13 @@
.side_menu#side_menu
- if @enterprise
- enterprise_side_menu_items(@enterprise).each do |item|
- next if !item[:show] || (item[:name] == 'vouchers' && !feature?(:vouchers, spree_current_user, @enterprise))
%a.menu_item{ href: item[:href] || "##{item[:name]}_panel", id: item[:name], data: { action: "tabs-and-panels#changeActivePanel tabs-and-panels#changeActiveTab", "tabs-and-panels-target": "tab" }, class: item[:selected] }
- next if !item[:show]
%a.menu_item{ href: item[:href] || "##{item[:name]}_panel", data: { action: "tabs-and-panels#activate", "tabs-and-panels-target": "tab", test: "link_for_#{item[:name]}" }, class: item[:selected] }
%i{ class: item[:icon_class] }
%span= t(".enterprise.#{item[:name] }")
- else
- enterprise_group_side_menu_items.each do |item|
%a.menu_item{ href: "##{item[:name]}_panel", class: item[:selected], id: item[:name], data: { action: "tabs-and-panels#changeActivePanel tabs-and-panels#changeActiveTab", "tabs-and-panels-target": "tab" } }
%a.menu_item{ href: "##{item[:name]}_panel", class: item[:selected], data: { action: "tabs-and-panels#activate", "tabs-and-panels-target": "tab", test: "link_for_#{item[:name]}" } }
%i{ class: item[:icon_class] }
%span= t(".enterprise_group.#{item[:name] }")

View File

@@ -1,5 +1,5 @@
.medium-6#checkout-payment-methods
- if feature?(:vouchers, spree_current_user, @order.distributor) && @order.distributor.vouchers.present?
- if @order.distributor.vouchers.present?
%div.checkout-substep
= render partial: "checkout/voucher_section", locals: { order: @order, voucher_adjustment: @order.voucher_adjustments.first }

View File

@@ -37,20 +37,20 @@
- @grouped_line_items.each_pair do |product_and_full_name, line_items|
%tr
%td
#{line_items.first.variant.sku}
= line_items.first.variant.sku
- if @distributors_pickup_times.many?
%td
#{raw(line_items.first.product.supplier.name)}
= line_items.first.product.supplier.name
%td
#{raw(product_and_full_name)}
= product_and_full_name
%td.text-right
#{line_items.sum(&:quantity)}
= line_items.sum(&:quantity)
%td.text-right
#{line_items.first.single_money}
= line_items.first.single_money
%td.text-right
#{Spree::Money.new(line_items.sum(&:total), currency: line_items.first.currency) }
= Spree::Money.new(line_items.sum(&:total), currency: line_items.first.currency)
%td.tax.text-right
#{Spree::Money.new(line_items.sum(&:included_tax), currency: line_items.first.currency) }
= Spree::Money.new(line_items.sum(&:included_tax), currency: line_items.first.currency)
%tr.total-row
%td
- if @distributors_pickup_times.many?
@@ -59,9 +59,9 @@
%td
%td
%td.text-right
#{@total}
= @total
%td.text-right
#{@tax_total}
= @tax_total
- if @customer_line_items
%p
= t :producer_mail_order_customer_text
@@ -85,33 +85,34 @@
- @customer_line_items.each do |line_item|
%tr
%td
#{line_item[:sku]}
= line_item[:sku]
- if @distributors_pickup_times.many?
%td
#{raw(line_item[:supplier_name])}
= line_item[:supplier_name]
%td
#{raw(line_item[:product_and_full_name])}
= line_item[:product_and_full_name]
%td.text-right
#{line_item[:quantity]}
= line_item[:quantity]
%td
#{raw(line_item[:first_name])}
= line_item[:first_name]
%td
#{raw(line_item[:last_name])}
= line_item[:last_name]
%p
= t :producer_mail_text_after
%p
#{t(:producer_mail_signoff)},
= t(:producer_mail_signoff)
,
%em
%p
#{@coordinator.name}
= @coordinator.name
%p
%br
#{@coordinator.address.address1}
= @coordinator.address.address1
%br
#{@coordinator.address.city}
= @coordinator.address.city
%br
#{@coordinator.address.zipcode}
= @coordinator.address.zipcode
%p
#{@coordinator.phone}
= @coordinator.phone
%p
#{@coordinator.contact.email}
= @coordinator.contact.email

View File

@@ -1,6 +1,6 @@
- if ContentConfig.home_page_alert_html.present?
.alert-cta
%h6= raw ContentConfig.home_page_alert_html
%h6= sanitize(ContentConfig.home_page_alert_html, scrubber: TrixScrubber.new)
- else
= render "shared/register_call"

View File

@@ -8,6 +8,6 @@
%p
= t('.require_login_link_html', login: ('<a data-action="click->login-modal#call">' + t('.login') + '</a>').html_safe)
%p
= t('.require_login_2_html', contact: link_to(t('.contact'), '#contact'), enterprise: current_distributor.name)
= t('.require_login_2_html', contact: link_to(t('.contact'), '#contact_panel', data: { action: "tabs-and-panels#activate" }), enterprise: current_distributor.name)
- else
= t('.require_customer_html', contact: link_to(t('.contact'), '#contact'), enterprise: current_distributor.name)
= t('.require_customer_html', contact: link_to(t('.contact'), '#contact_panel', data: { action: "tabs-and-panels#activate" }), enterprise: current_distributor.name)

View File

@@ -1,12 +1,12 @@
- if (@order&.distributor || current_distributor) == current_distributor
#shop-tabs{"data-controller": "tabs-and-panels shop-tabs", "data-tabs-and-panels-class-name-value": "selected"}
#shop-tabs{"data-controller": "tabs-and-panels", "data-action": "orderCycleSelected@window->tabs-and-panels#activateDefaultPanel", "data-tabs-and-panels-class-name-value": "selected"}
.tab-buttons
.flex.row
.columns.small-12.large-8
- shop_tabs.each do |tab|
.page
%a{ id: tab[:name], href: "##{tab[:name]}_panel", data: { action: "tabs-and-panels#changeActivePanel tabs-and-panels#changeActiveTab", "tabs-and-panels-target": "tab" }, class: ("selected" if tab[:default]) }=tab[:title]
%a{ href: "##{tab[:name]}_panel", data: { action: "tabs-and-panels#activate", "tabs-and-panels-target": "tab" }, class: ("selected" if tab[:default]) }=tab[:title]
.columns.large-4.show-for-large-up
= render partial: "shopping_shared/order_cycles"
- shop_tabs.each do |tab|

View File

@@ -1,3 +1,7 @@
- if show_generate_invoice_button?(@order)
.alert-box.warning
= t('.order_has_changed')
= render partial: 'spree/admin/shared/order_page_title'
= render partial: 'spree/admin/shared/order_tabs', locals: { current: 'Invoices' }

View File

@@ -1,6 +1,6 @@
%h5.inline-header
= "#{raw(line_item.variant.product.name)}"
= line_item.variant.product.name
- unless line_item.variant.product.name.include? line_item.name_to_display
%span= "- #{raw(line_item.name_to_display)}"
%span= "- #{line_item.name_to_display}"
- if line_item.unit_price_price_and_unit
= raw("(#{line_item.unit_price_price_and_unit})")
= raw("(#{line_item.unit_price_price_and_unit})")

View File

@@ -16,7 +16,7 @@
= render 'spree/shared/line_item_name', line_item: item
%br
%small
%em= raw(item.variant.product.supplier.name)
%em= item.variant.product.supplier.name
%td{:align => "right"}
= item.quantity
%td{:align => "right"}
@@ -28,7 +28,7 @@
- taxable = adjustment.adjustable_type == "Spree::Shipment" ? adjustment.adjustable : adjustment
%tr
%td
%strong= "#{raw(adjustment.label)}"
%strong= adjustment.label
%td{:align => "right"}
1
%td{:align => "right"}

View File

@@ -19,7 +19,7 @@
= render 'spree/shared/line_item_name', line_item: item
%br
%small
%em= raw(item.variant.product.supplier.name)
%em= item.variant.product.supplier.name
%td{:align => "right"}
= item.quantity
%td{:align => "right"}
@@ -33,7 +33,7 @@
- checkout_adjustments_for(@order, exclude: [:line_item]).reverse_each do |adjustment|
%tr
%td
%strong= "#{raw(adjustment.label)}"
%strong= adjustment.label
%td{:align => "right"}
%td{:align => "right"}
%td{:align => "right"}

View File

@@ -22,7 +22,7 @@
= render 'spree/admin/orders/_invoice/line_item_name', line_item: item
%br
%small
%em= raw(item.variant.product.supplier.name)
%em= item.variant.product.supplier.name
%td{:align => "right"}
= item.quantity
%td{:align => "right"}
@@ -37,8 +37,8 @@
= item.display_amount_with_adjustments_and_with_taxes
%tr
%td
%strong= "#{t(:shipping)} "
= "( #{t(:invoice_shipping_type)} #{raw(@order.shipping_method.name)} )"
%strong= "#{@order.shipping_method.category} "
= "(#{@order.shipping_method.name})"
%td{:align => "right"}
%td{:align => "right"}
%td{:align => "right"}
@@ -51,7 +51,7 @@
- @order.checkout_adjustments(exclude: [:line_item, :shipment]).reverse_each do |adjustment|
%tr
%td
%strong= "#{raw(adjustment.label)}"
%strong= adjustment.label
%td{:align => "right"}
%td{:align => "right"}
%td{:align => "right"}

View File

@@ -46,6 +46,8 @@
%br
= "#{t :invoice_number}:"
= @order.display_number
- if @order.previous_invoice.present?
= "#{t :invoice_cancel_and_replace_invoice} #{ @order.previous_invoice.display_number}"
%br
= t :invoice_issued_on
= l @order.invoice_date

View File

@@ -2,12 +2,12 @@
= render 'enterprises_header'
- if @enterprises.empty?
%div.sixteen.columns.alpha.list-item.red
%div.sixteen.columns.alpha.list-item.warning
%span.text.fifteen.columns.alpha
= t "spree_admin_enterprises_none_text"
%span.one.columns.omega
%span.icon-remove-sign
%a.sixteen.columns.alpha.button.bottom.red{ href: "#{main_app.new_admin_enterprise_path}" }
%a.sixteen.columns.alpha.button.bottom.warning{ href: "#{main_app.new_admin_enterprise_path}" }
= t "spree_admin_enterprises_none_create_a_new_enterprise"
%span.icon-arrow-right
@@ -27,6 +27,6 @@
%div.sixteen.columns.alpha.list
= render partial: 'enterprise_row', collection: @enterprises, as: :enterprise
%a.sixteen.columns.alpha.button.bottom.blue{ href: "#{main_app.admin_enterprises_path}" }
%a.sixteen.columns.alpha.button.bottom{ href: "#{main_app.admin_enterprises_path}" }
= t "spree_admin_overview_enterprises_footer"
%span.icon-arrow-right

View File

@@ -1,9 +1,9 @@
%div.header.sixteen.columns.alpha{ :class => "#{@enterprises.count > 0 ? "" : "red"}"}
%div.header.sixteen.columns.alpha{ :class => "#{@enterprises.count > 0 ? "" : "warning"}"}
%h3.thirteen.columns.alpha
= t "spree_admin_overview_enterprises_header"
- if @enterprises.any?
- if spree_current_user.can_own_more_enterprises?
%a.three.columns.omega.icon-plus.button.blue.white-bottom{ href: "#{main_app.new_admin_enterprise_path}" }
%a.three.columns.omega.icon-plus.button.white-bottom{ href: "#{main_app.new_admin_enterprise_path}" }
= t "spree_admin_enterprises_create_new"
- else
%a{ "ofn-with-tip" => t('.ofn_with_tip') }

View File

@@ -1,11 +1,11 @@
- color_class = @order_cycle_count > 0 ? "blue" : "orange"
- icon_class = @order_cycle_count > 0 ? "icon-ok-sign" : "icon-warning-sign"
- color_class = "warning" unless @order_cycle_count.positive?
- icon_class = @order_cycle_count.positive? ? "icon-ok-sign" : "icon-warning-sign"
%div.dashboard_item.seven.columns.omega#order_cycles
%div.header.sixteen.columns.alpha{class: color_class}
%h3.ten.columns.alpha
= t ".order_cycles"
- if @order_cycle_count > 0
%a.six.columns.omega.icon-plus.button.blue{ href: main_app.new_admin_order_cycle_path }
- if @order_cycle_count.positive?
%a.six.columns.omega.icon-plus.button{ href: main_app.new_admin_order_cycle_path }
= t "spree_admin_enterprises_create_new"
- else
%a{ "ofn-with-tip" => t(".order_cycles_tip") }
@@ -13,9 +13,9 @@
%div.sixteen.columns.alpha.list
%div.sixteen.columns.alpha.list-item{class: color_class}
%span.thirteen.columns.alpha
= t('.you_have_active', count: @order_cycle_count)
= t(".you_have_active", count: @order_cycle_count)
%span.three.columns.omega
%span{class: icon_class}
%a.sixteen.columns.alpha.button.bottom{ href: main_app.admin_order_cycles_path, class: color_class }
= t ".manage_order_cycles"
%span.icon-arrow-right
%a.sixteen.columns.alpha.button.bottom{ href: main_app.admin_order_cycles_path, class: color_class }
= t ".manage_order_cycles"
%span.icon-arrow-right

View File

@@ -1,29 +1,26 @@
- color_class = "warning" unless @product_count.positive?
- icon_class = @product_count.positive? ? "icon-ok-sign" : "icon-remove-sign"
%div.dashboard_item.seven.columns.alpha#products
%div.header.sixteen.columns.alpha{ :class => "#{@product_count > 0 ? "" : "red"}"}
%div.header.sixteen.columns.alpha{class: color_class}
%h3.ten.columns.alpha
= t "products"
- if @product_count > 0
%a.six.columns.omega.icon-plus.button.blue{ href: "#{new_admin_product_path}" }
- if @product_count.positive?
%a.six.columns.omega.icon-plus.button{ href: new_admin_product_path }
= t "spree_admin_enterprises_create_new"
- else
%a{ "ofn-with-tip" => t(".products_tip") }
= t "admin.whats_this"
%div.sixteen.columns.alpha.list
- if @product_count > 0
%div.sixteen.columns.alpha.list-item
%span.thirteen.columns.alpha
= t(".active_products", count: @product_count )
%span.three.columns.omega
%span.icon-ok-sign
%a.sixteen.columns.alpha.button.bottom.blue{ href: "#{admin_products_path}" }
= t "spree_admin_enterprises_producers_manage_products"
%span.icon-arrow-right
- else
%div.sixteen.columns.alpha.list-item.red
%span.thirteen.columns.alpha
= t(".active_products", count: @product_count )
%span.three.columns.omega
%span.icon-remove-sign
%a.sixteen.columns.alpha.button.bottom.red{ href: "#{new_admin_product_path}" }
= t "spree_admin_enterprises_create_new_product"
%span.icon-arrow-right
%div.sixteen.columns.alpha.list-item{class: color_class}
%span.thirteen.columns.alpha
= t(".active_products", count: @product_count)
%span.three.columns.omega
%span{class: icon_class}
- if @product_count.positive?
%a.sixteen.columns.alpha.button.bottom{ href: admin_products_path, class: color_class }
= t "spree_admin_enterprises_producers_manage_products"
%span.icon-arrow-right
- else
%a.sixteen.columns.alpha.button.bottom{ href: new_admin_product_path, class: color_class }
= t "spree_admin_enterprises_create_new_product"
%span.icon-arrow-right

View File

@@ -1,11 +1,10 @@
- content_for :page_title do
= t('dashboard')
- content_for :page_actions do
= render 'admin/shared/user_guide_link'
%div{ 'ng-app' => 'ofn.admin' }
%h1{ :style => 'margin-bottom: 30px' }
= t 'dashboard'
- if @enterprises.empty?
= render partial: "enterprises"

View File

@@ -1,6 +1,6 @@
- content_for :sub_menu do
%ul#sub_nav.inline-menu
= tab :products
= tab :products, :products_v3
= tab :properties
= tab :variant_overrides, url: main_app.admin_inventory_path, match_path: '/inventory'
= tab :import, url: main_app.admin_product_import_path, match_path: '/product_import'

View File

@@ -1,5 +1,5 @@
= tab :overview, label: 'dashboard', url: spree.admin_dashboard_path, icon: 'icon-dashboard'
= tab :products, :properties, :inventory, :product_import, :images, :variants, :product_properties, :group_buy_options, :seo, url: admin_products_path, icon: 'icon-th-large'
= tab :products, :properties, :inventory, :product_import, :images, :variants, :product_properties, :group_buy_options, :seo, :products_v3, :variant_overrides, url: admin_products_path, icon: 'icon-th-large'
= tab :order_cycles, url: main_app.admin_order_cycles_path, icon: 'icon-refresh'
= tab :orders, :subscriptions, :customer_details, :adjustments, :payments, :return_authorizations, url: admin_orders_path, icon: 'icon-shopping-cart'
= tab :reports, url: main_app.admin_reports_path, icon: 'icon-file'
@@ -8,4 +8,4 @@
= tab :customers, url: main_app.admin_customers_path
= tab :enterprise_groups, url: main_app.admin_enterprise_groups_path, label: 'groups'
- if can? :admin, Spree::User
= tab(:users, url: spree.admin_users_path, icon: 'icon-user')
= tab(:users, :enterprise_roles, url: spree.admin_users_path, icon: 'icon-user')

View File

@@ -59,6 +59,8 @@
%span= yield :sidebar_title
= 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}\";"

View File

@@ -20,7 +20,7 @@
= render 'spree/shared/line_item_name', line_item: item
%br
%small
%em= raw(item.variant.product.supplier.name)
%em= item.variant.product.supplier.name
%td
- if item.variant.sku.blank?
\-
@@ -43,7 +43,7 @@
- checkout_adjustments_for(@order, exclude: [:line_item]).reverse_each do |adjustment|
%tr
%td{align: "right", colspan: "3"}
= "#{raw(adjustment.label)}:"
= "#{adjustment.label}:"
%td{align: "right"}
= adjustment.display_amount
%tr

View File

@@ -6,7 +6,7 @@
= t(:order_back_to_cart)
- else
.columns.small-12.medium-6
= link_to "#{main_app.enterprise_shop_path(@order.distributor)}#/shop", class: "button expand" do
= link_to "#{main_app.enterprise_shop_path(@order.distributor)}#/shop_panel", class: "button expand" do
= t(:order_back_to_store)
.columns.small-12.medium-6
- if @order.distributor.website.present?

View File

@@ -1,6 +1,6 @@
%h5.inline-header
= "#{raw(line_item.product.name)}"
= "#{line_item.product.name}"
- unless line_item.product.name.include? line_item.name_to_display
%span= "- #{raw(line_item.name_to_display)}"
%span= "- #{line_item.name_to_display}"
- if line_item.options_text
= "(#{raw(line_item.options_text)})"
= "(#{line_item.options_text})"

View File

@@ -1,7 +1,7 @@
import { Controller } from "stimulus";
export default class extends Controller {
static values = { target: String };
static values = { target: String, modalDataset: Object };
open() {
let modal = document.getElementById(this.targetValue);
@@ -12,6 +12,21 @@ export default class extends Controller {
modalController.open();
}
setModalDataSetOnConfirm(event) {
try {
const modalId = this.targetValue;
const moodalConfirmButtonQuery = `#${modalId} #modal-confirm-button`;
const confirmButton = document.querySelector(moodalConfirmButtonQuery);
Object.keys(this.modalDatasetValue).forEach((datasetKey) => {
confirmButton.setAttribute(datasetKey, this.modalDatasetValue[datasetKey]);
});
} catch (e) {
// In case of any type of error in setting the dataset value, stop the further actions i.e. opening the modal
event.stopImmediatePropagation();
throw e;
}
}
getIdentifier() {
return "modal";
}

View File

@@ -2,6 +2,7 @@ import ApplicationController from "./application_controller";
export default class extends ApplicationController {
static targets = ["loading"];
static values = { currentId: Number };
connect() {
super.connect();

View File

@@ -1,22 +0,0 @@
import { Controller } from "stimulus";
export default class extends Controller {
connect() {
window.addEventListener("orderCycleSelected", this.orderCycleSelected);
}
disconnect() {
window.removeEventListener("orderCycleSelected", this.orderCycleSelected);
}
orderCycleSelected = (event) => {
window.dispatchEvent(
new CustomEvent("tabs-and-panels:click", {
detail: {
tab: "shop",
panel: "shop_panel",
},
})
);
};
}

View File

@@ -5,93 +5,46 @@ export default class extends Controller {
static values = { className: String };
connect() {
// hide all active panel
this.panelTargets.forEach((panel) => {
panel.style.display = "none";
});
// only display the default panel
this.defaultTarget.style.display = "block";
// Display panel specified in url anchor
const anchors = window.location.toString().split("#");
let anchor = anchors.length > 1 ? anchors.pop() : "";
if (anchor != "") {
// Conveniently AngularJs rewrite "example.com#panel" to "example.com#/panel" :(
// strip the starting / if any
if (anchor[0] == "/") {
anchor = anchor.slice(1);
}
// Add _panel to the anchor to match the panel id if needed
if (!anchor.includes("_panel")) {
anchor = `${anchor}_panel`;
}
this.updateActivePanel(anchor);
// tab
const tab_id = anchor.split("_panel").shift();
this.updateActiveTab(tab_id);
}
window.addEventListener("tabs-and-panels:click", (event) => {
this.simulateClick(event.detail.tab, event.detail.panel);
});
this._activateFromWindowLocationOrDefaultPanelTarget();
window.addEventListener("popstate", (event) => {
const newPanelId = event.target.location.hash.replace("#/", "");
const currentPanelId = this.currentActivePanel.id;
if (newPanelId !== currentPanelId) {
const newTabId = newPanelId.split("_panel").shift();
this.simulateClick(newTabId, newPanelId);
}
this._activateFromWindowLocationOrDefaultPanelTarget();
});
}
simulateClick(tab, panel) {
this.updateActivePanel(panel);
this.updateActiveTab(tab);
}
changeActivePanel(event) {
this.updateActivePanel(`${event.currentTarget.id}_panel`);
}
updateActivePanel(panel_id) {
const newActivePanel = this.panelTargets.find((panel) => panel.id == panel_id);
if (newActivePanel === undefined) {
// No panel found
return;
_activateFromWindowLocationOrDefaultPanelTarget() {
// Conveniently AngularJs rewrite "example.com#panel" to "example.com#/panel"
const hashWithoutSlash = window.location.hash.replace("/", "");
const tabWithSameHash = this.tabTargets.find((tab) => tab.hash == hashWithoutSlash);
if (hashWithoutSlash != "" && tabWithSameHash) {
this._activateByHash(tabWithSameHash.hash);
} else {
this._activateByHash(`#${this.defaultTarget.id}`);
}
this.currentActivePanel.style.display = "none";
newActivePanel.style.display = "block";
}
changeActiveTab(event) {
this.currentActiveTab.classList.remove(`${this.classNameValue}`);
event.currentTarget.classList.add(`${this.classNameValue}`);
activate(event) {
this._activateByHash(event.currentTarget.hash);
}
updateActiveTab(tab_id) {
const newActiveTab = this.tabTargets.find((tab) => tab.id == tab_id);
if (newActiveTab === undefined) {
// No tab found
return;
}
this.currentActiveTab.classList.remove(`${this.classNameValue}`);
newActiveTab.classList.add(`${this.classNameValue}`);
activateDefaultPanel() {
this._activateByHash(`#${this.defaultTarget.id}`);
}
get currentActiveTab() {
return this.tabTargets.find((tab) => tab.classList.contains("selected"));
}
get currentActivePanel() {
return this.panelTargets.find((panel) => panel.id == `${this.currentActiveTab.id}_panel`);
_activateByHash(hash) {
this.tabTargets.forEach((tab) => {
if (tab.hash == hash) {
tab.classList.add(this.classNameValue);
} else {
tab.classList.remove(this.classNameValue);
}
});
this.panelTargets.forEach((panel) => {
if (panel.id == hash.replace("#", "")) {
panel.style.display = "block";
} else {
panel.style.display = "none";
}
});
}
}

View File

@@ -83,6 +83,7 @@
@import "alert";
@import "animations";
@import "change_type_form";
@import "connected_apps";
@import "customers";
@import "dashboard_item";
@import "dashboard-single-ent";
@@ -111,6 +112,7 @@
@import "side_menu";
@import "tables";
@import "tag_rules";
@import "terms_of_service_banner";
@import "terms_of_service_files";
@import "validation";
@import "variant_overrides";

View File

@@ -0,0 +1,41 @@
#connected_apps_panel {
max-width: 615px;
}
.connected-app__head {
display: flex;
justify-content: space-between;
margin-bottom: 1em;
h3 {
margin-bottom: 1em;
}
}
.connected-app__description {
p {
margin-bottom: 1em;
}
}
.connected-app__note {
display: flex;
justify-content: space-between;
background-color: $color-14;
border: none;
border-left: $border-radius solid $color-3;
border-radius: $border-radius;
box-shadow: 0px 1px 0px rgba(0, 0, 0, 0.05), 0px 2px 2px rgba(0, 0, 0, 0.07);
margin: 2em 0;
padding: 0.5em 1em;
align-items: center;
gap: 1em;
* {
flex-shrink: 0;
}
p {
flex-shrink: 1;
}
}

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