From 2fdaa8b9ec37fceb2e1647864a9f694ce73fbe66 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Fri, 19 Apr 2024 02:05:46 +0500 Subject: [PATCH 01/20] 11060 - implement the scenario 2 and 3 --- app/services/permitted_attributes/product.rb | 1 + app/views/admin/products_v3/_content.html.haml | 2 +- app/views/admin/products_v3/_product_row.html.haml | 7 ++++--- app/views/admin/products_v3/_table.html.haml | 2 +- app/webpacker/css/admin/products_v3.scss | 6 ------ 5 files changed, 7 insertions(+), 11 deletions(-) diff --git a/app/services/permitted_attributes/product.rb b/app/services/permitted_attributes/product.rb index 1adc8ff7d9..fdb82d6421 100644 --- a/app/services/permitted_attributes/product.rb +++ b/app/services/permitted_attributes/product.rb @@ -10,6 +10,7 @@ module PermittedAttributes :display_as, :sku, :group_buy, :group_buy_unit_size, :taxon_ids, :primary_taxon_id, :tax_category_id, :meta_keywords, :notes, :inherits_properties, + :supplier_id, { product_properties_attributes: [:id, :property_name, :value], variants_attributes: [PermittedAttributes::Variant.attributes], image_attributes: [:attachment] } diff --git a/app/views/admin/products_v3/_content.html.haml b/app/views/admin/products_v3/_content.html.haml index dcb29e945f..df6860f6ba 100644 --- a/app/views/admin/products_v3/_content.html.haml +++ b/app/views/admin/products_v3/_content.html.haml @@ -15,7 +15,7 @@ .container.results .sixteen.columns = render partial: 'sort', locals: { pagy: pagy, search_term: search_term, producer_id: producer_id, category_id: category_id } - = render partial: 'table', locals: { products: products } + = render partial: 'table', locals: { products:, producer_options: } - if pagy.present? && pagy.pages > 1 = render partial: 'admin/shared/stimulus_pagination', locals: { pagy: pagy } - else diff --git a/app/views/admin/products_v3/_product_row.html.haml b/app/views/admin/products_v3/_product_row.html.haml index 5e11301a5e..a251f8d4f5 100644 --- a/app/views/admin/products_v3/_product_row.html.haml +++ b/app/views/admin/products_v3/_product_row.html.haml @@ -9,7 +9,7 @@ %td.field.naked_inputs = f.text_field :sku, 'aria-label': t('admin.products_page.columns.sku') = error_message_on product, :sku -%td.multi-field.naked_inputs{ 'data-controller': 'toggle-control', 'data-toggle-control-match-value': 'items' } +%td.field.naked_inputs{ 'data-controller': 'toggle-control', 'data-toggle-control-match-value': 'items' } = f.hidden_field :variant_unit = f.hidden_field :variant_unit_scale = f.select :variant_unit_with_scale, @@ -27,8 +27,9 @@ -# empty %td.align-right -# empty -%td.align-left - .content= product.supplier&.name +%td.naked_inputs.align-left + = f.select :supplier_id, options_for_select(producer_options, product.supplier&.id), {}, + data: { "controller": "tom-select", 'tom-select-placeholder-value': t('admin.products_v3.filters.search_for_producers')} %td.align-left -# empty %td.align-left diff --git a/app/views/admin/products_v3/_table.html.haml b/app/views/admin/products_v3/_table.html.haml index 78d32be8b2..0c755b5aaa 100644 --- a/app/views/admin/products_v3/_table.html.haml +++ b/app/views/admin/products_v3/_table.html.haml @@ -66,7 +66,7 @@ controller: "nested-form product", action: 'rails-nested-form:add->bulk-form#registerElements' } } %tr - = render partial: 'product_row', locals: { product:, f: product_form } + = render partial: 'product_row', locals: { f: product_form, product:, producer_options: } - product.variants.each_with_index do |variant, variant_index| = form.fields_for("products][#{product_index}][variants_attributes][", variant, index: variant_index) do |variant_form| diff --git a/app/webpacker/css/admin/products_v3.scss b/app/webpacker/css/admin/products_v3.scss index 8cb8ccbce2..115512ce36 100644 --- a/app/webpacker/css/admin/products_v3.scss +++ b/app/webpacker/css/admin/products_v3.scss @@ -170,12 +170,6 @@ .field { padding: 0; } - .multi-field { - // Allow wrap with small gap - display: flex; - flex-wrap: wrap; - gap: 3px; - } .ts-control { z-index: 0; // Avoid hovering over thead From ec4b920f8bb6b7e4f3de876d9645c9dc3eee336e Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Fri, 19 Apr 2024 02:09:29 +0500 Subject: [PATCH 02/20] 11060 - implement scenario 1 --- app/views/admin/products_v3/_product_row.html.haml | 7 ++++--- app/views/admin/products_v3/_table.html.haml | 9 +++++---- app/views/admin/products_v3/_variant_row.html.haml | 5 +++-- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/views/admin/products_v3/_product_row.html.haml b/app/views/admin/products_v3/_product_row.html.haml index a251f8d4f5..889b95fd43 100644 --- a/app/views/admin/products_v3/_product_row.html.haml +++ b/app/views/admin/products_v3/_product_row.html.haml @@ -27,9 +27,10 @@ -# empty %td.align-right -# empty -%td.naked_inputs.align-left - = f.select :supplier_id, options_for_select(producer_options, product.supplier&.id), {}, - data: { "controller": "tom-select", 'tom-select-placeholder-value': t('admin.products_v3.filters.search_for_producers')} +- if producer_options.many? + %td.naked_inputs.align-left + = f.select :supplier_id, options_for_select(producer_options, product.supplier&.id), {}, + data: { "controller": "tom-select", 'tom-select-placeholder-value': t('admin.products_v3.filters.search_for_producers')} %td.align-left -# empty %td.align-left diff --git a/app/views/admin/products_v3/_table.html.haml b/app/views/admin/products_v3/_table.html.haml index 0c755b5aaa..47fc94fd72 100644 --- a/app/views/admin/products_v3/_table.html.haml +++ b/app/views/admin/products_v3/_table.html.haml @@ -55,7 +55,8 @@ %th.align-left.with-input= t('admin.products_page.columns.unit') %th.align-left.with-input= t('admin.products_page.columns.price') %th.align-left.with-input= t('admin.products_page.columns.on_hand') - %th.align-left= t('admin.products_page.columns.producer') + - if producer_options.many? + %th.align-left= t('admin.products_page.columns.producer') %th.align-left= t('admin.products_page.columns.category') %th.align-left= t('admin.products_page.columns.tax_category') %th.align-left= t('admin.products_page.columns.inherits_properties') @@ -71,17 +72,17 @@ - product.variants.each_with_index do |variant, variant_index| = form.fields_for("products][#{product_index}][variants_attributes][", variant, index: variant_index) do |variant_form| %tr.condensed{ 'data-controller': "variant" } - = render partial: 'variant_row', locals: { variant:, f: variant_form } + = render partial: 'variant_row', locals: { variant:, f: variant_form, producer_options: } = form.fields_for("products][#{product_index}][variants_attributes][NEW_RECORD", product.variants.build) do |new_variant_form| %template{ 'data-nested-form-target': "template" } %tr.condensed{ 'data-controller': "variant" } - = render partial: 'variant_row', locals: { variant: new_variant_form.object, f: new_variant_form } + = render partial: 'variant_row', locals: { variant: new_variant_form.object, f: new_variant_form, producer_options: } %tr{ 'data-nested-form-target': "target" } %tr.condensed %td - %td{ colspan: 11 } + %td{ colspan: producer_options.many? ? 11 : 10 } %button.secondary.condensed.naked.icon-plus{ 'data-action': "nested-form#add", 'aria-label': t('.new_variant') } =t('.new_variant') diff --git a/app/views/admin/products_v3/_variant_row.html.haml b/app/views/admin/products_v3/_variant_row.html.haml index 97646ec1ba..a99badd55a 100644 --- a/app/views/admin/products_v3/_variant_row.html.haml +++ b/app/views/admin/products_v3/_variant_row.html.haml @@ -39,8 +39,9 @@ = f.label :on_demand do = f.check_box :on_demand, 'data-action': 'change->toggle-control#disableIfPresent change->popout#closeIfChecked' = t(:on_demand) -%td.align-left - .content= variant.product.supplier&.name # same as product +- if producer_options.many? + %td.align-left + .content= variant.product.supplier&.name # same as product %td.align-left .content= variant.primary_taxon&.name %td.align-left From 4360ddde036f648a66a2004dcb1e51ed8f103fd3 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Fri, 19 Apr 2024 13:20:03 +0500 Subject: [PATCH 03/20] 11060 - add variant categories dropdown --- app/views/admin/products_v3/_content.html.haml | 2 +- app/views/admin/products_v3/_table.html.haml | 4 ++-- app/views/admin/products_v3/_variant_row.html.haml | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/views/admin/products_v3/_content.html.haml b/app/views/admin/products_v3/_content.html.haml index df6860f6ba..1b50fa3f10 100644 --- a/app/views/admin/products_v3/_content.html.haml +++ b/app/views/admin/products_v3/_content.html.haml @@ -15,7 +15,7 @@ .container.results .sixteen.columns = render partial: 'sort', locals: { pagy: pagy, search_term: search_term, producer_id: producer_id, category_id: category_id } - = render partial: 'table', locals: { products:, producer_options: } + = render partial: 'table', locals: { products:, producer_options:, category_options: } - if pagy.present? && pagy.pages > 1 = render partial: 'admin/shared/stimulus_pagination', locals: { pagy: pagy } - else diff --git a/app/views/admin/products_v3/_table.html.haml b/app/views/admin/products_v3/_table.html.haml index 47fc94fd72..b95c9f5187 100644 --- a/app/views/admin/products_v3/_table.html.haml +++ b/app/views/admin/products_v3/_table.html.haml @@ -72,12 +72,12 @@ - product.variants.each_with_index do |variant, variant_index| = form.fields_for("products][#{product_index}][variants_attributes][", variant, index: variant_index) do |variant_form| %tr.condensed{ 'data-controller': "variant" } - = render partial: 'variant_row', locals: { variant:, f: variant_form, producer_options: } + = render partial: 'variant_row', locals: { variant:, f: variant_form, producer_options:, category_options: } = form.fields_for("products][#{product_index}][variants_attributes][NEW_RECORD", product.variants.build) do |new_variant_form| %template{ 'data-nested-form-target': "template" } %tr.condensed{ 'data-controller': "variant" } - = render partial: 'variant_row', locals: { variant: new_variant_form.object, f: new_variant_form, producer_options: } + = render partial: 'variant_row', locals: { variant: new_variant_form.object, f: new_variant_form, producer_options:, category_options: } %tr{ 'data-nested-form-target': "target" } %tr.condensed diff --git a/app/views/admin/products_v3/_variant_row.html.haml b/app/views/admin/products_v3/_variant_row.html.haml index a99badd55a..8ea77ca01f 100644 --- a/app/views/admin/products_v3/_variant_row.html.haml +++ b/app/views/admin/products_v3/_variant_row.html.haml @@ -43,7 +43,8 @@ %td.align-left .content= variant.product.supplier&.name # same as product %td.align-left - .content= variant.primary_taxon&.name + = f.select :primary_taxon_id, options_for_select(category_options, variant.primary_taxon_id), {}, + data: { "controller": "tom-select", 'tom-select-placeholder-value': t('admin.products_v3.filters.search_for_categories')} %td.align-left .content= (variant.tax_category_id ? variant.tax_category&.name : t('.none_tax_category')) # TODO: convert to dropdown %td.align-left From 5050c2e02bafacffc7ef5560159090754a769379 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Fri, 19 Apr 2024 13:27:39 +0500 Subject: [PATCH 04/20] 11060 - remove producer name from variant --- app/views/admin/products_v3/_variant_row.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/products_v3/_variant_row.html.haml b/app/views/admin/products_v3/_variant_row.html.haml index 8ea77ca01f..9e19c693ed 100644 --- a/app/views/admin/products_v3/_variant_row.html.haml +++ b/app/views/admin/products_v3/_variant_row.html.haml @@ -41,7 +41,7 @@ = t(:on_demand) - if producer_options.many? %td.align-left - .content= variant.product.supplier&.name # same as product + -# empty producer name %td.align-left = f.select :primary_taxon_id, options_for_select(category_options, variant.primary_taxon_id), {}, data: { "controller": "tom-select", 'tom-select-placeholder-value': t('admin.products_v3.filters.search_for_categories')} From b577a81f48334393f672a30141a6b7d6e388b464 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Fri, 19 Apr 2024 17:54:14 +0500 Subject: [PATCH 05/20] 11060 - add tax category field --- app/controllers/admin/products_v3_controller.rb | 6 +++++- app/views/admin/products_v3/_content.html.haml | 2 +- app/views/admin/products_v3/_table.html.haml | 4 ++-- app/views/admin/products_v3/_variant_row.html.haml | 7 ++++--- app/views/admin/products_v3/index.html.haml | 2 +- app/webpacker/controllers/bulk_form_controller.js | 9 ++++++++- config/locales/en.yml | 1 + 7 files changed, 22 insertions(+), 9 deletions(-) diff --git a/app/controllers/admin/products_v3_controller.rb b/app/controllers/admin/products_v3_controller.rb index 667706aeba..168fa001d0 100644 --- a/app/controllers/admin/products_v3_controller.rb +++ b/app/controllers/admin/products_v3_controller.rb @@ -7,7 +7,7 @@ module Admin def index fetch_products - render "index", locals: { producers:, categories:, flash: } + render "index", locals: { producers:, categories:, tax_category_options:, flash: } end def bulk_update @@ -59,6 +59,10 @@ module Admin Spree::Taxon.order(:name).map { |c| [c.name, c.id] } end + def tax_category_options + Spree::TaxCategory.order(:name).pluck(:name, :id) + end + def fetch_products product_query = OpenFoodNetwork::Permissions.new(spree_current_user) .editable_products.merge(product_scope).ransack(ransack_query).result diff --git a/app/views/admin/products_v3/_content.html.haml b/app/views/admin/products_v3/_content.html.haml index 1b50fa3f10..0a9459abae 100644 --- a/app/views/admin/products_v3/_content.html.haml +++ b/app/views/admin/products_v3/_content.html.haml @@ -15,7 +15,7 @@ .container.results .sixteen.columns = render partial: 'sort', locals: { pagy: pagy, search_term: search_term, producer_id: producer_id, category_id: category_id } - = render partial: 'table', locals: { products:, producer_options:, category_options: } + = render partial: 'table', locals: { products:, producer_options:, category_options:, tax_category_options: } - if pagy.present? && pagy.pages > 1 = render partial: 'admin/shared/stimulus_pagination', locals: { pagy: pagy } - else diff --git a/app/views/admin/products_v3/_table.html.haml b/app/views/admin/products_v3/_table.html.haml index b95c9f5187..4c0538e43c 100644 --- a/app/views/admin/products_v3/_table.html.haml +++ b/app/views/admin/products_v3/_table.html.haml @@ -72,12 +72,12 @@ - product.variants.each_with_index do |variant, variant_index| = form.fields_for("products][#{product_index}][variants_attributes][", variant, index: variant_index) do |variant_form| %tr.condensed{ 'data-controller': "variant" } - = render partial: 'variant_row', locals: { variant:, f: variant_form, producer_options:, category_options: } + = render partial: 'variant_row', locals: { variant:, f: variant_form, producer_options:, category_options:, tax_category_options: } = form.fields_for("products][#{product_index}][variants_attributes][NEW_RECORD", product.variants.build) do |new_variant_form| %template{ 'data-nested-form-target': "template" } %tr.condensed{ 'data-controller': "variant" } - = render partial: 'variant_row', locals: { variant: new_variant_form.object, f: new_variant_form, producer_options:, category_options: } + = render partial: 'variant_row', locals: { variant: new_variant_form.object, f: new_variant_form, producer_options:, category_options:, tax_category_options: } %tr{ 'data-nested-form-target': "target" } %tr.condensed diff --git a/app/views/admin/products_v3/_variant_row.html.haml b/app/views/admin/products_v3/_variant_row.html.haml index 9e19c693ed..2a243025ee 100644 --- a/app/views/admin/products_v3/_variant_row.html.haml +++ b/app/views/admin/products_v3/_variant_row.html.haml @@ -42,11 +42,12 @@ - if producer_options.many? %td.align-left -# empty producer name -%td.align-left +%td.field.naked_inputs = f.select :primary_taxon_id, options_for_select(category_options, variant.primary_taxon_id), {}, data: { "controller": "tom-select", 'tom-select-placeholder-value': t('admin.products_v3.filters.search_for_categories')} -%td.align-left - .content= (variant.tax_category_id ? variant.tax_category&.name : t('.none_tax_category')) # TODO: convert to dropdown +%td.field.naked_inputs + = f.select :tax_category_id, options_for_select(tax_category_options, variant.tax_category_id), {include_blank: t('.none_tax_category')}, + data: { "controller": "tom-select", 'tom-select-placeholder-value': t('.search_for_tax_categories')} %td.align-left -# empty %td.align-right diff --git a/app/views/admin/products_v3/index.html.haml b/app/views/admin/products_v3/index.html.haml index 4200cd0176..5087feddc2 100644 --- a/app/views/admin/products_v3/index.html.haml +++ b/app/views/admin/products_v3/index.html.haml @@ -15,7 +15,7 @@ = render partial: "content", locals: { products: @products, pagy: @pagy, search_term: @search_term, producer_options: producers, producer_id: @producer_id, category_options: categories, category_id: @category_id, - flashes: flash } + tax_category_options:, flashes: flash } - %w[product variant].each do |object_type| = render partial: 'delete_modal', locals: { object_type: } #modal-component diff --git a/app/webpacker/controllers/bulk_form_controller.js b/app/webpacker/controllers/bulk_form_controller.js index 602f7c0127..54a8a812df 100644 --- a/app/webpacker/controllers/bulk_form_controller.js +++ b/app/webpacker/controllers/bulk_form_controller.js @@ -135,10 +135,17 @@ export default class BulkFormController extends Controller { if (element.type == "checkbox") { return element.defaultChecked !== undefined && element.checked != element.defaultChecked; } else if (element.type == "select-one") { + // (weird) Behavior of select element's include_blank option in Rails: + // If a select field has include_blank option selected (its value will be ''), + // its respective option doesn't have the selected attribute + // but selectedOptions have that option present const defaultSelected = Array.from(element.options).find((opt) => opt.hasAttribute("selected"), ); - return element.selectedOptions[0] != defaultSelected; + const selectedOption = element.selectedOptions[0]; + const areBothBlank = selectedOption.value === '' && defaultSelected === undefined + + return !areBothBlank && selectedOption !== defaultSelected; } else { return element.defaultValue !== undefined && element.value != element.defaultValue; } diff --git a/config/locales/en.yml b/config/locales/en.yml index 1fe516fee8..f17baa2601 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -910,6 +910,7 @@ en: error: Unable to delete the variant variant_row: none_tax_category: None + search_for_tax_categories: "Search for tax categories" product_import: title: Product Import file_not_found: File not found or could not be opened From c153ff75f38fd8657436f9b9ad4cb6217d8f3759 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Fri, 19 Apr 2024 20:50:22 +0500 Subject: [PATCH 06/20] 11060 - add searchable dropdown component --- .../searchable_dropdown_component.rb | 41 +++++++++++++++++++ .../searchable_dropdown_component.html.haml | 1 + 2 files changed, 42 insertions(+) create mode 100644 app/components/searchable_dropdown_component.rb create mode 100644 app/components/searchable_dropdown_component/searchable_dropdown_component.html.haml diff --git a/app/components/searchable_dropdown_component.rb b/app/components/searchable_dropdown_component.rb new file mode 100644 index 0000000000..7a6992504e --- /dev/null +++ b/app/components/searchable_dropdown_component.rb @@ -0,0 +1,41 @@ +# frozen_string_literal: true + +class SearchableDropdownComponent < ViewComponent::Base + REMOVED_SEARCH_PLUGIN = {"tom-select-options-value": '{ "plugins": [] }'}.freeze + MINIMUM_OPTIONS_FOR_SEARCH_FILED = 11.freeze # at least 11 options are required for the search field + + def initialize( + form:, + name:, + options:, + selected_option:, + placeholder_value:, + include_blank: false + ) + @f = form + @name = name + @options = options + @selected_option = selected_option + @placeholder_value = placeholder_value + @include_blank = include_blank + end + + private + + attr_reader :f, :name, :options, :selected_option, :placeholder_value, :include_blank + + def classes + "fullwidth #{remove_search_plugin? ? 'no-input' : ''}" + end + + def data + { + "controller": "tom-select", + 'tom-select-placeholder-value': placeholder_value + }.merge(remove_search_plugin? ? REMOVED_SEARCH_PLUGIN : {}) + end + + def remove_search_plugin? + @should_remove_search_plugin ||= options.count < MINIMUM_OPTIONS_FOR_SEARCH_FILED + end +end diff --git a/app/components/searchable_dropdown_component/searchable_dropdown_component.html.haml b/app/components/searchable_dropdown_component/searchable_dropdown_component.html.haml new file mode 100644 index 0000000000..fbff09f1bf --- /dev/null +++ b/app/components/searchable_dropdown_component/searchable_dropdown_component.html.haml @@ -0,0 +1 @@ += f.select name, options_for_select(options, selected_option), { include_blank: }, class: classes, data: From f6efd47af2984d09426abf0b7e3e0d0759ca7755 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Fri, 19 Apr 2024 20:53:08 +0500 Subject: [PATCH 07/20] 11060 - use SearchableDropdownComponent for producer names --- app/views/admin/products_v3/_product_row.html.haml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/views/admin/products_v3/_product_row.html.haml b/app/views/admin/products_v3/_product_row.html.haml index 889b95fd43..eae60c0d9e 100644 --- a/app/views/admin/products_v3/_product_row.html.haml +++ b/app/views/admin/products_v3/_product_row.html.haml @@ -29,8 +29,11 @@ -# empty - if producer_options.many? %td.naked_inputs.align-left - = f.select :supplier_id, options_for_select(producer_options, product.supplier&.id), {}, - data: { "controller": "tom-select", 'tom-select-placeholder-value': t('admin.products_v3.filters.search_for_producers')} + = render(SearchableDropdownComponent.new(form: f, + name: :supplier_id, + options: producer_options, + selected_option: product.supplier_id, + placeholder_value: t('admin.products_v3.filters.search_for_producers'))) %td.align-left -# empty %td.align-left From aad48b4670079ea931432f85bf622ff38791c2cf Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Sat, 20 Apr 2024 00:20:58 +0500 Subject: [PATCH 08/20] 11060 - use SearchableDropdownComponent for categories or tax categories --- .../admin/products_v3/_variant_row.html.haml | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/app/views/admin/products_v3/_variant_row.html.haml b/app/views/admin/products_v3/_variant_row.html.haml index 2a243025ee..47117fa3cb 100644 --- a/app/views/admin/products_v3/_variant_row.html.haml +++ b/app/views/admin/products_v3/_variant_row.html.haml @@ -43,11 +43,18 @@ %td.align-left -# empty producer name %td.field.naked_inputs - = f.select :primary_taxon_id, options_for_select(category_options, variant.primary_taxon_id), {}, - data: { "controller": "tom-select", 'tom-select-placeholder-value': t('admin.products_v3.filters.search_for_categories')} + = render(SearchableDropdownComponent.new(form: f, + name: :primary_taxon_id, + options: category_options, + selected_option: variant.primary_taxon_id, + placeholder_value: t('admin.products_v3.filters.search_for_categories'))) %td.field.naked_inputs - = f.select :tax_category_id, options_for_select(tax_category_options, variant.tax_category_id), {include_blank: t('.none_tax_category')}, - data: { "controller": "tom-select", 'tom-select-placeholder-value': t('.search_for_tax_categories')} + = render(SearchableDropdownComponent.new(form: f, + name: :tax_category_id, + options: tax_category_options, + selected_option: variant.tax_category_id, + include_blank: t('.none_tax_category'), + placeholder_value: t('.search_for_tax_categories'))) %td.align-left -# empty %td.align-right From da34e7b780cc26c598166e06da60fc3608b59a0c Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Mon, 22 Apr 2024 01:35:28 +0500 Subject: [PATCH 09/20] 11060 - fix undefined method tax_category_options error in specs --- app/controllers/admin/products_v3_controller.rb | 3 ++- app/reflexes/products_reflex.rb | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/app/controllers/admin/products_v3_controller.rb b/app/controllers/admin/products_v3_controller.rb index 168fa001d0..92386e1231 100644 --- a/app/controllers/admin/products_v3_controller.rb +++ b/app/controllers/admin/products_v3_controller.rb @@ -24,7 +24,8 @@ module Admin elsif product_set.errors.present? @error_counts = { saved: product_set.saved_count, invalid: product_set.invalid.count } - render "index", status: :unprocessable_entity, locals: { producers:, categories:, flash: } + render "index", status: :unprocessable_entity, + locals: { producers:, categories:, tax_category_options:, flash: } end end diff --git a/app/reflexes/products_reflex.rb b/app/reflexes/products_reflex.rb index 9cad290331..a2800c83e4 100644 --- a/app/reflexes/products_reflex.rb +++ b/app/reflexes/products_reflex.rb @@ -89,7 +89,7 @@ class ProductsReflex < ApplicationReflex html: render(partial: "admin/products_v3/content", locals: { products: @products, pagy: @pagy, search_term: @search_term, producer_options: producers, producer_id: @producer_id, - category_options: categories, category_id: @category_id, + category_options: categories, tax_category_options:, category_id: @category_id, flashes: flash }) ) @@ -125,6 +125,10 @@ class ProductsReflex < ApplicationReflex Spree::Taxon.order(:name).map { |c| [c.name, c.id] } end + def tax_category_options + Spree::TaxCategory.order(:name).pluck(:name, :id) + end + def fetch_products product_query = OpenFoodNetwork::Permissions.new(current_user) .editable_products.merge(product_scope).ransack(ransack_query).result(distinct: true) From c12d6ab7f0769b1d893a4b4cdef91ed5455d7653 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Wed, 24 Apr 2024 02:44:32 +0500 Subject: [PATCH 10/20] 11060: revert 33b947be00563b67ca36475f277ceceaf8c68378 --- app/views/admin/products_v3/_product_row.html.haml | 13 ++++++------- app/views/admin/products_v3/_table.html.haml | 9 ++++----- app/views/admin/products_v3/_variant_row.html.haml | 5 ++--- spec/system/admin/products_v3/products_spec.rb | 2 +- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/app/views/admin/products_v3/_product_row.html.haml b/app/views/admin/products_v3/_product_row.html.haml index eae60c0d9e..06483a93df 100644 --- a/app/views/admin/products_v3/_product_row.html.haml +++ b/app/views/admin/products_v3/_product_row.html.haml @@ -27,13 +27,12 @@ -# empty %td.align-right -# empty -- if producer_options.many? - %td.naked_inputs.align-left - = render(SearchableDropdownComponent.new(form: f, - name: :supplier_id, - options: producer_options, - selected_option: product.supplier_id, - placeholder_value: t('admin.products_v3.filters.search_for_producers'))) +%td.naked_inputs.align-left + = render(SearchableDropdownComponent.new(form: f, + name: :supplier_id, + options: producer_options, + selected_option: product.supplier_id, + placeholder_value: t('admin.products_v3.filters.search_for_producers'))) %td.align-left -# empty %td.align-left diff --git a/app/views/admin/products_v3/_table.html.haml b/app/views/admin/products_v3/_table.html.haml index 4c0538e43c..10b62f911e 100644 --- a/app/views/admin/products_v3/_table.html.haml +++ b/app/views/admin/products_v3/_table.html.haml @@ -55,8 +55,7 @@ %th.align-left.with-input= t('admin.products_page.columns.unit') %th.align-left.with-input= t('admin.products_page.columns.price') %th.align-left.with-input= t('admin.products_page.columns.on_hand') - - if producer_options.many? - %th.align-left= t('admin.products_page.columns.producer') + %th.align-left= t('admin.products_page.columns.producer') %th.align-left= t('admin.products_page.columns.category') %th.align-left= t('admin.products_page.columns.tax_category') %th.align-left= t('admin.products_page.columns.inherits_properties') @@ -72,17 +71,17 @@ - product.variants.each_with_index do |variant, variant_index| = form.fields_for("products][#{product_index}][variants_attributes][", variant, index: variant_index) do |variant_form| %tr.condensed{ 'data-controller': "variant" } - = render partial: 'variant_row', locals: { variant:, f: variant_form, producer_options:, category_options:, tax_category_options: } + = render partial: 'variant_row', locals: { variant:, f: variant_form, category_options:, tax_category_options: } = form.fields_for("products][#{product_index}][variants_attributes][NEW_RECORD", product.variants.build) do |new_variant_form| %template{ 'data-nested-form-target': "template" } %tr.condensed{ 'data-controller': "variant" } - = render partial: 'variant_row', locals: { variant: new_variant_form.object, f: new_variant_form, producer_options:, category_options:, tax_category_options: } + = render partial: 'variant_row', locals: { variant: new_variant_form.object, f: new_variant_form, category_options:, tax_category_options: } %tr{ 'data-nested-form-target': "target" } %tr.condensed %td - %td{ colspan: producer_options.many? ? 11 : 10 } + %td{ colspan: 11 } %button.secondary.condensed.naked.icon-plus{ 'data-action': "nested-form#add", 'aria-label': t('.new_variant') } =t('.new_variant') diff --git a/app/views/admin/products_v3/_variant_row.html.haml b/app/views/admin/products_v3/_variant_row.html.haml index 47117fa3cb..936ede26a6 100644 --- a/app/views/admin/products_v3/_variant_row.html.haml +++ b/app/views/admin/products_v3/_variant_row.html.haml @@ -39,9 +39,8 @@ = f.label :on_demand do = f.check_box :on_demand, 'data-action': 'change->toggle-control#disableIfPresent change->popout#closeIfChecked' = t(:on_demand) -- if producer_options.many? - %td.align-left - -# empty producer name +%td.align-left + -# empty producer name %td.field.naked_inputs = render(SearchableDropdownComponent.new(form: f, name: :primary_taxon_id, diff --git a/spec/system/admin/products_v3/products_spec.rb b/spec/system/admin/products_v3/products_spec.rb index 5d69b524cc..aa9cee9512 100644 --- a/spec/system/admin/products_v3/products_spec.rb +++ b/spec/system/admin/products_v3/products_spec.rb @@ -1030,6 +1030,6 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl end def tax_category_column - @tax_category_column ||= 'td:nth-child(10)' + @tax_category_column ||= '[data-controller="variant"] > td:nth-child(10)' end end From 15ee4f6619c3666a9436e3ff6295a6b11b567373 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Sat, 27 Apr 2024 19:52:49 +0500 Subject: [PATCH 11/20] 11060: add specs --- .../searchable_dropdown_component.rb | 12 +- .../searchable_dropdown_component.html.haml | 2 +- .../admin/products_v3/_product_row.html.haml | 1 + .../admin/products_v3/_variant_row.html.haml | 2 + config/locales/en.yml | 4 + .../system/admin/products_v3/products_spec.rb | 148 ++++++++++++++++++ 6 files changed, 163 insertions(+), 6 deletions(-) diff --git a/app/components/searchable_dropdown_component.rb b/app/components/searchable_dropdown_component.rb index 7a6992504e..98365c4c8b 100644 --- a/app/components/searchable_dropdown_component.rb +++ b/app/components/searchable_dropdown_component.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true class SearchableDropdownComponent < ViewComponent::Base - REMOVED_SEARCH_PLUGIN = {"tom-select-options-value": '{ "plugins": [] }'}.freeze - MINIMUM_OPTIONS_FOR_SEARCH_FILED = 11.freeze # at least 11 options are required for the search field + REMOVED_SEARCH_PLUGIN = { 'tom-select-options-value': '{ "plugins": [] }' }.freeze + MINIMUM_OPTIONS_FOR_SEARCH_FILED = 11 # at least 11 options are required for the search field def initialize( form:, @@ -10,7 +10,8 @@ class SearchableDropdownComponent < ViewComponent::Base options:, selected_option:, placeholder_value:, - include_blank: false + include_blank: false, + aria_label: '' ) @f = form @name = name @@ -18,11 +19,12 @@ class SearchableDropdownComponent < ViewComponent::Base @selected_option = selected_option @placeholder_value = placeholder_value @include_blank = include_blank + @aria_label = aria_label end private - attr_reader :f, :name, :options, :selected_option, :placeholder_value, :include_blank + attr_reader :f, :name, :options, :selected_option, :placeholder_value, :include_blank, :aria_label def classes "fullwidth #{remove_search_plugin? ? 'no-input' : ''}" @@ -30,7 +32,7 @@ class SearchableDropdownComponent < ViewComponent::Base def data { - "controller": "tom-select", + controller: "tom-select", 'tom-select-placeholder-value': placeholder_value }.merge(remove_search_plugin? ? REMOVED_SEARCH_PLUGIN : {}) end diff --git a/app/components/searchable_dropdown_component/searchable_dropdown_component.html.haml b/app/components/searchable_dropdown_component/searchable_dropdown_component.html.haml index fbff09f1bf..10043eaa29 100644 --- a/app/components/searchable_dropdown_component/searchable_dropdown_component.html.haml +++ b/app/components/searchable_dropdown_component/searchable_dropdown_component.html.haml @@ -1 +1 @@ -= f.select name, options_for_select(options, selected_option), { include_blank: }, class: classes, data: += f.select name, options_for_select(options, selected_option), { include_blank: }, class: classes, data:, 'aria-label': aria_label diff --git a/app/views/admin/products_v3/_product_row.html.haml b/app/views/admin/products_v3/_product_row.html.haml index 06483a93df..3c12ac1b1b 100644 --- a/app/views/admin/products_v3/_product_row.html.haml +++ b/app/views/admin/products_v3/_product_row.html.haml @@ -30,6 +30,7 @@ %td.naked_inputs.align-left = render(SearchableDropdownComponent.new(form: f, name: :supplier_id, + aria_label: t('.producer_field_name'), options: producer_options, selected_option: product.supplier_id, placeholder_value: t('admin.products_v3.filters.search_for_producers'))) diff --git a/app/views/admin/products_v3/_variant_row.html.haml b/app/views/admin/products_v3/_variant_row.html.haml index 936ede26a6..53ea27aad5 100644 --- a/app/views/admin/products_v3/_variant_row.html.haml +++ b/app/views/admin/products_v3/_variant_row.html.haml @@ -46,6 +46,7 @@ name: :primary_taxon_id, options: category_options, selected_option: variant.primary_taxon_id, + aria_label: t('.category_field_name'), placeholder_value: t('admin.products_v3.filters.search_for_categories'))) %td.field.naked_inputs = render(SearchableDropdownComponent.new(form: f, @@ -53,6 +54,7 @@ options: tax_category_options, selected_option: variant.tax_category_id, include_blank: t('.none_tax_category'), + aria_label: t('.tax_category_field_name'), placeholder_value: t('.search_for_tax_categories'))) %td.align-left -# empty diff --git a/config/locales/en.yml b/config/locales/en.yml index f17baa2601..46197090c0 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -911,6 +911,10 @@ en: variant_row: none_tax_category: None search_for_tax_categories: "Search for tax categories" + category_field_name: "Category" + tax_category_field_name: "Tax Category" + product_row: + producer_field_name: "Producer" product_import: title: Product Import file_not_found: File not found or could not be opened diff --git a/spec/system/admin/products_v3/products_spec.rb b/spec/system/admin/products_v3/products_spec.rb index aa9cee9512..a39c1ac753 100644 --- a/spec/system/admin/products_v3/products_spec.rb +++ b/spec/system/admin/products_v3/products_spec.rb @@ -14,6 +14,10 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl login_as user end + let(:producer_search_selector) { 'input[placeholder="Search for producers"]' } + let(:categories_search_selector) { 'input[placeholder="Search for categories"]' } + let(:tax_categories_search_selector) { 'input[placeholder="Search for tax categories"]' } + it "can see the new product page" do visit admin_products_url expect(page).to have_content "Bulk Edit Products" @@ -666,6 +670,113 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl end end + describe "Changing producers, category and tax category" do + let!(:variant_a1) { + product_a.variants.first.tap{ |v| + v.update! display_name: "Medium box", sku: "APL-01", price: 5.25, on_hand: 5, + on_demand: false + } + } + let!(:product_a) { + create(:simple_product, name: "Apples", sku: "APL-00", + variant_unit: "weight", variant_unit_scale: 1) # Grams + } + + context "when they are under 11" do + before do + create_list(:supplier_enterprise, 9) + create_list(:tax_category, 9) + create_list(:taxon, 2) + + visit admin_products_url + end + + it "should not display search input, change the producers, category and tax category" do + producer_to_select = random_producer(product_a) + category_to_select = random_category(variant_a1) + tax_category_to_select = random_tax_category + + within row_containing_name(product_a.name) do + validate_tomselect_without_search!( + page, "Producer", + producer_to_select, + producer_search_selector + ) + end + + within row_containing_name(variant_a1.display_name) do + validate_tomselect_without_search!( + page, "Category", + category_to_select, + categories_search_selector + ) + validate_tomselect_without_search!( + page, "Tax Category", + tax_category_to_select, + tax_categories_search_selector + ) + end + + click_button "Save changes" + + expect(page).to have_content "Changes saved" + product_a.reload + variant_a1.reload + + expect(product_a.supplier.name).to eq(producer_to_select) + expect(variant_a1.primary_taxon.name).to eq(category_to_select) + expect(variant_a1.tax_category.name).to eq(tax_category_to_select) + end + end + + context "when they are over 11" do + before do + create_list(:supplier_enterprise, 11) + create_list(:tax_category, 11) + create_list(:taxon, 11) + + visit admin_products_url + end + + it "should display search input, change the producer" do + producer_to_select = random_producer(product_a) + category_to_select = random_category(variant_a1) + tax_category_to_select = random_tax_category + + within row_containing_name(product_a.name) do + validate_tomselect_with_search!( + page, "Producer", + producer_to_select, + producer_search_selector + ) + end + + within row_containing_name(variant_a1.display_name) do + validate_tomselect_with_search!( + page, "Category", + category_to_select, + categories_search_selector + ) + validate_tomselect_with_search!( + page, "Tax Category", + tax_category_to_select, + tax_categories_search_selector + ) + end + + click_button "Save changes" + + expect(page).to have_content "Changes saved" + product_a.reload + variant_a1.reload + + expect(product_a.supplier.name).to eq(producer_to_select) + expect(variant_a1.primary_taxon.name).to eq(category_to_select) + expect(variant_a1.tax_category.name).to eq(tax_category_to_select) + end + end + end + describe "edit image" do shared_examples "updating image" do it "saves product image" do @@ -1032,4 +1143,41 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl def tax_category_column @tax_category_column ||= '[data-controller="variant"] > td:nth-child(10)' end + + def validate_tomselect_without_search!(page, field_name, value, search_selector) + tomselect_wrapper = page.find_field(field_name).sibling(".ts-wrapper") + tomselect_wrapper.find(".ts-control").click + + expect(page).not_to have_selector(search_selector) + + tomselect_wrapper.find(:css, '.ts-dropdown .ts-dropdown-content .option', + text: value).click + end + + def validate_tomselect_with_search!(page, field_name, value, search_selector) + tomselect_wrapper = page.find_field(field_name).sibling(".ts-wrapper") + tomselect_wrapper.find(".ts-control").click + + expect(page).to have_selector(search_selector) + + tomselect_wrapper.find(:css, '.ts-dropdown input.dropdown-input').send_keys(value) + tomselect_wrapper.find(:css, '.ts-dropdown .ts-dropdown-content .option', text: value).click + end + + def random_producer(product) + Enterprise.is_primary_producer + .where.not(id: product.supplier.id) + .pluck(:name).sample + end + + def random_category(variant) + Spree::Taxon + .where.not(id: variant.primary_taxon.id) + .pluck(:name).sample + end + + def random_tax_category + Spree::TaxCategory + .pluck(:name).sample + end end From f386202ec22c4e38bc33be00cd5f6c6c14dd57d2 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Sun, 28 Apr 2024 00:57:54 +0500 Subject: [PATCH 12/20] 11060: fix lint issues --- app/components/searchable_dropdown_component.rb | 2 +- app/reflexes/products_reflex.rb | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/components/searchable_dropdown_component.rb b/app/components/searchable_dropdown_component.rb index 98365c4c8b..03ad6ea313 100644 --- a/app/components/searchable_dropdown_component.rb +++ b/app/components/searchable_dropdown_component.rb @@ -38,6 +38,6 @@ class SearchableDropdownComponent < ViewComponent::Base end def remove_search_plugin? - @should_remove_search_plugin ||= options.count < MINIMUM_OPTIONS_FOR_SEARCH_FILED + @remove_search_plugin ||= options.count < MINIMUM_OPTIONS_FOR_SEARCH_FILED end end diff --git a/app/reflexes/products_reflex.rb b/app/reflexes/products_reflex.rb index a2800c83e4..74a0b49873 100644 --- a/app/reflexes/products_reflex.rb +++ b/app/reflexes/products_reflex.rb @@ -89,8 +89,8 @@ class ProductsReflex < ApplicationReflex html: render(partial: "admin/products_v3/content", locals: { products: @products, pagy: @pagy, search_term: @search_term, producer_options: producers, producer_id: @producer_id, - category_options: categories, tax_category_options:, category_id: @category_id, - flashes: flash }) + category_options: categories, tax_category_options:, + category_id: @category_id, flashes: flash }) ) cable_ready.replace_state( From 227b677e4d7c71ad39333cd289b1697841f62afc Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Sun, 28 Apr 2024 03:38:53 +0500 Subject: [PATCH 13/20] 11060: fix specs --- spec/system/admin/products_v3/products_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/system/admin/products_v3/products_spec.rb b/spec/system/admin/products_v3/products_spec.rb index a39c1ac753..f4d77fa45f 100644 --- a/spec/system/admin/products_v3/products_spec.rb +++ b/spec/system/admin/products_v3/products_spec.rb @@ -684,7 +684,7 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl context "when they are under 11" do before do - create_list(:supplier_enterprise, 9) + create_list(:supplier_enterprise, 9, users: [user]) create_list(:tax_category, 9) create_list(:taxon, 2) @@ -731,7 +731,7 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl context "when they are over 11" do before do - create_list(:supplier_enterprise, 11) + create_list(:supplier_enterprise, 11, users: [user]) create_list(:tax_category, 11) create_list(:taxon, 11) From 3d60d84fc7cd8619fec5dd1f91a1688593194776 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Sun, 28 Apr 2024 16:19:22 +0500 Subject: [PATCH 14/20] add wait for flaky specs --- spec/system/admin/products_v3/products_spec.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/system/admin/products_v3/products_spec.rb b/spec/system/admin/products_v3/products_spec.rb index f4d77fa45f..2f4dde4718 100644 --- a/spec/system/admin/products_v3/products_spec.rb +++ b/spec/system/admin/products_v3/products_spec.rb @@ -752,11 +752,13 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl end within row_containing_name(variant_a1.display_name) do + sleep(0.1) validate_tomselect_with_search!( page, "Category", category_to_select, categories_search_selector ) + sleep(0.1) validate_tomselect_with_search!( page, "Tax Category", tax_category_to_select, From 7e555b4fcb7ef0e0fa43f6985589fba09695f2f5 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Tue, 30 Apr 2024 13:18:58 +0500 Subject: [PATCH 15/20] Update app/views/admin/products_v3/_product_row.html.haml Co-authored-by: David Cook --- app/views/admin/products_v3/_product_row.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/admin/products_v3/_product_row.html.haml b/app/views/admin/products_v3/_product_row.html.haml index 3c12ac1b1b..f82ef26933 100644 --- a/app/views/admin/products_v3/_product_row.html.haml +++ b/app/views/admin/products_v3/_product_row.html.haml @@ -27,7 +27,7 @@ -# empty %td.align-right -# empty -%td.naked_inputs.align-left +%td.naked_inputs = render(SearchableDropdownComponent.new(form: f, name: :supplier_id, aria_label: t('.producer_field_name'), From c291ff88ffe1b2ad430e157d540c5b9d0c844784 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Tue, 30 Apr 2024 13:23:39 +0500 Subject: [PATCH 16/20] 11060: remove duplicated supplier_id --- app/services/permitted_attributes/product.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/app/services/permitted_attributes/product.rb b/app/services/permitted_attributes/product.rb index fdb82d6421..1adc8ff7d9 100644 --- a/app/services/permitted_attributes/product.rb +++ b/app/services/permitted_attributes/product.rb @@ -10,7 +10,6 @@ module PermittedAttributes :display_as, :sku, :group_buy, :group_buy_unit_size, :taxon_ids, :primary_taxon_id, :tax_category_id, :meta_keywords, :notes, :inherits_properties, - :supplier_id, { product_properties_attributes: [:id, :property_name, :value], variants_attributes: [PermittedAttributes::Variant.attributes], image_attributes: [:attachment] } From 269e69852c1c39c358e528e63da6020584605a2e Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Tue, 30 Apr 2024 13:24:21 +0500 Subject: [PATCH 17/20] 11060: add style rule for the small gap --- app/webpacker/css/admin/products_v3.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/webpacker/css/admin/products_v3.scss b/app/webpacker/css/admin/products_v3.scss index 115512ce36..a06019bebb 100644 --- a/app/webpacker/css/admin/products_v3.scss +++ b/app/webpacker/css/admin/products_v3.scss @@ -171,6 +171,11 @@ padding: 0; } + .fullwidth + .field { + // Assume wrap, so add small gap + margin-top: 3px; + } + .ts-control { z-index: 0; // Avoid hovering over thead } From f07900ca4a46e435d6706d171562355ab097c862 Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Tue, 30 Apr 2024 14:08:30 +0500 Subject: [PATCH 18/20] 11060: refactor specs to have better separation of concerns --- spec/support/request/web_helper.rb | 14 +++++++ .../system/admin/products_v3/products_spec.rb | 38 ++++++++----------- 2 files changed, 30 insertions(+), 22 deletions(-) diff --git a/spec/support/request/web_helper.rb b/spec/support/request/web_helper.rb index 42d7cb65b6..71799e4030 100644 --- a/spec/support/request/web_helper.rb +++ b/spec/support/request/web_helper.rb @@ -112,6 +112,20 @@ module WebHelper tomselect_wrapper.find(:css, '.ts-dropdown .ts-dropdown-content .option', text: value).click end + def open_tomselect_to_validate!(page, field_name) + tomselect_wrapper = page.find_field(field_name).sibling(".ts-wrapper") + tomselect_wrapper.find(".ts-control").click # open the dropdown + + raise 'Please pass the block for expectations' unless block_given? + + # execute block containing expectations + yield + + tomselect_wrapper.find( + '.ts-dropdown .ts-dropdown-content .option.active', + ).click # close the dropdown by selecting the already selected value + end + def request_monitor_finished(controller = nil) page.evaluate_script("#{angular_scope(controller)}.scope().RequestMonitor.loading == false") end diff --git a/spec/system/admin/products_v3/products_spec.rb b/spec/system/admin/products_v3/products_spec.rb index 2f4dde4718..0eff69cde8 100644 --- a/spec/system/admin/products_v3/products_spec.rb +++ b/spec/system/admin/products_v3/products_spec.rb @@ -699,22 +699,23 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl within row_containing_name(product_a.name) do validate_tomselect_without_search!( page, "Producer", - producer_to_select, producer_search_selector ) + tomselect_select(producer_to_select, from: "Producer") end within row_containing_name(variant_a1.display_name) do validate_tomselect_without_search!( page, "Category", - category_to_select, categories_search_selector ) + tomselect_select(category_to_select, from: "Category") + validate_tomselect_without_search!( page, "Tax Category", - tax_category_to_select, tax_categories_search_selector ) + tomselect_select(tax_category_to_select, from: "Tax Category") end click_button "Save changes" @@ -746,24 +747,25 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl within row_containing_name(product_a.name) do validate_tomselect_with_search!( page, "Producer", - producer_to_select, producer_search_selector ) + tomselect_search_and_select(producer_to_select, from: "Producer") end within row_containing_name(variant_a1.display_name) do sleep(0.1) validate_tomselect_with_search!( page, "Category", - category_to_select, categories_search_selector ) + tomselect_search_and_select(category_to_select, from: "Category") + sleep(0.1) validate_tomselect_with_search!( page, "Tax Category", - tax_category_to_select, tax_categories_search_selector ) + tomselect_search_and_select(tax_category_to_select, from: "Tax Category") end click_button "Save changes" @@ -1146,24 +1148,16 @@ describe 'As an enterprise user, I can manage my products', feature: :admin_styl @tax_category_column ||= '[data-controller="variant"] > td:nth-child(10)' end - def validate_tomselect_without_search!(page, field_name, value, search_selector) - tomselect_wrapper = page.find_field(field_name).sibling(".ts-wrapper") - tomselect_wrapper.find(".ts-control").click - - expect(page).not_to have_selector(search_selector) - - tomselect_wrapper.find(:css, '.ts-dropdown .ts-dropdown-content .option', - text: value).click + def validate_tomselect_without_search!(page, field_name, search_selector) + open_tomselect_to_validate!(page, field_name) do + expect(page).not_to have_selector(search_selector) + end end - def validate_tomselect_with_search!(page, field_name, value, search_selector) - tomselect_wrapper = page.find_field(field_name).sibling(".ts-wrapper") - tomselect_wrapper.find(".ts-control").click - - expect(page).to have_selector(search_selector) - - tomselect_wrapper.find(:css, '.ts-dropdown input.dropdown-input').send_keys(value) - tomselect_wrapper.find(:css, '.ts-dropdown .ts-dropdown-content .option', text: value).click + def validate_tomselect_with_search!(page, field_name, search_selector) + open_tomselect_to_validate!(page, field_name) do + expect(page).to have_selector(search_selector) + end end def random_producer(product) From b1f20ffc14b8d676d719a5458d8ea316b426dd5a Mon Sep 17 00:00:00 2001 From: Ahmed Ejaz Date: Tue, 30 Apr 2024 14:40:59 +0500 Subject: [PATCH 19/20] 11060: create tomselect helper module --- spec/support/request/tomselect_helper.rb | 43 ++++++++++++++++++++++++ spec/support/request/web_helper.rb | 42 ++--------------------- 2 files changed, 45 insertions(+), 40 deletions(-) create mode 100644 spec/support/request/tomselect_helper.rb diff --git a/spec/support/request/tomselect_helper.rb b/spec/support/request/tomselect_helper.rb new file mode 100644 index 0000000000..7cce8cbe9e --- /dev/null +++ b/spec/support/request/tomselect_helper.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +module TomselectHelper + def tomselect_open(field_name) + page.find("##{field_name}-ts-control").click + end + + def tomselect_multiselect(value, options) + tomselect_wrapper = page.find_field(options[:from]).sibling(".ts-wrapper") + tomselect_wrapper.find(".ts-control").click + tomselect_wrapper.find(:css, '.ts-dropdown.multi .ts-dropdown-content .option', + text: value).click + end + + def tomselect_search_and_select(value, options) + tomselect_wrapper = page.find_field(options[:from]).sibling(".ts-wrapper") + tomselect_wrapper.find(".ts-control").click + # Use send_keys as setting the value directly doesn't trigger the search + tomselect_wrapper.find(:css, '.ts-dropdown input.dropdown-input').send_keys(value) + tomselect_wrapper.find(:css, '.ts-dropdown .ts-dropdown-content .option', text: value).click + end + + def tomselect_select(value, options) + tomselect_wrapper = page.find_field(options[:from]).sibling(".ts-wrapper") + tomselect_wrapper.find(".ts-control").click + + tomselect_wrapper.find(:css, '.ts-dropdown .ts-dropdown-content .option', text: value).click + end + + def open_tomselect_to_validate!(page, field_name) + tomselect_wrapper = page.find_field(field_name).sibling(".ts-wrapper") + tomselect_wrapper.find(".ts-control").click # open the dropdown + + raise 'Please pass the block for expectations' unless block_given? + + # execute block containing expectations + yield + + tomselect_wrapper.find( + '.ts-dropdown .ts-dropdown-content .option.active', + ).click # close the dropdown by selecting the already selected value + end +end diff --git a/spec/support/request/web_helper.rb b/spec/support/request/web_helper.rb index 71799e4030..a5c4924a83 100644 --- a/spec/support/request/web_helper.rb +++ b/spec/support/request/web_helper.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module WebHelper + include TomselectHelper + def have_input(name, opts = {}) selector = "[name='#{name}']" selector += "[placeholder='#{opts[:placeholder]}']" if opts.key? :placeholder @@ -86,46 +88,6 @@ module WebHelper find(:css, ".select2-result-label", text: options[:select_text] || value).click end - def tomselect_open(field_name) - page.find("##{field_name}-ts-control").click - end - - def tomselect_multiselect(value, options) - tomselect_wrapper = page.find_field(options[:from]).sibling(".ts-wrapper") - tomselect_wrapper.find(".ts-control").click - tomselect_wrapper.find(:css, '.ts-dropdown.multi .ts-dropdown-content .option', - text: value).click - end - - def tomselect_search_and_select(value, options) - tomselect_wrapper = page.find_field(options[:from]).sibling(".ts-wrapper") - tomselect_wrapper.find(".ts-control").click - # Use send_keys as setting the value directly doesn't trigger the search - tomselect_wrapper.find(:css, '.ts-dropdown input.dropdown-input').send_keys(value) - tomselect_wrapper.find(:css, '.ts-dropdown .ts-dropdown-content .option', text: value).click - end - - def tomselect_select(value, options) - tomselect_wrapper = page.find_field(options[:from]).sibling(".ts-wrapper") - tomselect_wrapper.find(".ts-control").click - - tomselect_wrapper.find(:css, '.ts-dropdown .ts-dropdown-content .option', text: value).click - end - - def open_tomselect_to_validate!(page, field_name) - tomselect_wrapper = page.find_field(field_name).sibling(".ts-wrapper") - tomselect_wrapper.find(".ts-control").click # open the dropdown - - raise 'Please pass the block for expectations' unless block_given? - - # execute block containing expectations - yield - - tomselect_wrapper.find( - '.ts-dropdown .ts-dropdown-content .option.active', - ).click # close the dropdown by selecting the already selected value - end - def request_monitor_finished(controller = nil) page.evaluate_script("#{angular_scope(controller)}.scope().RequestMonitor.loading == false") end From 7f40fd7adb358f948f087a7f504f2c6ce7590355 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 1 May 2024 09:36:57 +1000 Subject: [PATCH 20/20] Fix typo --- app/components/searchable_dropdown_component.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/components/searchable_dropdown_component.rb b/app/components/searchable_dropdown_component.rb index 03ad6ea313..9a53155085 100644 --- a/app/components/searchable_dropdown_component.rb +++ b/app/components/searchable_dropdown_component.rb @@ -2,7 +2,7 @@ class SearchableDropdownComponent < ViewComponent::Base REMOVED_SEARCH_PLUGIN = { 'tom-select-options-value': '{ "plugins": [] }' }.freeze - MINIMUM_OPTIONS_FOR_SEARCH_FILED = 11 # at least 11 options are required for the search field + MINIMUM_OPTIONS_FOR_SEARCH_FIELD = 11 # at least 11 options are required for the search field def initialize( form:, @@ -38,6 +38,6 @@ class SearchableDropdownComponent < ViewComponent::Base end def remove_search_plugin? - @remove_search_plugin ||= options.count < MINIMUM_OPTIONS_FOR_SEARCH_FILED + @remove_search_plugin ||= options.count < MINIMUM_OPTIONS_FOR_SEARCH_FIELD end end