mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-04 22:16:08 +00:00
Merge branch 'master' into redesign
This commit is contained in:
@@ -1,14 +1,11 @@
|
||||
angular.module("admin.enterprises").controller "EnterpriseIndexRowCtrl", ($scope) ->
|
||||
$scope.statusText = ->
|
||||
issueCount = (issue for issue in $scope.enterprise.issues when !issue.resolved).length
|
||||
if issueCount > 0
|
||||
$scope.statusClass = "issue"
|
||||
$scope.status = ->
|
||||
if $scope.enterprise.issues.length > 0
|
||||
"issue"
|
||||
else if $scope.enterprise.warnings.length > 0
|
||||
"warning"
|
||||
else
|
||||
warningCount = (warning for warning in $scope.enterprise.warnings when !warning.resolved).length
|
||||
if warningCount > 0
|
||||
$scope.statusClass = "warning"
|
||||
else
|
||||
$scope.statusClass = "ok"
|
||||
"ok"
|
||||
|
||||
|
||||
$scope.producerText = ->
|
||||
@@ -42,7 +39,6 @@ angular.module("admin.enterprises").controller "EnterpriseIndexRowCtrl", ($scope
|
||||
$scope.updateRowText = ->
|
||||
$scope.producer = $scope.producerText()
|
||||
$scope.package = $scope.packageText()
|
||||
$scope.status = $scope.statusText()
|
||||
$scope.producerError = ($scope.producer == "Choose")
|
||||
$scope.packageError = ($scope.package == "Choose")
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
angular.module("admin.enterprises").controller 'indexStatusPanelCtrl', ($scope, $filter) ->
|
||||
$scope.issues = $filter('filter')($scope.object.issues, {resolved: false })
|
||||
$scope.warnings = $filter('filter')($scope.object.warnings, {resolved: false})
|
||||
$scope.issues = $scope.object.issues
|
||||
$scope.warnings = $scope.object.warnings
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
angular.module("admin.indexUtils").directive "panelToggle", ->
|
||||
restrict: "C"
|
||||
transclude: true
|
||||
template: '<div ng-transclude></div><i class=\'icon-chevron-down\'"></i>'
|
||||
template: '<div ng-transclude></div><i class=\'icon-chevron\'></i>'
|
||||
require: "^panelToggleRow"
|
||||
scope:
|
||||
name: "@"
|
||||
|
||||
@@ -22,17 +22,11 @@ Darkswarm.directive "filterSelector", (FilterSelectorsService)->
|
||||
.map (selector)->
|
||||
selector.object.id
|
||||
|
||||
# This can be called from a parent scope
|
||||
# when data has been loaded, in order to pass
|
||||
# selectors up
|
||||
scope.$on 'loadFilterSelectors', ->
|
||||
scope.allSelectors = scope.selectors() if attr.allSelectors?
|
||||
|
||||
scope.$watchCollection "selectors()", (newValue, oldValue) ->
|
||||
scope.allSelectors = scope.selectors() if attr.allSelectors?
|
||||
scope.$watchCollection "objects()", (newValue, oldValue) ->
|
||||
scope.allSelectors = scope.buildSelectors()
|
||||
|
||||
# Build a list of selectors
|
||||
scope.selectors = ->
|
||||
scope.buildSelectors = ->
|
||||
# Generate a selector for each object.
|
||||
# NOTE: THESE ARE MEMOIZED to stop new selectors from being created constantly, otherwise function always returns non-identical results
|
||||
# This means the $digest cycle can never close and times out
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.row.enterprise_status_panel{ ng: { controller: 'indexStatusPanelCtrl' } }
|
||||
.alpha.sixteen.columns
|
||||
.alpha.omega.sixteen.columns
|
||||
|
||||
%h4.status-ok.text-center{ ng: { show: "issues.length == 0 && warnings.length == 0" } }
|
||||
%i.icon-ok-sign
|
||||
@@ -21,7 +21,7 @@
|
||||
%td.resolve
|
||||
%div{ ng: { bind: { html: "issue.link" } } }
|
||||
%tr{ ng: { repeat: "warning in warnings"} }
|
||||
%td.severity.text-center
|
||||
%td.severity
|
||||
%i.icon-warning-sign.warning
|
||||
%td.description
|
||||
%span{ bo: { bind: "warning.description" } }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
%div{bindonce:true, style: "display: inline-block" }
|
||||
%ul{ bindonce: true }
|
||||
%active-selector{ ng: { repeat: "selector in allSelectors", show: "ifDefined(selector.fits, true)" } }
|
||||
%render-svg{path: "{{selector.object.icon}}", ng: { if: "selector.object.icon"} }
|
||||
%span{"bo-text" => "selector.object.name"}
|
||||
|
||||
@@ -9,12 +9,10 @@
|
||||
%br
|
||||
|
||||
.filter-shopfront.taxon-selectors.inline-block
|
||||
%ul
|
||||
%filter-selector{ objects: "[product] | taxonsOf" }
|
||||
%filter-selector{ objects: "[product] | taxonsOf" }
|
||||
|
||||
.filter-shopfront.property-selectors.inline-block
|
||||
%ul
|
||||
%filter-selector{ objects: "[product] | propertiesWithValuesOf" }
|
||||
%filter-selector{ objects: "[product] | propertiesWithValuesOf" }
|
||||
|
||||
%div{"ng-if" => "product.description"}
|
||||
%hr
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
%ul
|
||||
-# In order for the single-line-selector scope to have access to the available selectors,
|
||||
%filter-selector{objects: "objects()", "active-selectors" => "activeSelectors", "all-selectors" => "allSelectors" }
|
||||
-# In order for the single-line-selector scope to have access to the available selectors,
|
||||
%filter-selector{objects: "objects()", "active-selectors" => "activeSelectors", "all-selectors" => "allSelectors" }
|
||||
|
||||
%li.more{ ng: { show: "overFlowSelectors().length > 0 || fitting" } }
|
||||
%ul{ ng: { if: "overFlowSelectors().length > 0 || fitting" } }
|
||||
%li.more
|
||||
%a.dropdown{ data: { dropdown: "{{ 'show-more-' + selectorName }}" }, ng: { class: "{active: selectedOverFlowSelectors().length > 0}" } }
|
||||
%span
|
||||
+ {{ overFlowSelectors().length }} more
|
||||
|
||||
@@ -96,6 +96,8 @@
|
||||
}
|
||||
|
||||
td.severity {
|
||||
text-align: center;
|
||||
|
||||
i {
|
||||
font-size: 1.5rem;
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ tr.panel-toggle-row {
|
||||
|
||||
position: relative;
|
||||
|
||||
i {
|
||||
i.icon-chevron::before {
|
||||
font-size: 1.2rem;
|
||||
content: "\f078";
|
||||
}
|
||||
|
||||
&::before {
|
||||
&.error::before {
|
||||
font-family: FontAwesome;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
@@ -24,23 +25,14 @@ tr.panel-toggle-row {
|
||||
right: 5px;
|
||||
font-size: 2rem;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
&.error::before {
|
||||
content: "\f071";
|
||||
color: #da5354;
|
||||
}
|
||||
|
||||
&.status {
|
||||
i.status::before {
|
||||
font-family: FontAwesome;
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
display: inline-block;
|
||||
text-decoration: inherit;
|
||||
i.icon-status::before {
|
||||
font-size: 1.5rem;
|
||||
opacity: 0.5;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
i.issue::before {
|
||||
@@ -59,16 +51,6 @@ tr.panel-toggle-row {
|
||||
}
|
||||
}
|
||||
|
||||
&.selected {
|
||||
background-color: #ffffff;
|
||||
border-left: 2px solid #444444;
|
||||
border-right: 2px solid #444444;
|
||||
border-top: 2px solid #444444;
|
||||
* {
|
||||
color: #1b3c56;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
background-color: #d0e2f6;
|
||||
@@ -76,7 +58,7 @@ tr.panel-toggle-row {
|
||||
color: #1b3c56;
|
||||
}
|
||||
|
||||
i.status::before {
|
||||
i.icon-status::before {
|
||||
opacity: 1.0;
|
||||
}
|
||||
}
|
||||
@@ -87,10 +69,27 @@ tr.panel-toggle-row {
|
||||
border-bottom: 2px solid #444444;
|
||||
|
||||
&.selected {
|
||||
background-color: #ffffff;
|
||||
border-left: 2px solid #444444;
|
||||
border-right: 2px solid #444444;
|
||||
border-top: 2px solid #444444;
|
||||
border-bottom: none;
|
||||
|
||||
&:hover {
|
||||
background-color: #ffffff;
|
||||
}
|
||||
|
||||
* {
|
||||
color: #1b3c56;
|
||||
}
|
||||
|
||||
i.icon-status::before {
|
||||
opacity: 1.0;
|
||||
}
|
||||
|
||||
i.icon-chevron::before {
|
||||
content: "\f077";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -120,10 +119,6 @@ tr.panel-row {
|
||||
|
||||
.column.alpha, .columns.alpha {
|
||||
padding-left: 20px;
|
||||
|
||||
&.sixteen {
|
||||
padding-right: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.column.omega, .columns.omega {
|
||||
|
||||
@@ -92,24 +92,23 @@
|
||||
span.filter-label
|
||||
opacity: 0.75
|
||||
|
||||
.filter-shopfront.taxon-selectors, .filter-shopfront.property-selectors
|
||||
background: transparent
|
||||
|
||||
single-line-selectors
|
||||
overflow-x: hidden
|
||||
white-space: nowrap
|
||||
|
||||
.f-dropdown
|
||||
overflow-x: auto
|
||||
white-space: normal
|
||||
|
||||
ul
|
||||
margin: 0
|
||||
ul, ul li
|
||||
list-style: none
|
||||
|
||||
|
||||
.filter-shopfront
|
||||
&.taxon-selectors, &.property-selectors
|
||||
background: transparent
|
||||
|
||||
single-line-selectors
|
||||
overflow-x: hidden
|
||||
white-space: nowrap
|
||||
|
||||
.f-dropdown
|
||||
overflow-x: auto
|
||||
white-space: normal
|
||||
|
||||
ul
|
||||
margin: 0
|
||||
display: inline-block
|
||||
ul, ul li
|
||||
list-style: none
|
||||
|
||||
// Shopfront taxons
|
||||
&.taxon-selectors
|
||||
|
||||
@@ -32,6 +32,12 @@ class EnterpriseRelationship < ActiveRecord::Base
|
||||
relationships = EnterpriseRelationship.includes(:child, :parent)
|
||||
relatives = {}
|
||||
|
||||
Enterprise.all.each do |e|
|
||||
relatives[e.id] ||= { distributors: Set.new, producers: Set.new }
|
||||
relatives[e.id][:producers] << e.id if e.is_primary_producer
|
||||
relatives[e.id][:distributors] << e.id if e.is_distributor
|
||||
end
|
||||
|
||||
relationships.each do |r|
|
||||
relatives[r.parent_id] ||= {distributors: Set.new, producers: Set.new}
|
||||
relatives[r.child_id] ||= {distributors: Set.new, producers: Set.new}
|
||||
|
||||
@@ -23,32 +23,34 @@ class Api::Admin::IndexEnterpriseSerializer < ActiveModel::Serializer
|
||||
end
|
||||
|
||||
def issues
|
||||
[
|
||||
{
|
||||
resolved: shipping_methods_ok?,
|
||||
description: "#{object.name} currently has no shipping methods.",
|
||||
link: "<a class='button fullwidth' href='#{spree.new_admin_shipping_method_path}'>Create New</a>"
|
||||
},
|
||||
{
|
||||
resolved: payment_methods_ok?,
|
||||
description: "#{object.name} currently has no payment methods.",
|
||||
link: "<a class='button fullwidth' href='#{spree.new_admin_payment_method_path}'>Create New</a>"
|
||||
},
|
||||
{
|
||||
resolved: object.confirmed?,
|
||||
description: "Email confirmation is pending. We've sent a confirmation email to #{object.email}.",
|
||||
link: "<a class='button fullwidth' href='#{enterprise_confirmation_path(enterprise: { id: object.id, email: object.email } )}' method='post'>Resend Email</a>"
|
||||
}
|
||||
]
|
||||
issues = []
|
||||
|
||||
issues << {
|
||||
description: "#{object.name} currently has no shipping methods.",
|
||||
link: "<a class='button fullwidth' href='#{spree.new_admin_shipping_method_path}'>Create New</a>"
|
||||
} unless shipping_methods_ok?
|
||||
|
||||
issues << {
|
||||
description: "#{object.name} currently has no payment methods.",
|
||||
link: "<a class='button fullwidth' href='#{spree.new_admin_payment_method_path}'>Create New</a>"
|
||||
} unless payment_methods_ok?
|
||||
|
||||
issues << {
|
||||
description: "Email confirmation is pending. We've sent a confirmation email to #{object.email}.",
|
||||
link: "<a class='button fullwidth' href='#{enterprise_confirmation_path(enterprise: { id: object.id, email: object.email } )}' method='post'>Resend Email</a>"
|
||||
} unless object.confirmed?
|
||||
|
||||
issues
|
||||
end
|
||||
|
||||
def warnings
|
||||
[
|
||||
{
|
||||
resolved: object.visible,
|
||||
description: "#{object.name} is not visible and so cannot be found on the map or in searches",
|
||||
link: "<a class='button fullwidth' href='#{edit_admin_enterprise_path(object)}'>Edit</a>"
|
||||
}
|
||||
]
|
||||
warnings = []
|
||||
|
||||
warnings << {
|
||||
description: "#{object.name} is not visible and so cannot be found on the map or in searches",
|
||||
link: "<a class='button fullwidth' href='#{edit_admin_enterprise_path(object)}'>Edit</a>"
|
||||
} unless object.visible
|
||||
|
||||
warnings
|
||||
end
|
||||
end
|
||||
|
||||
@@ -89,12 +89,12 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
|
||||
def producers
|
||||
relatives = options[:data].relatives[object.id]
|
||||
relatives ? ids_to_objs(relatives[:producers]) : []
|
||||
ids_to_objs(relatives.andand[:producers])
|
||||
end
|
||||
|
||||
def hubs
|
||||
relatives = options[:data].relatives[object.id]
|
||||
relatives ? ids_to_objs(relatives[:distributors]) : []
|
||||
ids_to_objs(relatives.andand[:distributors])
|
||||
end
|
||||
|
||||
# Map svg icons.
|
||||
@@ -139,6 +139,7 @@ class Api::CachedEnterpriseSerializer < ActiveModel::Serializer
|
||||
private
|
||||
|
||||
def ids_to_objs(ids)
|
||||
ids.andand.map { |id| {id: id} }
|
||||
return [] if ids.blank?
|
||||
ids.map { |id| {id: id} }
|
||||
end
|
||||
end
|
||||
|
||||
@@ -50,8 +50,8 @@
|
||||
%h5{ ng: { bind: "producer" } }
|
||||
%td.package.panel-toggle.text-center{ ng: { show: 'columns.package.visible', class: "{error: packageError}" }, name: "package" }
|
||||
%h5{ ng: { bind: "package" } }
|
||||
%td.status.panel-toggle.text-center{ ng: { show: 'columns.status.visible' }, bo: { class: "statusClass" }, name: "status" }
|
||||
%i.status{ bo: { class: "status" } }
|
||||
%td.status.panel-toggle.text-center{ ng: { show: 'columns.status.visible' }, name: "status" }
|
||||
%i.icon-status{ bo: { class: "status" } }
|
||||
%td.manage{ ng: { show: 'columns.manage.visible' } }
|
||||
%a.button.fullwidth{ bo: { href: 'enterprise.edit_path' } }
|
||||
Manage
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
.row
|
||||
-# = render partial: 'shared/components/filter_controls'
|
||||
.small-12.medium-6.columns
|
||||
= render partial: 'shared/components/filter_controls'
|
||||
-# .small-12.medium-6.columns
|
||||
= render partial: 'shared/components/show_profiles'
|
||||
|
||||
-# .row.animate-show{"ng-show" => "filtersActive"}
|
||||
-# .small-12.columns
|
||||
-# .row.filter-box
|
||||
-# .small-12.large-9.columns
|
||||
-# %h5.tdhead
|
||||
-# .light Filter by
|
||||
-# Type
|
||||
-# %ul.small-block-grid-2.medium-block-grid-4.large-block-grid-5
|
||||
-# %filter-selector{objects: "Enterprises.hubs | searchEnterprises:query | taxonsOf", "active-selectors" => "activeTaxons"}
|
||||
-# .small-12.large-3.columns
|
||||
-# %h5.tdhead
|
||||
-# .light Filter by
|
||||
-# Delivery
|
||||
-# %ul.small-block-grid-2.medium-block-grid-4.large-block-grid-2
|
||||
-# %shipping-type-selector{results: "shippingTypes"}
|
||||
-#
|
||||
-# = render partial: 'shared/components/filter_box'
|
||||
.row.animate-show{"ng-show" => "filtersActive"}
|
||||
.small-12.columns
|
||||
.row.filter-box
|
||||
.small-12.large-9.columns
|
||||
%h5.tdhead
|
||||
.light Filter by
|
||||
Type
|
||||
%filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-5{ objects: "Enterprises.hubs | searchEnterprises:query | taxonsOf", "active-selectors" => "activeTaxons" }
|
||||
.small-12.large-3.columns
|
||||
%h5.tdhead
|
||||
.light Filter by
|
||||
Delivery
|
||||
%ul.small-block-grid-2.medium-block-grid-4.large-block-grid-2
|
||||
%shipping-type-selector{results: "shippingTypes"}
|
||||
|
||||
= render partial: 'shared/components/filter_box'
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
-# .row
|
||||
-# = render partial: 'shared/components/filter_controls'
|
||||
-# .small-12.medium-6.columns.text-right
|
||||
-#
|
||||
-#
|
||||
-# .row.animate-show{"ng-show" => "filtersActive"}
|
||||
-# .small-12.columns
|
||||
-# .row.filter-box
|
||||
-# .small-12.columns
|
||||
-# %h5.tdhead
|
||||
-# .light Filter by
|
||||
-# Type
|
||||
-# %ul.small-block-grid-2.medium-block-grid-4.large-block-grid-6
|
||||
-# %filter-selector{objects: "Enterprises.producers | searchEnterprises:query | taxonsOf", "active-selectors" => "activeTaxons"}
|
||||
-# = render partial: 'shared/components/filter_box'
|
||||
.row
|
||||
= render partial: 'shared/components/filter_controls'
|
||||
.small-12.medium-6.columns.text-right
|
||||
|
||||
|
||||
.row.animate-show{"ng-show" => "filtersActive"}
|
||||
.small-12.columns
|
||||
.row.filter-box
|
||||
.small-12.columns
|
||||
%h5.tdhead
|
||||
.light Filter by
|
||||
Type
|
||||
%filter-selector.small-block-grid-2.medium-block-grid-4.large-block-grid-6{objects: "Enterprises.producers | searchEnterprises:query | taxonsOf", "active-selectors" => "activeTaxons"}
|
||||
= render partial: 'shared/components/filter_box'
|
||||
|
||||
@@ -12,6 +12,11 @@ module OpenFoodNetwork
|
||||
it "only loads activated relatives" do
|
||||
subject.relatives[enterprise.id][:producers].should_not include producer_inactive.id
|
||||
end
|
||||
|
||||
it "loads self where appropiate" do
|
||||
subject.relatives[producer.id][:producers].should include producer.id
|
||||
subject.relatives[enterprise.id][:distributors].should include enterprise.id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -72,14 +72,20 @@ describe EnterpriseRelationship do
|
||||
|
||||
describe "finding relatives" do
|
||||
let(:e1) { create(:supplier_enterprise) }
|
||||
let(:e2) { create(:supplier_enterprise, sells: 'any') }
|
||||
let(:e2) { create(:distributor_enterprise) }
|
||||
let!(:er) { create(:enterprise_relationship, parent: e1, child: e2) }
|
||||
let(:er_reverse) { create(:enterprise_relationship, parent: e2, child: e1) }
|
||||
|
||||
it "includes self where appropriate" do
|
||||
EnterpriseRelationship.relatives[e2.id][:distributors].should include e2.id
|
||||
EnterpriseRelationship.relatives[e2.id][:producers].should_not include e2.id
|
||||
end
|
||||
|
||||
it "categorises enterprises into distributors and producers" do
|
||||
e2.update_attribute :is_primary_producer, true
|
||||
EnterpriseRelationship.relatives.should ==
|
||||
{e1.id => {distributors: Set.new([e2.id]), producers: Set.new([e2.id])},
|
||||
e2.id => {distributors: Set.new([]), producers: Set.new([e1.id])}}
|
||||
{e1.id => {distributors: Set.new([e2.id]), producers: Set.new([e1.id, e2.id])},
|
||||
e2.id => {distributors: Set.new([e2.id]), producers: Set.new([e2.id, e1.id])}}
|
||||
end
|
||||
|
||||
it "finds inactive enterprises by default" do
|
||||
|
||||
Reference in New Issue
Block a user