From c781113a6511351cd24a7c4cc125ddcb87a2380c Mon Sep 17 00:00:00 2001 From: Rob Harrington Date: Thu, 26 Nov 2015 12:51:29 +1100 Subject: [PATCH] Adding filters to variant overrides interface --- .../directives/ofn-select2.js.coffee | 28 ++++++++++++++++ .../index_utils/filters/attr_filter.js.coffee | 12 +++++++ .../variant_overrides_controller.js.coffee | 15 ++++++--- .../services/variant_overrides.js.coffee | 2 +- .../variant_overrides.js.coffee | 2 +- .../stylesheets/admin/disabled.css.scss | 13 ++++++++ .../variant_overrides/_filters.html.haml | 26 +++++++++++++++ .../variant_overrides/_hub_choice.html.haml | 7 ---- .../variant_overrides/_products.html.haml | 4 +-- .../_products_product.html.haml | 4 +-- .../_products_variants.html.haml | 6 ++-- .../admin/variant_overrides/index.html.haml | 2 +- spec/features/admin/variant_overrides_spec.rb | 33 ++++++++++++++++--- ...ariant_overrides_controller_spec.js.coffee | 10 ++++-- 14 files changed, 134 insertions(+), 30 deletions(-) create mode 100644 app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee create mode 100644 app/assets/javascripts/admin/index_utils/filters/attr_filter.js.coffee create mode 100644 app/assets/stylesheets/admin/disabled.css.scss create mode 100644 app/views/admin/variant_overrides/_filters.html.haml delete mode 100644 app/views/admin/variant_overrides/_hub_choice.html.haml diff --git a/app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee b/app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee new file mode 100644 index 0000000000..ba7a4b54df --- /dev/null +++ b/app/assets/javascripts/admin/index_utils/directives/ofn-select2.js.coffee @@ -0,0 +1,28 @@ +angular.module("admin.indexUtils").directive "ofnSelect2", ($timeout, blankOption) -> + require: 'ngModel' + restrict: 'C' + scope: + data: "=" + minSearch: "@?" + text: "@?" + blank: "=?" + link: (scope, element, attrs, ngModel) -> + $timeout -> + scope.text ||= 'name' + scope.data.unshift(scope.blank) if scope.blank? && typeof scope.blank is "object" + element.select2 + minimumResultsForSearch: scope.minSearch || 0 + data: { results: scope.data, text: scope.text } + initSelection: (element, callback) -> + callback scope.data[0] + formatSelection: (item) -> + item[scope.text] + formatResult: (item) -> + item[scope.text] + + attrs.$observe 'disabled', (value) -> + element.select2('enable', !value) + + ngModel.$formatters.push (value) -> + element.select2('val', value) + value diff --git a/app/assets/javascripts/admin/index_utils/filters/attr_filter.js.coffee b/app/assets/javascripts/admin/index_utils/filters/attr_filter.js.coffee new file mode 100644 index 0000000000..c645b507f1 --- /dev/null +++ b/app/assets/javascripts/admin/index_utils/filters/attr_filter.js.coffee @@ -0,0 +1,12 @@ +# Used like a regular angular filter where an object is passed +# Adds the additional special case that a value of 0 for the filter +# acts as a bypass for that particular attribute +angular.module("admin.indexUtils").filter "attrFilter", ($filter) -> + return (objects, filters) -> + Object.keys(filters).reduce (filtered, attr) -> + filter = filters[attr] + return filtered if !filter? || filter == 0 + return $filter('filter')(filtered, (object) -> + object[attr] == filter + ) + , objects diff --git a/app/assets/javascripts/admin/variant_overrides/controllers/variant_overrides_controller.js.coffee b/app/assets/javascripts/admin/variant_overrides/controllers/variant_overrides_controller.js.coffee index 73ddfc8b2b..d3a57c572f 100644 --- a/app/assets/javascripts/admin/variant_overrides/controllers/variant_overrides_controller.js.coffee +++ b/app/assets/javascripts/admin/variant_overrides/controllers/variant_overrides_controller.js.coffee @@ -1,12 +1,19 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl", ($scope, $timeout, Indexer, SpreeApiAuth, PagedFetcher, StatusMessage, hubs, producers, hubPermissions, VariantOverrides, DirtyVariantOverrides) -> - $scope.hubs = hubs + $scope.hubs = Indexer.index hubs $scope.hub = null $scope.products = [] - $scope.producers = Indexer.index producers + $scope.producers = producers + $scope.producersByID = Indexer.index producers $scope.hubPermissions = hubPermissions $scope.variantOverrides = VariantOverrides.variantOverrides $scope.StatusMessage = StatusMessage + $scope.resetSelectFilters = -> + $scope.producerFilter = 0 + $scope.query = '' + + $scope.resetSelectFilters() + $scope.initialise = -> SpreeApiAuth.authorise() .then -> @@ -27,8 +34,7 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl", $scope.selectHub = -> - $scope.hub = (hub for hub in hubs when hub.id == $scope.hub_id)[0] - + $scope.hub = $scope.hubs[$scope.hub_id] $scope.displayDirty = -> if DirtyVariantOverrides.count() > 0 @@ -37,7 +43,6 @@ angular.module("admin.variantOverrides").controller "AdminVariantOverridesCtrl", else StatusMessage.clear() - $scope.update = -> if DirtyVariantOverrides.count() == 0 StatusMessage.display 'alert', 'No changes to save.' diff --git a/app/assets/javascripts/admin/variant_overrides/services/variant_overrides.js.coffee b/app/assets/javascripts/admin/variant_overrides/services/variant_overrides.js.coffee index c8ea397343..697d459b75 100644 --- a/app/assets/javascripts/admin/variant_overrides/services/variant_overrides.js.coffee +++ b/app/assets/javascripts/admin/variant_overrides/services/variant_overrides.js.coffee @@ -8,7 +8,7 @@ angular.module("admin.variantOverrides").factory "VariantOverrides", (variantOve @variantOverrides[vo.hub_id][vo.variant_id] = vo ensureDataFor: (hubs, products) -> - for hub in hubs + for hub_id, hub of hubs @variantOverrides[hub.id] ||= {} for product in products for variant in product.variants diff --git a/app/assets/javascripts/admin/variant_overrides/variant_overrides.js.coffee b/app/assets/javascripts/admin/variant_overrides/variant_overrides.js.coffee index 7a6f1ab2fa..4766bd464c 100644 --- a/app/assets/javascripts/admin/variant_overrides/variant_overrides.js.coffee +++ b/app/assets/javascripts/admin/variant_overrides/variant_overrides.js.coffee @@ -1 +1 @@ -angular.module("admin.variantOverrides", ["admin.indexUtils"]) +angular.module("admin.variantOverrides", ["admin.indexUtils", "pasvaz.bindonce"]) diff --git a/app/assets/stylesheets/admin/disabled.css.scss b/app/assets/stylesheets/admin/disabled.css.scss new file mode 100644 index 0000000000..a393c5d80b --- /dev/null +++ b/app/assets/stylesheets/admin/disabled.css.scss @@ -0,0 +1,13 @@ +label.disabled { + color: #c3c3c3; + pointer-events: none; +} + +input[type='button']:disabled { + background-color: #c3c3c3; + color: #ffffff; +} + +.select2-container-disabled { + pointer-events: none; +} diff --git a/app/views/admin/variant_overrides/_filters.html.haml b/app/views/admin/variant_overrides/_filters.html.haml new file mode 100644 index 0000000000..9dc90d7ad3 --- /dev/null +++ b/app/views/admin/variant_overrides/_filters.html.haml @@ -0,0 +1,26 @@ +.filters.sixteen.columns.alpha + .filter.four.columns.alpha + %label{ :for => 'query', ng: {class: '{disabled: !hub.id}'} }Quick Search + %br + %input.fullwidth{ :type => "text", :id => 'query', ng: { model: 'query', disabled: '!hub.id'} } + .two.columns   + .filter_select.four.columns + %label{ :for => 'hub_id', ng: { bind: 'hub_id ? "Shop" : "Select a shop"' } } + %br + %select.select2.fullwidth#hub_id{ 'ng-model' => 'hub_id', name: 'hub_id', ng: { options: 'hub.id as hub.name for (id, hub) in hubs', change: 'selectHub()' } } + .filter_select.four.columns + %label{ :for => 'producer_filter', ng: {class: '{disabled: !hub.id}'} }Producer + %br + %input.ofn-select2.fullwidth{ :id => 'producer_filter', type: 'number', style: 'display:none', data: 'producers', blank: "{id: 0, name: 'All'}", ng: { model: 'producerFilter', disabled: '!hub.id' } } + -# .filter_select{ :class => "three columns" } + -# %label{ :for => 'distributor_filter' }Hub + -# %br + -# %select{ :class => "three columns alpha", :id => 'distributor_filter', 'select2-min-search' => 5, 'ng-model' => 'distributorFilter', 'ng-options' => 'd.id as d.name for d in distributors'} + -# .filter_select{ :class => "three columns" } + -# %label{ :for => 'order_cycle_filter' }Order Cycle + -# %br + -# %select{ :class => "three columns alpha", :id => 'order_cycle_filter', 'select2-min-search' => 5, 'ng-model' => 'orderCycleFilter', 'ng-options' => 'oc.id as oc.name for oc in orderCycles', 'confirm-change' => "confirmRefresh()", 'ng-change' => 'refreshData()'} + .filter_clear.two.columns.omega + %label{ :for => 'clear_all_filters' } + %br + %input.red.fullwidth{ :type => 'button', :id => 'clear_all_filters', :value => "Clear All", ng: { click: "resetSelectFilters()", disabled: '!hub.id'} } diff --git a/app/views/admin/variant_overrides/_hub_choice.html.haml b/app/views/admin/variant_overrides/_hub_choice.html.haml deleted file mode 100644 index aa0f7ab738..0000000000 --- a/app/views/admin/variant_overrides/_hub_choice.html.haml +++ /dev/null @@ -1,7 +0,0 @@ -.row - .two.columns.alpha - Hub - .four.columns - %select.select2.fullwidth#hub_id{ 'ng-model' => 'hub_id', name: 'hub_id', 'ng-options' => 'hub.id as hub.name for hub in hubs' } - .ten.columns.omega - %input{ type: 'button', value: 'Go', 'ng-click' => 'selectHub()' } diff --git a/app/views/admin/variant_overrides/_products.html.haml b/app/views/admin/variant_overrides/_products.html.haml index cf11e8ac5d..fa5cfe0ec0 100644 --- a/app/views/admin/variant_overrides/_products.html.haml +++ b/app/views/admin/variant_overrides/_products.html.haml @@ -1,10 +1,10 @@ -%table.index.bulk{ng: {show: 'hub'}} +%table.index.bulk{ ng: {show: 'hub'}} %thead %tr %th Producer %th Product %th Price %th On hand - %tbody{ng: {repeat: 'product in products | hubPermissions:hubPermissions:hub.id'}} + %tbody{bindonce: true, ng: {repeat: 'product in products | hubPermissions:hubPermissions:hub.id | attrFilter:{producer_id:producerFilter} | filter:query' } } = render 'admin/variant_overrides/products_product' = render 'admin/variant_overrides/products_variants' diff --git a/app/views/admin/variant_overrides/_products_product.html.haml b/app/views/admin/variant_overrides/_products_product.html.haml index 52551e8e0b..9ce07b3aa6 100644 --- a/app/views/admin/variant_overrides/_products_product.html.haml +++ b/app/views/admin/variant_overrides/_products_product.html.haml @@ -1,5 +1,5 @@ %tr.product.even - %td {{ producers[product.producer_id].name }} - %td {{ product.name }} + %td{ bo: { bind: 'producersByID[product.producer_id].name'} } + %td{ bo: { bind: 'product.name'} } %td %td diff --git a/app/views/admin/variant_overrides/_products_variants.html.haml b/app/views/admin/variant_overrides/_products_variants.html.haml index bd48ea343c..2868b6f8f2 100644 --- a/app/views/admin/variant_overrides/_products_variants.html.haml +++ b/app/views/admin/variant_overrides/_products_variants.html.haml @@ -1,8 +1,8 @@ -%tr.variant{ng: {repeat: 'variant in product.variants'}} +%tr.variant{ id: "v_{{variant.id}}", ng: {repeat: 'variant in product.variants'}} %td %td - {{ variant.display_name }} - .variant-override-unit {{ variant.unit_to_display }} + %span{ bo: { bind: 'variant.display_name || ""'} } + .variant-override-unit{ bo: { bind: 'variant.unit_to_display'} } %td %input{name: 'variant-overrides-{{ variant.id }}-price', type: 'text', ng: {model: 'variantOverrides[hub.id][variant.id].price'}, placeholder: '{{ variant.price }}', 'ofn-track-variant-override' => 'price'} diff --git a/app/views/admin/variant_overrides/index.html.haml b/app/views/admin/variant_overrides/index.html.haml index 38563d00a2..8d0a4670d7 100644 --- a/app/views/admin/variant_overrides/index.html.haml +++ b/app/views/admin/variant_overrides/index.html.haml @@ -2,7 +2,7 @@ = render 'admin/variant_overrides/data' %div{ ng: { app: 'admin.variantOverrides', controller: 'AdminVariantOverridesCtrl', init: 'initialise()' } } - = render 'admin/variant_overrides/hub_choice' + = render 'admin/variant_overrides/filters' %div{ng: {show: 'hub'}} %h2 {{ hub.name }} diff --git a/spec/features/admin/variant_overrides_spec.rb b/spec/features/admin/variant_overrides_spec.rb index ee615f44f5..ec8b754abe 100644 --- a/spec/features/admin/variant_overrides_spec.rb +++ b/spec/features/admin/variant_overrides_spec.rb @@ -30,7 +30,6 @@ feature %q{ it "displays the hub" do visit '/admin/variant_overrides' select2_select hub.name, from: 'hub_id' - click_button 'Go' page.should have_selector 'h2', text: hub.name end @@ -59,7 +58,6 @@ feature %q{ before do visit '/admin/variant_overrides' select2_select hub.name, from: 'hub_id' - click_button 'Go' end it "displays the list of products with variants" do @@ -72,11 +70,37 @@ feature %q{ page.should have_table_row [producer_related.name, product_related.name, '', ''] page.should have_input "variant-overrides-#{variant_related.id}-price", placeholder: '2.34' page.should have_input "variant-overrides-#{variant_related.id}-count-on-hand", placeholder: '23' - end - it "filters the products to those the hub can override" do + # filters the products to those the hub can override page.should_not have_content producer_unrelated.name page.should_not have_content product_unrelated.name + + # Filters based on the producer select filter + expect(page).to have_selector "#v_#{variant.id}" + expect(page).to have_selector "#v_#{variant_related.id}" + select2_select producer.name, from: 'producer_filter' + expect(page).to have_selector "#v_#{variant.id}" + expect(page).to_not have_selector "#v_#{variant_related.id}" + select2_select 'All', from: 'producer_filter' + + # Filters based on the quick search box + expect(page).to have_selector "#v_#{variant.id}" + expect(page).to have_selector "#v_#{variant_related.id}" + fill_in 'query', with: product.name + expect(page).to have_selector "#v_#{variant.id}" + expect(page).to_not have_selector "#v_#{variant_related.id}" + fill_in 'query', with: '' + + # Clears the filters + expect(page).to have_selector "#v_#{variant.id}" + expect(page).to have_selector "#v_#{variant_related.id}" + select2_select producer.name, from: 'producer_filter' + fill_in 'query', with: product_related.name + expect(page).to_not have_selector "#v_#{variant.id}" + expect(page).to_not have_selector "#v_#{variant_related.id}" + click_button 'Clear All' + expect(page).to have_selector "#v_#{variant.id}" + expect(page).to have_selector "#v_#{variant_related.id}" end it "creates new overrides" do @@ -162,7 +186,6 @@ feature %q{ before do visit '/admin/variant_overrides' select2_select hub.name, from: 'hub_id' - click_button 'Go' end it "product values are affected by overrides" do diff --git a/spec/javascripts/unit/admin/controllers/variant_overrides_controller_spec.js.coffee b/spec/javascripts/unit/admin/controllers/variant_overrides_controller_spec.js.coffee index d553392de3..22b8300409 100644 --- a/spec/javascripts/unit/admin/controllers/variant_overrides_controller_spec.js.coffee +++ b/spec/javascripts/unit/admin/controllers/variant_overrides_controller_spec.js.coffee @@ -16,14 +16,18 @@ describe "VariantOverridesCtrl", -> null scope = {} - inject ($controller, Indexer, _VariantOverrides_) -> + inject ($controller, _VariantOverrides_) -> VariantOverrides = _VariantOverrides_ - ctrl = $controller 'AdminVariantOverridesCtrl', {$scope: scope, Indexer: Indexer, hubs: hubs, producers: producers, products: products, hubPermissions: hubPermissions, VariantOverrides: _VariantOverrides_} + ctrl = $controller 'AdminVariantOverridesCtrl', {$scope: scope, hubs: hubs, producers: producers, products: products, hubPermissions: hubPermissions, VariantOverrides: _VariantOverrides_} it "initialises the hub list and the chosen hub", -> - expect(scope.hubs).toEqual hubs + expect(scope.hubs).toEqual { 1: {id: 1, name: 'Hub'} } expect(scope.hub).toBeNull() + it "initialises select filters", -> + expect(scope.producerFilter).toEqual 0 + expect(scope.query).toEqual '' + it "adds products", -> spyOn(VariantOverrides, "ensureDataFor") expect(scope.products).toEqual []