mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-03-01 02:03:22 +00:00
Compare commits
1 Commits
v5.3.8
...
RachL-patc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5020cc740 |
56
.codeclimate.yml
Normal file
56
.codeclimate.yml
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
version: "2"
|
||||||
|
plugins:
|
||||||
|
rubocop:
|
||||||
|
enabled: true
|
||||||
|
channel: "rubocop-1-12"
|
||||||
|
config:
|
||||||
|
file: ".rubocop.yml"
|
||||||
|
scss-lint:
|
||||||
|
enabled: true
|
||||||
|
checks:
|
||||||
|
ImportantRule:
|
||||||
|
enabled: false
|
||||||
|
VendorPrefix:
|
||||||
|
enabled: false
|
||||||
|
LeadingZero:
|
||||||
|
enabled: false
|
||||||
|
PropertySortOrder:
|
||||||
|
enabled: false
|
||||||
|
StringQuotes:
|
||||||
|
enabled: false
|
||||||
|
DeclarationOrder:
|
||||||
|
enabled: false
|
||||||
|
NestingDepth:
|
||||||
|
enabled: false
|
||||||
|
|
||||||
|
duplication:
|
||||||
|
enabled: true
|
||||||
|
exclude_patterns:
|
||||||
|
- "db/**"
|
||||||
|
- "config/initializers/active_record_postgresql_referential_integrity_patch.rb"
|
||||||
|
checks:
|
||||||
|
argument-count:
|
||||||
|
enabled: false
|
||||||
|
complex-logic:
|
||||||
|
enabled: false
|
||||||
|
file-lines:
|
||||||
|
enabled: false
|
||||||
|
method-complexity:
|
||||||
|
enabled: false
|
||||||
|
method-count:
|
||||||
|
enabled: false
|
||||||
|
method-lines:
|
||||||
|
enabled: false
|
||||||
|
nested-control-flow:
|
||||||
|
enabled: false
|
||||||
|
return-statements:
|
||||||
|
enabled: false
|
||||||
|
similar-code:
|
||||||
|
enabled: false
|
||||||
|
identical-code:
|
||||||
|
enabled: false
|
||||||
|
exclude_patterns:
|
||||||
|
- "spec/**/*"
|
||||||
|
- "vendor/**/*"
|
||||||
|
- "app/assets/javascripts/shared/*"
|
||||||
|
- "app/assets/javascripts/jquery-migrate-1.0.0.js"
|
||||||
@@ -6,9 +6,9 @@
|
|||||||
# cp .env.development .env.local
|
# cp .env.development .env.local
|
||||||
|
|
||||||
# Locale for translation. Using a locale other than `en` tests the
|
# Locale for translation. Using a locale other than `en` tests the
|
||||||
# successful fallback to `en`. To see up-to-date text used in production,
|
# successful fallback to `en`. You will also see up-to-date text used
|
||||||
# set another locale in a local env file.
|
# in production
|
||||||
LOCALE="en_TST"
|
LOCALE="en_AU"
|
||||||
|
|
||||||
VERBOSE_QUERY_LOGS=true
|
VERBOSE_QUERY_LOGS=true
|
||||||
|
|
||||||
@@ -16,9 +16,8 @@ SECRET_TOKEN="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
|
|||||||
|
|
||||||
OFN_REDIS_URL="redis://localhost:6379/1"
|
OFN_REDIS_URL="redis://localhost:6379/1"
|
||||||
OFN_REDIS_JOBS_URL="redis://localhost:6379/2"
|
OFN_REDIS_JOBS_URL="redis://localhost:6379/2"
|
||||||
OFN_REDIS_CABLE_URL="redis://localhost:6379/0"
|
|
||||||
|
|
||||||
SITE_URL="localhost:3000"
|
SITE_URL="0.0.0.0:3000"
|
||||||
|
|
||||||
# Deactivate rack-timeout in development.
|
# Deactivate rack-timeout in development.
|
||||||
# https://github.com/zombocom/rack-timeout#configuring
|
# https://github.com/zombocom/rack-timeout#configuring
|
||||||
|
|||||||
18
.env.test
18
.env.test
@@ -1,17 +1,8 @@
|
|||||||
# ENV vars for the test environment
|
# ENV vars for the test environment
|
||||||
# Override locally with `.env.test.local`
|
# Override locally with `.env.test.local`
|
||||||
|
|
||||||
# Test env specific variables
|
# Locale for translation.
|
||||||
#
|
LOCALE="en_TEST"
|
||||||
# Adjust this to your computer. When you start test-driven development, you may
|
|
||||||
# want to reduce this value to avoid waiting for a test that you expect to fail.
|
|
||||||
CAPYBARA_MAX_WAIT_TIME="10"
|
|
||||||
|
|
||||||
# General app specific variables
|
|
||||||
|
|
||||||
# Locale for translation. Using a locale other than `en` tests the
|
|
||||||
# successful fallback to `en`.
|
|
||||||
LOCALE="en_TST"
|
|
||||||
|
|
||||||
OFN_REDIS_JOBS_URL="redis://localhost:6379/2"
|
OFN_REDIS_JOBS_URL="redis://localhost:6379/2"
|
||||||
|
|
||||||
@@ -20,13 +11,10 @@ STRIPE_INSTANCE_SECRET_KEY="bogus_key"
|
|||||||
STRIPE_CUSTOMER="bogus_customer"
|
STRIPE_CUSTOMER="bogus_customer"
|
||||||
STRIPE_ACCOUNT="bogus_account"
|
STRIPE_ACCOUNT="bogus_account"
|
||||||
STRIPE_CLIENT_ID="bogus_client_id"
|
STRIPE_CLIENT_ID="bogus_client_id"
|
||||||
|
STRIPE_PUBLIC_TEST_API_KEY="bogus_stripe_publishable_key"
|
||||||
|
|
||||||
SITE_URL="test.host"
|
SITE_URL="test.host"
|
||||||
|
|
||||||
# OIDC Settings for DFC authentication
|
|
||||||
# Find secrets in BitWarden.
|
|
||||||
# To get a refresh token: log into the OIDC provider, connect your OFN user to it at /admin/oidc_settings, then copy the token from the database:
|
|
||||||
# ./bin/rails runner 'puts "OPENID_REFRESH_TOKEN=\"#{OidcAccount.last.refresh_token}\""'
|
|
||||||
OPENID_APP_ID="test-provider"
|
OPENID_APP_ID="test-provider"
|
||||||
OPENID_APP_SECRET="dummy-openid-app-secret-token"
|
OPENID_APP_SECRET="dummy-openid-app-secret-token"
|
||||||
OPENID_REFRESH_TOKEN="dummy-refresh-token"
|
OPENID_REFRESH_TOKEN="dummy-refresh-token"
|
||||||
|
|||||||
2
.github/ISSUE_TEMPLATE/release.md
vendored
2
.github/ISSUE_TEMPLATE/release.md
vendored
@@ -13,7 +13,6 @@ assignees: ''
|
|||||||
- [ ] Include translations: `script/release/update_locales`
|
- [ ] Include translations: `script/release/update_locales`
|
||||||
- You need the [Transifex Client] installed on your local dev environement to run the script.
|
- You need the [Transifex Client] installed on your local dev environement to run the script.
|
||||||
- [ ] Increment version number: `git push upstream HEAD:refs/tags/vX.Y.Z`
|
- [ ] Increment version number: `git push upstream HEAD:refs/tags/vX.Y.Z`
|
||||||
Check for [minor or major breaking changes]
|
|
||||||
- Major: if server changes are required (eg. provision with ofn-install)
|
- Major: if server changes are required (eg. provision with ofn-install)
|
||||||
- Minor: larger change that is irreversible (eg. migration deleting data)
|
- Minor: larger change that is irreversible (eg. migration deleting data)
|
||||||
- Patch: all others. Shortcut: `script/release/tag`
|
- Patch: all others. Shortcut: `script/release/tag`
|
||||||
@@ -57,4 +56,3 @@ 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
|
[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
|
[#delivery-circle]: https://openfoodnetwork.slack.com/archives/C01T75H6G0Z
|
||||||
[Transifex Client]: https://developers.transifex.com/docs/cli
|
[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
|
|
||||||
25
.github/dependabot.yml
vendored
25
.github/dependabot.yml
vendored
@@ -4,28 +4,7 @@
|
|||||||
# Most of the configuration here is not used for security updates though.
|
# Most of the configuration here is not used for security updates though.
|
||||||
|
|
||||||
version: 2
|
version: 2
|
||||||
|
|
||||||
multi-ecosystem-groups:
|
|
||||||
turbo_power:
|
|
||||||
schedule:
|
|
||||||
interval: "daily"
|
|
||||||
|
|
||||||
updates:
|
updates:
|
||||||
- package-ecosystem: "bundler"
|
|
||||||
directory: "/"
|
|
||||||
patterns: ["turbo_power"]
|
|
||||||
multi-ecosystem-group: "turbo_power"
|
|
||||||
|
|
||||||
# Only specific requirements are specified in Gemfile, so don't touch it.
|
|
||||||
versioning-strategy: lockfile-only
|
|
||||||
|
|
||||||
- package-ecosystem: "npm"
|
|
||||||
directory: "/"
|
|
||||||
patterns: ["turbo_power"]
|
|
||||||
multi-ecosystem-group: "turbo_power"
|
|
||||||
|
|
||||||
# Only specific requirements are specified in package.json, so don't touch it.
|
|
||||||
versioning-strategy: lockfile-only
|
|
||||||
|
|
||||||
- package-ecosystem: "bundler"
|
- package-ecosystem: "bundler"
|
||||||
directory: "/"
|
directory: "/"
|
||||||
@@ -40,5 +19,5 @@ updates:
|
|||||||
schedule:
|
schedule:
|
||||||
interval: "daily"
|
interval: "daily"
|
||||||
|
|
||||||
# Only specific requirements are specified in package.json, so don't touch it.
|
# All versions are specified in package.json, so please update them.
|
||||||
versioning-strategy: lockfile-only
|
versioning-strategy: increase
|
||||||
|
|||||||
6
.github/release.yml
vendored
6
.github/release.yml
vendored
@@ -14,12 +14,6 @@ changelog:
|
|||||||
- technical changes only
|
- technical changes only
|
||||||
- user facing changes
|
- user facing changes
|
||||||
|
|
||||||
# These will require a minor or major version increment
|
|
||||||
- title: "Significant changes 🚀"
|
|
||||||
labels:
|
|
||||||
- breaking change
|
|
||||||
- major breaking change
|
|
||||||
|
|
||||||
# Posted in advance for #instance-managers
|
# Posted in advance for #instance-managers
|
||||||
- title: "User-facing changes 👀"
|
- title: "User-facing changes 👀"
|
||||||
labels:
|
labels:
|
||||||
|
|||||||
15
.github/test-events/dependabot-pr.json
vendored
15
.github/test-events/dependabot-pr.json
vendored
@@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"pull_request": {
|
|
||||||
"number": 13545,
|
|
||||||
"title": "Bump test from 7.0.4 to 7.0.8",
|
|
||||||
"user": {
|
|
||||||
"login": "dependabot[bot]"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"owner": {
|
|
||||||
"login": "openfoodfoundation"
|
|
||||||
},
|
|
||||||
"name": "openfoodnetwork"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
51
.github/workflows/brakeman-analysis.yml
vendored
Normal file
51
.github/workflows/brakeman-analysis.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# This workflow integrates Brakeman with GitHub's Code Scanning feature
|
||||||
|
# Brakeman is a static analysis security vulnerability scanner for Ruby on Rails applications
|
||||||
|
|
||||||
|
name: Brakeman Scan
|
||||||
|
|
||||||
|
# This section configures the trigger for the workflow. Feel free to customize depending on your convention
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
brakeman-scan:
|
||||||
|
permissions:
|
||||||
|
contents: read # for actions/checkout to fetch code
|
||||||
|
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
|
||||||
|
name: Brakeman Scan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# Checkout the repository to the GitHub Actions runner
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
|
# Customize the ruby version depending on your needs
|
||||||
|
- name: Setup Ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
ruby-version: '2.7'
|
||||||
|
|
||||||
|
- name: Setup Brakeman
|
||||||
|
env:
|
||||||
|
BRAKEMAN_VERSION: '5.4.0'
|
||||||
|
run: |
|
||||||
|
gem install brakeman --version $BRAKEMAN_VERSION
|
||||||
|
|
||||||
|
# Execute Brakeman CLI and generate a SARIF output with the security issues identified during the analysis
|
||||||
|
- name: Scan
|
||||||
|
continue-on-error: true
|
||||||
|
run: |
|
||||||
|
git show --no-patch # the commit being tested (which is often a merge due to actions/checkout@v3)
|
||||||
|
brakeman -f sarif -o output.sarif.json .
|
||||||
|
|
||||||
|
# Upload the SARIF file generated in the previous step
|
||||||
|
- name: Upload SARIF
|
||||||
|
uses: github/codeql-action/upload-sarif@v2
|
||||||
|
with:
|
||||||
|
sarif_file: output.sarif.json
|
||||||
227
.github/workflows/build.yml
vendored
227
.github/workflows/build.yml
vendored
@@ -17,7 +17,85 @@ permissions:
|
|||||||
contents: read
|
contents: read
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
controllers_and_models:
|
controllers:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:10
|
||||||
|
ports: ["5432:5432"]
|
||||||
|
options: >-
|
||||||
|
--health-cmd pg_isready
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: open_food_network_test
|
||||||
|
POSTGRES_USER: ofn
|
||||||
|
POSTGRES_PASSWORD: f00d
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# [n] - where the n is a number of parallel jobs you want to run your tests on.
|
||||||
|
# Use a higher number if you have slow tests to split them between more parallel jobs.
|
||||||
|
# Remember to update the value of the `ci_node_index` below to (0..n-1).
|
||||||
|
ci_node_total: [8]
|
||||||
|
# Indexes for parallel jobs (starting from zero).
|
||||||
|
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
|
||||||
|
ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup redis
|
||||||
|
uses: supercharge/redis-github-action@1.4.0
|
||||||
|
with:
|
||||||
|
redis-version: 6
|
||||||
|
|
||||||
|
- name: Set up Ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||||
|
|
||||||
|
# JS is required in order for webpacker to compile, in order to render templates containing image urls
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Install JS dependencies
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Set up database
|
||||||
|
run: |
|
||||||
|
bin/rake db:create db:schema:load
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
env:
|
||||||
|
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC: 864ef557d85ea8e603e086c0387d5154
|
||||||
|
KNAPSACK_PRO_CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
|
||||||
|
KNAPSACK_PRO_CI_NODE_INDEX: ${{ matrix.ci_node_index }}
|
||||||
|
KNAPSACK_PRO_LOG_LEVEL: info
|
||||||
|
# if you use Knapsack Pro Queue Mode you must set below env variable
|
||||||
|
# to be able to retry CI build and run previously recorded tests
|
||||||
|
# https://github.com/KnapsackPro/knapsack_pro-ruby#knapsack_pro_fixed_queue_split-remember-queue-split-on-retry-ci-node
|
||||||
|
# KNAPSACK_PRO_FIXED_QUEUE_SPLIT: false
|
||||||
|
# RSpec split test files by test examples feature - it's optional
|
||||||
|
# https://knapsackpro.com/faq/question/how-to-split-slow-rspec-test-files-by-test-examples-by-individual-it
|
||||||
|
#KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES: true
|
||||||
|
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/controllers/**/*_spec.rb}"
|
||||||
|
run: |
|
||||||
|
git show --no-patch # the commit being tested (which is often a merge due to actions/checkout@v3)
|
||||||
|
bin/rake knapsack_pro:rspec
|
||||||
|
|
||||||
|
- name: Save SimpleCov file
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: simplecov-chunk-controllers-${{ matrix.ci_node_index }}
|
||||||
|
path: coverage/*.*
|
||||||
|
retention-days: 2 # doesn't need to be long, because it's the combined results that matter
|
||||||
|
if-no-files-found: ignore
|
||||||
|
include-hidden-files: true
|
||||||
|
|
||||||
|
models:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
@@ -55,22 +133,13 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||||
|
|
||||||
# JS is required in order for webpacker to compile, in order to render templates containing image urls
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version-file: .node-version
|
|
||||||
cache: yarn
|
|
||||||
|
|
||||||
- name: Install JS dependencies
|
|
||||||
run: yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
- name: Set up database
|
- name: Set up database
|
||||||
run: |
|
run: |
|
||||||
bin/rails db:create db:schema:load
|
bin/rake db:create db:schema:load
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
env:
|
env:
|
||||||
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC: 864ef557d85ea8e603e086c0387d5154
|
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC: 09476e2ce491c12083df62768667c674
|
||||||
KNAPSACK_PRO_CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
|
KNAPSACK_PRO_CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
|
||||||
KNAPSACK_PRO_CI_NODE_INDEX: ${{ matrix.ci_node_index }}
|
KNAPSACK_PRO_CI_NODE_INDEX: ${{ matrix.ci_node_index }}
|
||||||
KNAPSACK_PRO_LOG_LEVEL: info
|
KNAPSACK_PRO_LOG_LEVEL: info
|
||||||
@@ -81,21 +150,20 @@ jobs:
|
|||||||
# RSpec split test files by test examples feature - it's optional
|
# RSpec split test files by test examples feature - it's optional
|
||||||
# https://knapsackpro.com/faq/question/how-to-split-slow-rspec-test-files-by-test-examples-by-individual-it
|
# https://knapsackpro.com/faq/question/how-to-split-slow-rspec-test-files-by-test-examples-by-individual-it
|
||||||
#KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES: true
|
#KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES: true
|
||||||
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/controllers/**/*_spec.rb,spec/models/**/*_spec.rb}"
|
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/models/**/*_spec.rb}"
|
||||||
run: |
|
run: |
|
||||||
git show --no-patch # the commit being tested (which is often a merge due to actions/checkout@v3)
|
bin/rake knapsack_pro:rspec
|
||||||
bin/rails assets:precompile knapsack_pro:rspec
|
|
||||||
|
|
||||||
- name: Save SimpleCov file
|
- name: Save SimpleCov file
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: simplecov-chunk-controllers-${{ matrix.ci_node_index }}
|
name: simplecov-chunk-models-${{ matrix.ci_node_index }}
|
||||||
path: coverage/*.*
|
path: coverage/*.*
|
||||||
retention-days: 2 # doesn't need to be long, because it's the combined results that matter
|
retention-days: 2 # doesn't need to be long, because it's the combined results that matter
|
||||||
if-no-files-found: ignore
|
if-no-files-found: ignore
|
||||||
include-hidden-files: true
|
include-hidden-files: true
|
||||||
|
|
||||||
system:
|
system_admin:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
services:
|
services:
|
||||||
postgres:
|
postgres:
|
||||||
@@ -116,10 +184,10 @@ jobs:
|
|||||||
# [n] - where the n is a number of parallel jobs you want to run your tests on.
|
# [n] - where the n is a number of parallel jobs you want to run your tests on.
|
||||||
# Use a higher number if you have slow tests to split them between more parallel jobs.
|
# Use a higher number if you have slow tests to split them between more parallel jobs.
|
||||||
# Remember to update the value of the `ci_node_index` below to (0..n-1).
|
# Remember to update the value of the `ci_node_index` below to (0..n-1).
|
||||||
ci_node_total: [19]
|
ci_node_total: [14]
|
||||||
# Indexes for parallel jobs (starting from zero).
|
# Indexes for parallel jobs (starting from zero).
|
||||||
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
|
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
|
||||||
ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
|
ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
@@ -143,7 +211,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up database
|
- name: Set up database
|
||||||
run: |
|
run: |
|
||||||
bin/rails db:create db:schema:load
|
bin/rake db:create db:schema:load
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
|
||||||
@@ -159,15 +227,15 @@ jobs:
|
|||||||
# RSpec split test files by test examples feature - it's optional
|
# RSpec split test files by test examples feature - it's optional
|
||||||
# https://knapsackpro.com/faq/question/how-to-split-slow-rspec-test-files-by-test-examples-by-individual-it
|
# https://knapsackpro.com/faq/question/how-to-split-slow-rspec-test-files-by-test-examples-by-individual-it
|
||||||
#KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES: true
|
#KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES: true
|
||||||
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/system/admin/**/*_spec.rb,spec/system/consumer/**/*_spec.rb}"
|
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/system/admin/**/*_spec.rb}"
|
||||||
|
|
||||||
run: |
|
run: |
|
||||||
bin/rails assets:precompile knapsack_pro:queue:rspec
|
bin/rake knapsack_pro:queue:rspec
|
||||||
|
|
||||||
- name: Save SimpleCov file
|
- name: Save SimpleCov file
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: simplecov-chunk-system-${{ matrix.ci_node_index }}
|
name: simplecov-chunk-system-admin-${{ matrix.ci_node_index }}
|
||||||
path: coverage/*.*
|
path: coverage/*.*
|
||||||
retention-days: 2 # doesn't need to be long, because it's the combined results that matter
|
retention-days: 2 # doesn't need to be long, because it's the combined results that matter
|
||||||
if-no-files-found: ignore
|
if-no-files-found: ignore
|
||||||
@@ -177,7 +245,94 @@ jobs:
|
|||||||
if: failure()
|
if: failure()
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: failed-system_${{ matrix.ci_node_index }}-tests-screenshots
|
name: failed-admin_${{ matrix.ci_node_index }}-tests-screenshots
|
||||||
|
path: tmp/capybara/screenshots/*.png
|
||||||
|
retention-days: 7
|
||||||
|
if-no-files-found: ignore
|
||||||
|
|
||||||
|
system_consumer:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:10
|
||||||
|
ports: ["5432:5432"]
|
||||||
|
options: >-
|
||||||
|
--health-cmd pg_isready
|
||||||
|
--health-interval 10s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 5
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: open_food_network_test
|
||||||
|
POSTGRES_USER: ofn
|
||||||
|
POSTGRES_PASSWORD: f00d
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# [n] - where the n is a number of parallel jobs you want to run your tests on.
|
||||||
|
# Use a higher number if you have slow tests to split them between more parallel jobs.
|
||||||
|
# Remember to update the value of the `ci_node_index` below to (0..n-1).
|
||||||
|
ci_node_total: [12]
|
||||||
|
# Indexes for parallel jobs (starting from zero).
|
||||||
|
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
|
||||||
|
ci_node_index: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- name: Setup redis
|
||||||
|
uses: supercharge/redis-github-action@1.4.0
|
||||||
|
with:
|
||||||
|
redis-version: 6
|
||||||
|
|
||||||
|
- name: Set up Ruby
|
||||||
|
uses: ruby/setup-ruby@v1
|
||||||
|
with:
|
||||||
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
cache: yarn
|
||||||
|
|
||||||
|
- name: Install JS dependencies
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: Set up database
|
||||||
|
run: |
|
||||||
|
bin/rake db:create db:schema:load
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
|
||||||
|
env:
|
||||||
|
KNAPSACK_PRO_TEST_SUITE_TOKEN_RSPEC: e52bd4390c853e6c5bdfe4d0334586c1
|
||||||
|
KNAPSACK_PRO_CI_NODE_TOTAL: ${{ matrix.ci_node_total }}
|
||||||
|
KNAPSACK_PRO_CI_NODE_INDEX: ${{ matrix.ci_node_index }}
|
||||||
|
KNAPSACK_PRO_LOG_LEVEL: info
|
||||||
|
# if you use Knapsack Pro Queue Mode you must set below env variable
|
||||||
|
# to be able to retry CI build and run previously recorded tests
|
||||||
|
# https://github.com/KnapsackPro/knapsack_pro-ruby#knapsack_pro_fixed_queue_split-remember-queue-split-on-retry-ci-node
|
||||||
|
KNAPSACK_PRO_FIXED_QUEUE_SPLIT: true
|
||||||
|
# RSpec split test files by test examples feature - it's optional
|
||||||
|
# https://knapsackpro.com/faq/question/how-to-split-slow-rspec-test-files-by-test-examples-by-individual-it
|
||||||
|
#KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES: true
|
||||||
|
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/system/consumer/**/*_spec.rb}"
|
||||||
|
|
||||||
|
run: |
|
||||||
|
bin/rake knapsack_pro:queue:rspec
|
||||||
|
|
||||||
|
- name: Save SimpleCov file
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: simplecov-chunk-system-consumer-${{ matrix.ci_node_index }}
|
||||||
|
path: coverage/*.*
|
||||||
|
retention-days: 2 # doesn't need to be long, because it's the combined results that matter
|
||||||
|
if-no-files-found: ignore
|
||||||
|
include-hidden-files: true
|
||||||
|
|
||||||
|
- name: Archive failed tests screenshots
|
||||||
|
if: failure()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: failed-consumer_${{ matrix.ci_node_index }}-tests-screenshots
|
||||||
path: tmp/capybara/screenshots/*.png
|
path: tmp/capybara/screenshots/*.png
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
if-no-files-found: ignore
|
if-no-files-found: ignore
|
||||||
@@ -231,7 +386,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up database
|
- name: Set up database
|
||||||
run: |
|
run: |
|
||||||
bin/rails db:create db:schema:load
|
bin/rake db:create db:schema:load
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
|
|
||||||
@@ -250,7 +405,7 @@ jobs:
|
|||||||
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/lib/**/*_spec.rb,spec/migrations/**/*_spec.rb,spec/serializers/**/*_spec.rb,engines/**/*_spec.rb}"
|
KNAPSACK_PRO_TEST_FILE_PATTERN: "{spec/lib/**/*_spec.rb,spec/migrations/**/*_spec.rb,spec/serializers/**/*_spec.rb,engines/**/*_spec.rb}"
|
||||||
|
|
||||||
run: |
|
run: |
|
||||||
bin/rails assets:precompile knapsack_pro:rspec
|
bin/rake knapsack_pro:rspec
|
||||||
|
|
||||||
- name: Save SimpleCov file
|
- name: Save SimpleCov file
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -282,10 +437,10 @@ jobs:
|
|||||||
# [n] - where the n is a number of parallel jobs you want to run your tests on.
|
# [n] - where the n is a number of parallel jobs you want to run your tests on.
|
||||||
# Use a higher number if you have slow tests to split them between more parallel jobs.
|
# Use a higher number if you have slow tests to split them between more parallel jobs.
|
||||||
# Remember to update the value of the `ci_node_index` below to (0..n-1).
|
# Remember to update the value of the `ci_node_index` below to (0..n-1).
|
||||||
ci_node_total: [3]
|
ci_node_total: [5]
|
||||||
# Indexes for parallel jobs (starting from zero).
|
# Indexes for parallel jobs (starting from zero).
|
||||||
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
|
# E.g. use [0, 1] for 2 parallel jobs, [0, 1, 2] for 3 parallel jobs, etc.
|
||||||
ci_node_index: [0, 1, 2]
|
ci_node_index: [0, 1, 2, 3, 4]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
@@ -310,7 +465,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Set up database
|
- name: Set up database
|
||||||
run: |
|
run: |
|
||||||
bin/rails db:create db:schema:load
|
bin/rake db:create db:schema:load
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
env:
|
env:
|
||||||
@@ -327,7 +482,7 @@ jobs:
|
|||||||
#KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES: true
|
#KNAPSACK_PRO_RSPEC_SPLIT_BY_TEST_EXAMPLES: true
|
||||||
KNAPSACK_PRO_TEST_FILE_EXCLUDE_PATTERN: "{engines/**/*_spec.rb,spec/models/**/*_spec.rb,spec/controllers/**/*_spec.rb,spec/serializers/**/*_spec.rb,spec/lib/**/*_spec.rb,spec/migrations/**/*_spec.rb,spec/system/**/*_spec.rb}"
|
KNAPSACK_PRO_TEST_FILE_EXCLUDE_PATTERN: "{engines/**/*_spec.rb,spec/models/**/*_spec.rb,spec/controllers/**/*_spec.rb,spec/serializers/**/*_spec.rb,spec/lib/**/*_spec.rb,spec/migrations/**/*_spec.rb,spec/system/**/*_spec.rb}"
|
||||||
run: |
|
run: |
|
||||||
bin/rails assets:precompile knapsack_pro:rspec
|
bin/rake knapsack_pro:rspec
|
||||||
|
|
||||||
- name: Save SimpleCov file
|
- name: Save SimpleCov file
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
@@ -379,9 +534,11 @@ jobs:
|
|||||||
collate_simplecov_results:
|
collate_simplecov_results:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
needs:
|
needs:
|
||||||
- controllers_and_models
|
- controllers
|
||||||
|
- models
|
||||||
- engines
|
- engines
|
||||||
- system
|
- system_admin
|
||||||
|
- system_consumer
|
||||||
- test_the_rest
|
- test_the_rest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -396,6 +553,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
pattern: simplecov-chunk-*
|
pattern: simplecov-chunk-*
|
||||||
path: tmp/simplecov
|
path: tmp/simplecov
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
- name: collate results from each of the workers
|
- name: collate results from each of the workers
|
||||||
run: bundle exec rake 'simplecov:collate_results[tmp/simplecov]'
|
run: bundle exec rake 'simplecov:collate_results[tmp/simplecov]'
|
||||||
@@ -408,8 +566,3 @@ jobs:
|
|||||||
retention-days: 7
|
retention-days: 7
|
||||||
if-no-files-found: ignore
|
if-no-files-found: ignore
|
||||||
include-hidden-files: true
|
include-hidden-files: true
|
||||||
- name: Compare SimpleCov results with Undercover
|
|
||||||
run: |
|
|
||||||
git fetch --no-tags origin ${{ github.event.pull_request.base.ref }}:master
|
|
||||||
bundle exec undercover
|
|
||||||
if: ${{ github.ref != 'refs/heads/master' }} # Does not run on master, as we can't fetch master in the master branch
|
|
||||||
|
|||||||
48
.github/workflows/linters.yml
vendored
48
.github/workflows/linters.yml
vendored
@@ -1,30 +1,50 @@
|
|||||||
name: Linters
|
name: Linters
|
||||||
on: [pull_request]
|
on: [push, pull_request]
|
||||||
permissions:
|
permissions:
|
||||||
contents: read # to fetch code (actions/checkout)
|
contents: read # to fetch code (actions/checkout)
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
rubocop:
|
||||||
name: reviewdog
|
name: runner / rubocop
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
- uses: actions/setup-node@v3
|
|
||||||
with:
|
|
||||||
node-version-file: .node-version
|
|
||||||
- name: Install JS dependencies
|
|
||||||
run: yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
- uses: ruby/setup-ruby@v1
|
- uses: ruby/setup-ruby@v1
|
||||||
with:
|
with:
|
||||||
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
||||||
|
|
||||||
- run: git show --no-patch # the commit being tested (which is often a merge due to actions/checkout@v3)
|
- run: git show --no-patch # the commit being tested (which is often a merge due to actions/checkout@v3)
|
||||||
|
|
||||||
- uses: reviewdog/action-setup@v1
|
- name: rubocop
|
||||||
|
uses: reviewdog/action-rubocop@v2
|
||||||
with:
|
with:
|
||||||
reviewdog_version: v0.21.0
|
rubocop_version: gemfile
|
||||||
|
rubocop_extensions: rubocop-rails:gemfile rubocop-rspec:gemfile
|
||||||
|
reporter: github-pr-check
|
||||||
|
level: error
|
||||||
|
filter_mode: nofilter
|
||||||
|
use_bundler: true
|
||||||
|
fail_on_error: true
|
||||||
|
prettier:
|
||||||
|
name: runner / prettier
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check out code
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
|
||||||
- run: ./script/reviewdog.sh
|
- uses: actions/setup-node@v3
|
||||||
env:
|
with:
|
||||||
REVIEWDOG_GITHUB_API_TOKEN: ${{ secrets.github_token }}
|
node-version-file: .node-version
|
||||||
|
|
||||||
|
- name: Install JS dependencies
|
||||||
|
run: yarn install --frozen-lockfile
|
||||||
|
|
||||||
|
- run: git show --no-patch # the commit being tested (which is often a merge due to actions/checkout@v3)
|
||||||
|
|
||||||
|
- name: prettier
|
||||||
|
uses: EPMatt/reviewdog-action-prettier@v1
|
||||||
|
with:
|
||||||
|
github_token: ${{ secrets.github_token }}
|
||||||
|
reporter: github-pr-check
|
||||||
|
level: error
|
||||||
|
fail_on_error: true
|
||||||
|
|||||||
51
.github/workflows/mapi.yml
vendored
Normal file
51
.github/workflows/mapi.yml
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
name: 'Mayhem for API'
|
||||||
|
on: workflow_dispatch
|
||||||
|
permissions:
|
||||||
|
contents: read # to fetch code (actions/checkout)
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
permissions:
|
||||||
|
contents: read # to fetch code (actions/checkout)
|
||||||
|
security-events: write # to upload SARIF results (github/codeql-action/upload-sarif)
|
||||||
|
if: ${{ github.repository_owner == 'openfoodfoundation' }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- run: docker/build
|
||||||
|
- run: docker compose up --detach
|
||||||
|
- run: until curl -f -s http://localhost:3000; do echo "waiting for api server"; sleep 1; done
|
||||||
|
- run: docker compose exec -T db psql postgresql://ofn:f00d@localhost:5432/open_food_network_dev --command="update spree_users set spree_api_key='testing' where login='ofn@example.com'"
|
||||||
|
# equivalent to Flipper.enable(:api_v1)
|
||||||
|
- run: docker compose exec -T db psql postgresql://ofn:f00d@localhost:5432/open_food_network_dev --command="insert into flipper_features (key, created_at, updated_at) values ('api_v1', localtimestamp, localtimestamp)"
|
||||||
|
- run: docker compose exec -T db psql postgresql://ofn:f00d@localhost:5432/open_food_network_dev --command="insert into flipper_gates (feature_key, key, value, created_at, updated_at) values ('api_v1', 'boolean', 'true', localtimestamp, localtimestamp)"
|
||||||
|
|
||||||
|
# Run Mayhem for API
|
||||||
|
- name: Run Mayhem for API
|
||||||
|
uses: ForAllSecure/mapi-action@v1
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
mapi-token: ${{ secrets.MAPI_TOKEN }}
|
||||||
|
api-url: http://localhost:3000
|
||||||
|
api-spec: swagger/v1.yaml
|
||||||
|
target: openfoodfoundation/openfoodnetwork
|
||||||
|
duration: 1min
|
||||||
|
sarif-report: mapi.sarif
|
||||||
|
html-report: mapi.html
|
||||||
|
run-args: |
|
||||||
|
--header-auth
|
||||||
|
X-Api-Token: testing
|
||||||
|
|
||||||
|
# Archive HTML report
|
||||||
|
- name: Archive Mayhem for API report
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: mapi-report
|
||||||
|
path: mapi.html
|
||||||
|
|
||||||
|
# Upload SARIF file (only available on public repos or github enterprise)
|
||||||
|
- name: Upload SARIF file
|
||||||
|
uses: github/codeql-action/upload-sarif@v2
|
||||||
|
with:
|
||||||
|
sarif_file: mapi.sarif
|
||||||
@@ -1,151 +0,0 @@
|
|||||||
name: Auto-move Dependabot PRs to Code Review
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
pull-requests: read
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request_target:
|
|
||||||
types: [opened]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
move-pr-to-code-review:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
if: github.event.pull_request.user.login == 'dependabot[bot]' || startsWith(github.event.pull_request.title, 'Bump')
|
|
||||||
steps:
|
|
||||||
- name: Generate GitHub App Token
|
|
||||||
id: app-token
|
|
||||||
uses: tibdex/github-app-token@v2
|
|
||||||
with:
|
|
||||||
app_id: ${{ secrets.DEPENDABOT_PR_APP_ID }}
|
|
||||||
private_key: ${{ secrets.DEPENDABOT_PR_APP_PRIVATE_KEY }}
|
|
||||||
installation_retrieval_mode: id
|
|
||||||
installation_retrieval_payload: ${{ secrets.DEPENDABOT_PR_APP_INSTALLATION_ID }}
|
|
||||||
|
|
||||||
- name: Move PR to Code Review in Project v2
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
github-token: ${{ steps.app-token.outputs.token }}
|
|
||||||
script: |
|
|
||||||
const projectNumber = 8; // for "OFN Delivery board"
|
|
||||||
const org = "openfoodfoundation";
|
|
||||||
const repo = context.repo.repo;
|
|
||||||
const prNumber = context.payload.pull_request.number;
|
|
||||||
const statusFieldName = "Status";
|
|
||||||
const statusValue = "Code review 🔎";
|
|
||||||
|
|
||||||
// ---- Helper: Get PR Node ID ----
|
|
||||||
async function getPrNodeId(owner, repo, number) {
|
|
||||||
const res = await github.graphql(`
|
|
||||||
query($owner: String!, $repo: String!, $number: Int!) {
|
|
||||||
repository(owner: $owner, name: $repo) {
|
|
||||||
pullRequest(number: $number) {
|
|
||||||
id
|
|
||||||
number
|
|
||||||
title
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`, { owner, repo, number });
|
|
||||||
return res.repository.pullRequest.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("🚀 Starting ProjectV2 automation...");
|
|
||||||
|
|
||||||
// ---- Step 1: Get Project and Fields ----
|
|
||||||
const projectRes = await github.graphql(`
|
|
||||||
query($org: String!, $number: Int!) {
|
|
||||||
organization(login: $org) {
|
|
||||||
projectV2(number: $number) {
|
|
||||||
id
|
|
||||||
title
|
|
||||||
fields(first: 50) {
|
|
||||||
nodes {
|
|
||||||
... on ProjectV2Field {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
... on ProjectV2SingleSelectField {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
options {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`, { org, number: projectNumber });
|
|
||||||
|
|
||||||
const project = projectRes.organization.projectV2;
|
|
||||||
if (!project) throw new Error(`❌ Project #${projectNumber} not found`);
|
|
||||||
|
|
||||||
console.log(`✅ Found project: ${project.title} (${project.id})`);
|
|
||||||
|
|
||||||
const statusField = project.fields.nodes.find(f => f.name === statusFieldName);
|
|
||||||
if (!statusField) throw new Error(`❌ Field '${statusFieldName}' not found`);
|
|
||||||
|
|
||||||
const option = statusField.options.find(o => o.name === statusValue);
|
|
||||||
if (!option) throw new Error(`❌ Option '${statusValue}' not found in '${statusFieldName}'`);
|
|
||||||
|
|
||||||
console.log(`✅ Found field '${statusFieldName}' and option '${statusValue}'`);
|
|
||||||
|
|
||||||
// ---- Step 2: Get PR Node ID ----
|
|
||||||
const prNodeId = await getPrNodeId(org, repo, prNumber);
|
|
||||||
console.log(`✅ PR #${prNumber} node ID: ${prNodeId}`);
|
|
||||||
|
|
||||||
// ---- Step 3: Check if PR is already in Project ----
|
|
||||||
const itemRes = await github.graphql(`
|
|
||||||
query($prId: ID!) {
|
|
||||||
node(id: $prId) {
|
|
||||||
... on PullRequest {
|
|
||||||
projectItems(first: 50) {
|
|
||||||
nodes {
|
|
||||||
id
|
|
||||||
project { id title }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`, { prId: prNodeId });
|
|
||||||
|
|
||||||
let projectItem = itemRes.node.projectItems.nodes.find(i => i.project.id === project.id);
|
|
||||||
|
|
||||||
if (!projectItem) {
|
|
||||||
console.log("ℹ️ PR not yet in project, adding...");
|
|
||||||
const addRes = await github.graphql(`
|
|
||||||
mutation($projectId: ID!, $contentId: ID!) {
|
|
||||||
addProjectV2ItemById(input: {projectId: $projectId, contentId: $contentId}) {
|
|
||||||
item { id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`, { projectId: project.id, contentId: prNodeId });
|
|
||||||
projectItem = addRes.addProjectV2ItemById.item;
|
|
||||||
console.log(`✅ Added PR to project: ${projectItem.id}`);
|
|
||||||
} else {
|
|
||||||
console.log(`ℹ️ PR already in project: ${projectItem.id}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Step 4: Update Status ----
|
|
||||||
await github.graphql(`
|
|
||||||
mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
|
|
||||||
updateProjectV2ItemFieldValue(input: {
|
|
||||||
projectId: $projectId,
|
|
||||||
itemId: $itemId,
|
|
||||||
fieldId: $fieldId,
|
|
||||||
value: { singleSelectOptionId: $optionId }
|
|
||||||
}) {
|
|
||||||
projectV2Item { id }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`, {
|
|
||||||
projectId: project.id,
|
|
||||||
itemId: projectItem.id,
|
|
||||||
fieldId: statusField.id,
|
|
||||||
optionId: option.id,
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log(`🎉 Moved PR #${prNumber} → '${statusValue}'`);
|
|
||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -59,4 +59,3 @@ yarn-debug.log*
|
|||||||
|
|
||||||
/config/credentials.yml.enc
|
/config/credentials.yml.enc
|
||||||
/config/master.key
|
/config/master.key
|
||||||
.secrets
|
|
||||||
|
|||||||
@@ -2,12 +2,19 @@
|
|||||||
# frameworks such as Jekyll/Middleman
|
# frameworks such as Jekyll/Middleman
|
||||||
skip_frontmatter: false
|
skip_frontmatter: false
|
||||||
|
|
||||||
inherits_from: .haml-lint_todo.yml
|
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
AltText:
|
AltText:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|
||||||
|
ClassAttributeWithStaticValue:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
ClassesBeforeIds:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
ConsecutiveComments:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
ConsecutiveSilentScripts:
|
ConsecutiveSilentScripts:
|
||||||
enabled: true
|
enabled: true
|
||||||
max_consecutive: 2
|
max_consecutive: 2
|
||||||
@@ -25,6 +32,7 @@ linters:
|
|||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
LineLength:
|
LineLength:
|
||||||
|
enabled: true
|
||||||
max: 80
|
max: 80
|
||||||
|
|
||||||
MultilinePipe:
|
MultilinePipe:
|
||||||
@@ -39,11 +47,24 @@ linters:
|
|||||||
RuboCop:
|
RuboCop:
|
||||||
enabled: false
|
enabled: false
|
||||||
|
|
||||||
|
RubyComments:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
SpaceBeforeScript:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
SpaceInsideHashAttributes:
|
SpaceInsideHashAttributes:
|
||||||
|
enabled: true
|
||||||
style: no_space
|
style: no_space
|
||||||
|
|
||||||
TagName:
|
TagName:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
|
TrailingWhitespace:
|
||||||
|
enabled: true
|
||||||
|
|
||||||
UnnecessaryInterpolation:
|
UnnecessaryInterpolation:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
|
||||||
|
UnnecessaryStringOutput:
|
||||||
|
enabled: true
|
||||||
|
|||||||
@@ -1,153 +0,0 @@
|
|||||||
# This configuration was generated by
|
|
||||||
# `haml-lint --auto-gen-config`
|
|
||||||
# on 2025-10-30 09:19:50 +0100 using Haml-Lint version 0.66.0.
|
|
||||||
# The point is for the user to remove these configuration records
|
|
||||||
# one by one as the lints are removed from the code base.
|
|
||||||
# Note that changes in the inspected code, or installation of new
|
|
||||||
# versions of Haml-Lint, may require this file to be generated again.
|
|
||||||
|
|
||||||
linters:
|
|
||||||
|
|
||||||
# Offense count: 35
|
|
||||||
ClassAttributeWithStaticValue:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 77
|
|
||||||
ClassesBeforeIds:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 18
|
|
||||||
ConsecutiveComments:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 22
|
|
||||||
ConsecutiveSilentScripts:
|
|
||||||
exclude:
|
|
||||||
- "app/views/admin/contents/_fieldset.html.haml"
|
|
||||||
- "app/views/admin/enterprises/form/_tag_rules.html.haml"
|
|
||||||
- "app/views/admin/order_cycles/edit.html.haml"
|
|
||||||
- "app/views/admin/products_v3/product_preview.turbo_stream.haml"
|
|
||||||
- "app/views/admin/reports/_date_range_form.html.haml"
|
|
||||||
- "app/views/checkout/_details.html.haml"
|
|
||||||
- "app/views/checkout/_payment.html.haml"
|
|
||||||
- "app/views/spree/admin/adjustments/_adjustments_table.html.haml"
|
|
||||||
- "app/views/spree/admin/orders/customer_details/_address_form.html.haml"
|
|
||||||
- "app/views/spree/admin/tax_categories/index.html.haml"
|
|
||||||
- "app/views/spree/admin/users/index.html.haml"
|
|
||||||
|
|
||||||
# Offense count: 14
|
|
||||||
FinalNewline:
|
|
||||||
exclude:
|
|
||||||
- "app/assets/javascripts/templates/shared/question_mark_with_tooltip.html.haml"
|
|
||||||
- "app/views/admin/enterprises/form/_social.html.haml"
|
|
||||||
- "app/views/admin/json/_injection_ams.html.haml"
|
|
||||||
- "app/views/admin/order_cycles/_date_time_warning_modal_content.html.haml"
|
|
||||||
- "app/views/admin/order_cycles/edit.html.haml"
|
|
||||||
- "app/views/admin/product_import/_ams_data.html.haml"
|
|
||||||
- "app/views/admin/reports/_row_group.haml"
|
|
||||||
- "app/views/admin/reports/filters/_enterprise_fee_summary.html.haml"
|
|
||||||
- "app/views/admin/reports/filters/_users_and_enterprises.html.haml"
|
|
||||||
- "app/views/shop/_blocked_cookies.html.haml"
|
|
||||||
- "app/views/spree/admin/orders/_invoice/_order_note.html.haml"
|
|
||||||
- "app/views/spree/admin/orders/invoice4.html.haml"
|
|
||||||
- "app/views/spree/admin/taxons/destroy_taxon.turbo_stream.haml"
|
|
||||||
- "app/views/spree/admin/users/_email_confirmation.html.haml"
|
|
||||||
|
|
||||||
# Offense count: 130
|
|
||||||
IdNames:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 5
|
|
||||||
Indentation:
|
|
||||||
exclude:
|
|
||||||
- "app/views/admin/products_v3/clone.turbo_stream.haml"
|
|
||||||
- "app/views/admin/products_v3/destroy_product_variant.turbo_stream.haml"
|
|
||||||
- "app/views/spree/admin/taxons/destroy_taxon.turbo_stream.haml"
|
|
||||||
|
|
||||||
# Offense count: 191
|
|
||||||
InlineStyles:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 589
|
|
||||||
InstanceVariables:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 2
|
|
||||||
LeadingCommentSpace:
|
|
||||||
exclude:
|
|
||||||
- "app/views/admin/reports/_row_group.haml"
|
|
||||||
|
|
||||||
# Offense count: 2331
|
|
||||||
LineLength:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 1
|
|
||||||
MultilinePipe:
|
|
||||||
exclude:
|
|
||||||
- "app/views/admin/reports/_rendering_options.html.haml"
|
|
||||||
|
|
||||||
# Offense count: 2
|
|
||||||
MultilineScript:
|
|
||||||
exclude:
|
|
||||||
- "app/views/admin/products_v3/product_preview.turbo_stream.haml"
|
|
||||||
- "app/views/checkout/_voucher_section.html.haml"
|
|
||||||
|
|
||||||
# Offense count: 2
|
|
||||||
RepeatedId:
|
|
||||||
exclude:
|
|
||||||
- "app/assets/javascripts/templates/admin/save_bar.html.haml"
|
|
||||||
|
|
||||||
# Offense count: 24
|
|
||||||
RubyComments:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 104
|
|
||||||
SpaceBeforeScript:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 3345
|
|
||||||
SpaceInsideHashAttributes:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 22
|
|
||||||
TrailingEmptyLines:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 73
|
|
||||||
TrailingWhitespace:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 13
|
|
||||||
UnnecessaryInterpolation:
|
|
||||||
exclude:
|
|
||||||
- "app/components/example_component/example_component.html.haml"
|
|
||||||
- "app/views/admin/product_import/_entries_table.html.haml"
|
|
||||||
- "app/views/admin/product_import/import.html.haml"
|
|
||||||
- "app/views/admin/variant_overrides/_filters.html.haml"
|
|
||||||
- "app/views/registration/steps/_introduction.html.haml"
|
|
||||||
- "app/views/spree/order_mailer/_shipping.html.haml"
|
|
||||||
- "app/views/spree/order_mailer/invoice_email.html.haml"
|
|
||||||
- "app/views/spree/shared/_shipment_delivery_details.html.haml"
|
|
||||||
- "app/views/spree/shared/_shipment_pickup_details.html.haml"
|
|
||||||
|
|
||||||
# Offense count: 68
|
|
||||||
UnnecessaryStringOutput:
|
|
||||||
enabled: false
|
|
||||||
|
|
||||||
# Offense count: 14
|
|
||||||
ViewLength:
|
|
||||||
exclude:
|
|
||||||
- "app/assets/javascripts/templates/admin/panels/enterprise_package.html.haml"
|
|
||||||
- "app/views/admin/customers/index.html.haml"
|
|
||||||
- "app/views/admin/enterprises/_new_form.html.haml"
|
|
||||||
- "app/views/admin/enterprises/form/_shop_preferences.html.haml"
|
|
||||||
- "app/views/admin/product_import/_import_review.html.haml"
|
|
||||||
- "app/views/admin/products_v3/product_preview.turbo_stream.haml"
|
|
||||||
- "app/views/checkout/_details.html.haml"
|
|
||||||
- "app/views/groups/show.html.haml"
|
|
||||||
- "app/views/producer_mailer/order_cycle_report.html.haml"
|
|
||||||
- "app/views/shared/_footer.html.haml"
|
|
||||||
- "app/views/spree/admin/orders/bulk_management.html.haml"
|
|
||||||
- "app/views/spree/admin/orders/invoice4.html.haml"
|
|
||||||
- "app/views/spree/admin/products/new.html.haml"
|
|
||||||
- "app/views/spree/admin/variants/_form.html.haml"
|
|
||||||
6
.hound.yml
Normal file
6
.hound.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
rubocop:
|
||||||
|
config_file: .rubocop_styleguide.yml
|
||||||
|
scss:
|
||||||
|
config_file: .scss-lint.yml
|
||||||
|
haml:
|
||||||
|
config_file: .haml-lint.yml
|
||||||
@@ -1 +1 @@
|
|||||||
24.10.0
|
17.9.1
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#
|
#
|
||||||
# The configuration is split into three files. Look into those files for more details.
|
# The configuration is split into three files. Look into those files for more details.
|
||||||
#
|
#
|
||||||
plugins:
|
require:
|
||||||
- rubocop-capybara
|
- rubocop-capybara
|
||||||
- rubocop-factory_bot
|
- rubocop-factory_bot
|
||||||
- rubocop-rails
|
- rubocop-rails
|
||||||
|
|||||||
@@ -3,20 +3,15 @@
|
|||||||
# These are the rules we agreed upon and we work towards.
|
# These are the rules we agreed upon and we work towards.
|
||||||
AllCops:
|
AllCops:
|
||||||
NewCops: enable
|
NewCops: enable
|
||||||
MigratedSchemaVersion: "20250111000000"
|
|
||||||
Exclude:
|
Exclude:
|
||||||
- bin/**/*
|
- bin/**/*
|
||||||
|
- db/**/*
|
||||||
- config/**/*
|
- config/**/*
|
||||||
- db/bad_migrations/*
|
|
||||||
- db/migrate/201*
|
|
||||||
- db/migrate/202[0-4]*
|
|
||||||
- db/schema.rb
|
|
||||||
- script/**/*
|
- script/**/*
|
||||||
- vendor/**/*
|
- vendor/**/*
|
||||||
- node_modules/**/*
|
- node_modules/**/*
|
||||||
# Excluding: inadequate Naming/FileName rule rejects GemFile name with camelcase
|
# Excluding: inadequate Naming/FileName rule rejects GemFile name with camelcase
|
||||||
- engines/web/Gemfile
|
- engines/web/Gemfile
|
||||||
- .undercover
|
|
||||||
|
|
||||||
Bundler/DuplicatedGem:
|
Bundler/DuplicatedGem:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
@@ -94,7 +89,7 @@ Metrics/PerceivedComplexity:
|
|||||||
Enabled: true
|
Enabled: true
|
||||||
Max: 14 # default 8
|
Max: 14 # default 8
|
||||||
|
|
||||||
Naming/PredicatePrefix:
|
Naming/PredicateName:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
Naming/VariableNumber:
|
Naming/VariableNumber:
|
||||||
@@ -103,8 +98,6 @@ Naming/VariableNumber:
|
|||||||
- street_address_2
|
- street_address_2
|
||||||
AllowedPatterns:
|
AllowedPatterns:
|
||||||
- _v[\d]+
|
- _v[\d]+
|
||||||
# Cf. conversation https://github.com/openfoodfoundation/openfoodnetwork/pull/13306#pullrequestreview-2831644286
|
|
||||||
- menu_[\d]
|
|
||||||
|
|
||||||
Rails/ApplicationRecord:
|
Rails/ApplicationRecord:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -118,10 +111,6 @@ Rails/ApplicationRecord:
|
|||||||
Rails/HasAndBelongsToMany:
|
Rails/HasAndBelongsToMany:
|
||||||
Enabled: false
|
Enabled: false
|
||||||
|
|
||||||
# Cf. conversation https://github.com/openfoodfoundation/openfoodnetwork/pull/13251
|
|
||||||
Rails/LexicallyScopedActionFilter:
|
|
||||||
Enabled: false
|
|
||||||
|
|
||||||
Rails/OutputSafety:
|
Rails/OutputSafety:
|
||||||
Exclude:
|
Exclude:
|
||||||
- spec/**/*
|
- spec/**/*
|
||||||
|
|||||||
@@ -1,43 +1,89 @@
|
|||||||
# This configuration was generated by
|
# This configuration was generated by
|
||||||
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 1400 --no-auto-gen-timestamp`
|
# `rubocop --auto-gen-config --auto-gen-only-exclude --exclude-limit 1400 --no-auto-gen-timestamp`
|
||||||
# using RuboCop version 1.81.7.
|
# using RuboCop version 1.64.1.
|
||||||
# The point is for the user to remove these configuration records
|
# The point is for the user to remove these configuration records
|
||||||
# one by one as the offenses are removed from the code base.
|
# one by one as the offenses are removed from the code base.
|
||||||
# Note that changes in the inspected code, or installation of new
|
# Note that changes in the inspected code, or installation of new
|
||||||
# versions of RuboCop, may require this file to be generated again.
|
# versions of RuboCop, may require this file to be generated again.
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
# This cop supports safe autocorrection (--autocorrect).
|
||||||
# Configuration parameters: RequireParenthesesForMethodChains.
|
Layout/EmptyLines:
|
||||||
Lint/AmbiguousRange:
|
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/models/concerns/permalink_generator.rb'
|
- 'app/services/products_renderer.rb'
|
||||||
|
|
||||||
# Offense count: 6
|
# Offense count: 16
|
||||||
Lint/CopDirectiveSyntax:
|
# Configuration parameters: AllowComments, AllowEmptyLambdas.
|
||||||
|
Lint/EmptyBlock:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/services/orders/bulk_cancel_service.rb'
|
- 'engines/catalog/config/routes.rb'
|
||||||
- 'lib/tasks/simplecov.rake'
|
- 'spec/components/distributor_title_component_spec.rb'
|
||||||
- 'spec/models/database_spec.rb'
|
- 'spec/components/example_component_spec.rb'
|
||||||
- 'spec/system/admin/bulk_order_management_spec.rb'
|
- 'spec/controllers/admin/subscription_line_items_controller_spec.rb'
|
||||||
- 'spec/system/admin/enterprise_relationships_spec.rb'
|
- 'spec/controllers/api/v0/shipments_controller_spec.rb'
|
||||||
|
- 'spec/controllers/concerns/extra_fields_spec.rb'
|
||||||
|
- 'spec/factories.rb'
|
||||||
|
- 'spec/factories/enterprise_factory.rb'
|
||||||
|
- 'spec/jobs/order_cycle_opened_job_spec.rb'
|
||||||
|
- 'spec/jobs/subscription_placement_job_spec.rb'
|
||||||
|
- 'spec/models/product_import/entry_validator_spec.rb'
|
||||||
|
|
||||||
# Offense count: 2
|
# Offense count: 4
|
||||||
Lint/DuplicateMethods:
|
# Configuration parameters: AllowComments.
|
||||||
|
Lint/EmptyClass:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/models/spree/order.rb'
|
- 'spec/lib/reports/report_loader_spec.rb'
|
||||||
- 'engines/order_management/app/services/order_management/subscriptions/form.rb'
|
|
||||||
|
|
||||||
# Offense count: 3
|
|
||||||
Lint/UselessConstantScoping:
|
|
||||||
Exclude:
|
|
||||||
- 'app/services/weights_and_measures.rb'
|
|
||||||
- 'lib/reporting/report_metadata_builder.rb'
|
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
Lint/UselessOr:
|
# Configuration parameters: AllowComments.
|
||||||
|
Lint/EmptyFile:
|
||||||
|
Exclude:
|
||||||
|
- 'spec/lib/open_food_network/enterprise_injection_data_spec.rb'
|
||||||
|
|
||||||
|
# Offense count: 2
|
||||||
|
Lint/FloatComparison:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/models/product_import/entry_validator.rb'
|
- 'app/models/product_import/entry_validator.rb'
|
||||||
|
- 'app/models/spree/gateway/pay_pal_express.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
Lint/IneffectiveAccessModifier:
|
||||||
|
Exclude:
|
||||||
|
- 'app/models/spree/user.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
Lint/NoReturnInBeginEndBlocks:
|
||||||
|
Exclude:
|
||||||
|
- 'app/controllers/payment_gateways/stripe_controller.rb'
|
||||||
|
|
||||||
|
# Offense count: 4
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
Lint/RedundantDirGlobSort:
|
||||||
|
Exclude:
|
||||||
|
- 'engines/catalog/spec/spec_helper.rb'
|
||||||
|
- 'engines/dfc_provider/spec/spec_helper.rb'
|
||||||
|
- 'spec/base_spec_helper.rb'
|
||||||
|
- 'spec/system_helper.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: AllowedMethods.
|
||||||
|
# AllowedMethods: instance_of?, kind_of?, is_a?, eql?, respond_to?, equal?, presence, present?
|
||||||
|
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).
|
||||||
|
# Configuration parameters: AutoCorrect.
|
||||||
|
Lint/UselessMethodDefinition:
|
||||||
|
Exclude:
|
||||||
|
- 'app/models/spree/gateway.rb'
|
||||||
|
|
||||||
# Offense count: 24
|
# Offense count: 24
|
||||||
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes, Max.
|
||||||
@@ -46,6 +92,7 @@ Metrics/AbcSize:
|
|||||||
- 'app/controllers/admin/enterprises_controller.rb'
|
- 'app/controllers/admin/enterprises_controller.rb'
|
||||||
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
||||||
- 'app/controllers/spree/admin/payments_controller.rb'
|
- 'app/controllers/spree/admin/payments_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/taxons_controller.rb'
|
||||||
- 'app/controllers/spree/admin/variants_controller.rb'
|
- 'app/controllers/spree/admin/variants_controller.rb'
|
||||||
- 'app/controllers/spree/orders_controller.rb'
|
- 'app/controllers/spree/orders_controller.rb'
|
||||||
- 'app/helpers/spree/admin/navigation_helper.rb'
|
- 'app/helpers/spree/admin/navigation_helper.rb'
|
||||||
@@ -75,12 +122,12 @@ Metrics/BlockLength:
|
|||||||
- 'lib/tasks/data.rake'
|
- 'lib/tasks/data.rake'
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# Configuration parameters: CountBlocks, CountModifierForms, Max.
|
# Configuration parameters: CountBlocks, Max.
|
||||||
Metrics/BlockNesting:
|
Metrics/BlockNesting:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/models/spree/payment/processing.rb'
|
- 'app/models/spree/payment/processing.rb'
|
||||||
|
|
||||||
# Offense count: 49
|
# Offense count: 46
|
||||||
# Configuration parameters: CountComments, Max, CountAsOne.
|
# Configuration parameters: CountComments, Max, CountAsOne.
|
||||||
Metrics/ClassLength:
|
Metrics/ClassLength:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -90,12 +137,12 @@ Metrics/ClassLength:
|
|||||||
- 'app/controllers/admin/resource_controller.rb'
|
- 'app/controllers/admin/resource_controller.rb'
|
||||||
- 'app/controllers/admin/subscriptions_controller.rb'
|
- 'app/controllers/admin/subscriptions_controller.rb'
|
||||||
- 'app/controllers/application_controller.rb'
|
- 'app/controllers/application_controller.rb'
|
||||||
- 'app/controllers/checkout_controller.rb'
|
|
||||||
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
||||||
- 'app/controllers/spree/admin/orders_controller.rb'
|
- 'app/controllers/spree/admin/orders_controller.rb'
|
||||||
- 'app/controllers/spree/admin/payment_methods_controller.rb'
|
- 'app/controllers/spree/admin/payment_methods_controller.rb'
|
||||||
- 'app/controllers/spree/admin/payments_controller.rb'
|
- 'app/controllers/spree/admin/payments_controller.rb'
|
||||||
- 'app/controllers/spree/admin/products_controller.rb'
|
- 'app/controllers/spree/admin/products_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/users_controller.rb'
|
||||||
- 'app/controllers/spree/orders_controller.rb'
|
- 'app/controllers/spree/orders_controller.rb'
|
||||||
- 'app/models/enterprise.rb'
|
- 'app/models/enterprise.rb'
|
||||||
- 'app/models/invoice/data_presenter.rb'
|
- 'app/models/invoice/data_presenter.rb'
|
||||||
@@ -121,9 +168,6 @@ Metrics/ClassLength:
|
|||||||
- 'app/services/cart_service.rb'
|
- 'app/services/cart_service.rb'
|
||||||
- 'app/services/order_cycles/form_service.rb'
|
- 'app/services/order_cycles/form_service.rb'
|
||||||
- 'app/services/orders/sync_service.rb'
|
- 'app/services/orders/sync_service.rb'
|
||||||
- 'app/services/permissions/order.rb'
|
|
||||||
- 'app/services/products_renderer.rb'
|
|
||||||
- 'app/services/sets/product_set.rb'
|
|
||||||
- 'engines/order_management/app/services/order_management/order/updater.rb'
|
- 'engines/order_management/app/services/order_management/order/updater.rb'
|
||||||
- 'lib/open_food_network/enterprise_fee_calculator.rb'
|
- 'lib/open_food_network/enterprise_fee_calculator.rb'
|
||||||
- 'lib/open_food_network/order_cycle_form_applicator.rb'
|
- 'lib/open_food_network/order_cycle_form_applicator.rb'
|
||||||
@@ -134,12 +178,12 @@ Metrics/ClassLength:
|
|||||||
- 'lib/reporting/reports/enterprise_fee_summary/scope.rb'
|
- 'lib/reporting/reports/enterprise_fee_summary/scope.rb'
|
||||||
- 'lib/reporting/reports/xero_invoices/base.rb'
|
- 'lib/reporting/reports/xero_invoices/base.rb'
|
||||||
|
|
||||||
# Offense count: 37
|
# Offense count: 32
|
||||||
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
||||||
Metrics/CyclomaticComplexity:
|
Metrics/CyclomaticComplexity:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/controllers/admin/enterprises_controller.rb'
|
- 'app/controllers/admin/enterprises_controller.rb'
|
||||||
- 'app/controllers/spree/admin/payments_controller.rb'
|
- 'app/controllers/spree/admin/taxons_controller.rb'
|
||||||
- 'app/controllers/spree/orders_controller.rb'
|
- 'app/controllers/spree/orders_controller.rb'
|
||||||
- 'app/helpers/checkout_helper.rb'
|
- 'app/helpers/checkout_helper.rb'
|
||||||
- 'app/helpers/order_cycles_helper.rb'
|
- 'app/helpers/order_cycles_helper.rb'
|
||||||
@@ -155,26 +199,24 @@ Metrics/CyclomaticComplexity:
|
|||||||
- 'app/models/spree/preferences/preferable_class_methods.rb'
|
- 'app/models/spree/preferences/preferable_class_methods.rb'
|
||||||
- 'app/models/spree/return_authorization.rb'
|
- 'app/models/spree/return_authorization.rb'
|
||||||
- 'app/models/spree/tax_rate.rb'
|
- 'app/models/spree/tax_rate.rb'
|
||||||
|
- 'app/models/spree/variant.rb'
|
||||||
- 'app/models/spree/zone.rb'
|
- 'app/models/spree/zone.rb'
|
||||||
- 'lib/open_food_network/enterprise_issue_validator.rb'
|
- 'lib/open_food_network/enterprise_issue_validator.rb'
|
||||||
- 'lib/reporting/reports/orders_and_fulfillment/order_cycle_customer_totals.rb'
|
|
||||||
- 'lib/reporting/reports/orders_and_fulfillment/order_cycle_supplier_totals.rb'
|
|
||||||
- 'lib/reporting/reports/payments/itemised_payment_totals.rb'
|
|
||||||
- 'lib/reporting/reports/payments/payment_totals.rb'
|
|
||||||
- 'lib/reporting/reports/sales_tax/sales_tax_totals_by_producer.rb'
|
|
||||||
- 'lib/reporting/reports/xero_invoices/base.rb'
|
- 'lib/reporting/reports/xero_invoices/base.rb'
|
||||||
- 'lib/spree/core/controller_helpers/order.rb'
|
- 'lib/spree/core/controller_helpers/order.rb'
|
||||||
- 'lib/spree/core/controller_helpers/respond_with.rb'
|
- 'lib/spree/core/controller_helpers/respond_with.rb'
|
||||||
- 'lib/spree/localized_number.rb'
|
- 'lib/spree/localized_number.rb'
|
||||||
- 'spec/models/product_importer_spec.rb'
|
- 'spec/models/product_importer_spec.rb'
|
||||||
|
|
||||||
# Offense count: 22
|
# Offense count: 24
|
||||||
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
# Configuration parameters: CountComments, Max, CountAsOne, AllowedMethods, AllowedPatterns.
|
||||||
Metrics/MethodLength:
|
Metrics/MethodLength:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/controllers/admin/enterprises_controller.rb'
|
- 'app/controllers/admin/enterprises_controller.rb'
|
||||||
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
- 'app/controllers/payment_gateways/paypal_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/taxons_controller.rb'
|
||||||
- 'app/controllers/spree/orders_controller.rb'
|
- 'app/controllers/spree/orders_controller.rb'
|
||||||
|
- 'app/helpers/spree/admin/navigation_helper.rb'
|
||||||
- 'app/models/spree/ability.rb'
|
- 'app/models/spree/ability.rb'
|
||||||
- 'app/models/spree/gateway/pay_pal_express.rb'
|
- 'app/models/spree/gateway/pay_pal_express.rb'
|
||||||
- 'app/models/spree/order/checkout.rb'
|
- 'app/models/spree/order/checkout.rb'
|
||||||
@@ -187,7 +229,7 @@ Metrics/MethodLength:
|
|||||||
- 'lib/spree/localized_number.rb'
|
- 'lib/spree/localized_number.rb'
|
||||||
- 'lib/tasks/sample_data/product_factory.rb'
|
- 'lib/tasks/sample_data/product_factory.rb'
|
||||||
|
|
||||||
# Offense count: 10
|
# Offense count: 49
|
||||||
# Configuration parameters: CountComments, Max, CountAsOne.
|
# Configuration parameters: CountComments, Max, CountAsOne.
|
||||||
Metrics/ModuleLength:
|
Metrics/ModuleLength:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -199,7 +241,46 @@ Metrics/ModuleLength:
|
|||||||
- 'app/helpers/spree/admin/orders_helper.rb'
|
- 'app/helpers/spree/admin/orders_helper.rb'
|
||||||
- 'app/models/spree/order/checkout.rb'
|
- 'app/models/spree/order/checkout.rb'
|
||||||
- 'app/models/spree/payment/processing.rb'
|
- 'app/models/spree/payment/processing.rb'
|
||||||
|
- 'engines/catalog/spec/services/catalog/product_import/products_reset_strategy_spec.rb'
|
||||||
|
- 'engines/order_management/spec/services/order_management/order/updater_spec.rb'
|
||||||
|
- 'engines/order_management/spec/services/order_management/stock/package_spec.rb'
|
||||||
|
- 'engines/order_management/spec/services/order_management/subscriptions/estimator_spec.rb'
|
||||||
|
- 'engines/order_management/spec/services/order_management/subscriptions/form_spec.rb'
|
||||||
|
- 'engines/order_management/spec/services/order_management/subscriptions/proxy_order_syncer_spec.rb'
|
||||||
|
- 'engines/order_management/spec/services/order_management/subscriptions/summarizer_spec.rb'
|
||||||
|
- 'engines/order_management/spec/services/order_management/subscriptions/summary_spec.rb'
|
||||||
|
- 'engines/order_management/spec/services/order_management/subscriptions/validator_spec.rb'
|
||||||
|
- 'engines/order_management/spec/services/order_management/subscriptions/variants_list_spec.rb'
|
||||||
- 'lib/open_food_network/column_preference_defaults.rb'
|
- 'lib/open_food_network/column_preference_defaults.rb'
|
||||||
|
- 'spec/controllers/admin/customers_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/order_cycles_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/order_cycles_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/payment_gateways/stripe_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/adjustments_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/payment_methods_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/variants_controller_spec.rb'
|
||||||
|
- 'spec/lib/open_food_network/address_finder_spec.rb'
|
||||||
|
- 'spec/lib/open_food_network/enterprise_fee_calculator_spec.rb'
|
||||||
|
- 'spec/lib/open_food_network/order_cycle_form_applicator_spec.rb'
|
||||||
|
- 'spec/lib/open_food_network/order_cycle_permissions_spec.rb'
|
||||||
|
- 'spec/lib/open_food_network/permissions_spec.rb'
|
||||||
|
- 'spec/lib/open_food_network/scope_variant_to_hub_spec.rb'
|
||||||
|
- 'spec/lib/open_food_network/tag_rule_applicator_spec.rb'
|
||||||
|
- 'spec/lib/reports/customers_report_spec.rb'
|
||||||
|
- 'spec/lib/reports/enterprise_fee_summary/authorizer_spec.rb'
|
||||||
|
- 'spec/lib/reports/order_cycle_management_report_spec.rb'
|
||||||
|
- 'spec/lib/reports/products_and_inventory_report_spec.rb'
|
||||||
|
- 'spec/lib/reports/users_and_enterprises_report_spec.rb'
|
||||||
|
- 'spec/models/spree/adjustment_spec.rb'
|
||||||
|
- 'spec/models/spree/credit_card_spec.rb'
|
||||||
|
- 'spec/models/spree/line_item_spec.rb'
|
||||||
|
- 'spec/models/spree/order/tax_spec.rb'
|
||||||
|
- 'spec/models/spree/product_spec.rb'
|
||||||
|
- 'spec/models/spree/shipping_method_spec.rb'
|
||||||
|
- 'spec/models/spree/tax_rate_spec.rb'
|
||||||
|
- 'spec/services/permissions/order_spec.rb'
|
||||||
|
- 'spec/services/variant_units/option_value_namer_spec.rb'
|
||||||
- 'spec/support/request/stripe_stubs.rb'
|
- 'spec/support/request/stripe_stubs.rb'
|
||||||
|
|
||||||
# Offense count: 7
|
# Offense count: 7
|
||||||
@@ -216,143 +297,340 @@ Metrics/ParameterLists:
|
|||||||
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
# Configuration parameters: AllowedMethods, AllowedPatterns, Max.
|
||||||
Metrics/PerceivedComplexity:
|
Metrics/PerceivedComplexity:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
- 'app/controllers/spree/admin/taxons_controller.rb'
|
||||||
- 'app/models/enterprise_relationship.rb'
|
- 'app/models/enterprise_relationship.rb'
|
||||||
- 'app/models/spree/ability.rb'
|
- 'app/models/spree/ability.rb'
|
||||||
- 'app/models/spree/order/checkout.rb'
|
- 'app/models/spree/order/checkout.rb'
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 8
|
||||||
# Configuration parameters: EnforcedStyle, AllowedPatterns, ForbiddenIdentifiers, ForbiddenPatterns.
|
Naming/AccessorMethodName:
|
||||||
# SupportedStyles: snake_case, camelCase
|
|
||||||
# ForbiddenIdentifiers: __id__, __send__
|
|
||||||
Naming/MethodName:
|
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'engines/dfc_provider/lib/dfc_provider/catalog_item.rb'
|
- 'app/controllers/spree/admin/taxonomies_controller.rb'
|
||||||
|
- 'app/mailers/producer_mailer.rb'
|
||||||
|
- 'app/models/spree/order.rb'
|
||||||
|
- 'app/services/checkout/post_checkout_actions.rb'
|
||||||
|
- 'lib/spree/core/controller_helpers/common.rb'
|
||||||
|
- 'spec/support/request/shop_workflow.rb'
|
||||||
|
- 'spec/support/request/web_helper.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# Configuration parameters: ForbiddenDelimiters.
|
||||||
|
# ForbiddenDelimiters: (?i-mx:(^|\s)(EO[A-Z]{1}|END)(\s|$))
|
||||||
|
Naming/HeredocDelimiterNaming:
|
||||||
|
Exclude:
|
||||||
|
- 'app/models/content_configuration.rb'
|
||||||
|
|
||||||
|
# Offense count: 5
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: EnforcedStyleForLeadingUnderscores.
|
||||||
|
# SupportedStylesForLeadingUnderscores: disallowed, required, optional
|
||||||
|
Naming/MemoizedInstanceVariableName:
|
||||||
|
Exclude:
|
||||||
|
- 'app/mailers/producer_mailer.rb'
|
||||||
|
- 'app/models/concerns/balance.rb'
|
||||||
|
- 'lib/open_food_network/address_finder.rb'
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
# Configuration parameters: MinNameLength, AllowNamesEndingInNumbers, AllowedNames, ForbiddenNames.
|
||||||
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
|
# AllowedNames: as, at, by, cc, db, id, if, in, io, ip, of, on, os, pp, to
|
||||||
Naming/MethodParameterName:
|
Naming/MethodParameterName:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'engines/dfc_provider/lib/dfc_provider/catalog_item.rb'
|
- 'app/services/process_payment_intent.rb'
|
||||||
|
|
||||||
# Offense count: 60
|
# Offense count: 28
|
||||||
# Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
|
# Configuration parameters: EnforcedStyle, CheckMethodNames, CheckSymbols, AllowedIdentifiers, AllowedPatterns.
|
||||||
# AllowedMethods: call
|
# SupportedStyles: snake_case, normalcase, non_integer
|
||||||
# WaywardPredicates: nonzero?
|
# AllowedIdentifiers: capture3, iso8601, rfc1123_date, rfc822, rfc2822, rfc3339, x86_64
|
||||||
Naming/PredicateMethod:
|
Naming/VariableNumber:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/controllers/admin/product_import_controller.rb'
|
- 'app/controllers/spree/orders_controller.rb'
|
||||||
- 'app/controllers/api/v0/order_cycles_controller.rb'
|
- 'app/models/content_configuration.rb'
|
||||||
- 'app/controllers/spree/admin/overview_controller.rb'
|
- 'app/models/preference_sections/main_links_section.rb'
|
||||||
- 'app/controllers/spree/admin/payments_controller.rb'
|
- 'lib/spree/core/controller_helpers/common.rb'
|
||||||
- 'app/controllers/voucher_adjustments_controller.rb'
|
- 'spec/controllers/spree/admin/search_controller_spec.rb'
|
||||||
- 'app/forms/enterprise_fees_bulk_update.rb'
|
- 'spec/factories/stock_location_factory.rb'
|
||||||
- 'app/forms/schedule_form.rb'
|
- 'spec/models/spree/stock_item_spec.rb'
|
||||||
- 'app/helpers/spree/orders_helper.rb'
|
- 'spec/models/spree/tax_rate_spec.rb'
|
||||||
- 'app/models/concerns/variant_stock.rb'
|
- 'spec/requests/api/orders_spec.rb'
|
||||||
- 'app/models/enterprise.rb'
|
|
||||||
- 'app/models/enterprise_fee.rb'
|
|
||||||
- 'app/models/invoice/data_presenter.rb'
|
|
||||||
- 'app/models/order_cycle.rb'
|
|
||||||
- 'app/models/product_import/entry_processor.rb'
|
|
||||||
- 'app/models/product_import/entry_validator.rb'
|
|
||||||
- 'app/models/spree/order.rb'
|
|
||||||
- 'app/models/spree/order_contents.rb'
|
|
||||||
- 'app/models/spree/payment.rb'
|
|
||||||
- 'app/models/spree/payment/processing.rb'
|
|
||||||
- 'app/models/spree/state_change.rb'
|
|
||||||
- 'app/models/spree/user.rb'
|
|
||||||
- 'app/reflexes/admin/orders_reflex.rb'
|
|
||||||
- 'app/serializers/api/admin/for_order_cycle/enterprise_serializer.rb'
|
|
||||||
- 'app/serializers/api/admin/index_enterprise_serializer.rb'
|
|
||||||
- 'app/serializers/api/admin/index_order_cycle_serializer.rb'
|
|
||||||
- 'app/serializers/api/admin/order_cycle_serializer.rb'
|
|
||||||
- 'app/serializers/api/admin/order_serializer.rb'
|
|
||||||
- 'app/serializers/api/admin/schedule_serializer.rb'
|
|
||||||
- 'app/serializers/api/admin/subscription_line_item_serializer.rb'
|
|
||||||
- 'app/serializers/api/admin/user_serializer.rb'
|
|
||||||
- 'app/serializers/api/admin/variant_serializer.rb'
|
|
||||||
- 'app/serializers/api/enterprise_shopfront_serializer.rb'
|
|
||||||
- 'app/serializers/api/enterprise_thin_serializer.rb'
|
|
||||||
- 'app/serializers/api/order_serializer.rb'
|
|
||||||
- 'app/serializers/api/uncached_enterprise_serializer.rb'
|
|
||||||
- 'app/services/cart_service.rb'
|
|
||||||
- 'app/services/orders/fetch_adjustments_service.rb'
|
|
||||||
- 'app/services/orders/workflow_service.rb'
|
|
||||||
- 'app/services/sets/model_set.rb'
|
|
||||||
- 'app/services/sets/order_cycle_set.rb'
|
|
||||||
- 'app/services/sets/product_set.rb'
|
|
||||||
- 'engines/dfc_provider/app/controllers/dfc_provider/addresses_controller.rb'
|
|
||||||
- 'lib/open_food_network/order_cycle_form_applicator.rb'
|
|
||||||
- 'lib/open_food_network/order_cycle_permissions.rb'
|
|
||||||
- 'lib/reporting/reports/enterprise_fee_summary/enterprise_fees_with_tax_report_by_order.rb'
|
|
||||||
- 'lib/reporting/reports/enterprise_fee_summary/enterprise_fees_with_tax_report_by_producer.rb'
|
|
||||||
- 'lib/tasks/data/check_invalid_address_used.rake'
|
|
||||||
|
|
||||||
# Offense count: 3
|
# Offense count: 142
|
||||||
# Configuration parameters: EnforcedStyle, AllowedIdentifiers, AllowedPatterns, ForbiddenIdentifiers, ForbiddenPatterns.
|
|
||||||
# SupportedStyles: snake_case, camelCase
|
|
||||||
Naming/VariableName:
|
|
||||||
Exclude:
|
|
||||||
- 'engines/dfc_provider/lib/dfc_provider/catalog_item.rb'
|
|
||||||
|
|
||||||
# Offense count: 6
|
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
Rails/FindByOrAssignmentMemoization:
|
# Configuration parameters: ResponseMethods.
|
||||||
|
# ResponseMethods: response, last_response
|
||||||
|
RSpecRails/HaveHttpStatus:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/controllers/admin/customers_controller.rb'
|
- 'spec/controllers/admin/bulk_line_items_controller_spec.rb'
|
||||||
- 'app/controllers/admin/resource_controller.rb'
|
- 'spec/controllers/admin/order_cycles_controller_spec.rb'
|
||||||
- 'app/controllers/api/v0/enterprise_fees_controller.rb'
|
- 'spec/controllers/admin/subscriptions_controller_spec.rb'
|
||||||
- 'app/controllers/api/v0/order_cycles_controller.rb'
|
- 'spec/controllers/api/v0/base_controller_spec.rb'
|
||||||
- 'lib/stripe/account_connector.rb'
|
- 'spec/controllers/api/v0/customers_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/enterprises_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/logos_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/order_cycles_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/product_images_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/products_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/promo_images_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/reports/packing_report_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/reports_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/shipments_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/statuses_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/taxons_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/terms_and_conditions_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/variants_controller_spec.rb'
|
||||||
|
- 'spec/controllers/cart_controller_spec.rb'
|
||||||
|
- 'spec/controllers/checkout_controller_spec.rb'
|
||||||
|
- 'spec/controllers/enterprises_controller_spec.rb'
|
||||||
|
- 'spec/controllers/line_items_controller_spec.rb'
|
||||||
|
- 'spec/controllers/shop_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/products_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/credit_cards_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/stripe/callbacks_controller_spec.rb'
|
||||||
|
- 'spec/controllers/stripe/webhooks_controller_spec.rb'
|
||||||
|
- 'spec/controllers/user_passwords_controller_spec.rb'
|
||||||
|
- 'spec/controllers/user_registrations_controller_spec.rb'
|
||||||
|
- 'spec/requests/api/routes_spec.rb'
|
||||||
|
- 'spec/requests/checkout/stripe_sca_spec.rb'
|
||||||
|
- 'spec/requests/home_controller_spec.rb'
|
||||||
|
- 'spec/requests/omniauth_callbacks_controller_spec.rb'
|
||||||
|
- 'spec/services/embedded_page_service_spec.rb'
|
||||||
|
- 'spec/support/api_helper.rb'
|
||||||
|
|
||||||
# Offense count: 32
|
# Offense count: 8
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
# This cop supports safe autocorrection (--autocorrect).
|
||||||
Rails/OrderArguments:
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: numeric, symbolic, be_status
|
||||||
|
RSpecRails/HttpStatus:
|
||||||
|
Exclude:
|
||||||
|
- 'spec/controllers/spree/admin/products_controller_spec.rb'
|
||||||
|
- 'spec/requests/api/orders_spec.rb'
|
||||||
|
|
||||||
|
# Offense count: 144
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: Inferences.
|
||||||
|
RSpecRails/InferredSpecType:
|
||||||
|
Exclude:
|
||||||
|
- 'engines/dfc_provider/spec/requests/addresses_spec.rb'
|
||||||
|
- 'engines/dfc_provider/spec/requests/catalog_items_spec.rb'
|
||||||
|
- 'engines/dfc_provider/spec/requests/enterprise_groups/affiliated_by_spec.rb'
|
||||||
|
- 'engines/dfc_provider/spec/requests/enterprise_groups_spec.rb'
|
||||||
|
- 'engines/dfc_provider/spec/requests/enterprises_spec.rb'
|
||||||
|
- 'engines/dfc_provider/spec/requests/offers_spec.rb'
|
||||||
|
- 'engines/dfc_provider/spec/requests/persons_spec.rb'
|
||||||
|
- 'engines/dfc_provider/spec/requests/social_medias_spec.rb'
|
||||||
|
- 'engines/dfc_provider/spec/requests/supplied_products_spec.rb'
|
||||||
|
- 'engines/web/spec/helpers/cookies_policy_helper_spec.rb'
|
||||||
|
- 'spec/controllers/admin/bulk_line_items_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/column_preferences_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/customers_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/enterprises_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/inventory_items_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/invoice_settings_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/matomo_settings_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/order_cycles_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/product_import_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/proxy_orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/reports_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/schedules_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/stripe_accounts_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/stripe_connect_settings_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/subscription_line_items_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/subscriptions_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/tag_rules_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/terms_of_service_files_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/variant_overrides_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/customers_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/enterprise_fees_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/enterprises_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/exchange_products_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/logos_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/order_cycles_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/product_images_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/products_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/promo_images_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/reports/packing_report_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/reports_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/shipments_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/shops_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/statuses_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/terms_and_conditions_controller_spec.rb'
|
||||||
|
- 'spec/controllers/api/v0/variants_controller_spec.rb'
|
||||||
|
- 'spec/controllers/base_controller_spec.rb'
|
||||||
|
- 'spec/controllers/cart_controller_spec.rb'
|
||||||
|
- 'spec/controllers/checkout_controller_spec.rb'
|
||||||
|
- 'spec/controllers/enterprises_controller_spec.rb'
|
||||||
|
- 'spec/controllers/groups_controller_spec.rb'
|
||||||
|
- 'spec/controllers/line_items_controller_spec.rb'
|
||||||
|
- 'spec/controllers/payment_gateways/paypal_controller_spec.rb'
|
||||||
|
- 'spec/controllers/payment_gateways/stripe_controller_spec.rb'
|
||||||
|
- 'spec/controllers/registration_controller_spec.rb'
|
||||||
|
- 'spec/controllers/shop_controller_spec.rb'
|
||||||
|
- 'spec/controllers/shops_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/adjustments_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/base_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/countries_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/general_settings_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/orders/customer_details_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/orders/invoices_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/orders/payments/payments_controller_refunds_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/orders/payments/payments_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/overview_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/payment_methods_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/products_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/return_authorizations_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/search_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/shipping_categories_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/shipping_methods_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/tax_rates_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/tax_settings_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/variants_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/api_keys_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/credit_cards_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/user_sessions_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/users_controller_spec.rb'
|
||||||
|
- 'spec/controllers/stripe/callbacks_controller_spec.rb'
|
||||||
|
- 'spec/controllers/stripe/webhooks_controller_spec.rb'
|
||||||
|
- 'spec/controllers/user_confirmations_controller_spec.rb'
|
||||||
|
- 'spec/controllers/user_passwords_controller_spec.rb'
|
||||||
|
- 'spec/controllers/user_registrations_controller_spec.rb'
|
||||||
|
- 'spec/controllers/webhook_endpoints_controller_spec.rb'
|
||||||
|
- 'spec/helpers/admin/enterprises_helper_spec.rb'
|
||||||
|
- 'spec/helpers/admin/orders_helper_spec.rb'
|
||||||
|
- 'spec/helpers/admin/reports_helper_spec.rb'
|
||||||
|
- 'spec/helpers/admin/subscriptions_helper_spec.rb'
|
||||||
|
- 'spec/helpers/application_helper_spec.rb'
|
||||||
|
- 'spec/helpers/checkout_helper_spec.rb'
|
||||||
|
- 'spec/helpers/i18n_helper_spec.rb'
|
||||||
|
- 'spec/helpers/injection_helper_spec.rb'
|
||||||
|
- 'spec/helpers/link_helper_spec.rb'
|
||||||
|
- 'spec/helpers/navigation_helper_spec.rb'
|
||||||
|
- 'spec/helpers/order_cycles_helper_spec.rb'
|
||||||
|
- 'spec/helpers/serializer_helper_spec.rb'
|
||||||
|
- 'spec/helpers/shop_helper_spec.rb'
|
||||||
|
- 'spec/helpers/spree/admin/base_helper_spec.rb'
|
||||||
|
- 'spec/helpers/spree/admin/general_settings_helper_spec.rb'
|
||||||
|
- 'spec/helpers/spree/admin/orders_helper_spec.rb'
|
||||||
|
- 'spec/helpers/spree/orders_helper_spec.rb'
|
||||||
|
- 'spec/helpers/tax_helper_spec.rb'
|
||||||
|
- 'spec/helpers/terms_and_conditions_helper_spec.rb'
|
||||||
|
- 'spec/jobs/connect_app_job_spec.rb'
|
||||||
|
- 'spec/mailers/producer_mailer_spec.rb'
|
||||||
|
- 'spec/mailers/subscription_mailer_spec.rb'
|
||||||
|
- 'spec/models/column_preference_spec.rb'
|
||||||
|
- 'spec/models/connected_app_spec.rb'
|
||||||
|
- 'spec/models/customer_spec.rb'
|
||||||
|
- 'spec/models/invoice_spec.rb'
|
||||||
|
- 'spec/models/oidc_account_spec.rb'
|
||||||
|
- 'spec/models/proxy_order_spec.rb'
|
||||||
|
- 'spec/models/report_blob_spec.rb'
|
||||||
|
- 'spec/models/semantic_link_spec.rb'
|
||||||
|
- 'spec/models/spree/gateway/stripe_sca_spec.rb'
|
||||||
|
- 'spec/models/subscription_spec.rb'
|
||||||
|
- 'spec/models/tag_rule/filter_order_cycles_spec.rb'
|
||||||
|
- 'spec/models/tag_rule/filter_payment_methods_spec.rb'
|
||||||
|
- 'spec/models/tag_rule/filter_products_spec.rb'
|
||||||
|
- 'spec/models/tag_rule/filter_shipping_methods_spec.rb'
|
||||||
|
- 'spec/models/tag_rule_spec.rb'
|
||||||
|
- 'spec/models/webhook_endpoint_spec.rb'
|
||||||
|
- 'spec/requests/admin/images_spec.rb'
|
||||||
|
- 'spec/requests/admin/product_import_spec.rb'
|
||||||
|
- 'spec/requests/admin/vouchers_spec.rb'
|
||||||
|
- 'spec/requests/api/orders_spec.rb'
|
||||||
|
- 'spec/requests/api/routes_spec.rb'
|
||||||
|
- 'spec/requests/api/v1/customers_spec.rb'
|
||||||
|
- 'spec/requests/api_docs_spec.rb'
|
||||||
|
- 'spec/requests/checkout/paypal_spec.rb'
|
||||||
|
- 'spec/requests/checkout/routes_spec.rb'
|
||||||
|
- 'spec/requests/checkout/stripe_sca_spec.rb'
|
||||||
|
- 'spec/requests/errors_spec.rb'
|
||||||
|
- 'spec/requests/home_controller_spec.rb'
|
||||||
|
- 'spec/requests/large_request_spec.rb'
|
||||||
|
- 'spec/requests/omniauth_callbacks_controller_spec.rb'
|
||||||
|
- 'spec/requests/spree/admin/overview_spec.rb'
|
||||||
|
- 'spec/requests/spree/admin/payments_spec.rb'
|
||||||
|
- 'spec/requests/voucher_adjustments_spec.rb'
|
||||||
|
- 'spec/routing/stripe_spec.rb'
|
||||||
|
|
||||||
|
# Offense count: 22
|
||||||
|
# Configuration parameters: IgnoreScopes, Include.
|
||||||
|
# Include: app/models/**/*.rb
|
||||||
|
Rails/InverseOf:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/controllers/admin/enterprise_fees_controller.rb'
|
|
||||||
- 'app/controllers/admin/enterprises_controller.rb'
|
|
||||||
- 'app/controllers/admin/order_cycles_controller.rb'
|
|
||||||
- 'app/controllers/admin/product_import_controller.rb'
|
|
||||||
- 'app/controllers/api/v0/states_controller.rb'
|
|
||||||
- 'app/controllers/spree/admin/overview_controller.rb'
|
|
||||||
- 'app/controllers/spree/admin/products_controller.rb'
|
|
||||||
- 'app/helpers/enterprises_helper.rb'
|
|
||||||
- 'app/models/enterprise.rb'
|
- 'app/models/enterprise.rb'
|
||||||
- 'app/models/enterprise_group.rb'
|
|
||||||
- 'app/models/enterprise_relationship_permission.rb'
|
|
||||||
- 'app/models/order_cycle.rb'
|
- 'app/models/order_cycle.rb'
|
||||||
- 'app/models/product_import/product_importer.rb'
|
|
||||||
- 'app/models/schedule.rb'
|
|
||||||
- 'app/models/spree/country.rb'
|
- 'app/models/spree/country.rb'
|
||||||
|
- 'app/models/spree/inventory_unit.rb'
|
||||||
|
- 'app/models/spree/line_item.rb'
|
||||||
- 'app/models/spree/order.rb'
|
- 'app/models/spree/order.rb'
|
||||||
- 'app/models/spree/shipping_rate.rb'
|
- 'app/models/spree/payment.rb'
|
||||||
- 'app/models/spree/user.rb'
|
- 'app/models/spree/price.rb'
|
||||||
- 'app/models/spree/zone.rb'
|
|
||||||
- 'app/models/subscription_line_item.rb'
|
|
||||||
- 'app/models/tag_rule.rb'
|
|
||||||
- 'app/models/variant_override.rb'
|
|
||||||
- 'lib/open_food_network/address_finder.rb'
|
|
||||||
- 'spec/services/orders/generate_invoice_service_spec.rb'
|
|
||||||
- 'spec/system/admin/order_cycles/simple_spec.rb'
|
|
||||||
|
|
||||||
# Offense count: 3
|
|
||||||
# This cop supports safe autocorrection (--autocorrect).
|
|
||||||
Rails/Presence:
|
|
||||||
Exclude:
|
|
||||||
- 'app/controllers/admin/enterprises_controller.rb'
|
|
||||||
- 'app/models/spree/product.rb'
|
- 'app/models/spree/product.rb'
|
||||||
|
- 'app/models/spree/stock_item.rb'
|
||||||
|
- 'app/models/spree/taxonomy.rb'
|
||||||
|
- 'app/models/spree/variant.rb'
|
||||||
|
- 'app/models/subscription_line_item.rb'
|
||||||
|
|
||||||
# Offense count: 6
|
# Offense count: 35
|
||||||
# This cop supports safe autocorrection (--autocorrect).
|
# Configuration parameters: Include.
|
||||||
# Configuration parameters: Severity.
|
# Include: app/controllers/**/*.rb, app/mailers/**/*.rb
|
||||||
Rails/RedirectBackOrTo:
|
Rails/LexicallyScopedActionFilter:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
- 'app/controllers/admin/enterprise_groups_controller.rb'
|
||||||
|
- 'app/controllers/admin/enterprises_controller.rb'
|
||||||
- 'app/controllers/admin/order_cycles_controller.rb'
|
- 'app/controllers/admin/order_cycles_controller.rb'
|
||||||
- 'app/controllers/locales_controller.rb'
|
- 'app/controllers/admin/producer_properties_controller.rb'
|
||||||
- 'app/controllers/spree/admin/invoices_controller.rb'
|
- 'app/controllers/admin/product_import_controller.rb'
|
||||||
- 'app/controllers/spree/admin/orders_controller.rb'
|
- 'app/controllers/admin/schedules_controller.rb'
|
||||||
|
- 'app/controllers/admin/subscriptions_controller.rb'
|
||||||
|
- 'app/controllers/concerns/checkout_callbacks.rb'
|
||||||
|
- 'app/controllers/registration_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/adjustments_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/payment_methods_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/payments_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/products_controller.rb'
|
||||||
- 'app/controllers/spree/admin/return_authorizations_controller.rb'
|
- 'app/controllers/spree/admin/return_authorizations_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/search_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/shipping_methods_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/users_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/zones_controller.rb'
|
||||||
|
- 'app/controllers/spree/users_controller.rb'
|
||||||
|
|
||||||
|
# Offense count: 56
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: Include.
|
||||||
|
# Include: spec/controllers/**/*.rb, spec/requests/**/*.rb, test/controllers/**/*.rb, test/integration/**/*.rb
|
||||||
|
Rails/ResponseParsedBody:
|
||||||
|
Exclude:
|
||||||
|
- 'spec/controllers/admin/bulk_line_items_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/customers_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/order_cycles_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/proxy_orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/schedules_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/stripe_accounts_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/subscription_line_items_controller_spec.rb'
|
||||||
|
- 'spec/controllers/admin/subscriptions_controller_spec.rb'
|
||||||
|
- 'spec/controllers/cart_controller_spec.rb'
|
||||||
|
- 'spec/controllers/line_items_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/search_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/credit_cards_controller_spec.rb'
|
||||||
|
- 'spec/controllers/user_registrations_controller_spec.rb'
|
||||||
|
|
||||||
|
# Offense count: 7
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: strict, flexible
|
||||||
|
Rails/TimeZone:
|
||||||
|
Exclude:
|
||||||
|
- 'app/models/spree/gateway/pay_pal_express.rb'
|
||||||
|
- 'spec/controllers/spree/credit_cards_controller_spec.rb'
|
||||||
|
- 'spec/services/order_cycles/webhook_service_spec.rb'
|
||||||
|
- 'spec/services/orders/customer_cancellation_service_spec.rb'
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# Configuration parameters: TransactionMethods.
|
# Configuration parameters: TransactionMethods.
|
||||||
@@ -360,25 +638,45 @@ Rails/TransactionExitStatement:
|
|||||||
Exclude:
|
Exclude:
|
||||||
- 'app/services/place_proxy_order.rb'
|
- 'app/services/place_proxy_order.rb'
|
||||||
|
|
||||||
# Offense count: 3
|
# Offense count: 5
|
||||||
|
# Configuration parameters: Include.
|
||||||
|
# Include: app/models/**/*.rb
|
||||||
|
Rails/UniqueValidationWithoutIndex:
|
||||||
|
Exclude:
|
||||||
|
- 'app/models/customer.rb'
|
||||||
|
- 'app/models/exchange.rb'
|
||||||
|
- 'app/models/spree/stock_item.rb'
|
||||||
|
- 'app/models/spree/tax_category.rb'
|
||||||
|
- 'app/models/spree/zone.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
Security/Open:
|
||||||
|
Exclude:
|
||||||
|
- 'app/services/image_importer.rb'
|
||||||
|
|
||||||
|
# Offense count: 7
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
Style/ArrayIntersect:
|
Style/ArrayIntersect:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/models/spree/ability.rb'
|
- 'app/models/spree/ability.rb'
|
||||||
- 'app/models/spree/variant.rb'
|
- 'app/models/tag_rule/filter_order_cycles.rb'
|
||||||
|
- 'app/models/tag_rule/filter_payment_methods.rb'
|
||||||
|
- 'app/models/tag_rule/filter_products.rb'
|
||||||
|
- 'app/models/tag_rule/filter_shipping_methods.rb'
|
||||||
|
- 'lib/open_food_network/tag_rule_applicator.rb'
|
||||||
|
- 'spec/support/matchers/select2_matchers.rb'
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
# This cop supports safe autocorrection (--autocorrect).
|
||||||
Style/BitwisePredicate:
|
# Configuration parameters: AllowOnConstant, AllowOnSelfClass.
|
||||||
|
Style/CaseEquality:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/helpers/admin/enterprises_helper.rb'
|
- 'spec/models/spree/payment_spec.rb'
|
||||||
|
|
||||||
# Offense count: 23
|
# Offense count: 23
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
# Configuration parameters: EnforcedStyle, EnforcedStyleForClasses, EnforcedStyleForModules.
|
# Configuration parameters: EnforcedStyle.
|
||||||
# SupportedStyles: nested, compact
|
# SupportedStyles: nested, compact
|
||||||
# SupportedStylesForClasses: ~, nested, compact
|
|
||||||
# SupportedStylesForModules: ~, nested, compact
|
|
||||||
Style/ClassAndModuleChildren:
|
Style/ClassAndModuleChildren:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'app/models/calculator/flat_percent_per_item.rb'
|
- 'app/models/calculator/flat_percent_per_item.rb'
|
||||||
@@ -404,35 +702,87 @@ Style/ClassAndModuleChildren:
|
|||||||
- 'lib/open_food_network/locking.rb'
|
- 'lib/open_food_network/locking.rb'
|
||||||
- 'spec/models/spree/payment_method_spec.rb'
|
- 'spec/models/spree/payment_method_spec.rb'
|
||||||
|
|
||||||
# Offense count: 14
|
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
||||||
Style/CollectionQuerying:
|
|
||||||
Exclude:
|
|
||||||
- 'app/controllers/spree/credit_cards_controller.rb'
|
|
||||||
- 'app/models/product_import/product_importer.rb'
|
|
||||||
- 'app/models/product_import/spreadsheet_entry.rb'
|
|
||||||
- 'app/models/spree/order.rb'
|
|
||||||
- 'app/models/spree/order_inventory.rb'
|
|
||||||
- 'app/models/spree/payment_method.rb'
|
|
||||||
- 'app/models/spree/user.rb'
|
|
||||||
- 'app/models/stripe_account.rb'
|
|
||||||
- 'app/services/order_cycles/warning_service.rb'
|
|
||||||
- 'lib/reporting/report_renderer.rb'
|
|
||||||
- 'lib/tasks/sample_data.rake'
|
|
||||||
|
|
||||||
# Offense count: 2
|
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
|
||||||
Style/HashSlice:
|
|
||||||
Exclude:
|
|
||||||
- 'app/services/product_filters.rb'
|
|
||||||
- 'lib/reporting/report_row_builder.rb'
|
|
||||||
|
|
||||||
# Offense count: 1
|
# Offense count: 1
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: always, always_true, never
|
||||||
|
Style/FrozenStringLiteralComment:
|
||||||
|
Exclude:
|
||||||
|
- '.simplecov'
|
||||||
|
|
||||||
|
# Offense count: 6
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
Style/GlobalStdStream:
|
||||||
|
Exclude:
|
||||||
|
- 'lib/tasks/data.rake'
|
||||||
|
- 'lib/tasks/missing_payments.rake'
|
||||||
|
- 'lib/tasks/sample_data/logging.rb'
|
||||||
|
- 'lib/tasks/subscriptions/debug.rake'
|
||||||
|
- 'lib/tasks/subscriptions/test.rake'
|
||||||
|
|
||||||
|
# Offense count: 12
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: AllowSplatArgument.
|
||||||
|
Style/HashConversion:
|
||||||
|
Exclude:
|
||||||
|
- 'app/controllers/admin/column_preferences_controller.rb'
|
||||||
|
- 'app/controllers/admin/variant_overrides_controller.rb'
|
||||||
|
- 'app/controllers/spree/admin/products_controller.rb'
|
||||||
|
- 'app/models/order_cycle.rb'
|
||||||
|
- 'app/models/product_import/product_importer.rb'
|
||||||
|
- 'app/models/spree/shipping_method.rb'
|
||||||
|
- 'app/serializers/api/admin/exchange_serializer.rb'
|
||||||
|
- 'app/services/variants_stock_levels.rb'
|
||||||
|
- '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: 4
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
Style/MapToHash:
|
Style/MapToHash:
|
||||||
Exclude:
|
Exclude:
|
||||||
|
- 'lib/reporting/report_query_template.rb'
|
||||||
|
- 'lib/reporting/report_row_builder.rb'
|
||||||
|
- 'lib/reporting/reports/enterprise_fee_summary/fee_summary.rb'
|
||||||
- 'lib/tasks/sample_data/user_factory.rb'
|
- 'lib/tasks/sample_data/user_factory.rb'
|
||||||
|
|
||||||
|
# Offense count: 3
|
||||||
|
Style/MissingRespondToMissing:
|
||||||
|
Exclude:
|
||||||
|
- 'app/helpers/application_helper.rb'
|
||||||
|
- 'app/models/spree/gateway.rb'
|
||||||
|
- 'app/models/spree/preferences/configuration.rb'
|
||||||
|
|
||||||
|
# Offense count: 22
|
||||||
|
# This cop supports safe autocorrection (--autocorrect).
|
||||||
|
Style/NestedModifier:
|
||||||
|
Exclude:
|
||||||
|
- 'spec/controllers/admin/subscriptions_controller_spec.rb'
|
||||||
|
- 'spec/controllers/line_items_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/admin/orders_controller_spec.rb'
|
||||||
|
- 'spec/controllers/spree/orders_controller_spec.rb'
|
||||||
|
- 'spec/factories/order_factory.rb'
|
||||||
|
- 'spec/models/proxy_order_spec.rb'
|
||||||
|
- 'spec/models/spree/line_item_spec.rb'
|
||||||
|
- 'spec/services/place_proxy_order_spec.rb'
|
||||||
|
- 'spec/system/admin/payments_stripe_spec.rb'
|
||||||
|
- 'spec/system/admin/reports_spec.rb'
|
||||||
|
|
||||||
# Offense count: 38
|
# Offense count: 38
|
||||||
Style/OpenStructUse:
|
Style/OpenStructUse:
|
||||||
Exclude:
|
Exclude:
|
||||||
@@ -462,21 +812,47 @@ Style/OptionalBooleanParameter:
|
|||||||
- 'lib/spree/core/controller_helpers/order.rb'
|
- 'lib/spree/core/controller_helpers/order.rb'
|
||||||
- 'spec/support/request/web_helper.rb'
|
- 'spec/support/request/web_helper.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: EnforcedStyle.
|
||||||
|
# SupportedStyles: short, verbose
|
||||||
|
Style/PreferredHashMethods:
|
||||||
|
Exclude:
|
||||||
|
- 'app/controllers/api/v0/shipments_controller.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: Methods.
|
||||||
|
Style/RedundantArgument:
|
||||||
|
Exclude:
|
||||||
|
- 'engines/dfc_provider/app/services/authorization_control.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# This cop supports safe autocorrection (--autocorrect).
|
||||||
|
Style/RedundantAssignment:
|
||||||
|
Exclude:
|
||||||
|
- 'spec/models/database_spec.rb'
|
||||||
|
|
||||||
|
# Offense count: 1
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: AutoCorrect, AllowComments.
|
||||||
|
Style/RedundantInitialize:
|
||||||
|
Exclude:
|
||||||
|
- 'spec/models/spree/gateway_spec.rb'
|
||||||
|
|
||||||
|
# Offense count: 19
|
||||||
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
|
# Configuration parameters: AllowedMethods, AllowedPatterns.
|
||||||
|
Style/ReturnNilInPredicateMethodDefinition:
|
||||||
|
Exclude:
|
||||||
|
- 'app/models/order_cycle.rb'
|
||||||
|
- 'app/serializers/api/admin/customer_serializer.rb'
|
||||||
|
- 'engines/order_management/app/services/order_management/subscriptions/validator.rb'
|
||||||
|
|
||||||
# Offense count: 3
|
# Offense count: 3
|
||||||
# This cop supports unsafe autocorrection (--autocorrect-all).
|
# This cop supports unsafe autocorrection (--autocorrect-all).
|
||||||
Style/RedundantFormat:
|
Style/SlicingWithRange:
|
||||||
Exclude:
|
Exclude:
|
||||||
- 'spec/models/product_importer_spec.rb'
|
- 'app/helpers/spree/admin/navigation_helper.rb'
|
||||||
- 'spec/requests/checkout/stripe_sca_spec.rb'
|
- 'app/services/embedded_page_service.rb'
|
||||||
- 'spec/system/consumer/account/cards_spec.rb'
|
- 'engines/order_management/app/services/order_management/subscriptions/validator.rb'
|
||||||
|
|
||||||
# Offense count: 8
|
|
||||||
# Configuration parameters: Max.
|
|
||||||
Style/SafeNavigationChainLength:
|
|
||||||
Exclude:
|
|
||||||
- 'app/controllers/concerns/extra_fields.rb'
|
|
||||||
- 'app/services/customer_syncer.rb'
|
|
||||||
- 'app/services/fdc_offer_broker.rb'
|
|
||||||
- 'engines/dfc_provider/app/services/dfc_catalog.rb'
|
|
||||||
- 'engines/dfc_provider/app/services/image_builder.rb'
|
|
||||||
- 'engines/dfc_provider/app/services/quantitative_value_builder.rb'
|
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
3.2.9
|
3.1.4
|
||||||
|
|||||||
19
.scss-lint.yml
Normal file
19
.scss-lint.yml
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
scss_files: 'app/assets/stylesheets/**/*.css.scss'
|
||||||
|
|
||||||
|
exclude: 'app/assets/stylesheets/shared/**'
|
||||||
|
|
||||||
|
linters:
|
||||||
|
ImportantRule:
|
||||||
|
enabled: false
|
||||||
|
VendorPrefix:
|
||||||
|
enabled: false
|
||||||
|
LeadingZero:
|
||||||
|
enabled: false
|
||||||
|
PropertySortOrder:
|
||||||
|
enabled: false
|
||||||
|
StringQuotes:
|
||||||
|
enabled: false
|
||||||
|
DeclarationOrder:
|
||||||
|
enabled: false
|
||||||
|
NestingDepth:
|
||||||
|
enabled: false
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
# .secrets file define github secrets value locally
|
|
||||||
DEPENDABOT_PR_APP_ID=123456
|
|
||||||
DEPENDABOT_PR_APP_INSTALLATION_ID=123456
|
|
||||||
DEPENDABOT_PR_APP_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n....\n-----END RSA PRIVATE KEY-----"
|
|
||||||
21
.simplecov
21
.simplecov
@@ -1,18 +1,19 @@
|
|||||||
#!/bin/env ruby
|
#!/bin/env ruby
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
SimpleCov.start 'rails' do
|
SimpleCov.start 'rails' do
|
||||||
# The rails profile contains some filters already:
|
|
||||||
#
|
|
||||||
# - "/test/"
|
|
||||||
# - "/features/"
|
|
||||||
# - "/spec/"
|
|
||||||
# - "/autotest/"
|
|
||||||
# - /^\/config\//
|
|
||||||
# - /^\/db\//
|
|
||||||
add_filter '/bin/'
|
add_filter '/bin/'
|
||||||
add_filter '/config/' # to include engine config
|
add_filter '/config/'
|
||||||
|
add_filter '/jobs/application_job.rb'
|
||||||
|
add_filter '/schemas/'
|
||||||
|
add_filter '/lib/generators'
|
||||||
|
add_filter '/spec/'
|
||||||
|
add_filter '/vendor/'
|
||||||
|
add_filter '/public'
|
||||||
|
add_filter '/swagger'
|
||||||
add_filter '/script'
|
add_filter '/script'
|
||||||
|
add_filter '/log'
|
||||||
|
add_filter '/db'
|
||||||
|
add_filter '/lib/tasks/sample_data/'
|
||||||
|
|
||||||
formatter SimpleCov::Formatter::SimpleFormatter
|
formatter SimpleCov::Formatter::SimpleFormatter
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
#!/bin/env ruby
|
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
--compare master
|
|
||||||
|
|
||||||
# This shouldn't be needed in undercover > 0.7.4
|
|
||||||
#
|
|
||||||
# * https://github.com/grodowski/undercover/issues/233
|
|
||||||
--exclude-files "bin/*,db/*,config/*,spec/*,engines/*/config/*,engines/*/spec/*"
|
|
||||||
118
Dockerfile
118
Dockerfile
@@ -1,34 +1,92 @@
|
|||||||
FROM ruby:3.2.9-alpine3.19 AS base
|
FROM ubuntu:20.04
|
||||||
ENV LANG=C.UTF-8 \
|
|
||||||
LC_ALL=C.UTF-8 \
|
|
||||||
TZ=Europe/London \
|
|
||||||
RAILS_ROOT=/usr/src/app \
|
|
||||||
BUNDLE_PATH=/bundles \
|
|
||||||
BUNDLE_APP_CONFIG=/bundles
|
|
||||||
RUN apk --no-cache upgrade && \
|
|
||||||
apk add --no-cache tzdata postgresql-client imagemagick imagemagick-jpeg && \
|
|
||||||
apk add --no-cache --virtual wkhtmltopdf
|
|
||||||
|
|
||||||
WORKDIR $RAILS_ROOT
|
ENV TZ Europe/London
|
||||||
|
|
||||||
# Development dependencies
|
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||||
FROM base AS development-base
|
|
||||||
RUN apk add --no-cache --virtual .build-deps \
|
|
||||||
build-base postgresql-dev git nodejs yarn && \
|
|
||||||
apk add --no-cache --virtual .dev-utils \
|
|
||||||
bash curl less vim chromium-chromedriver zlib-dev openssl-dev cmake\
|
|
||||||
readline-dev yaml-dev sqlite-dev libxml2-dev libxslt-dev libffi-dev vips-dev && \
|
|
||||||
curl -o /usr/local/bin/wait-for-it https://raw.githubusercontent.com/vishnubob/wait-for-it/master/wait-for-it.sh && \
|
|
||||||
chmod +x /usr/local/bin/wait-for-it
|
|
||||||
|
|
||||||
# Install yarn dependencies separately for caching
|
RUN echo "deb http://security.ubuntu.com/ubuntu bionic-security main" >> /etc/apt/sources.list
|
||||||
FROM development-base AS yarn-dependencies
|
|
||||||
COPY package.json yarn.lock ./
|
|
||||||
RUN yarn install --frozen-lockfile
|
|
||||||
|
|
||||||
# Install Ruby gems
|
# Install all the requirements
|
||||||
FROM development-base
|
RUN apt-get update && apt-get install -y \
|
||||||
COPY . $RAILS_ROOT
|
curl \
|
||||||
COPY Gemfile Gemfile.lock ./
|
git \
|
||||||
RUN bundle install --jobs "$(nproc)"
|
build-essential \
|
||||||
COPY --from=yarn-dependencies $RAILS_ROOT/node_modules ./node_modules
|
software-properties-common \
|
||||||
|
wget \
|
||||||
|
zlib1g-dev \
|
||||||
|
libreadline-dev \
|
||||||
|
libyaml-dev \
|
||||||
|
libffi-dev \
|
||||||
|
libxml2-dev \
|
||||||
|
libxslt1-dev \
|
||||||
|
wait-for-it \
|
||||||
|
imagemagick \
|
||||||
|
unzip \
|
||||||
|
libjemalloc-dev \
|
||||||
|
libssl-dev \
|
||||||
|
ca-certificates \
|
||||||
|
gnupg
|
||||||
|
|
||||||
|
# Setup ENV variables
|
||||||
|
ENV PATH /usr/local/src/rbenv/shims:/usr/local/src/rbenv/bin:/usr/local/src/nodenv/shims:/usr/local/src/nodenv/bin:$PATH
|
||||||
|
ENV RBENV_ROOT /usr/local/src/rbenv
|
||||||
|
ENV NODENV_ROOT /usr/local/src/nodenv
|
||||||
|
ENV CONFIGURE_OPTS --disable-install-doc
|
||||||
|
ENV BUNDLE_PATH /bundles
|
||||||
|
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so
|
||||||
|
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# trim spaces and line return from .ruby-version file
|
||||||
|
COPY .ruby-version .ruby-version.raw
|
||||||
|
RUN cat .ruby-version.raw | tr -d '\r\t ' > .ruby-version
|
||||||
|
|
||||||
|
# Install Rbenv & Ruby
|
||||||
|
RUN git clone --depth 1 https://github.com/rbenv/rbenv.git ${RBENV_ROOT} && \
|
||||||
|
git clone --depth 1 https://github.com/rbenv/ruby-build.git ${RBENV_ROOT}/plugins/ruby-build && \
|
||||||
|
echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh && \
|
||||||
|
RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install $(cat .ruby-version) && \
|
||||||
|
rbenv global $(cat .ruby-version)
|
||||||
|
|
||||||
|
# Install Postgres
|
||||||
|
RUN sh -c "echo 'deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main' >> /etc/apt/sources.list.d/pgdg.list" && \
|
||||||
|
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg >/dev/null && \
|
||||||
|
apt-get update && \
|
||||||
|
apt-get install -yqq --no-install-recommends postgresql-client-10 libpq-dev
|
||||||
|
|
||||||
|
|
||||||
|
# trim spaces and line return from .node-version file
|
||||||
|
COPY .node-version .node-version.raw
|
||||||
|
RUN cat .node-version.raw | tr -d '\r\t ' > .node-version
|
||||||
|
|
||||||
|
# Install Node and Yarn with Nodenv
|
||||||
|
RUN git clone --depth 1 https://github.com/nodenv/nodenv.git ${NODENV_ROOT} && \
|
||||||
|
git clone --depth 1 https://github.com/nodenv/node-build.git ${NODENV_ROOT}/plugins/node-build && \
|
||||||
|
git clone --depth 1 https://github.com/pine/nodenv-yarn-install.git ${NODENV_ROOT}/plugins/nodenv-yarn-install && \
|
||||||
|
git clone --depth 1 https://github.com/nodenv/nodenv-package-rehash.git ${NODENV_ROOT}/plugins/nodenv-package-rehash && \
|
||||||
|
echo 'eval "$(nodenv init -)"' >> /etc/profile.d/nodenv.sh && \
|
||||||
|
nodenv install $(cat .node-version) && \
|
||||||
|
nodenv global $(cat .node-version)
|
||||||
|
|
||||||
|
# Install Chrome
|
||||||
|
RUN wget --quiet -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
|
||||||
|
sh -c "echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' >> /etc/apt/sources.list.d/google-chrome.list" && \
|
||||||
|
apt-get update && \
|
||||||
|
apt-get install -fy google-chrome-stable
|
||||||
|
|
||||||
|
# Install Chromedriver
|
||||||
|
RUN wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.zip && \
|
||||||
|
unzip chromedriver_linux64.zip -d /usr/bin && \
|
||||||
|
chmod u+x /usr/bin/chromedriver
|
||||||
|
|
||||||
|
# Copy code and install app dependencies
|
||||||
|
COPY . /usr/src/app/
|
||||||
|
|
||||||
|
# Install Bundler
|
||||||
|
RUN ./script/install-bundler
|
||||||
|
|
||||||
|
# Install front-end dependencies
|
||||||
|
RUN yarn install
|
||||||
|
|
||||||
|
# Run bundler install in parallel with the amount of available CPUs
|
||||||
|
RUN bundle install --jobs="$(nproc)"
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
FROM ubuntu:20.04
|
|
||||||
|
|
||||||
ENV TZ Europe/London
|
|
||||||
|
|
||||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
|
||||||
|
|
||||||
RUN echo "deb http://security.ubuntu.com/ubuntu bionic-security main" >> /etc/apt/sources.list
|
|
||||||
|
|
||||||
# Install all the requirements
|
|
||||||
RUN apt-get update && apt-get install -y \
|
|
||||||
curl \
|
|
||||||
git \
|
|
||||||
build-essential \
|
|
||||||
software-properties-common \
|
|
||||||
wget \
|
|
||||||
zlib1g-dev \
|
|
||||||
libreadline-dev \
|
|
||||||
libyaml-dev \
|
|
||||||
libffi-dev \
|
|
||||||
libxml2-dev \
|
|
||||||
libxslt1-dev \
|
|
||||||
wait-for-it \
|
|
||||||
imagemagick \
|
|
||||||
unzip \
|
|
||||||
libjemalloc-dev \
|
|
||||||
libssl-dev \
|
|
||||||
ca-certificates \
|
|
||||||
gnupg \
|
|
||||||
cmake
|
|
||||||
|
|
||||||
# Setup ENV variables
|
|
||||||
ENV PATH /usr/local/src/rbenv/shims:/usr/local/src/rbenv/bin:/usr/local/src/nodenv/shims:/usr/local/src/nodenv/bin:$PATH
|
|
||||||
ENV RBENV_ROOT /usr/local/src/rbenv
|
|
||||||
ENV NODENV_ROOT /usr/local/src/nodenv
|
|
||||||
ENV CONFIGURE_OPTS --disable-install-doc
|
|
||||||
ENV BUNDLE_PATH /bundles
|
|
||||||
ENV LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so
|
|
||||||
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
# trim spaces and line return from .ruby-version file
|
|
||||||
COPY .ruby-version .ruby-version.raw
|
|
||||||
RUN cat .ruby-version.raw | tr -d '\r\t ' > .ruby-version
|
|
||||||
|
|
||||||
# Install Rbenv & Ruby
|
|
||||||
RUN git clone --depth 1 https://github.com/rbenv/rbenv.git ${RBENV_ROOT} && \
|
|
||||||
git clone --depth 1 https://github.com/rbenv/ruby-build.git ${RBENV_ROOT}/plugins/ruby-build && \
|
|
||||||
echo 'eval "$(rbenv init -)"' >> /etc/profile.d/rbenv.sh && \
|
|
||||||
RUBY_CONFIGURE_OPTS=--with-jemalloc rbenv install $(cat .ruby-version) && \
|
|
||||||
rbenv global $(cat .ruby-version)
|
|
||||||
|
|
||||||
# Install Postgres
|
|
||||||
RUN sh -c "echo 'deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main' >> /etc/apt/sources.list.d/pgdg.list" && \
|
|
||||||
curl https://www.postgresql.org/media/keys/ACCC4CF8.asc | gpg --dearmor | tee /etc/apt/trusted.gpg.d/apt.postgresql.org.gpg >/dev/null && \
|
|
||||||
apt-get update && \
|
|
||||||
apt-get install -yqq --no-install-recommends postgresql-client-10 libpq-dev
|
|
||||||
|
|
||||||
|
|
||||||
# trim spaces and line return from .node-version file
|
|
||||||
COPY .node-version .node-version.raw
|
|
||||||
RUN cat .node-version.raw | tr -d '\r\t ' > .node-version
|
|
||||||
|
|
||||||
# Install Node and Yarn with Nodenv
|
|
||||||
RUN git clone --depth 1 https://github.com/nodenv/nodenv.git ${NODENV_ROOT} && \
|
|
||||||
git clone --depth 1 https://github.com/nodenv/node-build.git ${NODENV_ROOT}/plugins/node-build && \
|
|
||||||
git clone --depth 1 https://github.com/pine/nodenv-yarn-install.git ${NODENV_ROOT}/plugins/nodenv-yarn-install && \
|
|
||||||
git clone --depth 1 https://github.com/nodenv/nodenv-package-rehash.git ${NODENV_ROOT}/plugins/nodenv-package-rehash && \
|
|
||||||
echo 'eval "$(nodenv init -)"' >> /etc/profile.d/nodenv.sh && \
|
|
||||||
nodenv install $(cat .node-version) && \
|
|
||||||
nodenv global $(cat .node-version)
|
|
||||||
|
|
||||||
# Install Chrome
|
|
||||||
RUN wget --quiet -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - && \
|
|
||||||
sh -c "echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' >> /etc/apt/sources.list.d/google-chrome.list" && \
|
|
||||||
apt-get update && \
|
|
||||||
apt-get install -fy google-chrome-stable
|
|
||||||
|
|
||||||
# Install Chromedriver
|
|
||||||
RUN wget https://chromedriver.storage.googleapis.com/2.41/chromedriver_linux64.zip && \
|
|
||||||
unzip chromedriver_linux64.zip -d /usr/bin && \
|
|
||||||
chmod u+x /usr/bin/chromedriver
|
|
||||||
|
|
||||||
# Copy code and install app dependencies
|
|
||||||
COPY . /usr/src/app/
|
|
||||||
|
|
||||||
# Install Bundler
|
|
||||||
RUN ./script/install-bundler
|
|
||||||
|
|
||||||
# Install front-end dependencies
|
|
||||||
RUN yarn install
|
|
||||||
|
|
||||||
# Run bundler install in parallel with the amount of available CPUs
|
|
||||||
RUN bundle install --jobs="$(nproc)"
|
|
||||||
@@ -73,7 +73,7 @@ To login as the default user, use:
|
|||||||
email: ofn@example.com
|
email: ofn@example.com
|
||||||
password: ofn123
|
password: ofn123
|
||||||
|
|
||||||
See [Locale and sample data] about loading data.
|
Seee [Locale and sample data] about loading data.
|
||||||
|
|
||||||
### Testing
|
### Testing
|
||||||
|
|
||||||
|
|||||||
31
Gemfile
31
Gemfile
@@ -1,6 +1,6 @@
|
|||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
source 'https://gem.coop'
|
source 'https://rubygems.org'
|
||||||
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
|
git_source(:github) { |repo_name| "https://github.com/#{repo_name}.git" }
|
||||||
|
|
||||||
ruby File.read('.ruby-version').chomp
|
ruby File.read('.ruby-version').chomp
|
||||||
@@ -14,19 +14,16 @@ gem "active_storage_validations"
|
|||||||
gem "aws-sdk-s3", require: false
|
gem "aws-sdk-s3", require: false
|
||||||
gem "image_processing"
|
gem "image_processing"
|
||||||
|
|
||||||
gem 'activemerchant'
|
gem 'activemerchant', '>= 1.78.0'
|
||||||
gem 'angular-rails-templates'
|
gem 'angular-rails-templates', '>= 0.3.0'
|
||||||
gem 'ransack', '~> 4.1.0'
|
gem 'ransack', '~> 4.1.0'
|
||||||
gem 'responders'
|
gem 'responders'
|
||||||
gem 'webpacker', '~> 5'
|
gem 'webpacker', '~> 5'
|
||||||
|
|
||||||
# Indirect dependency but we access it directly in JS specs.
|
|
||||||
# It turns out to be hard to upgrade but please do if you can.
|
|
||||||
gem 'sprockets', '~> 3.7'
|
|
||||||
|
|
||||||
gem 'i18n'
|
gem 'i18n'
|
||||||
gem 'i18n-js', '~> 3.9.0'
|
gem 'i18n-js', '~> 3.9.0'
|
||||||
gem 'rails-i18n'
|
gem 'rails-i18n'
|
||||||
|
gem 'rails_safe_tasks', '~> 1.0'
|
||||||
|
|
||||||
gem "activerecord-import"
|
gem "activerecord-import"
|
||||||
gem "db2fog", github: "openfoodfoundation/db2fog", branch: "rails-7"
|
gem "db2fog", github: "openfoodfoundation/db2fog", branch: "rails-7"
|
||||||
@@ -43,7 +40,7 @@ gem 'web', path: './engines/web'
|
|||||||
|
|
||||||
gem "activerecord-postgresql-adapter"
|
gem "activerecord-postgresql-adapter"
|
||||||
gem "arel-helpers", "~> 2.12"
|
gem "arel-helpers", "~> 2.12"
|
||||||
gem "pg"
|
gem "pg", "~> 1.2.3"
|
||||||
|
|
||||||
gem 'acts_as_list', '1.0.4'
|
gem 'acts_as_list', '1.0.4'
|
||||||
gem 'cancancan', '~> 1.15.0'
|
gem 'cancancan', '~> 1.15.0'
|
||||||
@@ -57,7 +54,7 @@ gem 'state_machines-activerecord'
|
|||||||
gem 'stringex', '~> 2.8.5', require: false
|
gem 'stringex', '~> 2.8.5', require: false
|
||||||
|
|
||||||
gem 'paypal-sdk-merchant', '1.117.2'
|
gem 'paypal-sdk-merchant', '1.117.2'
|
||||||
gem 'stripe', '~> 13'
|
gem 'stripe'
|
||||||
|
|
||||||
gem 'devise'
|
gem 'devise'
|
||||||
gem 'devise-encryptable'
|
gem 'devise-encryptable'
|
||||||
@@ -68,7 +65,7 @@ gem 'oauth2', '~> 1.4.7' # Used for Stripe Connect
|
|||||||
|
|
||||||
gem 'datafoodconsortium-connector'
|
gem 'datafoodconsortium-connector'
|
||||||
gem 'jsonapi-serializer'
|
gem 'jsonapi-serializer'
|
||||||
gem 'pagy', '~> 9'
|
gem 'pagy', '~> 5.1'
|
||||||
|
|
||||||
gem 'rswag-api'
|
gem 'rswag-api'
|
||||||
gem 'rswag-ui'
|
gem 'rswag-ui'
|
||||||
@@ -89,7 +86,7 @@ gem "active_model_serializers", "0.8.4"
|
|||||||
gem 'activerecord-session_store'
|
gem 'activerecord-session_store'
|
||||||
gem 'acts-as-taggable-on'
|
gem 'acts-as-taggable-on'
|
||||||
gem 'angularjs-file-upload-rails', '~> 2.4.1'
|
gem 'angularjs-file-upload-rails', '~> 2.4.1'
|
||||||
gem 'bigdecimal'
|
gem 'bigdecimal', '3.0.2'
|
||||||
gem 'bootsnap', require: false
|
gem 'bootsnap', require: false
|
||||||
gem 'geocoder'
|
gem 'geocoder'
|
||||||
gem 'gmaps4rails'
|
gem 'gmaps4rails'
|
||||||
@@ -155,7 +152,6 @@ end
|
|||||||
group :test, :development do
|
group :test, :development do
|
||||||
gem 'bullet'
|
gem 'bullet'
|
||||||
gem 'capybara'
|
gem 'capybara'
|
||||||
gem 'capybara-shadowdom'
|
|
||||||
gem 'cuprite'
|
gem 'cuprite'
|
||||||
gem 'database_cleaner', require: false
|
gem 'database_cleaner', require: false
|
||||||
gem 'debug', '>= 1.0.0'
|
gem 'debug', '>= 1.0.0'
|
||||||
@@ -170,14 +166,13 @@ group :test, :development do
|
|||||||
gem 'rswag'
|
gem 'rswag'
|
||||||
gem 'shoulda-matchers'
|
gem 'shoulda-matchers'
|
||||||
gem 'stimulus_reflex_testing', github: "podia/stimulus_reflex_testing", branch: :main
|
gem 'stimulus_reflex_testing', github: "podia/stimulus_reflex_testing", branch: :main
|
||||||
|
gem 'timecop'
|
||||||
end
|
end
|
||||||
|
|
||||||
group :test do
|
group :test do
|
||||||
gem 'pdf-reader'
|
gem 'pdf-reader'
|
||||||
gem 'puffing-billy'
|
|
||||||
gem 'rails-controller-testing'
|
gem 'rails-controller-testing'
|
||||||
gem 'simplecov', require: false
|
gem 'simplecov', require: false
|
||||||
gem 'undercover', require: false
|
|
||||||
gem 'vcr', require: false
|
gem 'vcr', require: false
|
||||||
gem 'webmock', require: false
|
gem 'webmock', require: false
|
||||||
# See spec/spec_helper.rb for instructions
|
# See spec/spec_helper.rb for instructions
|
||||||
@@ -185,19 +180,15 @@ group :test do
|
|||||||
end
|
end
|
||||||
|
|
||||||
group :development do
|
group :development do
|
||||||
|
gem 'debugger-linecache'
|
||||||
gem 'foreman'
|
gem 'foreman'
|
||||||
gem 'haml_lint', require: false
|
|
||||||
gem 'i18n-tasks'
|
|
||||||
gem 'listen'
|
gem 'listen'
|
||||||
gem 'pry'
|
gem 'pry', '~> 0.13.0'
|
||||||
gem 'query_count'
|
gem 'query_count'
|
||||||
gem 'rails-erd'
|
gem 'rails-erd'
|
||||||
gem 'rubocop'
|
gem 'rubocop'
|
||||||
gem 'rubocop-capybara'
|
|
||||||
gem 'rubocop-factory_bot'
|
|
||||||
gem 'rubocop-rails'
|
gem 'rubocop-rails'
|
||||||
gem 'rubocop-rspec'
|
gem 'rubocop-rspec'
|
||||||
gem 'rubocop-rspec_rails'
|
|
||||||
gem 'spring'
|
gem 'spring'
|
||||||
gem 'spring-commands-rspec'
|
gem 'spring-commands-rspec'
|
||||||
gem 'spring-commands-rubocop'
|
gem 'spring-commands-rubocop'
|
||||||
|
|||||||
768
Gemfile.lock
768
Gemfile.lock
File diff suppressed because it is too large
Load Diff
@@ -1,5 +0,0 @@
|
|||||||
# Foreman Procfile for Docker env. Start all dev server processes with: `bundle exec foreman start -f Procfile.docker`
|
|
||||||
|
|
||||||
webpack: WEBPACKER_DEV_SERVER_HOST=0.0.0.0 ./bin/webpack-dev-server
|
|
||||||
sidekiq: DEV_CACHING=true bundle exec sidekiq -q mailers -q default
|
|
||||||
rails: WEBPACKER_DEV_SERVER_HOST=0.0.0.0 DEV_CACHING=true bundle exec rails s -p 3000 -b 0.0.0.0
|
|
||||||
@@ -67,5 +67,8 @@
|
|||||||
// foundation
|
// foundation
|
||||||
//= require ../shared/mm-foundation-tpls-0.9.0-20180826174721.min.js
|
//= require ../shared/mm-foundation-tpls-0.9.0-20180826174721.min.js
|
||||||
|
|
||||||
|
// LocalStorage
|
||||||
|
//= require ../shared/angular-local-storage.js
|
||||||
|
|
||||||
// requires the rest of the JS code in this folder
|
// requires the rest of the JS code in this folder
|
||||||
//= require_tree .
|
//= require_tree .
|
||||||
|
|||||||
393
app/assets/javascripts/admin/bulk_product_update.js.coffee
Normal file
393
app/assets/javascripts/admin/bulk_product_update.js.coffee
Normal file
@@ -0,0 +1,393 @@
|
|||||||
|
angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, $location, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser, ProductFiltersUrl) ->
|
||||||
|
$scope.StatusMessage = StatusMessage
|
||||||
|
|
||||||
|
$scope.columns = Columns.columns
|
||||||
|
|
||||||
|
$scope.variant_unit_options = VariantUnitManager.variantUnitOptions()
|
||||||
|
|
||||||
|
$scope.RequestMonitor = RequestMonitor
|
||||||
|
$scope.pagination = BulkProducts.pagination
|
||||||
|
$scope.per_page_options = [
|
||||||
|
{id: 15, name: t('js.admin.orders.index.per_page', results: 15)},
|
||||||
|
{id: 50, name: t('js.admin.orders.index.per_page', results: 50)},
|
||||||
|
{id: 100, name: t('js.admin.orders.index.per_page', results: 100)}
|
||||||
|
]
|
||||||
|
|
||||||
|
$scope.q = {
|
||||||
|
producerFilter: ""
|
||||||
|
categoryFilter: ""
|
||||||
|
importDateFilter: ""
|
||||||
|
query: ""
|
||||||
|
sorting: ""
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.sorting = "name asc"
|
||||||
|
$scope.producers = producers
|
||||||
|
$scope.taxons = Taxons.all
|
||||||
|
$scope.tax_categories = tax_categories
|
||||||
|
$scope.page = 1
|
||||||
|
$scope.per_page = 15
|
||||||
|
$scope.products = BulkProducts.products
|
||||||
|
$scope.DisplayProperties = DisplayProperties
|
||||||
|
|
||||||
|
$scope.sortOptions = SortOptions
|
||||||
|
|
||||||
|
$scope.initialise = ->
|
||||||
|
$scope.q = ProductFiltersUrl.loadFromUrl($location.search())
|
||||||
|
$scope.fetchProducts()
|
||||||
|
|
||||||
|
$scope.$watchCollection '[q.query, q.producerFilter, q.categoryFilter, q.importDateFilter, per_page]', ->
|
||||||
|
$scope.page = 1 # Reset page when changing filters for new search
|
||||||
|
|
||||||
|
$scope.changePage = (newPage) ->
|
||||||
|
$scope.page = newPage
|
||||||
|
$scope.fetchProducts()
|
||||||
|
|
||||||
|
$scope.fetchProducts = ->
|
||||||
|
removeClearedValues()
|
||||||
|
params = {
|
||||||
|
'q[name_cont]': $scope.q.query,
|
||||||
|
'q[variants_supplier_id_eq]': $scope.q.producerFilter,
|
||||||
|
'q[variants_primary_taxon_id_eq]': $scope.q.categoryFilter,
|
||||||
|
'q[s]': $scope.sorting,
|
||||||
|
import_date: $scope.q.importDateFilter,
|
||||||
|
page: $scope.page,
|
||||||
|
per_page: $scope.per_page
|
||||||
|
}
|
||||||
|
RequestMonitor.load(BulkProducts.fetch(params).$promise).then ->
|
||||||
|
# update url with the filters used
|
||||||
|
$location.search(ProductFiltersUrl.generate($scope.q))
|
||||||
|
$scope.resetProducts()
|
||||||
|
|
||||||
|
removeClearedValues = ->
|
||||||
|
delete $scope.q.producerFilter if $scope.q.producerFilter == "0"
|
||||||
|
delete $scope.q.categoryFilter if $scope.q.categoryFilter == "0"
|
||||||
|
delete $scope.q.importDateFilter if $scope.q.importDateFilter == "0"
|
||||||
|
|
||||||
|
$timeout ->
|
||||||
|
if $scope.showLatestImport
|
||||||
|
$scope.q.importDateFilter = $scope.importDates[1].id
|
||||||
|
|
||||||
|
$scope.resetProducts = ->
|
||||||
|
DirtyProducts.clear()
|
||||||
|
StatusMessage.clear()
|
||||||
|
|
||||||
|
$scope.updateOnHand = (product) ->
|
||||||
|
on_demand_variants = []
|
||||||
|
if product.variants
|
||||||
|
on_demand_variants = (variant for id, variant of product.variants when variant.on_demand)
|
||||||
|
|
||||||
|
unless product.on_demand || on_demand_variants.length > 0
|
||||||
|
product.on_hand = $scope.onHand(product)
|
||||||
|
|
||||||
|
|
||||||
|
$scope.onHand = (product) ->
|
||||||
|
onHand = 0
|
||||||
|
if product.hasOwnProperty("variants") and product.variants instanceof Object
|
||||||
|
for id, variant of product.variants
|
||||||
|
onHand = onHand + parseInt(if variant.on_hand > 0 then variant.on_hand else 0)
|
||||||
|
else
|
||||||
|
onHand = "error"
|
||||||
|
onHand
|
||||||
|
|
||||||
|
$scope.shiftTab = (tab) ->
|
||||||
|
$scope.visibleTab.visible = false unless $scope.visibleTab == tab || $scope.visibleTab == undefined
|
||||||
|
tab.visible = !tab.visible
|
||||||
|
$scope.visibleTab = tab
|
||||||
|
|
||||||
|
$scope.resetSelectFilters = ->
|
||||||
|
$scope.q.query = ""
|
||||||
|
$scope.q.producerFilter = "0"
|
||||||
|
$scope.q.categoryFilter = "0"
|
||||||
|
$scope.q.importDateFilter = "0"
|
||||||
|
$scope.fetchProducts()
|
||||||
|
|
||||||
|
$scope.$watch 'sortOptions', (sort) ->
|
||||||
|
return unless sort && sort.predicate != ""
|
||||||
|
|
||||||
|
$scope.sorting = sort.getSortingExpr(defaultDirection: "asc")
|
||||||
|
$scope.fetchProducts()
|
||||||
|
, true
|
||||||
|
|
||||||
|
confirm_unsaved_changes = () ->
|
||||||
|
(DirtyProducts.count() > 0 and confirm(t("unsaved_changes_confirmation"))) or (DirtyProducts.count() == 0)
|
||||||
|
|
||||||
|
editProductUrl = (product, variant) ->
|
||||||
|
"/admin/products/" + product.id + ((if variant then "/variants/" + variant.id else "")) + "/edit"
|
||||||
|
|
||||||
|
$scope.editWarn = (product, variant) ->
|
||||||
|
if confirm_unsaved_changes()
|
||||||
|
$window.location.href = ProductFiltersUrl.buildUrl(editProductUrl(product, variant), $scope.q)
|
||||||
|
|
||||||
|
$scope.toggleShowAllVariants = ->
|
||||||
|
showVariants = !DisplayProperties.showVariants 0
|
||||||
|
$scope.products.forEach (product) ->
|
||||||
|
DisplayProperties.setShowVariants product.id, showVariants
|
||||||
|
DisplayProperties.setShowVariants 0, showVariants
|
||||||
|
|
||||||
|
$scope.addVariant = (product) ->
|
||||||
|
# Set new variant category to same as last product variant category to keep compactibility with deleted variant callback to set new variant category
|
||||||
|
newVariantId = $scope.nextVariantId();
|
||||||
|
newVariantCategoryId = product.variants[product.variants.length - 1]?.category_id
|
||||||
|
product.variants.push
|
||||||
|
id: newVariantId
|
||||||
|
unit_value: null
|
||||||
|
unit_description: null
|
||||||
|
on_demand: false
|
||||||
|
display_as: null
|
||||||
|
display_name: null
|
||||||
|
on_hand: null
|
||||||
|
price: null
|
||||||
|
tax_category_id: null
|
||||||
|
category_id: newVariantCategoryId
|
||||||
|
DisplayProperties.setShowVariants product.id, true
|
||||||
|
DirtyProducts.addVariantProperty(product.id, newVariantId, 'category_id', newVariantCategoryId)
|
||||||
|
|
||||||
|
|
||||||
|
$scope.nextVariantId = ->
|
||||||
|
$scope.variantIdCounter = 0 unless $scope.variantIdCounter?
|
||||||
|
$scope.variantIdCounter -= 1
|
||||||
|
$scope.variantIdCounter
|
||||||
|
|
||||||
|
$scope.deleteProduct = (product) ->
|
||||||
|
if confirm(t('are_you_sure'))
|
||||||
|
$http(
|
||||||
|
method: "DELETE"
|
||||||
|
url: "/api/v0/products/" + product.id
|
||||||
|
).then (response) ->
|
||||||
|
$scope.products.splice $scope.products.indexOf(product), 1
|
||||||
|
DirtyProducts.deleteProduct product.id
|
||||||
|
$scope.displayDirtyProducts()
|
||||||
|
|
||||||
|
|
||||||
|
$scope.deleteVariant = (product, variant) ->
|
||||||
|
if product.variants.length > 1
|
||||||
|
if !$scope.variantSaved(variant)
|
||||||
|
$scope.removeVariant(product, variant)
|
||||||
|
else
|
||||||
|
if confirm(t("are_you_sure"))
|
||||||
|
$http(
|
||||||
|
method: "DELETE"
|
||||||
|
url: "/api/v0/products/" + product.id + "/variants/" + variant.id
|
||||||
|
).then (response) ->
|
||||||
|
$scope.removeVariant(product, variant)
|
||||||
|
else
|
||||||
|
alert(t("delete_product_variant"))
|
||||||
|
|
||||||
|
$scope.removeVariant = (product, variant) ->
|
||||||
|
product.variants.splice product.variants.indexOf(variant), 1
|
||||||
|
DirtyProducts.deleteVariant product.id, variant.id
|
||||||
|
$scope.displayDirtyProducts()
|
||||||
|
|
||||||
|
|
||||||
|
$scope.cloneProduct = (product) ->
|
||||||
|
BulkProducts.cloneProduct product
|
||||||
|
|
||||||
|
$scope.hasVariants = (product) ->
|
||||||
|
product.variants.length > 0
|
||||||
|
|
||||||
|
|
||||||
|
$scope.hasUnit = (variant) ->
|
||||||
|
variant.variant_unit_with_scale?
|
||||||
|
|
||||||
|
$scope.variantSaved = (variant) ->
|
||||||
|
variant.hasOwnProperty('id') && variant.id > 0
|
||||||
|
|
||||||
|
|
||||||
|
$scope.hasOnDemandVariants = (product) ->
|
||||||
|
(variant for id, variant of product.variants when variant.on_demand).length > 0
|
||||||
|
|
||||||
|
|
||||||
|
$scope.submitProducts = ->
|
||||||
|
# Pack pack $scope.products, so they will match the list returned from the server,
|
||||||
|
# then pack $scope.dirtyProducts, ensuring that the correct product info is sent to the server.
|
||||||
|
$scope.packProduct product for id, product of $scope.products
|
||||||
|
$scope.packProduct product for id, product of DirtyProducts.all()
|
||||||
|
|
||||||
|
productsToSubmit = filterSubmitProducts(DirtyProducts.all())
|
||||||
|
if productsToSubmit.length > 0
|
||||||
|
$scope.updateProducts productsToSubmit # Don't submit an empty list
|
||||||
|
else
|
||||||
|
StatusMessage.display 'alert', t("products_change")
|
||||||
|
|
||||||
|
|
||||||
|
$scope.updateProducts = (productsToSubmit) ->
|
||||||
|
$scope.displayUpdating()
|
||||||
|
$http(
|
||||||
|
method: "POST"
|
||||||
|
url: "/admin/products/bulk_update"
|
||||||
|
data:
|
||||||
|
products: productsToSubmit
|
||||||
|
filters:
|
||||||
|
'q[name_cont]': $scope.q.query
|
||||||
|
'q[variants_supplier_id_eq]': $scope.q.producerFilter
|
||||||
|
'q[variants_primary_taxon_id_eq]': $scope.q.categoryFilter
|
||||||
|
'q[s]': $scope.sorting
|
||||||
|
import_date: $scope.q.importDateFilter
|
||||||
|
page: $scope.page
|
||||||
|
per_page: $scope.per_page
|
||||||
|
).then((response) ->
|
||||||
|
DirtyProducts.clear()
|
||||||
|
BulkProducts.updateVariantLists(response.data.products || [])
|
||||||
|
$timeout -> $scope.displaySuccess()
|
||||||
|
).catch (response) ->
|
||||||
|
if response.status == 400 && response.data.errors?
|
||||||
|
errorsString = ErrorsParser.toString(response.data.errors, response.status)
|
||||||
|
$scope.displayFailure t("products_update_error") + "\n" + errorsString
|
||||||
|
else
|
||||||
|
$scope.displayFailure t("products_update_error_data") + response.status
|
||||||
|
|
||||||
|
$scope.cancel = (destination) ->
|
||||||
|
$window.location = destination
|
||||||
|
|
||||||
|
$scope.packProduct = (product) ->
|
||||||
|
if product.variants
|
||||||
|
for id, variant of product.variants
|
||||||
|
$scope.packVariant variant
|
||||||
|
|
||||||
|
|
||||||
|
$scope.packVariant = (variant) ->
|
||||||
|
if variant.variant_unit_with_scale
|
||||||
|
match = variant.variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/)
|
||||||
|
if match
|
||||||
|
variant.variant_unit = match[1]
|
||||||
|
variant.variant_unit_scale = parseFloat(match[2])
|
||||||
|
else
|
||||||
|
variant.variant_unit = variant.variant_unit_with_scale
|
||||||
|
variant.variant_unit_scale = null
|
||||||
|
|
||||||
|
if variant.hasOwnProperty("unit_value_with_description")
|
||||||
|
match = variant.unit_value_with_description.match(/^([\d\.\,]+(?= |$)|)( |)(.*)$/)
|
||||||
|
if match
|
||||||
|
variant.unit_value = parseFloat(match[1].replace(",", "."))
|
||||||
|
variant.unit_value = null if isNaN(variant.unit_value)
|
||||||
|
if variant.unit_value && variant.variant_unit_scale
|
||||||
|
variant.unit_value = parseFloat(window.bigDecimal.multiply(variant.unit_value, variant.variant_unit_scale, 2))
|
||||||
|
variant.unit_description = match[3]
|
||||||
|
|
||||||
|
$scope.incrementLimit = ->
|
||||||
|
if $scope.limit < $scope.products.length
|
||||||
|
$scope.limit = $scope.limit + 5
|
||||||
|
|
||||||
|
|
||||||
|
$scope.displayUpdating = ->
|
||||||
|
StatusMessage.display 'progress', t("saving")
|
||||||
|
|
||||||
|
|
||||||
|
$scope.displaySuccess = ->
|
||||||
|
StatusMessage.display 'success',t("products_changes_saved")
|
||||||
|
$scope.bulk_product_form.$setPristine()
|
||||||
|
|
||||||
|
|
||||||
|
$scope.displayFailure = (failMessage) ->
|
||||||
|
StatusMessage.display 'failure', t("products_update_error_msg") + " #{failMessage}"
|
||||||
|
|
||||||
|
|
||||||
|
$scope.displayDirtyProducts = ->
|
||||||
|
count = DirtyProducts.count()
|
||||||
|
switch count
|
||||||
|
when 0 then StatusMessage.clear()
|
||||||
|
when 1 then StatusMessage.display 'notice', t("one_product_unsaved")
|
||||||
|
else StatusMessage.display 'notice', t("products_unsaved", n: count)
|
||||||
|
|
||||||
|
|
||||||
|
filterSubmitProducts = (productsToFilter) ->
|
||||||
|
filteredProducts = []
|
||||||
|
if productsToFilter instanceof Object
|
||||||
|
angular.forEach productsToFilter, (product) ->
|
||||||
|
if product.hasOwnProperty("id")
|
||||||
|
filteredProduct = {id: product.id}
|
||||||
|
filteredVariants = []
|
||||||
|
hasUpdatableProperty = false
|
||||||
|
|
||||||
|
if product.hasOwnProperty("variants")
|
||||||
|
angular.forEach product.variants, (variant) ->
|
||||||
|
result = filterSubmitVariant variant
|
||||||
|
filteredVariant = result.filteredVariant
|
||||||
|
variantHasUpdatableProperty = result.hasUpdatableProperty
|
||||||
|
filteredVariants.push filteredVariant if variantHasUpdatableProperty
|
||||||
|
|
||||||
|
if product.hasOwnProperty("sku")
|
||||||
|
filteredProduct.sku = product.sku
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if product.hasOwnProperty("name")
|
||||||
|
filteredProduct.name = product.name
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if product.hasOwnProperty("price")
|
||||||
|
filteredProduct.price = product.price
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if product.hasOwnProperty("on_hand") and filteredVariants.length == 0 #only update if no variants present
|
||||||
|
filteredProduct.on_hand = product.on_hand
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if product.hasOwnProperty("on_demand") and filteredVariants.length == 0 #only update if no variants present
|
||||||
|
filteredProduct.on_demand = product.on_demand
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if product.hasOwnProperty("inherits_properties")
|
||||||
|
filteredProduct.inherits_properties = product.inherits_properties
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if filteredVariants.length > 0 # Note that the name of the property changes to enable mass assignment of variants attributes with rails
|
||||||
|
filteredProduct.variants_attributes = filteredVariants
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
filteredProducts.push filteredProduct if hasUpdatableProperty
|
||||||
|
|
||||||
|
filteredProducts
|
||||||
|
|
||||||
|
|
||||||
|
filterSubmitVariant = (variant) ->
|
||||||
|
hasUpdatableProperty = false
|
||||||
|
filteredVariant = {}
|
||||||
|
if not variant.deleted_at? and variant.hasOwnProperty("id")
|
||||||
|
filteredVariant.id = variant.id unless variant.id <= 0
|
||||||
|
if variant.hasOwnProperty("sku")
|
||||||
|
filteredVariant.sku = variant.sku
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("on_hand")
|
||||||
|
filteredVariant.on_hand = variant.on_hand
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("on_demand")
|
||||||
|
filteredVariant.on_demand = variant.on_demand
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("price")
|
||||||
|
filteredVariant.price = variant.price
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("unit_value")
|
||||||
|
filteredVariant.unit_value = variant.unit_value
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("unit_description")
|
||||||
|
filteredVariant.unit_description = variant.unit_description
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("display_name")
|
||||||
|
filteredVariant.display_name = variant.display_name
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("tax_category_id")
|
||||||
|
filteredVariant.tax_category_id = variant.tax_category_id
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("category_id")
|
||||||
|
filteredVariant.primary_taxon_id = variant.category_id
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("display_as")
|
||||||
|
filteredVariant.display_as = variant.display_as
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("producer_id")
|
||||||
|
filteredVariant.supplier_id = variant.producer_id
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("variant_unit_with_scale")
|
||||||
|
filteredVariant.variant_unit = variant.variant_unit
|
||||||
|
filteredVariant.variant_unit_scale = variant.variant_unit_scale
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
if variant.hasOwnProperty("variant_unit_name")
|
||||||
|
filteredVariant.variant_unit_name = variant.variant_unit_name
|
||||||
|
hasUpdatableProperty = true
|
||||||
|
|
||||||
|
{filteredVariant: filteredVariant, hasUpdatableProperty: hasUpdatableProperty}
|
||||||
|
|
||||||
|
|
||||||
|
toObjectWithIDKeys = (array) ->
|
||||||
|
object = {}
|
||||||
|
|
||||||
|
for i of array
|
||||||
|
if array[i] instanceof Object and array[i].hasOwnProperty("id")
|
||||||
|
object[array[i].id] = angular.copy(array[i])
|
||||||
|
object[array[i].id].variants = toObjectWithIDKeys(array[i].variants) if array[i].hasOwnProperty("variants") and array[i].variants instanceof Array
|
||||||
|
|
||||||
|
object
|
||||||
@@ -11,9 +11,6 @@ angular.module("admin.customers").controller "customersCtrl", ($scope, $q, $filt
|
|||||||
$scope.confirmRefresh = (event) ->
|
$scope.confirmRefresh = (event) ->
|
||||||
event.preventDefault() unless pendingChanges.unsavedCount() == 0 || confirm(t("unsaved_changes_warning"))
|
event.preventDefault() unless pendingChanges.unsavedCount() == 0 || confirm(t("unsaved_changes_warning"))
|
||||||
|
|
||||||
$scope.hasUnsavedChanges = ->
|
|
||||||
pendingChanges.yes()
|
|
||||||
|
|
||||||
$scope.$watch "shop_id", ->
|
$scope.$watch "shop_id", ->
|
||||||
if $scope.shop_id?
|
if $scope.shop_id?
|
||||||
CurrentShop.shop = $filter('filter')($scope.shops, {id: parseInt($scope.shop_id)}, true)[0]
|
CurrentShop.shop = $filter('filter')($scope.shops, {id: parseInt($scope.shop_id)}, true)[0]
|
||||||
|
|||||||
@@ -55,6 +55,12 @@ angular.module("admin.enterprises")
|
|||||||
else
|
else
|
||||||
alert ("#{manager.email}" + " " + t("is_already_manager"))
|
alert ("#{manager.email}" + " " + t("is_already_manager"))
|
||||||
|
|
||||||
|
$scope.removeLogo = ->
|
||||||
|
$scope.performEnterpriseAction("removeLogo", "immediate_logo_removal_warning", "removed_logo_successfully")
|
||||||
|
|
||||||
|
$scope.removePromoImage = ->
|
||||||
|
$scope.performEnterpriseAction("removePromoImage", "immediate_promo_image_removal_warning", "removed_promo_image_successfully")
|
||||||
|
|
||||||
$scope.performEnterpriseAction = (enterpriseActionName, warning_message_key, success_message_key) ->
|
$scope.performEnterpriseAction = (enterpriseActionName, warning_message_key, success_message_key) ->
|
||||||
return unless confirm($scope.translation(warning_message_key))
|
return unless confirm($scope.translation(warning_message_key))
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ angular.module("admin.enterprises", [
|
|||||||
"admin.side_menu",
|
"admin.side_menu",
|
||||||
"admin.taxons",
|
"admin.taxons",
|
||||||
'admin.indexUtils',
|
'admin.indexUtils',
|
||||||
|
'admin.tagRules',
|
||||||
'admin.dropdown',
|
'admin.dropdown',
|
||||||
'ngSanitize']
|
'ngSanitize']
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,16 +4,15 @@ angular.module("admin.indexUtils").directive "objForUpdate", (switchClass, pendi
|
|||||||
type: "@objForUpdate"
|
type: "@objForUpdate"
|
||||||
attr: "@attrForUpdate"
|
attr: "@attrForUpdate"
|
||||||
link: (scope, element, attrs) ->
|
link: (scope, element, attrs) ->
|
||||||
scope.savedValue = scope.object()[scope.attr] || ""
|
scope.savedValue = scope.object()[scope.attr]
|
||||||
|
|
||||||
scope.$watch "object().#{scope.attr}", (value) ->
|
scope.$watch "object().#{scope.attr}", (value) ->
|
||||||
strValue = value || ""
|
if value == scope.savedValue
|
||||||
if strValue == scope.savedValue
|
|
||||||
pendingChanges.remove(scope.object().id, scope.attr)
|
pendingChanges.remove(scope.object().id, scope.attr)
|
||||||
scope.clear()
|
scope.clear()
|
||||||
else
|
else
|
||||||
scope.pending()
|
scope.pending()
|
||||||
addPendingChange(scope.attr, strValue)
|
addPendingChange(scope.attr, value ? "")
|
||||||
|
|
||||||
scope.reset = (value) ->
|
scope.reset = (value) ->
|
||||||
scope.savedValue = value
|
scope.savedValue = value
|
||||||
|
|||||||
@@ -16,10 +16,7 @@ angular.module("admin.indexUtils").factory "pendingChanges", ($q, resources, Sta
|
|||||||
remove: (id, attr) =>
|
remove: (id, attr) =>
|
||||||
if @pendingChanges.hasOwnProperty("#{id}")
|
if @pendingChanges.hasOwnProperty("#{id}")
|
||||||
delete @pendingChanges["#{id}"]["#{attr}"]
|
delete @pendingChanges["#{id}"]["#{attr}"]
|
||||||
|
delete @pendingChanges["#{id}"] if @changeCount( @pendingChanges["#{id}"] ) < 1
|
||||||
if @changeCount( @pendingChanges["#{id}"] ) < 1
|
|
||||||
delete @pendingChanges["#{id}"]
|
|
||||||
StatusMessage.clear()
|
|
||||||
|
|
||||||
submitAll: (form=null) =>
|
submitAll: (form=null) =>
|
||||||
all = []
|
all = []
|
||||||
@@ -50,8 +47,5 @@ angular.module("admin.indexUtils").factory "pendingChanges", ($q, resources, Sta
|
|||||||
unsavedCount: ->
|
unsavedCount: ->
|
||||||
Object.keys(@pendingChanges).length
|
Object.keys(@pendingChanges).length
|
||||||
|
|
||||||
yes: ->
|
|
||||||
@unsavedCount() > 0
|
|
||||||
|
|
||||||
changeCount: (objectChanges) ->
|
changeCount: (objectChanges) ->
|
||||||
Object.keys(objectChanges).length
|
Object.keys(objectChanges).length
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
angular.module("admin.indexUtils").factory "switchClass", ($timeout, StatusMessage) ->
|
angular.module("admin.indexUtils").factory "switchClass", ($timeout) ->
|
||||||
return (element, classToAdd, removeClasses, timeout) ->
|
return (element, classToAdd, removeClasses, timeout) ->
|
||||||
$timeout.cancel element.timeout if element.timeout
|
$timeout.cancel element.timeout if element.timeout
|
||||||
element.removeClass className for className in removeClasses
|
element.removeClass className for className in removeClasses
|
||||||
@@ -7,6 +7,4 @@ angular.module("admin.indexUtils").factory "switchClass", ($timeout, StatusMessa
|
|||||||
if timeout && intRegex.test(timeout)
|
if timeout && intRegex.test(timeout)
|
||||||
element.timeout = $timeout(->
|
element.timeout = $timeout(->
|
||||||
element.removeClass classToAdd
|
element.removeClass classToAdd
|
||||||
StatusMessage.clear()
|
|
||||||
, timeout, true)
|
, timeout, true)
|
||||||
element
|
|
||||||
|
|||||||
@@ -19,6 +19,18 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
|||||||
$scope.page = 1
|
$scope.page = 1
|
||||||
$scope.per_page = $scope.per_page_options[0].id
|
$scope.per_page = $scope.per_page_options[0].id
|
||||||
$scope.filterByVariantId = null
|
$scope.filterByVariantId = null
|
||||||
|
searchThrough = ["order_distributor_name",
|
||||||
|
"order_bill_address_phone",
|
||||||
|
"order_bill_address_firstname",
|
||||||
|
"order_bill_address_lastname",
|
||||||
|
"order_bill_address_full_name",
|
||||||
|
"order_bill_address_full_name_reversed",
|
||||||
|
"order_bill_address_full_name_with_comma",
|
||||||
|
"order_bill_address_full_name_with_comma_reversed",
|
||||||
|
"variant_supplier_name",
|
||||||
|
"order_email",
|
||||||
|
"order_number",
|
||||||
|
"product_name"].join("_or_") + "_cont"
|
||||||
|
|
||||||
$scope.confirmRefresh = ->
|
$scope.confirmRefresh = ->
|
||||||
LineItems.allSaved() || confirm(t("unsaved_changes_warning"))
|
LineItems.allSaved() || confirm(t("unsaved_changes_warning"))
|
||||||
@@ -63,10 +75,11 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
|||||||
[formattedStartDate, formattedEndDate] = $scope.formatDates($scope.startDate, $scope.endDate)
|
[formattedStartDate, formattedEndDate] = $scope.formatDates($scope.startDate, $scope.endDate)
|
||||||
|
|
||||||
RequestMonitor.load LineItems.index(
|
RequestMonitor.load LineItems.index(
|
||||||
|
"q[#{searchThrough}]": $scope.query,
|
||||||
|
"q[variant_id_eq]": $scope.filterByVariantId if $scope.filterByVariantId,
|
||||||
"q[order_state_not_eq]": "canceled",
|
"q[order_state_not_eq]": "canceled",
|
||||||
"q[order_shipment_state_not_eq]": "shipped",
|
"q[order_shipment_state_not_eq]": "shipped",
|
||||||
"q[order_completed_at_not_null]": "true",
|
"q[order_completed_at_not_null]": "true",
|
||||||
"q[variant_id_eq]": $scope.filterByVariantId if $scope.filterByVariantId,
|
|
||||||
"q[order_distributor_id_eq]": $scope.distributorFilter,
|
"q[order_distributor_id_eq]": $scope.distributorFilter,
|
||||||
"q[variant_supplier_id_eq]": $scope.supplierFilter,
|
"q[variant_supplier_id_eq]": $scope.supplierFilter,
|
||||||
"q[order_order_cycle_id_eq]": $scope.orderCycleFilter,
|
"q[order_order_cycle_id_eq]": $scope.orderCycleFilter,
|
||||||
@@ -74,8 +87,7 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
|||||||
"q[order_completed_at_lt]": if formattedEndDate then formattedEndDate else undefined,
|
"q[order_completed_at_lt]": if formattedEndDate then formattedEndDate else undefined,
|
||||||
"q[s]": "order_completed_at desc",
|
"q[s]": "order_completed_at desc",
|
||||||
"page": $scope.page,
|
"page": $scope.page,
|
||||||
"per_page": $scope.per_page,
|
"per_page": $scope.per_page
|
||||||
"search_query": $scope.query
|
|
||||||
)
|
)
|
||||||
|
|
||||||
$scope.formatDates = (startDate, endDate) ->
|
$scope.formatDates = (startDate, endDate) ->
|
||||||
@@ -85,7 +97,7 @@ angular.module("admin.lineItems").controller 'LineItemsCtrl', ($scope, $timeout,
|
|||||||
|
|
||||||
$scope.loadAssociatedData = ->
|
$scope.loadAssociatedData = ->
|
||||||
RequestMonitor.load $scope.distributors = Enterprises.index(action: "visible", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
|
RequestMonitor.load $scope.distributors = Enterprises.index(action: "visible", ams_prefix: "basic", "q[sells_in][]": ["own", "any"])
|
||||||
RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{moment().subtract(1,'year').format()}")
|
RequestMonitor.load $scope.orderCycles = OrderCycles.index(ams_prefix: "basic", as: "distributor", "q[orders_close_at_gt]": "#{moment().subtract(90,'days').format()}")
|
||||||
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "visible", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
|
RequestMonitor.load $scope.suppliers = Enterprises.index(action: "visible", ams_prefix: "basic", "q[is_primary_producer_eq]": "true")
|
||||||
|
|
||||||
$scope.dereferenceLoadedData = ->
|
$scope.dereferenceLoadedData = ->
|
||||||
|
|||||||
@@ -5,8 +5,6 @@ angular.module("admin.orders").controller "orderCtrl", ($scope, shops, orderCycl
|
|||||||
|
|
||||||
$scope.distributor_id = parseInt($attrs.ofnDistributorId)
|
$scope.distributor_id = parseInt($attrs.ofnDistributorId)
|
||||||
$scope.order_cycle_id = parseInt($attrs.ofnOrderCycleId)
|
$scope.order_cycle_id = parseInt($attrs.ofnOrderCycleId)
|
||||||
$scope.search_variants_as = $attrs.ofnSearchVariantsAs
|
|
||||||
$scope.order_id = $attrs.ofnOrderId
|
|
||||||
|
|
||||||
$scope.validOrderCycle = (oc) ->
|
$scope.validOrderCycle = (oc) ->
|
||||||
$scope.orderCycleHasDistributor oc, parseInt($scope.distributor_id)
|
$scope.orderCycleHasDistributor oc, parseInt($scope.distributor_id)
|
||||||
|
|||||||
@@ -15,4 +15,4 @@ angular.module("admin.paymentMethods").controller "StripeController", ($scope, $
|
|||||||
permalink = shops.filter((shop) ->
|
permalink = shops.filter((shop) ->
|
||||||
shop.id == $scope.paymentMethod.preferred_enterprise_id
|
shop.id == $scope.paymentMethod.preferred_enterprise_id
|
||||||
)[0].permalink
|
)[0].permalink
|
||||||
"/admin/enterprises/#{permalink}/edit#/payment_methods_panel"
|
"/admin/enterprises/#{permalink}/edit#/payment_methods"
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
angular.module("ofn.admin").controller "ProductImageCtrl", ($scope, ProductImageService) ->
|
||||||
|
$scope.imageUploader = ProductImageService.imageUploader
|
||||||
|
$scope.imagePreview = ProductImageService.imagePreview
|
||||||
|
|
||||||
|
$scope.$watch 'product.image_url', (newValue, oldValue) ->
|
||||||
|
if newValue != oldValue
|
||||||
|
$scope.imagePreview = newValue
|
||||||
|
$scope.uploadModal.close()
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
angular.module("ofn.admin").directive "imageModal", ($modal, ProductImageService) ->
|
||||||
|
restrict: 'C'
|
||||||
|
link: (scope, elem, attrs, ctrl) ->
|
||||||
|
elem.on "click", (ev) =>
|
||||||
|
scope.uploadModal = $modal.open(templateUrl: 'admin/modals/image_upload.html', controller: ctrl, scope: scope, windowClass: 'simple-modal')
|
||||||
|
ProductImageService.configure(scope.product)
|
||||||
@@ -8,4 +8,10 @@ angular.module("admin.resources").factory 'EnterpriseResource', ($resource) ->
|
|||||||
isArray: true
|
isArray: true
|
||||||
'update':
|
'update':
|
||||||
method: 'PUT'
|
method: 'PUT'
|
||||||
|
'removeLogo':
|
||||||
|
url: '/api/v0/enterprises/:id/logo.json'
|
||||||
|
method: 'DELETE'
|
||||||
|
'removePromoImage':
|
||||||
|
url: '/api/v0/enterprises/:id/promo_image.json'
|
||||||
|
method: 'DELETE'
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
angular.module("admin.resources").factory 'ProductResource', ($resource) ->
|
||||||
|
$resource('/admin/product/:id/:action.json', {}, {
|
||||||
|
'index':
|
||||||
|
url: '/api/v0/products/bulk_products.json'
|
||||||
|
method: 'GET'
|
||||||
|
})
|
||||||
@@ -39,6 +39,17 @@ angular.module("admin.resources").factory 'Enterprises', ($q, $filter, Enterpris
|
|||||||
resetAttribute: (enterprise, attribute) ->
|
resetAttribute: (enterprise, attribute) ->
|
||||||
enterprise[attribute] = @pristineByID[enterprise.id][attribute]
|
enterprise[attribute] = @pristineByID[enterprise.id][attribute]
|
||||||
|
|
||||||
|
performActionOnEnterpriseResource = (resourceAction) ->
|
||||||
|
(enterprise) ->
|
||||||
|
deferred = $q.defer()
|
||||||
|
resourceAction({id: enterprise.permalink}, ((data) =>
|
||||||
|
@pristineByID[enterprise.id] = angular.copy(data)
|
||||||
|
deferred.resolve(data)
|
||||||
|
), ((response) ->
|
||||||
|
deferred.reject(response)
|
||||||
|
))
|
||||||
|
deferred.promise
|
||||||
|
|
||||||
findByID: (id) ->
|
findByID: (id) ->
|
||||||
@byID[id]
|
@byID[id]
|
||||||
|
|
||||||
@@ -50,3 +61,5 @@ angular.module("admin.resources").factory 'Enterprises', ($q, $filter, Enterpris
|
|||||||
$filter('filter')(enterprises, term)
|
$filter('filter')(enterprises, term)
|
||||||
|
|
||||||
|
|
||||||
|
removeLogo: performActionOnEnterpriseResource(EnterpriseResource.removeLogo)
|
||||||
|
removePromoImage: performActionOnEnterpriseResource(EnterpriseResource.removePromoImage)
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
angular.module("ofn.admin").factory "BulkProducts", (ProductResource, dataFetcher, $http) ->
|
||||||
|
new class BulkProducts
|
||||||
|
products: []
|
||||||
|
pagination: {}
|
||||||
|
|
||||||
|
fetch: (params) ->
|
||||||
|
ProductResource.index params, (data) =>
|
||||||
|
@products.length = 0
|
||||||
|
@addProducts data.products
|
||||||
|
angular.extend(@pagination, data.pagination)
|
||||||
|
|
||||||
|
cloneProduct: (product) ->
|
||||||
|
$http.post("/api/v0/products/" + product.id + "/clone").then (response) =>
|
||||||
|
dataFetcher("/api/v0/products/" + response.data.id + "?template=bulk_show").then (newProduct) =>
|
||||||
|
@unpackProduct newProduct
|
||||||
|
@insertProductAfter(product, newProduct)
|
||||||
|
|
||||||
|
updateVariantLists: (serverProducts) ->
|
||||||
|
for server_product in serverProducts
|
||||||
|
product = @findProductInList(server_product.id, @products)
|
||||||
|
product.variants = server_product.variants
|
||||||
|
@loadVariantUnitValues product.variants
|
||||||
|
|
||||||
|
find: (id) ->
|
||||||
|
@findProductInList id, @products
|
||||||
|
|
||||||
|
findProductInList: (id, product_list) ->
|
||||||
|
products = (product for product in product_list when product.id == id)
|
||||||
|
if products.length == 0 then null else products[0]
|
||||||
|
|
||||||
|
addProducts: (products) ->
|
||||||
|
for product in products
|
||||||
|
@unpackProduct product
|
||||||
|
@products.push product
|
||||||
|
|
||||||
|
insertProductAfter: (product, newProduct) ->
|
||||||
|
index = @products.indexOf(product)
|
||||||
|
@products.splice(index + 1, 0, newProduct)
|
||||||
|
|
||||||
|
unpackProduct: (product) ->
|
||||||
|
@loadVariantUnit product
|
||||||
|
|
||||||
|
loadVariantUnit: (product) ->
|
||||||
|
@loadVariantUnitValues product.variants if product.variants
|
||||||
|
|
||||||
|
loadVariantUnitValues: (variants) ->
|
||||||
|
for variant in variants
|
||||||
|
@loadVariantUnitValue variant
|
||||||
|
|
||||||
|
loadVariantUnitValue: (variant) ->
|
||||||
|
variant.variant_unit_with_scale =
|
||||||
|
if variant.variant_unit && variant.variant_unit_scale && variant.variant_unit != 'items'
|
||||||
|
"#{variant.variant_unit}_#{variant.variant_unit_scale}"
|
||||||
|
else if variant.variant_unit
|
||||||
|
variant.variant_unit
|
||||||
|
else
|
||||||
|
null
|
||||||
|
|
||||||
|
unit_value = @variantUnitValue variant
|
||||||
|
unit_value = if unit_value? then unit_value else ''
|
||||||
|
variant.unit_value_with_description = "#{unit_value} #{variant.unit_description || ''}".trim()
|
||||||
|
|
||||||
|
variantUnitValue: (variant) ->
|
||||||
|
if variant.unit_value?
|
||||||
|
if variant.variant_unit_scale
|
||||||
|
variant_unit_value = @divideAsInteger variant.unit_value, variant.variant_unit_scale
|
||||||
|
parseFloat(window.bigDecimal.round(variant_unit_value, 2))
|
||||||
|
else
|
||||||
|
variant.unit_value
|
||||||
|
else
|
||||||
|
null
|
||||||
|
|
||||||
|
# forces integer division to avoid javascript floating point imprecision
|
||||||
|
# using one billion as the multiplier so that it works for numbers with up to 9 decimal places
|
||||||
|
divideAsInteger: (a, b) ->
|
||||||
|
(a * 1000000000) / (b * 1000000000)
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
angular.module("admin.indexUtils").factory 'KeyValueMapStore', (localStorageService)->
|
||||||
|
new class KeyValueMapStore
|
||||||
|
localStorageKey: ''
|
||||||
|
storableKeys: []
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
localStorageService.setStorageType("sessionStorage")
|
||||||
|
|
||||||
|
getStoredKeyValueMap: ->
|
||||||
|
localStorageService.get(@localStorageKey) || {}
|
||||||
|
|
||||||
|
setStoredValues: (source) ->
|
||||||
|
keyValueMap = {}
|
||||||
|
for key in @storableKeys
|
||||||
|
keyValueMap[key] = source[key]
|
||||||
|
localStorageService.set(@localStorageKey, keyValueMap)
|
||||||
|
|
||||||
|
restoreValues: (target) ->
|
||||||
|
storedKeyValueMap = @getStoredKeyValueMap()
|
||||||
|
|
||||||
|
return false if _.isEmpty(storedKeyValueMap)
|
||||||
|
|
||||||
|
for k,v of storedKeyValueMap
|
||||||
|
target[k] = v
|
||||||
|
|
||||||
|
return true
|
||||||
|
|
||||||
|
clearKeyValueMap: () ->
|
||||||
|
localStorageService.remove(@localStorageKey)
|
||||||
@@ -187,17 +187,18 @@ addVariantFromStockLocation = function() {
|
|||||||
$('#stock_details').hide();
|
$('#stock_details').hide();
|
||||||
|
|
||||||
var variant_id = $('input.variant_autocomplete').val();
|
var variant_id = $('input.variant_autocomplete').val();
|
||||||
var quantity = $("input.quantity").val();
|
var stock_location_id = $(this).data('stock-location-id');
|
||||||
|
var quantity = $("input.quantity[data-stock-location-id='" + stock_location_id + "']").val();
|
||||||
|
|
||||||
var shipment = _.find(shipments, function(shipment){
|
var shipment = _.find(shipments, function(shipment){
|
||||||
return shipment.state == 'ready' || shipment.state == 'pending';
|
return shipment.stock_location_id == stock_location_id && (shipment.state == 'ready' || shipment.state == 'pending');
|
||||||
});
|
});
|
||||||
|
|
||||||
if(shipment==undefined){
|
if(shipment==undefined){
|
||||||
$.ajax({
|
$.ajax({
|
||||||
type: "POST",
|
type: "POST",
|
||||||
url: Spree.url(Spree.routes.orders_api + "/" + order_number + "/shipments.json"),
|
url: Spree.url(Spree.routes.orders_api + "/" + order_number + "/shipments.json"),
|
||||||
data: { variant_id: variant_id, quantity: quantity }
|
data: { variant_id: variant_id, quantity: quantity, stock_location_id: stock_location_id }
|
||||||
}).done(function( msg ) {
|
}).done(function( msg ) {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}).error(function( msg ) {
|
}).error(function( msg ) {
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $filter, enterprise) ->
|
||||||
|
$scope.tagGroups = enterprise.tag_groups
|
||||||
|
$scope.defaultTagGroup = enterprise.default_tag_group
|
||||||
|
|
||||||
|
$scope.visibilityOptions = [ { id: "visible", name: t('js.tag_rules.visible') }, { id: "hidden", name: t('js.tag_rules.not_visible') } ]
|
||||||
|
|
||||||
|
$scope.updateRuleCounts = ->
|
||||||
|
index = $scope.defaultTagGroup.rules.length
|
||||||
|
for tagGroup in $filter('orderBy')($scope.tagGroups, 'position')
|
||||||
|
tagGroup.startIndex = index
|
||||||
|
index = index + tagGroup.rules.length
|
||||||
|
|
||||||
|
$scope.updateRuleCounts()
|
||||||
|
|
||||||
|
$scope.updateTagsRulesFor = (tagGroup) ->
|
||||||
|
for tagRule in tagGroup.rules
|
||||||
|
tagRule.preferred_customer_tags = (tag.text for tag in tagGroup.tags).join(",")
|
||||||
|
|
||||||
|
$scope.addNewRuleTo = (tagGroup, ruleType) ->
|
||||||
|
newRule =
|
||||||
|
id: null
|
||||||
|
is_default: tagGroup == $scope.defaultTagGroup
|
||||||
|
preferred_customer_tags: (tag.text for tag in tagGroup.tags).join(",")
|
||||||
|
type: "TagRule::#{ruleType}"
|
||||||
|
switch ruleType
|
||||||
|
when "FilterShippingMethods"
|
||||||
|
newRule.peferred_shipping_method_tags = []
|
||||||
|
newRule.preferred_matched_shipping_methods_visibility = "visible"
|
||||||
|
when "FilterPaymentMethods"
|
||||||
|
newRule.peferred_payment_method_tags = []
|
||||||
|
newRule.preferred_matched_payment_methods_visibility = "visible"
|
||||||
|
when "FilterProducts"
|
||||||
|
newRule.peferred_variant_tags = []
|
||||||
|
newRule.preferred_matched_variants_visibility = "visible"
|
||||||
|
when "FilterOrderCycles"
|
||||||
|
newRule.peferred_exchange_tags = []
|
||||||
|
newRule.preferred_matched_order_cycles_visibility = "visible"
|
||||||
|
tagGroup.rules.push(newRule)
|
||||||
|
$scope.updateRuleCounts()
|
||||||
|
|
||||||
|
$scope.addNewTag = ->
|
||||||
|
$scope.tagGroups.push { tags: [], rules: [], position: $scope.tagGroups.length + 1 }
|
||||||
|
|
||||||
|
$scope.deleteTagRule = (tagGroup, tagRule) ->
|
||||||
|
index = tagGroup.rules.indexOf(tagRule)
|
||||||
|
return unless index >= 0
|
||||||
|
if tagRule.id is null
|
||||||
|
tagGroup.rules.splice(index, 1)
|
||||||
|
$scope.updateRuleCounts()
|
||||||
|
else
|
||||||
|
if confirm("Are you sure?")
|
||||||
|
$http
|
||||||
|
method: "DELETE"
|
||||||
|
url: "/admin/enterprises/#{enterprise.id}/tag_rules/#{tagRule.id}.json"
|
||||||
|
.then ->
|
||||||
|
tagGroup.rules.splice(index, 1)
|
||||||
|
$scope.updateRuleCounts()
|
||||||
|
$scope.enterprise_form.$setDirty()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
angular.module("admin.tagRules").directive "invertNumber", ->
|
||||||
|
restrict: "A"
|
||||||
|
require: "ngModel"
|
||||||
|
link: (scope, element, attrs, ngModel) ->
|
||||||
|
ngModel.$parsers.push (viewValue) ->
|
||||||
|
return -parseInt(viewValue) unless isNaN(parseInt(viewValue))
|
||||||
|
viewValue
|
||||||
|
|
||||||
|
ngModel.$formatters.push (modelValue) ->
|
||||||
|
return -parseInt(modelValue) unless isNaN(parseInt(modelValue))
|
||||||
|
modelValue
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
angular.module("admin.tagRules").directive 'newTagRuleDialog', ($rootScope, $compile, $templateCache, DialogDefaults) ->
|
||||||
|
restrict: 'A'
|
||||||
|
scope:
|
||||||
|
tagGroup: '='
|
||||||
|
addNewRuleTo: '='
|
||||||
|
link: (scope, element, attr) ->
|
||||||
|
# Compile modal template
|
||||||
|
template = $compile($templateCache.get('admin/new_tag_rule_dialog.html'))(scope)
|
||||||
|
|
||||||
|
scope.ruleTypes = [
|
||||||
|
{ id: "FilterProducts", name: t('js.tag_rules.show_hide_variants') }
|
||||||
|
{ id: "FilterShippingMethods", name: t('js.tag_rules.show_hide_shipping') }
|
||||||
|
{ id: "FilterPaymentMethods", name: t('js.tag_rules.show_hide_payment') }
|
||||||
|
{ id: "FilterOrderCycles", name: t('js.tag_rules.show_hide_order_cycles') }
|
||||||
|
]
|
||||||
|
|
||||||
|
scope.ruleType = scope.ruleTypes[0].id
|
||||||
|
|
||||||
|
# Set Dialog options
|
||||||
|
template.dialog(DialogDefaults)
|
||||||
|
|
||||||
|
# Link opening of dialog to click event on element
|
||||||
|
element.bind 'click', (e) ->
|
||||||
|
template.dialog('open')
|
||||||
|
$rootScope.$evalAsync()
|
||||||
|
|
||||||
|
scope.addRule = (tagGroup, ruleType) ->
|
||||||
|
scope.addNewRuleTo(tagGroup, ruleType)
|
||||||
|
template.dialog('close')
|
||||||
|
$rootScope.$evalAsync()
|
||||||
|
return
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
angular.module("admin.tagRules").directive "tagRule", ->
|
||||||
|
restrict: "C"
|
||||||
|
templateUrl: "admin/tag_rules/tag_rule.html"
|
||||||
|
link: (scope, element, attrs) ->
|
||||||
|
scope.opt =
|
||||||
|
"TagRule::FilterShippingMethods":
|
||||||
|
textTop: t('js.admin.tag_rules.shipping_method_tagged_top')
|
||||||
|
textBottom: t('js.admin.tag_rules.shipping_method_tagged_bottom')
|
||||||
|
taggable: "shipping_method"
|
||||||
|
tagsAttr: "shipping_method_tags"
|
||||||
|
tagListAttr: "preferred_shipping_method_tags"
|
||||||
|
inputTemplate: "admin/tag_rules/filter_shipping_methods_input.html"
|
||||||
|
tagListFor: (rule) ->
|
||||||
|
rule.preferred_shipping_method_tags
|
||||||
|
"TagRule::FilterPaymentMethods":
|
||||||
|
textTop: t('js.admin.tag_rules.payment_method_tagged_top')
|
||||||
|
textBottom: t('js.admin.tag_rules.payment_method_tagged_bottom')
|
||||||
|
taggable: "payment_method"
|
||||||
|
tagsAttr: "payment_method_tags"
|
||||||
|
tagListAttr: "preferred_payment_method_tags"
|
||||||
|
inputTemplate: "admin/tag_rules/filter_payment_methods_input.html"
|
||||||
|
tagListFor: (rule) ->
|
||||||
|
rule.preferred_payment_method_tags
|
||||||
|
"TagRule::FilterOrderCycles":
|
||||||
|
textTop: t('js.admin.tag_rules.order_cycle_tagged_top')
|
||||||
|
textBottom: t('js.admin.tag_rules.order_cycle_tagged_bottom')
|
||||||
|
taggable: "exchange"
|
||||||
|
tagsAttr: "exchange_tags"
|
||||||
|
tagListAttr: "preferred_exchange_tags"
|
||||||
|
inputTemplate: "admin/tag_rules/filter_order_cycles_input.html"
|
||||||
|
tagListFor: (rule) ->
|
||||||
|
rule.preferred_exchange_tags
|
||||||
|
"TagRule::FilterProducts":
|
||||||
|
textTop: t('js.admin.tag_rules.inventory_tagged_top')
|
||||||
|
textBottom: t('js.admin.tag_rules.inventory_tagged_bottom')
|
||||||
|
taggable: "variant"
|
||||||
|
tagsAttr: "variant_tags"
|
||||||
|
tagListAttr: "preferred_variant_tags"
|
||||||
|
inputTemplate: "admin/tag_rules/filter_products_input.html"
|
||||||
|
tagListFor: (rule) ->
|
||||||
|
rule.preferred_variant_tags
|
||||||
@@ -26,8 +26,6 @@ angular.module("admin.utils").directive "variantAutocomplete", ($timeout) ->
|
|||||||
order_cycle_id: scope.order_cycle_id
|
order_cycle_id: scope.order_cycle_id
|
||||||
eligible_for_subscriptions: scope.eligible_for_subscriptions
|
eligible_for_subscriptions: scope.eligible_for_subscriptions
|
||||||
include_out_of_stock: scope.include_out_of_stock
|
include_out_of_stock: scope.include_out_of_stock
|
||||||
search_variants_as: scope.search_variants_as
|
|
||||||
order_id: scope.order_id
|
|
||||||
results: (data, page) ->
|
results: (data, page) ->
|
||||||
window.variants = data # this is how spree auto complete JS code picks up variants
|
window.variants = data # this is how spree auto complete JS code picks up variants
|
||||||
results: data
|
results: data
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#= require angular-google-maps.min.js
|
#= require angular-google-maps.min.js
|
||||||
#= require ../shared/mm-foundation-tpls-0.9.0-20180826174721.min.js
|
#= require ../shared/mm-foundation-tpls-0.9.0-20180826174721.min.js
|
||||||
#= require ../shared/ng-infinite-scroll.min.js
|
#= require ../shared/ng-infinite-scroll.min.js
|
||||||
|
#= require ../shared/angular-local-storage.js
|
||||||
#= require ../shared/angular-slideables.js
|
#= require ../shared/angular-slideables.js
|
||||||
#= require ../shared/shared
|
#= require ../shared/shared
|
||||||
#= require_tree ../shared/directives
|
#= require_tree ../shared/directives
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
angular.module("Darkswarm", [
|
angular.module("Darkswarm", [
|
||||||
'ngResource',
|
'ngResource',
|
||||||
'mm.foundation',
|
'mm.foundation',
|
||||||
|
'LocalStorageModule',
|
||||||
'infinite-scroll',
|
'infinite-scroll',
|
||||||
'angular-flash.service',
|
'angular-flash.service',
|
||||||
'templates',
|
'templates',
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
angular.module('Darkswarm').directive "activeTableHubLink", (CurrentHub, CurrentOrder) ->
|
angular.module('Darkswarm').directive "activeTableHubLink", (CurrentHub, CurrentOrder) ->
|
||||||
# Change the text of the hub link based on CurrentHub
|
# Change the text of the hub link based on CurrentHub
|
||||||
# To be used with ofnChangeHub
|
# To be used with ofnEmptiesCart
|
||||||
# Takes "change" and "shop" as text string attributes
|
# Takes "change" and "shop" as text string attributes
|
||||||
restrict: "A"
|
restrict: "A"
|
||||||
scope:
|
scope:
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
angular.module('Darkswarm').directive "darkerBackground", ->
|
||||||
|
restrict: "A"
|
||||||
|
link: (scope, elm, attr)->
|
||||||
|
toggleClass = (value) ->
|
||||||
|
elm.closest('.page-view').toggleClass("with-darker-background", value)
|
||||||
|
|
||||||
|
toggleClass(true)
|
||||||
|
|
||||||
|
# if an OrderCycle is selected, disable darker background
|
||||||
|
scope.$watch 'order_cycle.order_cycle_id', (newvalue, oldvalue) ->
|
||||||
|
toggleClass(false) if newvalue
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
# Allows disabling of link buttons via disabled attribute.
|
||||||
|
# This is normally ignored, ie the link appears disabled but is still clickable.
|
||||||
|
|
||||||
|
angular.module('Darkswarm').directive "disableDynamically", ->
|
||||||
|
restrict: 'A'
|
||||||
|
|
||||||
|
link: (scope, element, attrs) ->
|
||||||
|
element.on 'click', (e) ->
|
||||||
|
if attrs.disabled
|
||||||
|
e.preventDefault()
|
||||||
|
return
|
||||||
|
|
||||||
|
scope.$on "$destroy", ->
|
||||||
|
element.off("click")
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
angular.module('Darkswarm').directive "ofnDisableScroll", ()->
|
||||||
|
# Stops scrolling from incrementing or decrementing input value
|
||||||
|
# Useful for number inputs
|
||||||
|
restrict: 'A'
|
||||||
|
link: (scope, element, attrs)->
|
||||||
|
element.bind 'focus', ->
|
||||||
|
element.bind 'mousewheel', (e)->
|
||||||
|
e.preventDefault()
|
||||||
|
element.bind 'blur', ->
|
||||||
|
element.unbind 'mousewheel'
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
angular.module('Darkswarm').directive "ofnInlineAlert", ->
|
||||||
|
restrict: 'A'
|
||||||
|
scope: true
|
||||||
|
link: (scope, elem, attrs) ->
|
||||||
|
scope.visible = true
|
||||||
|
scope.close = ->
|
||||||
|
scope.visible = false
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
angular.module('Darkswarm').directive "integer", ->
|
||||||
|
restrict: 'A'
|
||||||
|
link: (scope, elem, attr) ->
|
||||||
|
elem.bind 'input', ->
|
||||||
|
elem.val Math.round(elem.val())
|
||||||
@@ -20,13 +20,10 @@ angular.module('Darkswarm').directive 'mapSearch', ($timeout, Search) ->
|
|||||||
$timeout =>
|
$timeout =>
|
||||||
map = ctrl.getMap()
|
map = ctrl.getMap()
|
||||||
|
|
||||||
if !map
|
searchBox = scope.createSearchBox map
|
||||||
alert(t('gmap_load_failure'))
|
scope.bindSearchResponse map, searchBox
|
||||||
else
|
scope.biasResults map, searchBox
|
||||||
searchBox = scope.createSearchBox map
|
scope.performUrlSearch map
|
||||||
scope.bindSearchResponse map, searchBox
|
|
||||||
scope.biasResults map, searchBox
|
|
||||||
scope.performUrlSearch map
|
|
||||||
|
|
||||||
scope.createSearchBox = (map) ->
|
scope.createSearchBox = (map) ->
|
||||||
map.controls[google.maps.ControlPosition.TOP_LEFT].push scope.input
|
map.controls[google.maps.ControlPosition.TOP_LEFT].push scope.input
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ angular.module('Darkswarm').directive 'ofnOpenStreetMap', ($window, MapCentreCal
|
|||||||
|
|
||||||
buildMarker = (enterprise, latlng, title) ->
|
buildMarker = (enterprise, latlng, title) ->
|
||||||
icon = L.icon
|
icon = L.icon
|
||||||
iconAnchor: [14, 33]
|
|
||||||
iconSize: [28, 33]
|
|
||||||
iconUrl: enterprise.icon
|
iconUrl: enterprise.icon
|
||||||
marker = L.marker latlng,
|
marker = L.marker latlng,
|
||||||
draggable: true,
|
draggable: true,
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
angular.module('Darkswarm').directive "ofnPageAlert", ($timeout) ->
|
||||||
|
restrict: 'A'
|
||||||
|
scope: true
|
||||||
|
link: (scope, elem, attrs) ->
|
||||||
|
moveSelectors = [".off-canvas-wrap .inner-wrap",
|
||||||
|
".off-canvas-wrap .inner-wrap .fixed",
|
||||||
|
".off-canvas-fixed .top-bar",
|
||||||
|
".off-canvas-fixed ofn-flash",
|
||||||
|
".off-canvas-fixed nav.tab-bar",
|
||||||
|
".off-canvas-fixed .page-alert"]
|
||||||
|
|
||||||
|
container_elems = $(moveSelectors.join(", "))
|
||||||
|
|
||||||
|
# Wait a moment after page load before showing the alert. Otherwise we often miss the
|
||||||
|
# start of the animation.
|
||||||
|
$timeout ->
|
||||||
|
container_elems.addClass("move-up")
|
||||||
|
, 1000
|
||||||
|
|
||||||
|
scope.close = ->
|
||||||
|
container_elems.removeClass("move-up")
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
angular.module('Darkswarm').directive "renderSvg", ()->
|
||||||
|
# Magical directive that'll render SVGs from URLs
|
||||||
|
# If only there were a neater way of doing this
|
||||||
|
restrict: 'E'
|
||||||
|
priority: 99
|
||||||
|
template: "<svg-wrapper></svg-wrapper>"
|
||||||
|
|
||||||
|
# Fetch SVG via ajax, inject into page using DOM
|
||||||
|
link: (scope, elem, attr)->
|
||||||
|
if /.svg/.test attr.path # Only do this if we've got an svg
|
||||||
|
$.ajax
|
||||||
|
url: attr.path
|
||||||
|
success: (html)->
|
||||||
|
elem.html($(html).find("svg"))
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
angular.module('Darkswarm').directive "ofnScrollTo", ($location, $anchorScroll)->
|
||||||
|
# Onclick sets $location.hash to attrs.ofnScrollTo
|
||||||
|
# Then triggers anchorScroll
|
||||||
|
restrict: 'A'
|
||||||
|
link: (scope, element, attrs)->
|
||||||
|
element.bind 'click', (ev)->
|
||||||
|
ev.stopPropagation()
|
||||||
|
$location.hash attrs.ofnScrollTo
|
||||||
|
$anchorScroll()
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
angular.module('Darkswarm').factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, Messages) ->
|
angular.module('Darkswarm').factory 'Cart', (CurrentOrder, Variants, $timeout, $http, $modal, $rootScope, $resource, localStorageService, Messages) ->
|
||||||
# Handles syncing of current cart/order state to server
|
# Handles syncing of current cart/order state to server
|
||||||
new class Cart
|
new class Cart
|
||||||
dirty: false
|
dirty: false
|
||||||
@@ -113,6 +113,7 @@ angular.module('Darkswarm').factory 'Cart', (CurrentOrder, Variants, $timeout, $
|
|||||||
|
|
||||||
clear: ->
|
clear: ->
|
||||||
@line_items = []
|
@line_items = []
|
||||||
|
localStorageService.clearAll() # One day this will have to be moar GRANULAR
|
||||||
|
|
||||||
isOnlyItemInOrder: (id) =>
|
isOnlyItemInOrder: (id) =>
|
||||||
deletedItem = @line_items_finalised.find((item) -> item.id == id)
|
deletedItem = @line_items_finalised.find((item) -> item.id == id)
|
||||||
|
|||||||
546
app/assets/javascripts/shared/angular-local-storage.js
vendored
Normal file
546
app/assets/javascripts/shared/angular-local-storage.js
vendored
Normal file
@@ -0,0 +1,546 @@
|
|||||||
|
/**
|
||||||
|
* An Angular module that gives you access to the browsers local storage
|
||||||
|
* @version v0.5.0 - 2016-08-29
|
||||||
|
* @link https://github.com/grevory/angular-local-storage
|
||||||
|
* @author grevory <greg@gregpike.ca>
|
||||||
|
* @license MIT License, http://www.opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
(function (window, angular) {
|
||||||
|
var isDefined = angular.isDefined,
|
||||||
|
isUndefined = angular.isUndefined,
|
||||||
|
isNumber = angular.isNumber,
|
||||||
|
isObject = angular.isObject,
|
||||||
|
isArray = angular.isArray,
|
||||||
|
extend = angular.extend,
|
||||||
|
toJson = angular.toJson;
|
||||||
|
|
||||||
|
angular
|
||||||
|
.module('LocalStorageModule', [])
|
||||||
|
.provider('localStorageService', function() {
|
||||||
|
// You should set a prefix to avoid overwriting any local storage variables from the rest of your app
|
||||||
|
// e.g. localStorageServiceProvider.setPrefix('yourAppName');
|
||||||
|
// With provider you can use config as this:
|
||||||
|
// myApp.config(function (localStorageServiceProvider) {
|
||||||
|
// localStorageServiceProvider.prefix = 'yourAppName';
|
||||||
|
// });
|
||||||
|
this.prefix = 'ls';
|
||||||
|
|
||||||
|
// You could change web storage type localstorage or sessionStorage
|
||||||
|
this.storageType = 'localStorage';
|
||||||
|
|
||||||
|
// Cookie options (usually in case of fallback)
|
||||||
|
// expiry = Number of days before cookies expire // 0 = Does not expire
|
||||||
|
// path = The web path the cookie represents
|
||||||
|
// secure = Wether the cookies should be secure (i.e only sent on HTTPS requests)
|
||||||
|
this.cookie = {
|
||||||
|
expiry: 30,
|
||||||
|
path: '/',
|
||||||
|
secure: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Decides wether we should default to cookies if localstorage is not supported.
|
||||||
|
this.defaultToCookie = true;
|
||||||
|
|
||||||
|
// Send signals for each of the following actions?
|
||||||
|
this.notify = {
|
||||||
|
setItem: true,
|
||||||
|
removeItem: false
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setter for the prefix
|
||||||
|
this.setPrefix = function(prefix) {
|
||||||
|
this.prefix = prefix;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setter for the storageType
|
||||||
|
this.setStorageType = function(storageType) {
|
||||||
|
this.storageType = storageType;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
// Setter for defaultToCookie value, default is true.
|
||||||
|
this.setDefaultToCookie = function (shouldDefault) {
|
||||||
|
this.defaultToCookie = !!shouldDefault; // Double-not to make sure it's a bool value.
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
// Setter for cookie config
|
||||||
|
this.setStorageCookie = function(exp, path, secure) {
|
||||||
|
this.cookie.expiry = exp;
|
||||||
|
this.cookie.path = path;
|
||||||
|
this.cookie.secure = secure;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setter for cookie domain
|
||||||
|
this.setStorageCookieDomain = function(domain) {
|
||||||
|
this.cookie.domain = domain;
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Setter for notification config
|
||||||
|
// itemSet & itemRemove should be booleans
|
||||||
|
this.setNotify = function(itemSet, itemRemove) {
|
||||||
|
this.notify = {
|
||||||
|
setItem: itemSet,
|
||||||
|
removeItem: itemRemove
|
||||||
|
};
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
this.$get = ['$rootScope', '$window', '$document', '$parse','$timeout', function($rootScope, $window, $document, $parse, $timeout) {
|
||||||
|
var self = this;
|
||||||
|
var prefix = self.prefix;
|
||||||
|
var cookie = self.cookie;
|
||||||
|
var notify = self.notify;
|
||||||
|
var storageType = self.storageType;
|
||||||
|
var webStorage;
|
||||||
|
|
||||||
|
// When Angular's $document is not available
|
||||||
|
if (!$document) {
|
||||||
|
$document = document;
|
||||||
|
} else if ($document[0]) {
|
||||||
|
$document = $document[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there is a prefix set in the config lets use that with an appended period for readability
|
||||||
|
if (prefix.substr(-1) !== '.') {
|
||||||
|
prefix = !!prefix ? prefix + '.' : '';
|
||||||
|
}
|
||||||
|
var deriveQualifiedKey = function(key) {
|
||||||
|
return prefix + key;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Removes prefix from the key.
|
||||||
|
var underiveQualifiedKey = function (key) {
|
||||||
|
return key.replace(new RegExp('^' + prefix, 'g'), '');
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if the key is within our prefix namespace.
|
||||||
|
var isKeyPrefixOurs = function (key) {
|
||||||
|
return key.indexOf(prefix) === 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Checks the browser to see if local storage is supported
|
||||||
|
var checkSupport = function () {
|
||||||
|
try {
|
||||||
|
var supported = (storageType in $window && $window[storageType] !== null);
|
||||||
|
|
||||||
|
// When Safari (OS X or iOS) is in private browsing mode, it appears as though localStorage
|
||||||
|
// is available, but trying to call .setItem throws an exception.
|
||||||
|
//
|
||||||
|
// "QUOTA_EXCEEDED_ERR: DOM Exception 22: An attempt was made to add something to storage
|
||||||
|
// that exceeded the quota."
|
||||||
|
var key = deriveQualifiedKey('__' + Math.round(Math.random() * 1e7));
|
||||||
|
if (supported) {
|
||||||
|
webStorage = $window[storageType];
|
||||||
|
webStorage.setItem(key, '');
|
||||||
|
webStorage.removeItem(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return supported;
|
||||||
|
} catch (e) {
|
||||||
|
// Only change storageType to cookies if defaulting is enabled.
|
||||||
|
if (self.defaultToCookie)
|
||||||
|
storageType = 'cookie';
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var browserSupportsLocalStorage = checkSupport();
|
||||||
|
|
||||||
|
// Directly adds a value to local storage
|
||||||
|
// If local storage is not available in the browser use cookies
|
||||||
|
// Example use: localStorageService.add('library','angular');
|
||||||
|
var addToLocalStorage = function (key, value, type) {
|
||||||
|
setStorageType(type);
|
||||||
|
|
||||||
|
// Let's convert undefined values to null to get the value consistent
|
||||||
|
if (isUndefined(value)) {
|
||||||
|
value = null;
|
||||||
|
} else {
|
||||||
|
value = toJson(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this browser does not support local storage use cookies
|
||||||
|
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
|
||||||
|
if (!browserSupportsLocalStorage) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notify.setItem) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: 'cookie'});
|
||||||
|
}
|
||||||
|
return addToCookies(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (webStorage) {
|
||||||
|
webStorage.setItem(deriveQualifiedKey(key), value);
|
||||||
|
}
|
||||||
|
if (notify.setItem) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.setitem', {key: key, newvalue: value, storageType: self.storageType});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||||
|
return addToCookies(key, value);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Directly get a value from local storage
|
||||||
|
// Example use: localStorageService.get('library'); // returns 'angular'
|
||||||
|
var getFromLocalStorage = function (key, type) {
|
||||||
|
setStorageType(type);
|
||||||
|
|
||||||
|
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
|
||||||
|
if (!browserSupportsLocalStorage) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||||
|
}
|
||||||
|
|
||||||
|
return getFromCookies(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = webStorage ? webStorage.getItem(deriveQualifiedKey(key)) : null;
|
||||||
|
// angular.toJson will convert null to 'null', so a proper conversion is needed
|
||||||
|
// FIXME not a perfect solution, since a valid 'null' string can't be stored
|
||||||
|
if (!item || item === 'null') {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(item);
|
||||||
|
} catch (e) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove an item from local storage
|
||||||
|
// Example use: localStorageService.remove('library'); // removes the key/value pair of library='angular'
|
||||||
|
//
|
||||||
|
// This is var-arg removal, check the last argument to see if it is a storageType
|
||||||
|
// and set type accordingly before removing.
|
||||||
|
//
|
||||||
|
var removeFromLocalStorage = function () {
|
||||||
|
// can't pop on arguments, so we do this
|
||||||
|
var consumed = 0;
|
||||||
|
if (arguments.length >= 1 &&
|
||||||
|
(arguments[arguments.length - 1] === 'localStorage' ||
|
||||||
|
arguments[arguments.length - 1] === 'sessionStorage')) {
|
||||||
|
consumed = 1;
|
||||||
|
setStorageType(arguments[arguments.length - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var i, key;
|
||||||
|
for (i = 0; i < arguments.length - consumed; i++) {
|
||||||
|
key = arguments[i];
|
||||||
|
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
|
||||||
|
if (!browserSupportsLocalStorage) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notify.removeItem) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {key: key, storageType: 'cookie'});
|
||||||
|
}
|
||||||
|
removeFromCookies(key);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try {
|
||||||
|
webStorage.removeItem(deriveQualifiedKey(key));
|
||||||
|
if (notify.removeItem) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.removeitem', {
|
||||||
|
key: key,
|
||||||
|
storageType: self.storageType
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||||
|
removeFromCookies(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Return array of keys for local storage
|
||||||
|
// Example use: var keys = localStorageService.keys()
|
||||||
|
var getKeysForLocalStorage = function (type) {
|
||||||
|
setStorageType(type);
|
||||||
|
|
||||||
|
if (!browserSupportsLocalStorage) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
var prefixLength = prefix.length;
|
||||||
|
var keys = [];
|
||||||
|
for (var key in webStorage) {
|
||||||
|
// Only return keys that are for this app
|
||||||
|
if (key.substr(0, prefixLength) === prefix) {
|
||||||
|
try {
|
||||||
|
keys.push(key.substr(prefixLength));
|
||||||
|
} catch (e) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.Description);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Remove all data for this app from local storage
|
||||||
|
// Also optionally takes a regular expression string and removes the matching key-value pairs
|
||||||
|
// Example use: localStorageService.clearAll();
|
||||||
|
// Should be used mostly for development purposes
|
||||||
|
var clearAllFromLocalStorage = function (regularExpression, type) {
|
||||||
|
setStorageType(type);
|
||||||
|
|
||||||
|
// Setting both regular expressions independently
|
||||||
|
// Empty strings result in catchall RegExp
|
||||||
|
var prefixRegex = !!prefix ? new RegExp('^' + prefix) : new RegExp();
|
||||||
|
var testRegex = !!regularExpression ? new RegExp(regularExpression) : new RegExp();
|
||||||
|
|
||||||
|
if (!browserSupportsLocalStorage && self.defaultToCookie || self.storageType === 'cookie') {
|
||||||
|
if (!browserSupportsLocalStorage) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.warning', 'LOCAL_STORAGE_NOT_SUPPORTED');
|
||||||
|
}
|
||||||
|
return clearAllFromCookies();
|
||||||
|
}
|
||||||
|
if (!browserSupportsLocalStorage && !self.defaultToCookie)
|
||||||
|
return false;
|
||||||
|
var prefixLength = prefix.length;
|
||||||
|
|
||||||
|
for (var key in webStorage) {
|
||||||
|
// Only remove items that are for this app and match the regular expression
|
||||||
|
if (prefixRegex.test(key) && testRegex.test(key.substr(prefixLength))) {
|
||||||
|
try {
|
||||||
|
removeFromLocalStorage(key.substr(prefixLength));
|
||||||
|
} catch (e) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||||
|
return clearAllFromCookies();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Checks the browser to see if cookies are supported
|
||||||
|
var browserSupportsCookies = (function() {
|
||||||
|
try {
|
||||||
|
return $window.navigator.cookieEnabled ||
|
||||||
|
("cookie" in $document && ($document.cookie.length > 0 ||
|
||||||
|
($document.cookie = "test").indexOf.call($document.cookie, "test") > -1));
|
||||||
|
} catch (e) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
|
// Directly adds a value to cookies
|
||||||
|
// Typically used as a fallback if local storage is not available in the browser
|
||||||
|
// Example use: localStorageService.cookie.add('library','angular');
|
||||||
|
var addToCookies = function (key, value, daysToExpiry, secure) {
|
||||||
|
|
||||||
|
if (isUndefined(value)) {
|
||||||
|
return false;
|
||||||
|
} else if(isArray(value) || isObject(value)) {
|
||||||
|
value = toJson(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!browserSupportsCookies) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var expiry = '',
|
||||||
|
expiryDate = new Date(),
|
||||||
|
cookieDomain = '';
|
||||||
|
|
||||||
|
if (value === null) {
|
||||||
|
// Mark that the cookie has expired one day ago
|
||||||
|
expiryDate.setTime(expiryDate.getTime() + (-1 * 24 * 60 * 60 * 1000));
|
||||||
|
expiry = "; expires=" + expiryDate.toGMTString();
|
||||||
|
value = '';
|
||||||
|
} else if (isNumber(daysToExpiry) && daysToExpiry !== 0) {
|
||||||
|
expiryDate.setTime(expiryDate.getTime() + (daysToExpiry * 24 * 60 * 60 * 1000));
|
||||||
|
expiry = "; expires=" + expiryDate.toGMTString();
|
||||||
|
} else if (cookie.expiry !== 0) {
|
||||||
|
expiryDate.setTime(expiryDate.getTime() + (cookie.expiry * 24 * 60 * 60 * 1000));
|
||||||
|
expiry = "; expires=" + expiryDate.toGMTString();
|
||||||
|
}
|
||||||
|
if (!!key) {
|
||||||
|
var cookiePath = "; path=" + cookie.path;
|
||||||
|
if (cookie.domain) {
|
||||||
|
cookieDomain = "; domain=" + cookie.domain;
|
||||||
|
}
|
||||||
|
/* Providing the secure parameter always takes precedence over config
|
||||||
|
* (allows developer to mix and match secure + non-secure) */
|
||||||
|
if (typeof secure === 'boolean') {
|
||||||
|
if (secure === true) {
|
||||||
|
/* We've explicitly specified secure,
|
||||||
|
* add the secure attribute to the cookie (after domain) */
|
||||||
|
cookieDomain += "; secure";
|
||||||
|
}
|
||||||
|
// else - secure has been supplied but isn't true - so don't set secure flag, regardless of what config says
|
||||||
|
}
|
||||||
|
else if (cookie.secure === true) {
|
||||||
|
// secure parameter wasn't specified, get default from config
|
||||||
|
cookieDomain += "; secure";
|
||||||
|
}
|
||||||
|
$document.cookie = deriveQualifiedKey(key) + "=" + encodeURIComponent(value) + expiry + cookiePath + cookieDomain;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.error', e.message);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Directly get a value from a cookie
|
||||||
|
// Example use: localStorageService.cookie.get('library'); // returns 'angular'
|
||||||
|
var getFromCookies = function (key) {
|
||||||
|
if (!browserSupportsCookies) {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.error', 'COOKIES_NOT_SUPPORTED');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cookies = $document.cookie && $document.cookie.split(';') || [];
|
||||||
|
for(var i=0; i < cookies.length; i++) {
|
||||||
|
var thisCookie = cookies[i];
|
||||||
|
while (thisCookie.charAt(0) === ' ') {
|
||||||
|
thisCookie = thisCookie.substring(1,thisCookie.length);
|
||||||
|
}
|
||||||
|
if (thisCookie.indexOf(deriveQualifiedKey(key) + '=') === 0) {
|
||||||
|
var storedValues = decodeURIComponent(thisCookie.substring(prefix.length + key.length + 1, thisCookie.length));
|
||||||
|
try {
|
||||||
|
return JSON.parse(storedValues);
|
||||||
|
} catch(e) {
|
||||||
|
return storedValues;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
var removeFromCookies = function (key) {
|
||||||
|
addToCookies(key,null);
|
||||||
|
};
|
||||||
|
|
||||||
|
var clearAllFromCookies = function () {
|
||||||
|
var thisCookie = null;
|
||||||
|
var prefixLength = prefix.length;
|
||||||
|
var cookies = $document.cookie.split(';');
|
||||||
|
for(var i = 0; i < cookies.length; i++) {
|
||||||
|
thisCookie = cookies[i];
|
||||||
|
|
||||||
|
while (thisCookie.charAt(0) === ' ') {
|
||||||
|
thisCookie = thisCookie.substring(1, thisCookie.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
var key = thisCookie.substring(prefixLength, thisCookie.indexOf('='));
|
||||||
|
removeFromCookies(key);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var getStorageType = function() {
|
||||||
|
return storageType;
|
||||||
|
};
|
||||||
|
|
||||||
|
var setStorageType = function(type) {
|
||||||
|
if (type && storageType !== type) {
|
||||||
|
storageType = type;
|
||||||
|
browserSupportsLocalStorage = checkSupport();
|
||||||
|
}
|
||||||
|
return browserSupportsLocalStorage;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add a listener on scope variable to save its changes to local storage
|
||||||
|
// Return a function which when called cancels binding
|
||||||
|
var bindToScope = function(scope, key, def, lsKey, type) {
|
||||||
|
lsKey = lsKey || key;
|
||||||
|
var value = getFromLocalStorage(lsKey, type);
|
||||||
|
|
||||||
|
if (value === null && isDefined(def)) {
|
||||||
|
value = def;
|
||||||
|
} else if (isObject(value) && isObject(def)) {
|
||||||
|
value = extend(value, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
$parse(key).assign(scope, value);
|
||||||
|
|
||||||
|
return scope.$watch(key, function(newVal) {
|
||||||
|
addToLocalStorage(lsKey, newVal, type);
|
||||||
|
}, isObject(scope[key]));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add listener to local storage, for update callbacks.
|
||||||
|
if (browserSupportsLocalStorage) {
|
||||||
|
if ($window.addEventListener) {
|
||||||
|
$window.addEventListener("storage", handleStorageChangeCallback, false);
|
||||||
|
$rootScope.$on('$destroy', function() {
|
||||||
|
$window.removeEventListener("storage", handleStorageChangeCallback);
|
||||||
|
});
|
||||||
|
} else if($window.attachEvent){
|
||||||
|
// attachEvent and detachEvent are proprietary to IE v6-10
|
||||||
|
$window.attachEvent("onstorage", handleStorageChangeCallback);
|
||||||
|
$rootScope.$on('$destroy', function() {
|
||||||
|
$window.detachEvent("onstorage", handleStorageChangeCallback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback handler for storage changed.
|
||||||
|
function handleStorageChangeCallback(e) {
|
||||||
|
if (!e) { e = $window.event; }
|
||||||
|
if (notify.setItem) {
|
||||||
|
if (isKeyPrefixOurs(e.key)) {
|
||||||
|
var key = underiveQualifiedKey(e.key);
|
||||||
|
// Use timeout, to avoid using $rootScope.$apply.
|
||||||
|
$timeout(function () {
|
||||||
|
$rootScope.$broadcast('LocalStorageModule.notification.changed', { key: key, newvalue: e.newValue, storageType: self.storageType });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return localStorageService.length
|
||||||
|
// ignore keys that not owned
|
||||||
|
var lengthOfLocalStorage = function(type) {
|
||||||
|
setStorageType(type);
|
||||||
|
|
||||||
|
var count = 0;
|
||||||
|
var storage = $window[storageType];
|
||||||
|
for(var i = 0; i < storage.length; i++) {
|
||||||
|
if(storage.key(i).indexOf(prefix) === 0 ) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
isSupported: browserSupportsLocalStorage,
|
||||||
|
getStorageType: getStorageType,
|
||||||
|
setStorageType: setStorageType,
|
||||||
|
set: addToLocalStorage,
|
||||||
|
add: addToLocalStorage, //DEPRECATED
|
||||||
|
get: getFromLocalStorage,
|
||||||
|
keys: getKeysForLocalStorage,
|
||||||
|
remove: removeFromLocalStorage,
|
||||||
|
clearAll: clearAllFromLocalStorage,
|
||||||
|
bind: bindToScope,
|
||||||
|
deriveKey: deriveQualifiedKey,
|
||||||
|
underiveKey: underiveQualifiedKey,
|
||||||
|
length: lengthOfLocalStorage,
|
||||||
|
defaultToCookie: this.defaultToCookie,
|
||||||
|
cookie: {
|
||||||
|
isSupported: browserSupportsCookies,
|
||||||
|
set: addToCookies,
|
||||||
|
add: addToCookies, //DEPRECATED
|
||||||
|
get: getFromCookies,
|
||||||
|
remove: removeFromCookies,
|
||||||
|
clearAll: clearAllFromCookies
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}];
|
||||||
|
});
|
||||||
|
})(window, window.angular);
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
window.OFNShared = angular.module("OFNShared", [
|
window.OFNShared = angular.module("OFNShared", [
|
||||||
"mm.foundation",
|
"mm.foundation",
|
||||||
|
"LocalStorageModule"
|
||||||
]).config ($httpProvider) ->
|
]).config ($httpProvider) ->
|
||||||
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"
|
$httpProvider.defaults.headers.common["Accept"] = "application/json, text/javascript, */*"
|
||||||
|
|||||||
@@ -2,13 +2,13 @@
|
|||||||
.ofn-drop-down-label
|
.ofn-drop-down-label
|
||||||
= " #{t('admin.columns')}".html_safe
|
= " #{t('admin.columns')}".html_safe
|
||||||
%span{ 'ng-class' => "expanded && 'icon-caret-up' || !expanded && 'icon-caret-down'" }
|
%span{ 'ng-class' => "expanded && 'icon-caret-up' || !expanded && 'icon-caret-down'" }
|
||||||
.menu{ 'ng-show' => "expanded" }
|
%div.menu{ 'ng-show' => "expanded" }
|
||||||
.menu_items
|
.menu_items
|
||||||
.menu_item{ "ng-repeat": "column in columns", "ng-click": "toggle(column);" }
|
.menu_item{ "ng-repeat": "column in columns", "ng-click": "toggle(column);" }
|
||||||
%input{ type: "checkbox", "ng-checked": "column.visible" }
|
%input{ type: "checkbox", "ng-checked": "column.visible" }
|
||||||
%span
|
%span
|
||||||
{{ column.name }}
|
{{ column.name }}
|
||||||
%hr
|
%hr
|
||||||
.menu_item.text-center
|
%div.menu_item.text-center
|
||||||
%input.fullwidth.orange{ type: "button", "ng-value": "saved() ? 'Saved': 'Saving'", "ng-show": "saved() || saving", "ng-disabled": "saved()" }
|
%input.fullwidth.orange{ type: "button", "ng-value": "saved() ? 'Saved': 'Saving'", "ng-show": "saved() || saving", "ng-disabled": "saved()" }
|
||||||
%input.fullwidth.red{ type: "button", value: t('admin.column_save_as_default').html_safe, "ng-show": "!saved() && !saving", "ng-click": "saveColumnPreferences(action)" }
|
%input.fullwidth.red{ type: "button", value: t('admin.column_save_as_default').html_safe, "ng-show": "!saved() && !saving", "ng-click": "saveColumnPreferences(action)" }
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
%i.fa.fa-times-circle{'aria-hidden' => "true"}
|
%i.fa.fa-times-circle{'aria-hidden' => "true"}
|
||||||
|
|
||||||
%form#image_upload{ name: 'form', novalidate: true, enctype: 'multipart/form-data', multipart: true, "ng-controller": "ProductImageCtrl" }
|
%form#image_upload{ name: 'form', novalidate: true, enctype: 'multipart/form-data', multipart: true, "ng-controller": "ProductImageCtrl" }
|
||||||
.image-preview
|
%div.image-preview
|
||||||
%img.spinner{ src: image_path("/spinning-circles.svg"), "ng-hide": "!imageUploader.isUploading" }
|
%img.spinner{ src: image_path("/spinning-circles.svg"), "ng-hide": "!imageUploader.isUploading" }
|
||||||
%img.preview{ "ng-src": "{{imagePreview}}", "ng-class": "{'faded': imageUploader.isUploading}" }
|
%img.preview{ "ng-src": "{{imagePreview}}", "ng-class": "{'faded': imageUploader.isUploading}" }
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
#new-tag-rule-dialog
|
||||||
|
.text-normal.margin-bottom-30.text-center
|
||||||
|
{{ 'js.admin.new_tag_rule_dialog.select_rule_type' | t }}
|
||||||
|
|
||||||
|
.text-center.margin-bottom-30
|
||||||
|
-# %select.fullwidth{ 'select2-min-search' => 5, 'ng-model' => 'newRuleType', 'ng-options' => 'ruleType.id as ruleType.name for ruleType in availableRuleTypes' }
|
||||||
|
%input.ofn-select2.fullwidth{ id: 'rule_type_selector', data: "ruleTypes", "min-search": "5", "ng-model": "ruleType" }
|
||||||
|
|
||||||
|
.text-center
|
||||||
|
%input.button.red.icon-plus{ type: 'button', value: "{{ 'js.admin.new_tag_rule_dialog.add_rule' | t }}", "ng-click": 'addRule(tagGroup, ruleType)' }
|
||||||
@@ -3,4 +3,4 @@
|
|||||||
%span.text-normal
|
%span.text-normal
|
||||||
{{ 'admin.tags' | t }}
|
{{ 'admin.tags' | t }}
|
||||||
%br
|
%br
|
||||||
%tags-with-translation.fullwidth{ object: 'object', form: 'order_cycle_form', id: 'tags_with_translation'}
|
%tags-with-translation.fullwidth{ object: 'object' }
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
%div
|
||||||
|
%input{ type: "number", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_calculator_attributes_preferred_flat_percent", min: -100, max: 100, "invert-number": true, "ng-model": "rule.calculator.preferred_flat_percent" }
|
||||||
|
%span.text-normal %
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
%div
|
||||||
|
%input.fullwidth.light.ofn-select2{ id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_order_cycles_visibility", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_order_cycles_visibility]", data: 'visibilityOptions', "min-search": 5, "ng-model": "rule.preferred_matched_order_cycles_visibility", "ng-if": "!rule.is_default" }
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_order_cycles_visibility", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_order_cycles_visibility]", "ng-value": "'hidden'", "ng-if": "rule.is_default" }
|
||||||
|
%span.text-normal{ "ng-if": "rule.is_default" }
|
||||||
|
=t(:not_visible)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
%div
|
||||||
|
%input.fullwidth.light.ofn-select2{ id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_payment_methods_visibility", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_payment_methods_visibility]", data: 'visibilityOptions', "min-search": 5, "ng-model": "rule.preferred_matched_payment_methods_visibility", "ng-if": "!rule.is_default" }
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_payment_methods_visibility", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_payment_methods_visibility]", "ng-value": "'hidden'", "ng-if": "rule.is_default" }
|
||||||
|
%span.text-normal{ "ng-if": "rule.is_default" }
|
||||||
|
= t(:not_visible)
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
%div
|
||||||
|
%input.fullwidth.light.ofn-select2{ id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_variants_visibility", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_variants_visibility]", data: 'visibilityOptions', "min-search": 5, "ng-model": "rule.preferred_matched_variants_visibility", "ng-if": "!rule.is_default" }
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_variants_visibility", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_variants_visibility]", "ng-value": "'hidden'", "ng-if": "rule.is_default" }
|
||||||
|
%span.text-normal{ "ng-if": "rule.is_default" }
|
||||||
|
= t(:not_visible)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
%div
|
||||||
|
%input.fullwidth.light.ofn-select2{ id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_shipping_methods_visibility", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_shipping_methods_visibility]", data: 'visibilityOptions', "min-search": 5, "ng-model": "rule.preferred_matched_shipping_methods_visibility", "ng-if": "!rule.is_default" }
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_matched_shipping_methods_visibility", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_matched_shipping_methods_visibility]", "ng-value": "'hidden'", "ng-if": "rule.is_default" }
|
||||||
|
%span.text-normal{ "ng-if": "rule.is_default" }
|
||||||
|
= t(:not_visible)
|
||||||
|
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
%div{ id: "tr_{{tagGroup.startIndex + $index}}" }
|
||||||
|
%table
|
||||||
|
%colgroup
|
||||||
|
%col.text{ width: "35%" }
|
||||||
|
%col.inputs{ width: "55%" }
|
||||||
|
%col.actions{ width: "10%" }
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_id", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][id]", "ng-value": "rule.id" }
|
||||||
|
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_type", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][type]", "ng-value": "rule.type" }
|
||||||
|
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_priority", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][priority]", "ng-value": "tagGroup.startIndex + $index" }
|
||||||
|
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_is_default", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][is_default]", "ng-value": "rule.is_default" }
|
||||||
|
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_customer_tags", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_customer_tags]", "ng-value": "rule.preferred_customer_tags" }
|
||||||
|
|
||||||
|
%input{ type: "hidden", id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_preferred_{{opt[rule.type].taggable}}_tags", name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][preferred_{{opt[rule.type].taggable}}_tags]", "ng-value": "opt[rule.type].tagListFor(rule)" }
|
||||||
|
|
||||||
|
%span.text-normal {{ opt[rule.type].textTop }}
|
||||||
|
%td
|
||||||
|
%tags-with-translation{ object: "rule", max: 1, "tags-attr" => "{{opt[rule.type].tagsAttr}}", "tag-list-attr" => "{{opt[rule.type].tagListAttr}}" }
|
||||||
|
%td.actions{ rowspan: 2 }
|
||||||
|
%a{ class: "delete-tag-rule icon-trash no-text", "ng-click": "deleteTagRule(tagGroup || defaultTagGroup, rule)" }
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%span.text-normal {{ opt[rule.type].textBottom }}
|
||||||
|
%td
|
||||||
|
%div{ "ng-include": "opt[rule.type].inputTemplate" }
|
||||||
|
|
||||||
|
%hr
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
// please update the modal html in app/components/out_of_stock_modal_component/out_of_stock_modal_component.html.haml if updating this template
|
|
||||||
%a.close-reveal-modal{"ng-click" => "$close()"}
|
%a.close-reveal-modal{"ng-click" => "$close()"}
|
||||||
%i.ofn-i_009-close
|
%i.ofn-i_009-close
|
||||||
|
|
||||||
@@ -13,4 +12,4 @@
|
|||||||
%span{'ng-if' => "v.on_hand == 0"}
|
%span{'ng-if' => "v.on_hand == 0"}
|
||||||
{{ 'js.out_of_stock.now_out_of_stock' | t }}
|
{{ 'js.out_of_stock.now_out_of_stock' | t }}
|
||||||
%span{'ng-if' => "v.on_hand > 0"}
|
%span{'ng-if' => "v.on_hand > 0"}
|
||||||
{{ 'js.out_of_stock.only_n_remaining' | t:{ num: v.on_hand } }}
|
{{ 'js.out_of_stock.only_n_remainging' | t:{ num: v.on_hand } }}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.contact-container
|
%div.contact-container
|
||||||
.modal-centered{"ng-if" => "::enterprise.email_address || enterprise.website || enterprise.phone || enterprise.whatsapp_phone"}
|
%div.modal-centered{"ng-if" => "::enterprise.email_address || enterprise.website || enterprise.phone || enterprise.whatsapp_phone"}
|
||||||
%p.modal-header {{'contact' | t}}
|
%p.modal-header {{'contact' | t}}
|
||||||
%p{"ng-if" => "::enterprise.phone", "ng-bind" => "::enterprise.phone"}
|
%p{"ng-if" => "::enterprise.phone", "ng-bind" => "::enterprise.phone"}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.modal-centered{ "ng-if" => "::enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
|
%div.modal-centered{ "ng-if" => "::enterprise.twitter || enterprise.facebook || enterprise.linkedin || enterprise.instagram"}
|
||||||
%p.modal-header {{'follow' | t}}
|
%p.modal-header {{'follow' | t}}
|
||||||
.follow-icons
|
.follow-icons
|
||||||
%span{"ng-if" => "::enterprise.twitter"}
|
%span{"ng-if" => "::enterprise.twitter"}
|
||||||
|
|||||||
@@ -7,12 +7,12 @@
|
|||||||
.columns.small-12.fat
|
.columns.small-12.fat
|
||||||
%div{"ng-if" => "::enterprise.name"}
|
%div{"ng-if" => "::enterprise.name"}
|
||||||
%label{"ng-bind-html" => "::'shop_for_products_html' | t:{enterprise: enterprise.name}"}
|
%label{"ng-bind-html" => "::'shop_for_products_html' | t:{enterprise: enterprise.name}"}
|
||||||
.show-for-medium-up{"ng-if" => "::!enterprise.name"}
|
%div.show-for-medium-up{"ng-if" => "::!enterprise.name"}
|
||||||
|
|
||||||
.row
|
.row
|
||||||
.columns.small-12
|
.columns.small-12
|
||||||
%a.cta-hub{"ng-repeat" => "hub in enterprise.hubs | filter:{id: '!'+enterprise.id} | orderBy:'-active'",
|
%a.cta-hub{"ng-repeat" => "hub in enterprise.hubs | filter:{id: '!'+enterprise.id} | orderBy:'-active'",
|
||||||
"ng-href" => "{{::hub.path}}#/shop_panel",
|
"ng-href" => "{{::hub.path}}#/shop_panel", "ofn-empties-cart" => "hub",
|
||||||
"ng-class" => "::{primary: hub.active, secondary: !hub.active}",
|
"ng-class" => "::{primary: hub.active, secondary: !hub.active}",
|
||||||
"ng-click" => "$close()",
|
"ng-click" => "$close()",
|
||||||
"ofn-change-hub" => "hub"}
|
"ofn-change-hub" => "hub"}
|
||||||
|
|||||||
@@ -12,6 +12,11 @@ img {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.collapse {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
-webkit-text-size-adjust: none;
|
-webkit-text-size-adjust: none;
|
||||||
@@ -27,6 +32,18 @@ a {
|
|||||||
color: #0096ad;
|
color: #0096ad;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
text-decoration: none;
|
||||||
|
color: #FFF;
|
||||||
|
background-color: #666;
|
||||||
|
padding: 10px 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 10px;
|
||||||
|
text-align: center;
|
||||||
|
cursor: pointer;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
p.callout {
|
p.callout {
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
background-color: #e1f0f5;
|
background-color: #e1f0f5;
|
||||||
@@ -104,12 +121,6 @@ table.order-summary {
|
|||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logo {
|
|
||||||
vertical-align: middle;
|
|
||||||
max-height: 50px;
|
|
||||||
max-width: 247px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.social .soc-btn {
|
.social .soc-btn {
|
||||||
padding: 3px 7px;
|
padding: 3px 7px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@@ -167,11 +178,17 @@ del.quantity_was {
|
|||||||
|
|
||||||
table.head-wrap {
|
table.head-wrap {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: #f2f2f2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.collapse {
|
.header.container table td {
|
||||||
margin: 0;
|
&.logo {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.label {
|
||||||
|
padding: 15px;
|
||||||
|
padding-left: 0px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* -------------------------------------
|
/* -------------------------------------
|
||||||
@@ -250,6 +267,10 @@ h6 {
|
|||||||
color: #999;
|
color: #999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.collapse {
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
p, ul {
|
p, ul {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
@@ -361,6 +382,12 @@ ul {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.column-wrap {
|
||||||
|
padding: 0 !important;
|
||||||
|
margin: 0 auto;
|
||||||
|
max-width: 600px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.column table {
|
.column table {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class AddTagRuleModalComponent < ModalComponent
|
|
||||||
def initialize(id:, tag_rule_types:, current_index:, div_id:, is_default: false,
|
|
||||||
customer_tag: "", hidden_field_customer_tag_options: {} )
|
|
||||||
super
|
|
||||||
|
|
||||||
@close_button = false
|
|
||||||
@modal_class = "tiny"
|
|
||||||
|
|
||||||
@tag_rule_types = tag_rule_types
|
|
||||||
@current_index = current_index
|
|
||||||
@div_id = div_id
|
|
||||||
@is_default = is_default
|
|
||||||
@customer_tag = customer_tag
|
|
||||||
@hidden_field_customer_tag_options = hidden_field_customer_tag_options
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :tag_rule_types, :current_index, :div_id, :is_default, :customer_tag,
|
|
||||||
:hidden_field_customer_tag_options
|
|
||||||
end
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
-# as far as I can tell we can't pass content to the parent template while rendering ie: something like :
|
|
||||||
-# = render_parent do
|
|
||||||
-# .something
|
|
||||||
-# my content
|
|
||||||
-# Workarount is to copy the ModalComponent template
|
|
||||||
%div{ id: @id, "data-controller": @data_controller, "data-action": @data_action, "data-modal-instant-value": @instant, **@options }
|
|
||||||
.reveal-modal-bg.fade{ "data-modal-target": "background", "data-action": "click->modal#close" }
|
|
||||||
.reveal-modal.fade.modal-component{ "data-modal-target": "modal", class: @modal_class }
|
|
||||||
#new-tag-rule-dialog{ "data-controller": "add-tag-rule-modal",
|
|
||||||
"data-add-tag-rule-modal-index-value": current_index }
|
|
||||||
|
|
||||||
-# Ideally we would use event to communicate the update of customer tag, but we would need
|
|
||||||
-# the element with "data-controller": "add-tag-rule-modal"
|
|
||||||
-# to be parent of the element with "data-controller": "tag-rule-group-form"
|
|
||||||
-# so it could respond to event generated by "tag-rule-group-form".
|
|
||||||
-# Here we are in the opposite situation so we use a hidden field to store the value of
|
|
||||||
-# the customer tag, so it can be updated by "tag-rule-group-form"
|
|
||||||
= hidden_field_tag "customer_tag", customer_tag, { "data-add-tag-rule-modal-target": "ruleCustomerTag" }.merge(hidden_field_customer_tag_options)
|
|
||||||
.text-normal.margin-bottom-30.text-center
|
|
||||||
= t('components.add_tag_rule_modal.select_rule_type')
|
|
||||||
.text-center.margin-bottom-30
|
|
||||||
= select_tag :rule_type_selector, options_for_select(tag_rule_types), { "data-controller": "tom-select", "data-add-tag-rule-modal-target": "rule", class: "primary no-search" }
|
|
||||||
.text-center
|
|
||||||
%input.button.red.icon-plus{ type: 'button',
|
|
||||||
value: "#{t('components.add_tag_rule_modal.add_rule')}",
|
|
||||||
"data-action": "click->add-tag-rule-modal#add click->modal#close",
|
|
||||||
"data-add-tag-rule-modal-div-id-param": div_id,
|
|
||||||
"data-add-tag-rule-modal-is-default-param": "#{is_default}"}
|
|
||||||
|
|
||||||
- if close_button?
|
|
||||||
.text-center
|
|
||||||
%input{ class: "button icon-plus #{close_button_class}", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->modal#close" }
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import { Controller } from "stimulus";
|
|
||||||
import showHttpError from "../../webpacker/js/services/show_http_error";
|
|
||||||
|
|
||||||
export default class extends Controller {
|
|
||||||
static targets = ["rule", "ruleCustomerTag"];
|
|
||||||
static values = { index: Number };
|
|
||||||
|
|
||||||
add({ params }) {
|
|
||||||
const rule_type = this.ruleTarget.value;
|
|
||||||
const index = this.indexValue;
|
|
||||||
const divId = params["divId"];
|
|
||||||
const isDefault = params["isDefault"];
|
|
||||||
const customerTags = this.hasRuleCustomerTagTarget
|
|
||||||
? this.ruleCustomerTagTarget.value
|
|
||||||
: undefined;
|
|
||||||
|
|
||||||
const urlParams = new URLSearchParams();
|
|
||||||
urlParams.append("rule_type", rule_type);
|
|
||||||
urlParams.append("index", index);
|
|
||||||
urlParams.append("div_id", divId);
|
|
||||||
urlParams.append("is_default", isDefault);
|
|
||||||
if (customerTags != undefined) {
|
|
||||||
urlParams.append("customer_tags", customerTags);
|
|
||||||
}
|
|
||||||
|
|
||||||
// fetch from backend
|
|
||||||
fetch(`tag_rules/new?${urlParams}`, {
|
|
||||||
method: "GET",
|
|
||||||
headers: {
|
|
||||||
Accept: "text/vnd.turbo-stream.html",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((response) => {
|
|
||||||
if (!response.ok) {
|
|
||||||
showHttpError(response.status);
|
|
||||||
throw response;
|
|
||||||
}
|
|
||||||
return response.text();
|
|
||||||
})
|
|
||||||
.then((html) => {
|
|
||||||
Turbo.renderStreamMessage(html);
|
|
||||||
this.indexValue = parseInt(index) + 1;
|
|
||||||
})
|
|
||||||
.catch((error) => console.error(error));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,3 +1 @@
|
|||||||
- # the stimulus contoller "example-component--example" lives in app/component/example_component/example_controller.js
|
%h1 #{@title}
|
||||||
%div{ "data-controller": "example-component--example"}
|
|
||||||
%h1 #{@title}
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
// This controller will be called "example", ie "js-file-name" minus the "_controller.js"
|
|
||||||
// see controller/index.js for more info
|
|
||||||
import { Controller } from "stimulus";
|
|
||||||
|
|
||||||
export default class extends Controller {}
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
.ofn-drop-down.ofn-drop-down-v2{ data: { controller: "multiple-checked-select" } }
|
.ofn-drop-down.ofn-drop-down-v2{ data: { controller: "multiple-checked-select" } }
|
||||||
.ofn-drop-down-label{ "data-multiple-checked-select-target": "button" }
|
%div.ofn-drop-down-label{ "data-multiple-checked-select-target": "button" }
|
||||||
%span{class: "label"}= t('admin.columns')
|
%span{class: "label"}= t('admin.columns')
|
||||||
%span{ class: "icon-caret-down", "data-multiple-checked-select-target": "caret" }
|
%span{ class: "icon-caret-down", "data-multiple-checked-select-target": "caret" }
|
||||||
.menu{ class: "hidden", "data-multiple-checked-select-target": "options" }
|
%div.menu{ class: "hidden", "data-multiple-checked-select-target": "options" }
|
||||||
.filter
|
%div.filter
|
||||||
%input{ type: "text", "data-multiple-checked-select-target": "filter", placeholder: I18n.t('components.multiple_checked_select.filter_placeholder') }
|
%input{ type: "text", "data-multiple-checked-select-target": "filter", placeholder: I18n.t('components.multiple_checked_select.filter_placeholder') }
|
||||||
%hr
|
%hr
|
||||||
.menu_items
|
%div.menu_items
|
||||||
- @options.each do |option|
|
- @options.each do |option|
|
||||||
%label.menu_item{ "data-multiple-checked-select-target": "option", "data-value": option[1], "data-label": option[0] }
|
%label.menu_item{ "data-multiple-checked-select-target": "option", "data-value": option[1], "data-label": option[0] }
|
||||||
%input{ type: "checkbox", checked: @selected.include?(option[1]), name: "#{@name}[]", value: option[1] }
|
%input{ type: "checkbox", checked: @selected.include?(option[1]), name: "#{@name}[]", value: option[1] }
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class OutOfStockModalComponent < ModalComponent
|
|
||||||
def initialize(id:, variants: [], redirect: false)
|
|
||||||
super(id:, modal_class: "medium", instant: true)
|
|
||||||
|
|
||||||
@variants = variants
|
|
||||||
@redirect = redirect
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
%div{ id: @id, "data-controller": "modal out-of-stock-modal", "data-action": "keyup@document->modal#closeIfEscapeKey modal:closing->out-of-stock-modal#redirect", "data-modal-instant-value": @instant, "data-out-of-stock-modal-redirect-value": @redirect }
|
|
||||||
.reveal-modal-bg.fade{ "data-modal-target": "background", "data-action": "click->modal#close" }
|
|
||||||
.reveal-modal.fade.modal-component{ "data-modal-target": "modal", class: @modal_class }
|
|
||||||
- # please update app/assets/javascripts/templates/out_of_stock.html.haml if updating this view
|
|
||||||
%a.close-reveal-modal{"data-action": "click->modal#close" }
|
|
||||||
%i.ofn-i_009-close
|
|
||||||
%h3
|
|
||||||
= t("js.out_of_stock.reduced_stock_available")
|
|
||||||
%p
|
|
||||||
= t("js.out_of_stock.out_of_stock_text")
|
|
||||||
- @variants.each do |variant|
|
|
||||||
- if variant.on_hand == 0
|
|
||||||
%p
|
|
||||||
%em
|
|
||||||
= "#{variant.name_to_display} - #{variant.unit_to_display}"
|
|
||||||
%span
|
|
||||||
= t("js.out_of_stock.now_out_of_stock")
|
|
||||||
- if variant.on_hand > 0
|
|
||||||
%p
|
|
||||||
%em
|
|
||||||
= "#{variant.name_to_display} - #{variant.unit_to_display}"
|
|
||||||
%span
|
|
||||||
= t("js.out_of_stock.only_n_remaining", num: variant.on_hand)
|
|
||||||
|
|
||||||
.text-center
|
|
||||||
%input{ class: "button icon-plus #{close_button_class}", type: 'button', value: t('js.admin.modals.close'), "data-action": "click->modal#close" }
|
|
||||||
@@ -30,7 +30,7 @@ class SearchableDropdownComponent < ViewComponent::Base
|
|||||||
:aria_label, :other_attrs
|
:aria_label, :other_attrs
|
||||||
|
|
||||||
def classes
|
def classes
|
||||||
"fullwidth #{'no-input' if remove_search_plugin?}"
|
"fullwidth #{remove_search_plugin? ? 'no-input' : ''}"
|
||||||
end
|
end
|
||||||
|
|
||||||
def data
|
def data
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class TagListInputComponent < ViewComponent::Base
|
|
||||||
def initialize(name:, tags:,
|
|
||||||
placeholder: I18n.t("components.tag_list_input.default_placeholder"),
|
|
||||||
only_one: false,
|
|
||||||
aria_label: nil,
|
|
||||||
hidden_field_data_options: {},
|
|
||||||
autocomplete_url: "")
|
|
||||||
@name = name
|
|
||||||
@tags = tags
|
|
||||||
@placeholder = placeholder
|
|
||||||
@only_one = only_one
|
|
||||||
@aria_label_option = aria_label ? { 'aria-label': aria_label } : {}
|
|
||||||
@hidden_field_data_options = hidden_field_data_options
|
|
||||||
@autocomplete_url = autocomplete_url
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :name, :tags, :placeholder, :only_one, :aria_label_option,
|
|
||||||
:hidden_field_data_options, :autocomplete_url
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def display
|
|
||||||
return "none" if tags.length >= 1 && only_one == true
|
|
||||||
|
|
||||||
"block"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
%div{ "data-controller": "tag-list-input", "data-tag-list-input-only-one-value": "#{only_one}", "data-tag-list-input-url-value": autocomplete_url, "data-action": "autocomplete.change->tag-list-input#addTag" }
|
|
||||||
.tags-input
|
|
||||||
.tags
|
|
||||||
- # We use display:none instead of hidden field, so changes to the value can be picked up by the bulkFormController
|
|
||||||
= text_field_tag name, tags.join(","), {"data-tag-list-input-target": "tagList", "style": "display: none"}.merge(hidden_field_data_options)
|
|
||||||
%ul.tag-list{"data-tag-list-input-target": "list"}
|
|
||||||
%template{"data-tag-list-input-target": "template"}
|
|
||||||
%li.tag-item
|
|
||||||
.tag-template
|
|
||||||
%span
|
|
||||||
%a.remove-button{ "data-action": "click->tag-list-input#removeTag" }
|
|
||||||
×
|
|
||||||
- tags.each do |tag|
|
|
||||||
%li.tag-item
|
|
||||||
.tag-template
|
|
||||||
%span=tag
|
|
||||||
%a.remove-button{ "data-action": "click->tag-list-input#removeTag" }
|
|
||||||
×
|
|
||||||
= text_field_tag("variant_add_tag",
|
|
||||||
nil,
|
|
||||||
{ class: "input",
|
|
||||||
placeholder: placeholder,
|
|
||||||
"data-action": "keydown.enter->tag-list-input#keyboardAddTag keyup->tag-list-input#filterInput blur->tag-list-input#onBlur focus->tag-list-input#onInputChange",
|
|
||||||
"data-tag-list-input-target": "input",
|
|
||||||
**aria_label_option,
|
|
||||||
style: "display: #{display};"})
|
|
||||||
%ul.suggestion-list{ "data-tag-list-input-target": "results" , hidden: true }
|
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
// Tags input
|
|
||||||
.tags-input {
|
|
||||||
display: block;
|
|
||||||
|
|
||||||
.tags {
|
|
||||||
-moz-appearance: textfield;
|
|
||||||
-webkit-appearance: textfield;
|
|
||||||
overflow: hidden;
|
|
||||||
word-wrap: break-word;
|
|
||||||
cursor: text;
|
|
||||||
background-color: #fff;
|
|
||||||
height: 100%;
|
|
||||||
box-shadow: none;
|
|
||||||
|
|
||||||
&:has(.changed) {
|
|
||||||
border: 1px solid $color-txt-changed-brd;
|
|
||||||
border-radius: 4px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag-error {
|
|
||||||
color: $color-error;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tag-list {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
list-style-type: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
li.tag-item {
|
|
||||||
border-radius: 3px;
|
|
||||||
margin: 2px 0 2px 3px;
|
|
||||||
padding: 0 0 0 5px;
|
|
||||||
display: inline-block;
|
|
||||||
float: left;
|
|
||||||
font-size: 14px;
|
|
||||||
line-height: 25px;
|
|
||||||
border: none;
|
|
||||||
box-shadow: none;
|
|
||||||
color: white !important;
|
|
||||||
background-image: none;
|
|
||||||
background-color: $teal;
|
|
||||||
|
|
||||||
.remove-button {
|
|
||||||
border-left: 1px solid darken($teal, 5);
|
|
||||||
margin-left: 2px;
|
|
||||||
padding: 0 6px;
|
|
||||||
background: 0 0;
|
|
||||||
cursor: pointer;
|
|
||||||
vertical-align: middle;
|
|
||||||
font-size: 14px;
|
|
||||||
color: white;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: rgba(0, 0, 0, 0.05);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.input {
|
|
||||||
border: 0;
|
|
||||||
outline: 0;
|
|
||||||
margin: 2px;
|
|
||||||
padding: 0 0 0 5px;
|
|
||||||
float: left;
|
|
||||||
height: 26px;
|
|
||||||
font-size: 14px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ul.suggestion-list {
|
|
||||||
margin-top: 5px;
|
|
||||||
padding: 5px 0;
|
|
||||||
z-index: $tag-drop-down-z-index;
|
|
||||||
width: fit-content;
|
|
||||||
background-color: #fff;
|
|
||||||
border: 1px solid rgba(0, 0, 0, 0.2);
|
|
||||||
box-shadow: $shadow-dropdown;
|
|
||||||
list-style-type: none;
|
|
||||||
max-height: 280px;
|
|
||||||
overflow-y: auto;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
li.suggestion-item {
|
|
||||||
padding: 5px 10px;
|
|
||||||
cursor: pointer;
|
|
||||||
white-space: nowrap;
|
|
||||||
overflow: hidden;
|
|
||||||
text-overflow: ellipsis;
|
|
||||||
color: #000;
|
|
||||||
background-color: #fff;
|
|
||||||
width: stretch;
|
|
||||||
|
|
||||||
&.active,
|
|
||||||
&:hover {
|
|
||||||
color: #fff;
|
|
||||||
background-color: $color-link-visited;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
import { Autocomplete } from "stimulus-autocomplete";
|
|
||||||
|
|
||||||
// Extend the stimulus-autocomplete controller, so we can load tag with existing rules
|
|
||||||
// The autocomplete functionality is only loaded if the url value is set
|
|
||||||
// For more informatioon on "stimulus-autocomplete", see:
|
|
||||||
// https://github.com/afcapel/stimulus-autocomplete/tree/main
|
|
||||||
//
|
|
||||||
export default class extends Autocomplete {
|
|
||||||
static targets = ["tagList", "input", "template", "list"];
|
|
||||||
static values = { onlyOne: Boolean };
|
|
||||||
|
|
||||||
connect() {
|
|
||||||
// Don't start autocomplete controller if we don't have an url
|
|
||||||
if (this.urlValue.length == 0) return;
|
|
||||||
|
|
||||||
super.connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
addTag(event) {
|
|
||||||
const newTagName = this.inputTarget.value.trim().replaceAll(" ", "-");
|
|
||||||
if (newTagName.length == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if tag already exist
|
|
||||||
const tags = this.tagListTarget.value.split(",");
|
|
||||||
const index = tags.indexOf(newTagName);
|
|
||||||
if (index != -1) {
|
|
||||||
// highlight the value in red
|
|
||||||
this.inputTarget.classList.add("tag-error");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// add to tagList
|
|
||||||
if (this.tagListTarget.value == "") {
|
|
||||||
this.tagListTarget.value = newTagName;
|
|
||||||
} else {
|
|
||||||
this.tagListTarget.value = this.tagListTarget.value.concat(`,${newTagName}`);
|
|
||||||
}
|
|
||||||
// manualy dispatch an Input event so the change can get picked up by other controllers
|
|
||||||
this.tagListTarget.dispatchEvent(new InputEvent("input"));
|
|
||||||
|
|
||||||
// Create new li component with value
|
|
||||||
const newTagElement = this.templateTarget.content.cloneNode(true);
|
|
||||||
const spanElement = newTagElement.querySelector("span");
|
|
||||||
spanElement.innerText = newTagName;
|
|
||||||
this.listTarget.appendChild(newTagElement);
|
|
||||||
|
|
||||||
// Clear new tag value
|
|
||||||
this.inputTarget.value = "";
|
|
||||||
|
|
||||||
// hide tag input if limited to one tag
|
|
||||||
if (this.tagListTarget.value.split(",").length == 1 && this.onlyOneValue == true) {
|
|
||||||
this.inputTarget.style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
keyboardAddTag(event) {
|
|
||||||
// prevent hotkey form submitting the form (default action for "enter" key)
|
|
||||||
if (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addTag();
|
|
||||||
}
|
|
||||||
|
|
||||||
removeTag(event) {
|
|
||||||
// Text to remove
|
|
||||||
const tagName = event.srcElement.previousElementSibling.textContent;
|
|
||||||
|
|
||||||
// Remove tag from list
|
|
||||||
const tags = this.tagListTarget.value.split(",");
|
|
||||||
this.tagListTarget.value = tags.filter((tag) => tag != tagName).join(",");
|
|
||||||
|
|
||||||
// manualy dispatch an Input event so the change gets picked up by the bulk form controller
|
|
||||||
this.tagListTarget.dispatchEvent(new InputEvent("input"));
|
|
||||||
|
|
||||||
// Remove HTML element from the list
|
|
||||||
event.srcElement.parentElement.parentElement.remove();
|
|
||||||
|
|
||||||
// Make sure the tag input is displayed
|
|
||||||
if (this.tagListTarget.value.length == 0) {
|
|
||||||
this.inputTarget.style.display = "block";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filterInput(event) {
|
|
||||||
// clear error class if key is not enter
|
|
||||||
if (event.key !== "Enter") {
|
|
||||||
this.inputTarget.classList.remove("tag-error");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Strip comma from tag name
|
|
||||||
if (event.key === ",") {
|
|
||||||
event.srcElement.value = event.srcElement.value.replace(",", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add tag if we don't have an autocomplete list open
|
|
||||||
onBlur() {
|
|
||||||
// check if we have any autocomplete results
|
|
||||||
if (this.resultsTarget.childElementCount == 0) this.addTag();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override original to add tag filtering
|
|
||||||
replaceResults(html) {
|
|
||||||
const filteredHtml = this.#filterResults(html);
|
|
||||||
|
|
||||||
// Don't show result if we don't have anything to show
|
|
||||||
if (filteredHtml.length == 0) return;
|
|
||||||
|
|
||||||
super.replaceResults(filteredHtml);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Override original to all empty query, which will return all existing tags
|
|
||||||
onInputChange = () => {
|
|
||||||
if (this.urlValue.length == 0) return;
|
|
||||||
|
|
||||||
if (this.hasHiddenTarget) this.hiddenTarget.value = "";
|
|
||||||
|
|
||||||
const query = this.inputTarget.value.trim();
|
|
||||||
if (query.length >= this.minLengthValue) {
|
|
||||||
this.fetchResults(query);
|
|
||||||
} else {
|
|
||||||
this.hideAndRemoveOptions();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//private
|
|
||||||
|
|
||||||
#filterResults(html) {
|
|
||||||
const existingTags = this.tagListTarget.value.split(",");
|
|
||||||
// Parse the HTML
|
|
||||||
const parser = new DOMParser();
|
|
||||||
const doc = parser.parseFromString(html, "text/html");
|
|
||||||
const lis = doc.getElementsByTagName("li");
|
|
||||||
// Filter
|
|
||||||
let filteredHtml = "";
|
|
||||||
for (let li of lis) {
|
|
||||||
if (!existingTags.includes(li.dataset.autocompleteValue)) {
|
|
||||||
filteredHtml += li.outerHTML;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return filteredHtml;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
class TagRuleFormComponent < ViewComponent::Base
|
|
||||||
def initialize(rule:, index:, customer_tags: "",
|
|
||||||
hidden_field_customer_tag_options: {})
|
|
||||||
@rule = rule
|
|
||||||
@index = index
|
|
||||||
@customer_tags = customer_tags
|
|
||||||
@hidden_field_customer_tag_options = hidden_field_customer_tag_options
|
|
||||||
end
|
|
||||||
|
|
||||||
attr_reader :rule, :index, :customer_tags, :hidden_field_customer_tag_options
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def element_name(name)
|
|
||||||
"enterprise[tag_rules_attributes][#{index}][#{name}]"
|
|
||||||
end
|
|
||||||
|
|
||||||
def rule_data # rubocop:disable Metrics/MethodLength
|
|
||||||
case rule.type
|
|
||||||
when "TagRule::FilterShippingMethods"
|
|
||||||
{
|
|
||||||
text_top: t('components.tag_rule_form.tag_rules.shipping_method_tagged_top'),
|
|
||||||
text_bottom: t('components.tag_rule_form.tag_rules.shipping_method_tagged_bottom'),
|
|
||||||
taggable: "shipping_method",
|
|
||||||
visibility_field: "preferred_matched_shipping_methods_visibility",
|
|
||||||
}
|
|
||||||
when "TagRule::FilterPaymentMethods"
|
|
||||||
{
|
|
||||||
text_top: t('components.tag_rule_form.tag_rules.payment_method_tagged_top'),
|
|
||||||
text_bottom: t('components.tag_rule_form.tag_rules.payment_method_tagged_bottom'),
|
|
||||||
taggable: "payment_method",
|
|
||||||
visibility_field: "preferred_matched_payment_methods_visibility",
|
|
||||||
}
|
|
||||||
when "TagRule::FilterOrderCycles"
|
|
||||||
{
|
|
||||||
text_top: t('components.tag_rule_form.tag_rules.order_cycle_tagged_top'),
|
|
||||||
text_bottom: t('components.tag_rule_form.tag_rules.order_cycle_tagged_bottom'),
|
|
||||||
taggable: "exchange",
|
|
||||||
visibility_field: "preferred_matched_order_cycles_visibility",
|
|
||||||
}
|
|
||||||
when "TagRule::FilterProducts"
|
|
||||||
{
|
|
||||||
text_top: t('components.tag_rule_form.tag_rules.inventory_tagged_top'),
|
|
||||||
text_bottom: t('components.tag_rule_form.tag_rules.inventory_tagged_bottom'),
|
|
||||||
taggable: "variant",
|
|
||||||
visibility_field: "preferred_matched_variants_visibility",
|
|
||||||
}
|
|
||||||
when "TagRule::FilterVariants"
|
|
||||||
{
|
|
||||||
text_top: t('components.tag_rule_form.tag_rules.variant_tagged_top'),
|
|
||||||
text_bottom: t('components.tag_rule_form.tag_rules.variant_tagged_bottom'),
|
|
||||||
taggable: "variant",
|
|
||||||
visibility_field: "preferred_matched_variants_visibility",
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def visibility_options
|
|
||||||
[
|
|
||||||
[t('components.tag_rule_form.tag_rules.visible'), "visible"],
|
|
||||||
[t('components.tag_rule_form.tag_rules.not_visible'), "hidden"]
|
|
||||||
]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user