Merge pull request #12546 from dacook/buu/change-columns-11055

[BUU] Change product columns to be shown
This commit is contained in:
David Cook
2024-06-19 09:25:47 +10:00
committed by GitHub
22 changed files with 347 additions and 162 deletions

View File

@@ -31,7 +31,7 @@ angular.module("admin.indexUtils").factory 'Columns', ($rootScope, $http, $injec
savePreferences: (action_name) =>
$http
method: "PUT"
url: "/admin/column_preferences/bulk_update"
url: "/admin/column_preferences/bulk_update.json"
data:
action_name: action_name
column_preferences: (preference for column_name, preference of @columns)

View File

@@ -5,8 +5,9 @@
%div.menu{ 'ng-show' => "expanded" }
.menu_items
.menu_item{ "ng-repeat": "column in columns", "ng-click": "toggle(column);" }
%input.redesigned-input{ type: "checkbox", "ng-checked": "column.visible" }
{{ column.name }}
%input{ type: "checkbox", "ng-checked": "column.visible" }
%span
{{ column.name }}
%hr
%div.menu_item.text-center
%input.fullwidth.orange{ type: "button", "ng-value": "saved() ? 'Saved': 'Saving'", "ng-show": "saved() || saving", "ng-disabled": "saved()" }

View File

@@ -9,5 +9,5 @@
%div.menu_items
- @options.each do |option|
%label.menu_item{ "data-multiple-checked-select-target": "option", "data-value": option[1], "data-label": option[0] }
%input.redesigned-input{ type: "checkbox", checked: @selected.include?(option[1]), name: "#{@name}[]", value: option[1] }
= option[0]
%input{ type: "checkbox", checked: @selected.include?(option[1]), name: "#{@name}[]", value: option[1] }
%span= option[0]

View File

@@ -4,17 +4,25 @@ module Admin
class ColumnPreferencesController < Admin::ResourceController
before_action :load_collection, only: [:bulk_update]
respond_to :json
def bulk_update
@cp_set.collection.each { |cp| authorize! :bulk_update, cp }
if @cp_set.save
render json: @cp_set.collection, each_serializer: Api::Admin::ColumnPreferenceSerializer
elsif @cp_set.errors.present?
render json: { errors: @cp_set.errors }, status: :bad_request
else
render body: nil, status: :internal_server_error
respond_to do |format|
if @cp_set.save
format.json {
render json: @cp_set.collection, each_serializer: Api::Admin::ColumnPreferenceSerializer
}
format.turbo_stream {
flash.now[:success] = t('.success')
render :bulk_update, locals: { action: permitted_params[:action_name] }
}
else
format.json { render json: { errors: @cp_set.errors }, status: :bad_request }
format.turbo_stream {
flash.now[:error] = @cp_set.errors.full_messages.to_sentence
render :bulk_update, locals: { action: permitted_params[:action_name] }
}
end
end
end
@@ -28,11 +36,26 @@ module Admin
end
def load_collection
collection_hash = Hash[permitted_params[:column_preferences].
each_with_index.map { |cp, i| [i, cp] }]
collection_hash.select!{ |_i, cp| cp[:action_name] == permitted_params[:action_name] }
@cp_set = Sets::ColumnPreferenceSet.new(@column_preferences,
collection_attributes: collection_hash)
collection_attributes = nil
respond_to do |format|
format.json do
collection_attributes = Hash[permitted_params[:column_preferences].
each_with_index.map { |cp, i| [i, cp] }]
collection_attributes.select!{ |_i, cp|
cp[:action_name] == permitted_params[:action_name]
}
end
format.all do
# Inject action name and user ID for each column_preference
collection_attributes = permitted_params[:column_preferences].to_h.each_value { |cp|
cp[:action_name] = permitted_params[:action_name]
cp[:user_id] = spree_current_user.id
}
end
end
@cp_set = Sets::ColumnPreferenceSet.new(@column_preferences, collection_attributes:)
end
def collection

View File

@@ -0,0 +1,23 @@
= form_with url: bulk_update_admin_column_preferences_path, method: :put,
id: :bulk_admin_column_preferences_form, class: "column-preferences",
html: { 'data-controller': "column-preferences" } do |f|
= hidden_field_tag :action_name, action
/ DC: this makes my Chrome DevTools crash when inspecting the <details> element. If problem continues, we need to use a different method.
%details.ofn-drop-down.ofn-drop-down-v2.right{ 'data-controller': "dropdown" }
%summary.ofn-drop-down-label
= t('admin.columns')
%span.icon-caret
.menu
.menu_items
- ColumnPreference.for(spree_current_user, action).each_with_index do |column_preference, index|
= f.fields_for("column_preferences", column_preference, index:) do |cp_form|
= cp_form.hidden_field :id
= cp_form.hidden_field :column_name
%label.menu_item
= cp_form.check_box :visible, 'data-column-name': column_preference.column_name
%span= t("admin.products_page.columns." + column_preference.column_name)
.actions
= f.submit t('admin.column_save_as_default'), class: "secondary fullwidth"

View File

@@ -0,0 +1,3 @@
= turbo_stream.replace "bulk_admin_column_preferences_form" do
= render partial: "admin/shared/flashes", locals: { flashes: flash } if defined? flash
= render partial: 'form', locals: { action: }

View File

@@ -1,13 +1,13 @@
%td.with-image{ id: "image-#{product.id}" }
%td.col-image.with-image{ id: "image-#{product.id}" }
= render partial: "product_image", locals: { product: }
%td.field.align-left.header.naked_inputs
%td.col-name.field.align-left.header.naked_inputs
= f.hidden_field :id
= f.text_field :name, 'aria-label': t('admin.products_page.columns.name')
= error_message_on product, :name
%td.field.naked_inputs
%td.col-sku.field.naked_inputs
= f.text_field :sku, 'aria-label': t('admin.products_page.columns.sku')
= error_message_on product, :sku
%td.field.naked_inputs{ 'data-controller': 'toggle-control', 'data-toggle-control-match-value': 'items' }
%td.col-unit_scale.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,
@@ -19,23 +19,23 @@
.field
= f.text_field :variant_unit_name, 'aria-label': t('items'), 'data-toggle-control-target': 'control', style: (product.variant_unit == "items" ? "" : "display: none")
= error_message_on product, :variant_unit_name, 'data-toggle-control-target': 'control'
%td.align-right
%td.col-unit.align-right
-# empty
%td.align-right
%td.col-price.align-right
-# empty
%td.align-right
%td.col-on_hand.align-right
-# empty
%td.naked_inputs
%td.col-producer.naked_inputs
= 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')))
%td.align-left
%td.col-category.align-left
-# empty
%td.align-left
%td.align-left
%td.col-tax_category.align-left
%td.col-inherits_properties.align-left
.content= product.inherits_properties ? 'YES' : 'NO' #TODO: consider using https://github.com/RST-J/human_attribute_values, else use I18n.t (also below)
%td.align-right
= render(VerticalEllipsisMenu::Component.new) do

View File

@@ -1,5 +1,5 @@
#sort
%div
%div.pagination-description
- if pagy.present?
= t(".pagination.total_html", total: pagy.count, from: pagy.from, to: pagy.to)
@@ -13,3 +13,6 @@
options_for_select([15, 25, 50, 100].collect{|i| [t('.pagination.per_page.per_page', num: i), i]}, pagy&.items),
class: "no-input per-page",
data: { controller: "tom-select search", action: "change->search#changePerPage", "tom-select-options-value": '{ "plugins": [] }'}
/ Columns dropdown
= render partial: "admin/column_preferences/form", locals: { action: "products_v3_index" }

View File

@@ -13,20 +13,21 @@
= hidden_field_tag :producer_id, @producer_id
= hidden_field_tag :category_id, @category_id
%table.products
%table.products{ 'data-column-preferences-target': "table" }
%colgroup
%col{ width:"56" }= # Img (size + padding)
%col= # (grow to fill) Name
%col{ width:"5%"}
%col{ width:"8%"}
%col{ width:"8%"}
%col{ width:"5%"}
%col{ width:"10%"}
%col{ width:"15%"}= # Producer
%col{ width:"8%"}
%col{ width:"8%"}
%col{ width:"8%"}
%col{ width:"8%"}= # Actions
-# The `min-width` property works in Chrome but not Firefox so is considered progressive enhancement.
%col.col-image{ width:"56px" }= # (image size + padding)
%col.col-name{ style:"min-width: 6em" }= # (grow to fill)
%col.col-sku{ width:"8%", style:"min-width: 6em" }
%col.col-unit_scale{ width:"8%" }
%col.col-unit{ width:"8%" }
%col.col-price{ width:"5%", style:"min-width: 5em" }
%col.col-on_hand{ width:"10%"}
%col.col-producer{ style:"min-width: 6em" }= # (grow to fill)
%col.col-category{ width:"8%" }
%col.col-tax_category{ width:"8%" }
%col.col-inherits_properties{ width:"5%" }
%col{ width:"5%", style:"min-width: 3em"}= # Actions
%thead
%tr
%td.form-actions-wrapper{ colspan: 12 }
@@ -48,18 +49,18 @@
= t('.reset')
= form.submit t('.save'), class: "medium"
%tr
%th.align-left= # image
%th.col-image.align-left= # image
= render partial: 'spree/admin/shared/stimulus_sortable_header',
locals: { column: :name, sorted: params.dig(:q, :s), default: 'name asc' }
%th.align-left.with-input= t('admin.products_page.columns.sku')
%th.align-left.with-input= t('admin.products_page.columns.unit_scale')
%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')
%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')
%th.align-left.col-sku.with-input= t('admin.products_page.columns.sku')
%th.align-left.col-unit_scale.with-input= t('admin.products_page.columns.unit_scale')
%th.align-left.col-unit.with-input= t('admin.products_page.columns.unit')
%th.align-left.col-price.with-input= t('admin.products_page.columns.price')
%th.align-left.col-on_hand.with-input= t('admin.products_page.columns.on_hand')
%th.align-left.col-producer= t('admin.products_page.columns.producer')
%th.align-left.col-category= t('admin.products_page.columns.category')
%th.align-left.col-tax_category= t('admin.products_page.columns.tax_category')
%th.align-left.col-inherits_properties= t('admin.products_page.columns.inherits_properties')
%th.align-right= t('admin.products_page.columns.actions')
- products.each_with_index do |product, product_index|
= form.fields_for("products", product, index: product_index) do |product_form|

View File

@@ -1,15 +1,15 @@
%td
%td.col-image
-# empty
%td.field.naked_inputs
%td.col-name.field.naked_inputs
= f.hidden_field :id
= f.text_field :display_name, 'aria-label': t('admin.products_page.columns.name'), placeholder: variant.product.name
= error_message_on variant, :display_name
%td.field.naked_inputs
%td.col-sku.field.naked_inputs
= f.text_field :sku, 'aria-label': t('admin.products_page.columns.sku')
= error_message_on variant, :sku
%td
%td.col-unit_scale
-# empty
%td.field.popout{'data-controller': "popout", 'data-popout-update-display-value': "false"}
%td.col-unit.field.popout{'data-controller': "popout", 'data-popout-update-display-value': "false"}
= f.button :unit_to_display, class: "popout__button", 'aria-label': t('admin.products_page.columns.unit'), 'data-popout-target': "button" do
= variant.unit_to_display # Show the generated summary of unit values
%div.popout__container{ style: 'display: none;', 'data-controller': 'toggle-control', 'data-popout-target': "dialog" }
@@ -25,10 +25,10 @@
= f.label :display_as, t('admin.products_page.columns.display_as')
= f.text_field :display_as, placeholder: VariantUnits::OptionValueNamer.new(variant).name
= error_message_on variant, :unit_value
%td.field.naked_inputs
%td.col-price.field.naked_inputs
= f.text_field :price, 'aria-label': t('admin.products_page.columns.price'), value: number_to_currency(variant.price, unit: '')&.strip # TODO: add a spec to prove that this formatting is necessary. If so, it should be in a shared form helper for currency inputs
= error_message_on variant, :price
%td.field.popout{'data-controller': "popout"}
%td.col-on_hand.field.popout{'data-controller': "popout"}
%button.popout__button{'data-popout-target': "button", 'aria-label': t('admin.products_page.columns.on_hand')}
= variant.on_demand ? t(:on_demand) : variant.on_hand
%div.popout__container{ style: 'display: none;', 'data-controller': 'toggle-control', 'data-popout-target': "dialog" }
@@ -39,16 +39,16 @@
= 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
%td.col-producer.align-left
-# empty producer name
%td.field.naked_inputs
%td.col-category.field.naked_inputs
= render(SearchableDropdownComponent.new(form: f,
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
%td.col-tax_category.field.naked_inputs
= render(SearchableDropdownComponent.new(form: f,
name: :tax_category_id,
options: tax_category_options,
@@ -57,7 +57,7 @@
aria_label: t('.tax_category_field_name'),
placeholder_value: t('.search_for_tax_categories')))
= error_message_on variant, :tax_category
%td.align-left
%td.col-inherits_properties.align-left
-# empty
%td.align-right
= render(VerticalEllipsisMenu::Component.new) do

View File

@@ -1,4 +1,4 @@
%th
%th{ class: "col-#{column}" }
%a{ "data-controller": "search", "data-action": "click->search#changeSorting", "data-column": "#{column}", "data-current": (sorted || default).to_s }
= t("spree.admin.shared.sortable_header.#{column.to_s}")

View File

@@ -0,0 +1,43 @@
import { Controller } from "stimulus";
// Manage column visibility according to checkbox selection
//
export default class ColumnPreferencesController extends Controller {
connect() {
this.table = document.querySelector('table[data-column-preferences-target="table"]');
this.cols = Array.from(this.table.querySelectorAll('col'));
this.colSpanCells = this.table.querySelectorAll('th[colspan],td[colspan]');
// Initialise data-default-col-span
this.colSpanCells.forEach((cell)=> {
cell.dataset.defaultColSpan ||= cell.colSpan;
});
this.checkboxes = Array.from(this.element.querySelectorAll("input[type=checkbox]"));
for (const element of this.checkboxes) {
// On initial load
this.#showHideColumn(element);
// On checkbox changed
element.addEventListener("change", this.#showHideColumn.bind(this));
}
}
// private
#showHideColumn(e) {
const element = e.target || e;
const name = element.dataset.columnName;
this.table.classList.toggle(`hide-${name}`, !element.checked);
// Reset cell colspans
const hiddenColCount = this.checkboxes.filter((checkbox)=> !checkbox.checked).length;
for(const cell of this.colSpanCells) {
const span = parseInt(cell.dataset.defaultColSpan, 10) - hiddenColCount;
cell.colSpan = span;
};
}
#showHideElement(element, show) {
element.style.display = show ? "" : "none";
}
}

View File

@@ -1,5 +1,6 @@
import { Controller } from "stimulus";
// Close a <details> element when click outside
export default class extends Controller {
connect() {

View File

@@ -6,32 +6,3 @@
}
}
}
input[type="checkbox"].redesigned-input {
position: relative;
top: 1px;
-moz-appearance: none;
-webkit-appearance: none;
-o-appearance: none;
appearance: none;
outline: none;
content: none;
cursor: pointer;
&:before {
font-family: "FontAwesome";
content: "\f00c";
font-size: 15px;
color: transparent !important;
background: transparent !important;
display: block;
width: 15px;
height: 15px;
border: 1px solid #809cb1;
margin-right: 7px;
}
&:checked:before {
color: $color-txt-text !important;
}
}

View File

@@ -96,7 +96,8 @@
// "Naked" inputs. Row hover helps reveal them.
.naked_inputs {
input:not([type="checkbox"]), .ts-control {
input:not([type="checkbox"]),
.ts-control {
background-color: $color-tbl-cell-bg;
}
}
@@ -179,6 +180,18 @@
.ts-control {
z-index: 0; // Avoid hovering over thead
}
// Hide columns
$columns:
"image", "name", "sku", "unit_scale", "unit", "price", "on_hand", "producer", "category",
"tax_category", "inherits_properties";
@each $col in $columns {
&.hide-#{$col} {
.col-#{$col} {
display: none;
}
}
}
}
#no-products {
@@ -214,6 +227,10 @@
display: none;
}
.pagination-description {
flex-grow: 1; // Grow to fill space
}
.with-dropdown {
display: flex;
justify-content: space-between;
@@ -221,7 +238,11 @@
gap: 10px;
}
.per-page {
width: 10em;
width: 9em;
}
.column-preferences .ofn-drop-down-label {
width: 13em;
}
}
@@ -370,7 +391,7 @@
border-radius: $border-radius;
box-shadow: 0px 0px 8px 0px rgba($near-black, 0.25);
.field{
.field {
margin-bottom: 0.75em;
&:last-child {
@@ -424,7 +445,7 @@
opacity: 0;
}
}
.slide-out {
animation: slideOutLeft 0.5s forwards;
}

View File

@@ -101,8 +101,6 @@
> span {
width: auto;
text-transform: uppercase;
font-size: 85%;
font-weight: 600;
}
@@ -113,7 +111,7 @@
top: 100%;
left: 0px;
padding: 5px 0px;
border: 1px solid #adadad;
border-radius: $border-radius;
background-color: #ffffff;
box-shadow: 1px 3px 10px #888888;
z-index: 100;
@@ -181,6 +179,25 @@
}
}
summary:after {
content: "\f078";
font-family: FontAwesome;
position: relative;
top: 3px;
font-size: 13px;
}
&[open] >,
details[open] > {
summary:after {
content: "\f077";
font-family: FontAwesome;
}
}
}
.ofn-drop-down:not(.ofn-dropdown-v2) {
> details {
margin: -7px -15px;
padding: 7px 15px;
@@ -190,21 +207,14 @@
display: inline-block;
list-style: none;
width: auto;
text-transform: uppercase;
font-size: 85%;
font-weight: 600;
margin: -8px -15px;
padding: 8px 15px;
}
> details > summary:after {
content: "\f0d7";
font-family: FontAwesome;
}
> details[open] > summary:after {
content: "\f0d8";
font-family: FontAwesome;
&:after {
position: relative;
top: -1px;
font-size: 12px;
}
}
}
@@ -212,8 +222,11 @@
border: 1px solid $lighter-grey;
background-color: $lighter-grey;
padding: 0px;
line-height: normal;
@include border-radius($border-radius);
&:hover {
&:hover,
&.expanded {
border-color: $lighter-grey;
}
@@ -263,17 +276,22 @@
cursor: pointer;
padding-top: 4px;
padding-bottom: 5px;
text-transform: uppercase;
font-size: 85%;
font-size: inherit;
// Align checkbox and text
& > * {
vertical-align: middle;
}
}
}
.actions {
margin-top: 5px;
margin-right: 15px; // Compensate for scrollbar on menu_items
padding: 2px 10px;
&:hover {
background-color: inherit;
}
}
}
.ofn-drop-down.ofn-drop-down-v2 {
// Add very specific styling here for components that are in transition:
// ie. the ones using the two classes above
.ofn-drop-down-label {
padding-top: 7px;
padding-bottom: 7px;
}
}

View File

@@ -571,6 +571,7 @@ en:
per_page: "%{count} items per page"
colums: Columns
columns:
image: Image
name: Name
unit_scale: Unit scale
unit: Unit
@@ -661,7 +662,7 @@ en:
choose: "Choose..."
please_select: Please select...
column_save_as_default: Save As Default
column_save_as_default: Save as default
columns: Columns
actions: Actions
viewing: "Viewing: %{current_view_name}"
@@ -760,6 +761,9 @@ en:
balance_due: "Balance Due"
destroy:
has_associated_subscriptions: "Delete failed: This customer has active subscriptions. Cancel them first."
column_preferences:
bulk_update:
success: "Column preferences saved"
contents:
edit:
title: Content

View File

@@ -95,7 +95,7 @@ Openfoodnetwork::Application.routes.draw do
resource :contents
resources :column_preferences, only: [], format: :json do
resources :column_preferences, only: [] do
put :bulk_update, on: :collection
end

View File

@@ -77,6 +77,24 @@ module OpenFoodNetwork
}
end
def products_v3_index_columns
I18n.with_options scope: 'admin.products_page.columns' do
{
image: { name: t(:image), visible: true },
name: { name: t(:name), visible: true },
sku: { name: t(:sku), visible: true },
unit: { name: t(:unit), visible: true },
unit_scale: { name: t(:unit_scale), visible: true },
price: { name: t(:price), visible: true },
on_hand: { name: t(:on_hand), visible: true },
producer: { name: t(:producer), visible: true },
category: { name: t(:category), visible: true },
tax_category: { name: t(:tax_category), visible: true },
inherits_properties: { name: t(:inherits_properties), visible: true },
}
end
end
def enterprises_index_columns
node = "admin.enterprises.index"
{

View File

@@ -9,13 +9,26 @@ RSpec.describe Admin::ColumnPreferencesController, type: :controller do
let!(:user1) { create(:user) }
let!(:user2) { create(:user) }
let!(:enterprise) { create(:enterprise, owner: user1, users: [user1, user2]) }
let!(:column_preference) {
ColumnPreference.create(user_id: user1.id, action_name: 'enterprises_index',
column_name: "name", visible: true)
}
shared_examples "where I own the preferences submitted" do
before do
allow(controller).to receive(:spree_current_user) { user1 }
end
it "allows me to update the column preferences" do
spree_put :bulk_update, format: request_format, action_name: "enterprises_index",
column_preferences: column_preference_params
expect(ColumnPreference.where(user_id: user1.id,
action_name: 'enterprises_index').count).to be 3
end
end
context "json" do
let!(:column_preference) {
ColumnPreference.create(user_id: user1.id, action_name: 'enterprises_index',
column_name: "name", visible: true)
}
let(:request_format) { :json }
let(:column_preference_params) {
[
{ id: column_preference.id, user_id: user1.id, action_name: "enterprises_index",
@@ -27,28 +40,47 @@ RSpec.describe Admin::ColumnPreferencesController, type: :controller do
]
}
it_behaves_like "where I own the preferences submitted"
context "where I don't own the preferences submitted" do
before do
allow(controller).to receive(:spree_current_user) { user2 }
end
it "prevents me from updating the column preferences" do
spree_put :bulk_update, format: :json, action_name: "enterprises_index",
spree_put :bulk_update, format: request_format, action_name: "enterprises_index",
column_preferences: column_preference_params
expect(ColumnPreference.count).to be 1
end
end
end
context "where I own the preferences submitted" do
context "turbo_stream" do
let(:request_format) { :turbo_stream }
let(:column_preference_params) {
{
'0': { id: column_preference.id, column_name: "name", visible: "0" },
'1': { id: nil, column_name: "producer", visible: "1" },
'2': { id: nil, column_name: "status", visible: "1" },
}
}
it_behaves_like "where I own the preferences submitted"
context "where I don't own the preferences submitted" do
before do
allow(controller).to receive(:spree_current_user) { user1 }
allow(controller).to receive(:spree_current_user) { user2 }
end
it "allows me to update the column preferences" do
spree_put :bulk_update, format: :json, action_name: "enterprises_index",
column_preferences: column_preference_params
expect(ColumnPreference.where(user_id: user1.id,
action_name: 'enterprises_index').count).to be 3
# This has the same effect as the JSON action, but due to differing implementation,
# it has different expections.
it "prevents me from updating the column preferences" do
expect {
spree_put :bulk_update, format: request_format, action_name: "enterprises_index",
column_preferences: column_preference_params
}.to raise_error(ActiveRecord::RecordNotUnique)
expect(column_preference.reload.visible).to eq true
end
end
end

View File

@@ -3,10 +3,10 @@
module AdminHelper
def toggle_columns(*labels)
# open dropdown
# case insensitive search for "Columns" text
find("div#columns-dropdown", text: /columns/i).click
columns_dropdown = ofn_drop_down("Columns")
columns_dropdown.click
within "div#columns-dropdown" do
within columns_dropdown do
labels.each do |label|
# Convert label to case-insensitive regexp if not one already
label = /#{label}/i unless label.is_a?(Regexp)
@@ -16,6 +16,10 @@ module AdminHelper
end
# close dropdown
find("div#columns-dropdown", text: /columns/i).click
columns_dropdown.click
end
def ofn_drop_down(label)
find(".ofn-drop-down", text: /#{label}/i)
end
end

View File

@@ -3,6 +3,7 @@
require "system_helper"
RSpec.describe 'As an enterprise user, I can manage my products', feature: :admin_style_v3 do
include AdminHelper
include WebHelper
include AuthenticationHelper
include FileHelper
@@ -30,29 +31,45 @@ RSpec.describe 'As an enterprise user, I can manage my products', feature: :admi
end
end
describe "using the page" do
describe "using column display dropdown" do
let(:product) { create(:simple_product) }
describe "column selector" do
let!(:product) { create(:simple_product) }
before do
pending "Pending implementation, issue #11055"
login_as_admin
visit spree.admin_products_path
before do
visit admin_products_url
end
it "hides column and remembers saved preference" do
# Name shows by default
expect(page).to have_checked_field "Name"
expect(page).to have_selector "th", text: "Name"
expect_other_columns_visible
# Name is hidden
ofn_drop_down("Columns").click
within ofn_drop_down("Columns") do
uncheck "Name"
end
expect(page).not_to have_selector "th", text: "Name"
expect_other_columns_visible
it "shows a column display dropdown, which shows a list of columns when clicked" do
expect(page).to have_selector "th", text: "NAME"
expect(page).to have_selector "th", text: "PRODUCER"
expect(page).to have_selector "th", text: "PRICE"
expect(page).to have_selector "th", text: "ON HAND"
# Preference saved
click_on "Save as default"
expect(page).to have_content "Column preferences saved"
refresh
toggle_columns /^.{0,1}Producer$/i
expect(page).not_to have_selector "th", text: "PRODUCER"
expect(page).to have_selector "th", text: "NAME"
expect(page).to have_selector "th", text: "PRICE"
expect(page).to have_selector "th", text: "ON HAND"
# Preference remembered
ofn_drop_down("Columns").click
within ofn_drop_down("Columns") do
expect(page).to have_unchecked_field "Name"
end
expect(page).not_to have_selector "th", text: "Name"
expect_other_columns_visible
end
def expect_other_columns_visible
expect(page).to have_selector "th", text: "Producer"
expect(page).to have_selector "th", text: "Price"
expect(page).to have_selector "th", text: "On Hand"
end
end
@@ -321,6 +338,8 @@ RSpec.describe 'As an enterprise user, I can manage my products', feature: :admi
end
end
describe "columns"
describe "updating" do
let!(:variant_a1) {
product_a.variants.first.tap{ |v|