workarea-browse_option 2.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.editorconfig +20 -0
- data/.github/ISSUE_TEMPLATE/bug_report.md +37 -0
- data/.github/ISSUE_TEMPLATE/documentation-request.md +17 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.gitignore +14 -0
- data/CHANGELOG.md +315 -0
- data/CODE_OF_CONDUCT.md +3 -0
- data/CONTRIBUTING.md +3 -0
- data/Gemfile +12 -0
- data/LICENSE +52 -0
- data/README.md +67 -0
- data/Rakefile +52 -0
- data/app/controllers/workarea/admin/categorizations_controller.decorator +25 -0
- data/app/controllers/workarea/admin/featured_products_controller.decorator +63 -0
- data/app/models/workarea/catalog/product.decorator +20 -0
- data/app/models/workarea/featured_browse_option_products.rb +13 -0
- data/app/models/workarea/search/storefront/product_option.rb +51 -0
- data/app/models/workarea/search/storefront/product_option_image_url.rb +18 -0
- data/app/queries/workarea/categorization.decorator +12 -0
- data/app/queries/workarea/search/product_entries.decorator +17 -0
- data/app/queries/workarea/search/related_products.decorator +30 -0
- data/app/services/workarea/browse_option_ids.rb +39 -0
- data/app/view_models/workarea/admin/bulk_action_product_edit_view_model.decorator +10 -0
- data/app/view_models/workarea/admin/featured_browse_option_product_view_model.rb +18 -0
- data/app/view_models/workarea/admin/featured_browse_option_products_view_model.rb +23 -0
- data/app/view_models/workarea/admin/featured_products_search_view_model.rb +45 -0
- data/app/view_models/workarea/admin/product_view_model.decorator +9 -0
- data/app/view_models/workarea/storefront/product_view_model/cache_key.decorator +12 -0
- data/app/view_models/workarea/storefront/product_view_model/image_collection.decorator +26 -0
- data/app/view_models/workarea/storefront/product_view_model.decorator +15 -0
- data/app/views/workarea/admin/bulk_action_product_edits/_browse_option_field.html.haml +10 -0
- data/app/views/workarea/admin/catalog_products/_browse_option_attribute_card.html.haml +3 -0
- data/app/views/workarea/admin/catalog_products/_browse_option_field.html.haml +3 -0
- data/app/views/workarea/api/storefront/products/_browse_option_field.json.jbuilder +2 -0
- data/app/workers/workarea/bulk_index_products.decorator +34 -0
- data/app/workers/workarea/index_category_changes.decorator +7 -0
- data/app/workers/workarea/index_product.decorator +18 -0
- data/bin/rails +17 -0
- data/config/initializers/appends.rb +21 -0
- data/config/initializers/configuration.rb +17 -0
- data/config/locales/en.yml +8 -0
- data/lib/tasks/browse_option_tasks.rake +4 -0
- data/lib/workarea/browse_option/engine.rb +20 -0
- data/lib/workarea/browse_option/version.rb +5 -0
- data/lib/workarea/browse_option.rb +11 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/config/manifest.js +4 -0
- data/test/dummy/app/assets/images/.keep +0 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/controllers/concerns/.keep +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/jobs/application_job.rb +2 -0
- data/test/dummy/app/mailers/application_mailer.rb +4 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/app/views/layouts/mailer.html.erb +13 -0
- data/test/dummy/app/views/layouts/mailer.text.erb +1 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +34 -0
- data/test/dummy/bin/update +29 -0
- data/test/dummy/config/application.rb +20 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/cable.yml +9 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +57 -0
- data/test/dummy/config/environments/production.rb +86 -0
- data/test/dummy/config/environments/test.rb +43 -0
- data/test/dummy/config/initializers/application_controller_renderer.rb +6 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +5 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/new_framework_defaults.rb +18 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/workarea.rb +5 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/puma.rb +47 -0
- data/test/dummy/config/routes.rb +6 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config/spring.rb +6 -0
- data/test/dummy/config.ru +5 -0
- data/test/dummy/db/seeds.rb +10 -0
- data/test/dummy/lib/assets/.keep +0 -0
- data/test/dummy/log/.keep +0 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/apple-touch-icon-precomposed.png +0 -0
- data/test/dummy/public/apple-touch-icon.png +0 -0
- data/test/dummy/public/favicon.ico +1 -0
- data/test/fixtures/files/large.jpg +0 -0
- data/test/fixtures/files/medium.jpg +0 -0
- data/test/integration/workarea/admin/browse_option_categorizations_integration_test.rb +47 -0
- data/test/integration/workarea/admin/browse_option_featured_products_integration_test.rb +45 -0
- data/test/integration/workarea/api/storefront/browse_option_product_integration_test.rb +74 -0
- data/test/models/workarea/catalog/browse_option_product_test.rb +20 -0
- data/test/models/workarea/featured_browse_option_products_test.rb +28 -0
- data/test/models/workarea/search/storefront/product_option_image_url_test.rb +19 -0
- data/test/models/workarea/search/storefront/product_option_test.rb +105 -0
- data/test/queries/workarea/browse_option_categorization_test.rb +20 -0
- data/test/queries/workarea/search/product_entries_test.decorator +19 -0
- data/test/queries/workarea/search/related_products_test.decorator +39 -0
- data/test/services/workarea/browse_option_ids_test.rb +63 -0
- data/test/system/workarea/admin/browse_option_featured_products_system_test.rb +57 -0
- data/test/system/workarea/admin/bulk_action_product_edit_browse_option_test.rb +54 -0
- data/test/system/workarea/storefront/browse_option_system_test.rb +110 -0
- data/test/test_helper.rb +10 -0
- data/test/view_models/workarea/admin/browse_option_product_view_model_test.rb +22 -0
- data/test/view_models/workarea/storefront/browse_option_product_view_model_test.rb +74 -0
- data/test/view_models/workarea/storefront/product_view_model/image_collection_test.rb +74 -0
- data/test/workers/workarea/browse_option_index_product_test.rb +37 -0
- data/test/workers/workarea/bulk_index_products_test.decorator +49 -0
- data/workarea-browse_option.gemspec +21 -0
- metadata +184 -0
@@ -0,0 +1,63 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Admin::FeaturedProductsController, with: :browse_option do
|
3
|
+
def select
|
4
|
+
search = Search::AdminProducts.new(view_model_options)
|
5
|
+
@search = Admin::FeaturedProductsSearchViewModel.new(
|
6
|
+
search,
|
7
|
+
view_model_options
|
8
|
+
)
|
9
|
+
end
|
10
|
+
|
11
|
+
def add
|
12
|
+
product_id, option = BrowseOptionIds.split(params[:product_id])
|
13
|
+
product = Catalog::Product.find(product_id)
|
14
|
+
|
15
|
+
@featurable.add_product(params[:product_id])
|
16
|
+
|
17
|
+
flash[:success] = t(
|
18
|
+
'workarea.admin.featured_products.flash_messages.added',
|
19
|
+
name: product.name
|
20
|
+
)
|
21
|
+
|
22
|
+
render(
|
23
|
+
partial: 'workarea/admin/featured_products/selected',
|
24
|
+
locals: {
|
25
|
+
featurable: @featurable,
|
26
|
+
product: wrap_in_browse_option_view_model(product, option)
|
27
|
+
}
|
28
|
+
)
|
29
|
+
end
|
30
|
+
|
31
|
+
def remove
|
32
|
+
product_id, option = BrowseOptionIds.split(params[:product_id])
|
33
|
+
product = Catalog::Product.find(product_id)
|
34
|
+
|
35
|
+
@featurable.remove_product(params[:product_id])
|
36
|
+
|
37
|
+
flash[:success] = t(
|
38
|
+
'workarea.admin.featured_products.flash_messages.removed',
|
39
|
+
name: product.name
|
40
|
+
)
|
41
|
+
|
42
|
+
render(
|
43
|
+
partial: 'workarea/admin/featured_products/unselected',
|
44
|
+
locals: {
|
45
|
+
featurable: @featurable,
|
46
|
+
product: wrap_in_browse_option_view_model(product, option)
|
47
|
+
}
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def wrap_in_browse_option_view_model(product, option)
|
54
|
+
return Admin::ProductViewModel.wrap(product) \
|
55
|
+
unless product.browse_option.present?
|
56
|
+
|
57
|
+
Admin::FeaturedBrowseOptionProductViewModel.wrap(
|
58
|
+
product,
|
59
|
+
product.browse_option => option
|
60
|
+
)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Catalog::Product, with: :browse_option do
|
3
|
+
decorated do
|
4
|
+
field :browse_option, type: String
|
5
|
+
end
|
6
|
+
|
7
|
+
def browses_by_option?
|
8
|
+
browse_option.present?
|
9
|
+
end
|
10
|
+
|
11
|
+
def browse_options
|
12
|
+
variants
|
13
|
+
.select(&:active?)
|
14
|
+
.map { |v| v.fetch_detail(browse_option) }
|
15
|
+
.flatten
|
16
|
+
.reject(&:blank?)
|
17
|
+
.uniq
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Workarea
|
2
|
+
module FeaturedBrowseOptionProducts
|
3
|
+
def featured_product?(id)
|
4
|
+
product_ids.any? do |product_id|
|
5
|
+
product_id == id || BrowseOptionIds.extract(product_id) == id
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
def unique_product_ids
|
10
|
+
product_ids.map { |id| BrowseOptionIds.extract(id) }.uniq
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Search
|
3
|
+
class Storefront
|
4
|
+
class ProductOption < Product
|
5
|
+
def id
|
6
|
+
"#{super}-#{value.optionize}"
|
7
|
+
end
|
8
|
+
|
9
|
+
# URL to the primary image for display in autocomplete results.
|
10
|
+
#
|
11
|
+
# @return [String]
|
12
|
+
#
|
13
|
+
def primary_image
|
14
|
+
ProductOptionImageUrl.new(model, option: value).url
|
15
|
+
end
|
16
|
+
|
17
|
+
def option
|
18
|
+
options[:option]
|
19
|
+
end
|
20
|
+
|
21
|
+
def category_positions
|
22
|
+
Catalog::ProductPositions.find(
|
23
|
+
BrowseOptionIds.for(model, value),
|
24
|
+
categories: categorization.to_models
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def value
|
29
|
+
options[:value].to_s
|
30
|
+
end
|
31
|
+
|
32
|
+
def variants
|
33
|
+
@variants ||= model.variants.select do |variant|
|
34
|
+
variant.matches_detail?(option, value)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def skus
|
39
|
+
variants.map(&:sku)
|
40
|
+
end
|
41
|
+
|
42
|
+
def as_document
|
43
|
+
result = super
|
44
|
+
result[:keywords][:option] = value
|
45
|
+
result[:facets][option] = [value]
|
46
|
+
result
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Search
|
3
|
+
class Storefront
|
4
|
+
class ProductOptionImageUrl < Workarea::ProductPrimaryImageUrl
|
5
|
+
def initialize(product, image_size: :small_thumb, option:)
|
6
|
+
super(product, image_size)
|
7
|
+
@option = option
|
8
|
+
end
|
9
|
+
|
10
|
+
def image
|
11
|
+
@product.images.find_by(option: @option)
|
12
|
+
rescue Mongoid::Errors::DocumentNotFound
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Categorization, with: :browse_option do
|
3
|
+
private
|
4
|
+
|
5
|
+
def manual_models
|
6
|
+
return [] if @product.blank?
|
7
|
+
@manual_models ||= Catalog::Category.by_product(
|
8
|
+
[@product.id, *BrowseOptionIds.all_for(@product)]
|
9
|
+
).to_a
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Search::ProductEntries, with: :browse_option do
|
3
|
+
def index_entries_for(product)
|
4
|
+
if product.browses_by_option?
|
5
|
+
product.browse_options.map do |value|
|
6
|
+
Search::Storefront::ProductOption.new(
|
7
|
+
product,
|
8
|
+
option: product.browse_option,
|
9
|
+
value: value
|
10
|
+
)
|
11
|
+
end
|
12
|
+
else
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Search::RelatedProducts, with: :browse_option do
|
3
|
+
def search_product_ids
|
4
|
+
@search_product_ids ||= products.flat_map { |p| search_model_for(p) }.map(&:id)
|
5
|
+
end
|
6
|
+
|
7
|
+
def exclude_search_product_ids
|
8
|
+
@exclude_search_product_ids ||=
|
9
|
+
begin
|
10
|
+
catalog_ids = Array(params[:exclude_product_ids])
|
11
|
+
products = Catalog::Product.any_in(id: catalog_ids).to_a
|
12
|
+
products.flat_map { |p| search_model_for(p) }.map(&:id)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def search_model_for(product)
|
17
|
+
if product.browses_by_option?
|
18
|
+
product.browse_options.map do |value|
|
19
|
+
Search::Storefront::ProductOption.new(
|
20
|
+
product,
|
21
|
+
option: product.browse_option,
|
22
|
+
value: value
|
23
|
+
)
|
24
|
+
end
|
25
|
+
else
|
26
|
+
Search::Storefront::Product.new(product)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Workarea
|
2
|
+
class BrowseOptionIds
|
3
|
+
class << self
|
4
|
+
def all_for(product, options = [])
|
5
|
+
return [product.id] unless product.browses_by_option?
|
6
|
+
|
7
|
+
(Array.wrap(options).presence || product.browse_options).map do |option|
|
8
|
+
build(product.id, option.optionize)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def for(product, option = nil)
|
13
|
+
return product.id unless product.browses_by_option?
|
14
|
+
|
15
|
+
if option.present?
|
16
|
+
build(product.id, option.optionize)
|
17
|
+
else
|
18
|
+
all_for(product).first
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def build(product_id, option)
|
23
|
+
[product_id, conjunction, option.optionize].join
|
24
|
+
end
|
25
|
+
|
26
|
+
def split(browse_option_id)
|
27
|
+
browse_option_id.to_s.split(conjunction)
|
28
|
+
end
|
29
|
+
|
30
|
+
def extract(browse_option_id)
|
31
|
+
split(browse_option_id).first
|
32
|
+
end
|
33
|
+
|
34
|
+
def conjunction
|
35
|
+
Workarea.config.browse_option_product_id_conjunction
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Admin
|
3
|
+
# Used for displaying each product option in feature product UI
|
4
|
+
class FeaturedBrowseOptionProductViewModel < ProductViewModel
|
5
|
+
def id
|
6
|
+
BrowseOptionIds.for(model, browse_option_value)
|
7
|
+
end
|
8
|
+
|
9
|
+
def name
|
10
|
+
[model.name, browse_option_value&.titleize].compact.join(' - ')
|
11
|
+
end
|
12
|
+
|
13
|
+
def browse_option_value
|
14
|
+
@options[model.browse_option]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Admin
|
3
|
+
module FeaturedBrowseOptionProductsViewModel
|
4
|
+
def featured_products
|
5
|
+
@featured_products ||=
|
6
|
+
begin
|
7
|
+
models = Catalog::Product.any_in(id: model.unique_product_ids).to_a
|
8
|
+
|
9
|
+
results = model.product_ids.map do |id|
|
10
|
+
id, option = BrowseOptionIds.split(id)
|
11
|
+
tmp = models.detect { |m| m.id == id }
|
12
|
+
next unless tmp.present?
|
13
|
+
|
14
|
+
Admin::FeaturedBrowseOptionProductViewModel.new(
|
15
|
+
tmp,
|
16
|
+
tmp.browse_option => option&.optionize
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Workarea
|
2
|
+
module Admin
|
3
|
+
class FeaturedProductsSearchViewModel < SearchViewModel
|
4
|
+
def results
|
5
|
+
@results ||= PagedArray.from(
|
6
|
+
browse_option_results,
|
7
|
+
model.results.page,
|
8
|
+
model.results.per_page,
|
9
|
+
total
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Yes, I know this is dumb. But there seems to be a bug with flat_map and
|
14
|
+
# flatten that is driving me fucking crazy and i need to avoid it.
|
15
|
+
#
|
16
|
+
def browse_option_results
|
17
|
+
results = []
|
18
|
+
|
19
|
+
persisted_results.each do |model|
|
20
|
+
if model.browses_by_option?
|
21
|
+
model.browse_options.each do |option|
|
22
|
+
results.push(
|
23
|
+
FeaturedBrowseOptionProductViewModel.wrap(
|
24
|
+
model,
|
25
|
+
view_model_options_for(model).merge(
|
26
|
+
model.browse_option => option.optionize
|
27
|
+
)
|
28
|
+
)
|
29
|
+
)
|
30
|
+
end
|
31
|
+
else
|
32
|
+
results.push(
|
33
|
+
FeaturedBrowseOptionProductViewModel.wrap(
|
34
|
+
model,
|
35
|
+
view_model_options_for(model)
|
36
|
+
)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
results
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Storefront::ProductViewModel::CacheKey, with: :browse_option do
|
3
|
+
private
|
4
|
+
|
5
|
+
def option_parts
|
6
|
+
option = @product.browse_option
|
7
|
+
return super unless option.present? && @options[option].present?
|
8
|
+
|
9
|
+
super.unshift(@options[option])
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Storefront::ProductViewModel::ImageCollection, with: :browse_option do
|
3
|
+
|
4
|
+
def primary
|
5
|
+
@browse_option_primary ||= browse_option_image || super
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
|
10
|
+
def browse_option_image
|
11
|
+
unless @product.browses_by_option? && current_browse_option.present?
|
12
|
+
return
|
13
|
+
end
|
14
|
+
|
15
|
+
@all.detect do |image|
|
16
|
+
image.option&.optionize.in?(
|
17
|
+
Array(current_browse_option).map(&:optionize)
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def current_browse_option
|
23
|
+
@options[:option] || @options[@product.browse_option.optionize]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate Storefront::ProductViewModel, with: :browse_option do
|
3
|
+
def browse_link_options
|
4
|
+
@browse_link_options_with_browse_option ||= super.tap do |link_options|
|
5
|
+
link_options[browse_option.optionize] =
|
6
|
+
options[:option] if options[:option].present?
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def current_browse_option
|
11
|
+
return nil unless browse_option.present?
|
12
|
+
options[:option] || options[browse_option.optionize]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
.bulk-actions__sub-section
|
2
|
+
.grid
|
3
|
+
.grid__cell
|
4
|
+
.property-toggle
|
5
|
+
.property-toggle__checkbox
|
6
|
+
= check_box_tag 'toggle_browses_by', nil, nil, class: 'toggle-property__check-box'
|
7
|
+
.property-toggle__property
|
8
|
+
.property
|
9
|
+
= label_tag 'bulk_action[settings][browse_option]', t('workarea.admin.catalog_products.browse_by_option'), class: 'property__name'
|
10
|
+
= select_tag 'bulk_action[settings][browse_option]', options_for_select(bulk_action.browse_options), disabled: true, class: 'toggle-property__input text-box', data: { property_toggle_allow_blank: '' }
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate BulkIndexProducts, with: :browse_option do
|
3
|
+
class_methods do
|
4
|
+
def perform(ids = Catalog::Product.pluck(:id))
|
5
|
+
ids = ids.map { |id| BrowseOptionIds.extract(id) }.uniq
|
6
|
+
super(ids)
|
7
|
+
end
|
8
|
+
|
9
|
+
def perform_by_models(products)
|
10
|
+
return if products.blank?
|
11
|
+
delete_existing_documents(products)
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def delete_existing_documents(products)
|
18
|
+
I18n.for_each_locale do
|
19
|
+
ids = products.map do |product|
|
20
|
+
id = Search::Storefront::Product.new(product).keywords[:catalog_id]
|
21
|
+
id.gsub(Workarea.config.search_index_id_escape_regex) { |match| "\\#{match}" }
|
22
|
+
end
|
23
|
+
query = { query: { terms: { 'keywords.catalog_id': ids } } }
|
24
|
+
hits = Search::Storefront.search(query)['hits']['hits']
|
25
|
+
documents = hits.map do |hit|
|
26
|
+
{ id: hit['_source']['id'], bulk_action: :delete }
|
27
|
+
end
|
28
|
+
|
29
|
+
Search::Storefront.bulk(documents)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Workarea
|
2
|
+
decorate IndexProduct, with: :browse_option do
|
3
|
+
class_methods do
|
4
|
+
def perform(product)
|
5
|
+
clear(product)
|
6
|
+
super
|
7
|
+
end
|
8
|
+
|
9
|
+
def clear(product)
|
10
|
+
id = Search::Storefront::Product.new(product).keywords[:catalog_id]
|
11
|
+
id.gsub!(Workarea.config.search_index_id_escape_regex) { |match| "\\#{match}" }
|
12
|
+
hits = Search::Storefront.search("keywords.catalog_id:#{id}")['hits']['hits']
|
13
|
+
|
14
|
+
hits.each { |hit| Search::Storefront.delete(hit['_id']) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/bin/rails
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
3
|
+
# installed from the root of your application.
|
4
|
+
|
5
|
+
ENGINE_ROOT = File.expand_path('../..', __FILE__)
|
6
|
+
ENGINE_PATH = File.expand_path('../../lib/browse_option/engine', __FILE__)
|
7
|
+
|
8
|
+
# Set up gems listed in the Gemfile.
|
9
|
+
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
10
|
+
require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
|
11
|
+
|
12
|
+
require 'action_controller/railtie'
|
13
|
+
require 'action_mailer/railtie'
|
14
|
+
require 'sprockets/railtie'
|
15
|
+
require 'rails/test_unit/railtie'
|
16
|
+
|
17
|
+
require 'rails/engine/commands'
|
@@ -0,0 +1,21 @@
|
|
1
|
+
Workarea.append_partials(
|
2
|
+
'admin.product_fields',
|
3
|
+
'workarea/admin/catalog_products/browse_option_field'
|
4
|
+
)
|
5
|
+
|
6
|
+
Workarea.append_partials(
|
7
|
+
'admin.product_attributes_card',
|
8
|
+
'workarea/admin/catalog_products/browse_option_attribute_card'
|
9
|
+
)
|
10
|
+
|
11
|
+
Workarea.append_partials(
|
12
|
+
'admin.product_bulk_update_settings',
|
13
|
+
'workarea/admin/bulk_action_product_edits/browse_option_field'
|
14
|
+
)
|
15
|
+
|
16
|
+
if Workarea::Plugin.installed?('Workarea::Api::Storefront')
|
17
|
+
Workarea.append_partials(
|
18
|
+
'api.storefront.product_details',
|
19
|
+
'workarea/api/storefront/products/browse_option_field'
|
20
|
+
)
|
21
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Workarea.configure do |config|
|
2
|
+
# Used to find irregular characters in product ids that can cause issues
|
3
|
+
# with finding a document in elasticsearch when reindexing.
|
4
|
+
config.search_index_id_escape_regex = %r{
|
5
|
+
( [-!\(\)\{\}\[\]^"~*?:\\\/] # A special character
|
6
|
+
| && # Boolean &&
|
7
|
+
| \|\| # Boolean ||
|
8
|
+
)
|
9
|
+
}x
|
10
|
+
|
11
|
+
# Used to combine product_id and browse option value when storing
|
12
|
+
# each option in featured products in the format of [ID][CONJUNCTION][OPTION]
|
13
|
+
# i.e. 1018-5915--blue. Changing this after a category has featured a browse
|
14
|
+
# option will not update the category automatically and will require a
|
15
|
+
# reindex of products.
|
16
|
+
config.browse_option_product_id_conjunction = '--'
|
17
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Workarea
|
2
|
+
module BrowseOption
|
3
|
+
class Engine < ::Rails::Engine
|
4
|
+
include Workarea::Plugin
|
5
|
+
isolate_namespace Workarea::BrowseOption
|
6
|
+
|
7
|
+
config.to_prepare do
|
8
|
+
Catalog::Category.include(FeaturedBrowseOptionProducts)
|
9
|
+
Search::Customization.include(FeaturedBrowseOptionProducts)
|
10
|
+
|
11
|
+
Admin::CategoryViewModel.include(
|
12
|
+
Admin::FeaturedBrowseOptionProductsViewModel
|
13
|
+
)
|
14
|
+
Admin::SearchCustomizationViewModel.include(
|
15
|
+
Admin::FeaturedBrowseOptionProductsViewModel
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/test/dummy/Rakefile
ADDED
File without changes
|