Tag Rules can be rearranged in UI to set priority

This commit is contained in:
Rob Harrington
2016-05-27 13:53:25 +10:00
parent cb9e3b43f9
commit a1c7a44fa0
12 changed files with 95 additions and 32 deletions

View File

@@ -1,16 +1,16 @@
angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, enterprise) ->
angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, $filter, enterprise) ->
$scope.tagGroups = enterprise.tag_groups
$scope.defaultTagGroup = enterprise.default_tag_group
$scope.visibilityOptions = [ { id: "visible", name: "VISIBLE" }, { id: "hidden", name: "NOT VISIBLE" } ]
updateRuleCounts = ->
$scope.updateRuleCounts = ->
index = $scope.defaultTagGroup.rules.length
for tagGroup in $scope.tagGroups
for tagGroup in $filter('orderBy')($scope.tagGroups, 'position')
tagGroup.startIndex = index
index = index + tagGroup.rules.length
updateRuleCounts()
$scope.updateRuleCounts()
$scope.updateTagsRulesFor = (tagGroup) ->
for tagRule in tagGroup.rules
@@ -38,17 +38,17 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, ente
newRule.peferred_exchange_tags = []
newRule.preferred_matched_order_cycles_visibility = "visible"
tagGroup.rules.push(newRule)
updateRuleCounts()
$scope.updateRuleCounts()
$scope.addNewTag = ->
$scope.tagGroups.push { tags: [], rules: [] }
$scope.tagGroups.push { tags: [], rules: [], position: $scope.tagGroups.length + 1 }
$scope.deleteTagRule = (tagGroup, tagRule) ->
index = tagGroup.rules.indexOf(tagRule)
return unless index >= 0
if tagRule.id is null
tagGroup.rules.splice(index, 1)
updateRuleCounts()
$scope.updateRuleCounts()
else
if confirm("Are you sure?")
$http
@@ -56,4 +56,4 @@ angular.module("admin.tagRules").controller "TagRulesCtrl", ($scope, $http, ente
url: "/admin/enterprises/#{enterprise.id}/tag_rules/#{tagRule.id}.json"
.success ->
tagGroup.rules.splice(index, 1)
updateRuleCounts()
$scope.updateRuleCounts()

View File

@@ -0,0 +1,36 @@
angular.module("admin.utils").directive "ofnSortable", ($timeout, $parse) ->
restrict: "E"
scope:
items: '@'
position: '@'
afterSort: '&'
handle: "@"
axis: "@"
link: (scope, element, attrs) ->
$timeout ->
scope.axis ||= "y"
scope.handle ||= ".handle"
getScopePos = $parse(scope.position)
setScopePos = getScopePos.assign
element.sortable
handle: scope.handle
helper: 'clone'
axis: scope.axis
items: scope.items
appendTo: element
update: (event, ui) ->
sortableSiblings = ($(ss) for ss in ui.item.siblings(scope.items))
offset = Math.min(ui.item.index(), sortableSiblings[0].index())
newPos = ui.item.index() - offset + 1
oldPos = getScopePos(ui.item.scope())
if newPos < oldPos
for sibScope in sortableSiblings.map((ss) -> ss.scope())
pos = getScopePos(sibScope)
setScopePos(sibScope, pos + 1) if pos >= newPos && pos < oldPos
else if newPos > oldPos
for sibScope in sortableSiblings.map((ss) -> ss.scope())
pos = getScopePos(sibScope)
setScopePos(sibScope, pos - 1) if pos > oldPos && pos <= newPos
setScopePos(ui.item.scope(), newPos)
scope.afterSort()

View File

@@ -16,6 +16,11 @@
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][type]",
ng: { value: "rule.type" } }
%input{ type: "hidden",
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_priority",
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][priority]",
ng: { value: "tagGroup.startIndex + $index" } }
%input{ type: "hidden",
id: "enterprise_tag_rules_attributes_{{tagGroup.startIndex + $index}}_is_default",
name: "enterprise[tag_rules_attributes][{{tagGroup.startIndex + $index}}][is_default]",

View File

@@ -5,7 +5,14 @@
font-weight: bold;
}
.customer_tag {
.header {
cursor: move;
}
}
.customer_tag, .default_rules {
background-color: #ffffff;
border: 1px solid #cee1f4;
margin-bottom: 40px;

View File

@@ -5,9 +5,11 @@ class TagRule < ActiveRecord::Base
validates :enterprise, presence: true
attr_accessible :enterprise, :enterprise_id, :is_default, :preferred_customer_tags
attr_accessible :enterprise, :enterprise_id, :is_default, :priority
attr_accessible :preferred_customer_tags
scope :for, ->(enterprise) { where(enterprise_id: enterprise) }
scope :prioritised, -> { order('priority ASC') }
def self.mapping_for(enterprises)
self.for(enterprises).inject({}) do |mapping, rule|

View File

@@ -9,9 +9,12 @@ class Api::Admin::EnterpriseSerializer < ActiveModel::Serializer
has_many :users, serializer: Api::Admin::UserSerializer
def tag_groups
object.tag_rules.reject(&:is_default).each_with_object([]) do |tag_rule, tag_groups|
object.tag_rules.prioritised.reject(&:is_default).each_with_object([]) do |tag_rule, tag_groups|
tag_group = find_match(tag_groups, tag_rule.preferred_customer_tags.split(",").map{ |t| { text: t } })
tag_groups << tag_group if tag_group[:rules].empty?
if tag_group[:rules].empty?
tag_groups << tag_group
tag_group[:position] = tag_groups.count
end
tag_group[:rules] << Api::Admin::TagRuleSerializer.new(tag_rule).serializable_hash
end
end

View File

@@ -1,11 +1,11 @@
.row{ ng: { controller: "TagRulesCtrl" } }
.eleven.columns.alpha.omega
.eleven.columns.alpha.omega
%ofn-sortable{ axis: "y", handle: ".header", items: '.customer_tag', position: "tagGroup.position", after: { sort: "updateRuleCounts()" } }
.no_tags{ ng: { show: "tagGroups.length == 0" } }
No tags apply to this enterprise yet
= render 'admin/enterprises/form/tag_rules/default_rules'
-# = render 'customer_tags'
.customer_tag{ ng: { repeat: "tagGroup in tagGroups" } }
.customer_tag{ id: "tg_{{tagGroup.position}}", ng: { repeat: "tagGroup in tagGroups" } }
.header
%table
%colgroup

View File

@@ -0,0 +1,5 @@
class AddPriorityToTagRule < ActiveRecord::Migration
def change
add_column :tag_rules, :priority, :integer, default: 99, null: false
end
end

View File

@@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20160520065217) do
ActiveRecord::Schema.define(:version => 20160527012603) do
create_table "account_invoices", :force => true do |t|
t.integer "user_id", :null => false
@@ -1164,6 +1164,7 @@ ActiveRecord::Schema.define(:version => 20160520065217) do
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.boolean "is_default", :default => false, :null => false
t.integer "priority", :default => 99, :null => false
end
create_table "taggings", :force => true do |t|

View File

@@ -40,7 +40,7 @@ module OpenFoodNetwork
def rules
return @rules unless @rules.nil?
@rules = rule_class.for(enterprise)
@rules = rule_class.prioritised.for(enterprise)
end
def customer_rules

View File

@@ -170,6 +170,9 @@ feature 'Tag Rules', js: true do
select2_select 'VISIBLE', from: "enterprise_tag_rules_attributes_4_preferred_matched_shipping_methods_visibility"
end
# Moving the Shipping Methods to top priority
find(".customer_tag#tg_4 .header", ).drag_to find(".customer_tag#tg_1 .header")
# # DiscountOrder rule
# within "#tr_2" do
# expect(page).to have_field "enterprise_tag_rules_attributes_2_calculator_attributes_preferred_flat_percent", with: '0'
@@ -178,27 +181,31 @@ feature 'Tag Rules', js: true do
click_button 'Update'
# FilterShippingMethods rule
expect(default_fsm_tag_rule.preferred_customer_tags).to eq ""
# DEFAULT FilterShippingMethods rule
expect(default_fsm_tag_rule.reload.preferred_customer_tags).to eq ""
expect(default_fsm_tag_rule.preferred_shipping_method_tags).to eq "local,volunteers-only"
expect(default_fsm_tag_rule.preferred_matched_shipping_methods_visibility).to eq "hidden"
# FilterShippingMethods rule
expect(fsm_tag_rule.reload.priority).to eq 1
expect(fsm_tag_rule.preferred_customer_tags).to eq "local,volunteer"
expect(fsm_tag_rule.preferred_shipping_method_tags).to eq "local,volunteers-only4"
expect(fsm_tag_rule.preferred_matched_shipping_methods_visibility).to eq "visible"
# FilterProducts rule
expect(fp_tag_rule.reload.priority).to eq 2
expect(fp_tag_rule.preferred_customer_tags).to eq "member,volunteer"
expect(fp_tag_rule.preferred_variant_tags).to eq "member,volunteers-only1"
expect(fp_tag_rule.preferred_matched_variants_visibility).to eq "hidden"
# FilterPaymentMethods rule
expect(fpm_tag_rule.reload.priority).to eq 3
expect(fpm_tag_rule.preferred_customer_tags).to eq "trusted,volunteer"
expect(fpm_tag_rule.preferred_payment_method_tags).to eq "trusted,volunteers-only2"
expect(fpm_tag_rule.preferred_matched_payment_methods_visibility).to eq "visible"
# FilterPaymentMethods rule
# FilterOrderCycles rule
expect(foc_tag_rule.reload.priority).to eq 4
expect(foc_tag_rule.preferred_customer_tags).to eq "wholesale,volunteer"
expect(foc_tag_rule.preferred_exchange_tags).to eq "wholesale,volunteers-only3"
expect(foc_tag_rule.preferred_matched_order_cycles_visibility).to eq "hidden"

View File

@@ -3,12 +3,12 @@ require 'open_food_network/tag_rule_applicator'
module OpenFoodNetwork
describe TagRuleApplicator do
let!(:enterprise) { create(:distributor_enterprise) }
let!(:oc_tag_rule) { create(:filter_order_cycles_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag1", preferred_exchange_tags: "tag1", preferred_matched_order_cycles_visibility: "visible" )}
let!(:product_tag_rule1) { create(:filter_products_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag1", preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "visible" ) }
let!(:product_tag_rule2) { create(:filter_products_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag1", preferred_variant_tags: "tag3", preferred_matched_variants_visibility: "hidden" ) }
let!(:product_tag_rule3) { create(:filter_products_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag2", preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "visible" ) }
let!(:default_product_tag_rule) { create(:filter_products_tag_rule, enterprise: enterprise, is_default: true, preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "hidden" ) }
let!(:sm_tag_rule) { create(:filter_shipping_methods_tag_rule, enterprise: enterprise, preferred_customer_tags: "tag1", preferred_shipping_method_tags: "tag1", preferred_matched_shipping_methods_visibility: "visible" )}
let!(:oc_tag_rule) { create(:filter_order_cycles_tag_rule, enterprise: enterprise, priority: 6, preferred_customer_tags: "tag1", preferred_exchange_tags: "tag1", preferred_matched_order_cycles_visibility: "visible" )}
let!(:product_tag_rule1) { create(:filter_products_tag_rule, enterprise: enterprise, priority: 5, preferred_customer_tags: "tag1", preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "visible" ) }
let!(:product_tag_rule2) { create(:filter_products_tag_rule, enterprise: enterprise, priority: 4, preferred_customer_tags: "tag1", preferred_variant_tags: "tag3", preferred_matched_variants_visibility: "hidden" ) }
let!(:product_tag_rule3) { create(:filter_products_tag_rule, enterprise: enterprise, priority: 3, preferred_customer_tags: "tag2", preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "visible" ) }
let!(:default_product_tag_rule) { create(:filter_products_tag_rule, enterprise: enterprise, priority: 2, is_default: true, preferred_variant_tags: "tag1", preferred_matched_variants_visibility: "hidden" ) }
let!(:sm_tag_rule) { create(:filter_shipping_methods_tag_rule, enterprise: enterprise, priority: 1, preferred_customer_tags: "tag1", preferred_shipping_method_tags: "tag1", preferred_matched_shipping_methods_visibility: "visible" )}
describe "initialisation" do
context "when enterprise is nil" do
@@ -68,19 +68,16 @@ module OpenFoodNetwork
expect(applicator.customer_tags).to eq ["tag1"]
end
it "selects only rules of the specified type" do
expect(rules).to include product_tag_rule1, product_tag_rule2, product_tag_rule3, default_product_tag_rule
expect(rules).not_to include oc_tag_rule, sm_tag_rule
it "selects only rules of the specified type, in order of priority" do
expect(rules).to eq [default_product_tag_rule, product_tag_rule3, product_tag_rule2, product_tag_rule1]
end
it "splits rules into those which match customer tags and those which don't" do
expect(customer_rules).to include product_tag_rule1, product_tag_rule2
expect(customer_rules).not_to include default_product_tag_rule, product_tag_rule3, oc_tag_rule, sm_tag_rule
it "splits rules into those which match customer tags and those which don't, in order of priority" do
expect(customer_rules).to eq [product_tag_rule2, product_tag_rule1]
end
it "splits out default rules" do
expect(default_rules).to include default_product_tag_rule
expect(default_rules).not_to include product_tag_rule1, product_tag_rule2, product_tag_rule3, oc_tag_rule, sm_tag_rule
expect(default_rules).to eq [default_product_tag_rule]
end
end
end