diff --git a/app/assets/javascripts/admin/order_cycles/controllers/edit.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/edit.js.coffee index fd426eb455..227c6a3045 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/edit.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/edit.js.coffee @@ -1,5 +1,5 @@ angular.module('admin.orderCycles') - .controller 'AdminEditOrderCycleCtrl', ($scope, $filter, $location, OrderCycle, Enterprise, EnterpriseFee, StatusMessage) -> + .controller 'AdminEditOrderCycleCtrl', ($scope, $filter, $location, $window, OrderCycle, Enterprise, EnterpriseFee, StatusMessage) -> order_cycle_id = $location.absUrl().match(/\/admin\/order_cycles\/(\d+)/)[1] $scope.enterprises = Enterprise.index(order_cycle_id: order_cycle_id) $scope.supplier_enterprises = Enterprise.producer_enterprises @@ -12,6 +12,9 @@ angular.module('admin.orderCycles') $scope.StatusMessage = StatusMessage + $scope.$watch 'order_cycle_form.$dirty', (newValue) -> + StatusMessage.display 'notice', 'You have unsaved changes' if newValue + $scope.loaded = -> Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded @@ -60,6 +63,7 @@ angular.module('admin.orderCycles') $scope.removeExchange = ($event, exchange) -> $event.preventDefault() OrderCycle.removeExchange(exchange) + $scope.order_cycle_form.$dirty = true $scope.addCoordinatorFee = ($event) -> $event.preventDefault() @@ -81,4 +85,9 @@ angular.module('admin.orderCycles') OrderCycle.removeDistributionOfVariant(variant_id) $scope.submit = (destination) -> + StatusMessage.display 'progress', "Saving..." OrderCycle.update(destination) + $scope.order_cycle_form.$setPristine() + + $scope.cancel = (destination) -> + $window.location = destination diff --git a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee index bf00bb3df1..99c2e2649c 100644 --- a/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee +++ b/app/assets/javascripts/admin/order_cycles/controllers/simple_edit.js.coffee @@ -9,6 +9,9 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", $scope.order_cycle = OrderCycle.load $scope.orderCycleId(), (order_cycle) => $scope.init() + $scope.$watch 'order_cycle_form.$dirty', (newValue) -> + StatusMessage.display 'notice', 'You have unsaved changes' if newValue + $scope.loaded = -> Enterprise.loaded && EnterpriseFee.loaded && OrderCycle.loaded @@ -35,5 +38,6 @@ angular.module('admin.orderCycles').controller "AdminSimpleEditOrderCycleCtrl", OrderCycle.removeCoordinatorFee(index) $scope.submit = (destination) -> + StatusMessage.display 'progress', "Saving..." OrderCycle.mirrorIncomingToOutgoingProducts() OrderCycle.update(destination) diff --git a/app/assets/javascripts/admin/utils/directives/save_bar.js.coffee b/app/assets/javascripts/admin/utils/directives/save_bar.js.coffee index 13e4f84bc6..0999679394 100644 --- a/app/assets/javascripts/admin/utils/directives/save_bar.js.coffee +++ b/app/assets/javascripts/admin/utils/directives/save_bar.js.coffee @@ -1,8 +1,8 @@ angular.module("admin.utils").directive "saveBar", (StatusMessage) -> restrict: "E" scope: - save: "&" form: "=" + buttons: "=" templateUrl: "admin/save_bar.html" link: (scope, element, attrs) -> scope.StatusMessage = StatusMessage diff --git a/app/assets/javascripts/templates/admin/save_bar.html.haml b/app/assets/javascripts/templates/admin/save_bar.html.haml index 452e81f6e3..08b7cbdf3d 100644 --- a/app/assets/javascripts/templates/admin/save_bar.html.haml +++ b/app/assets/javascripts/templates/admin/save_bar.html.haml @@ -1,6 +1,7 @@ #save-bar.animate-show{ ng: { show: 'form.$dirty || StatusMessage.active()' } } - .twelve.columns.alpha - %h5#status-message{ ng: { style: 'StatusMessage.statusMessage.style' } } - {{ StatusMessage.statusMessage.text || " " }} - .four.columns.omega.text-right - %input.red{type: "button", value: "Save Changes", ng: { disabled: '!form.$dirty', click: "save()" } } + .container + .eight.columns.alpha + %h5#status-message{ ng: { style: 'StatusMessage.statusMessage.style' } } + {{ StatusMessage.statusMessage.text || " " }} + .eight.columns.omega.text-right + %input{"ng-repeat" => "button in buttons", type: "button", value: "{{button.text}}", ng: { class: "button.class", click: "button.action(button.param)" } } diff --git a/app/assets/stylesheets/admin/components/save_bar.sass b/app/assets/stylesheets/admin/components/save_bar.sass index c6b1236490..87dcce82f9 100644 --- a/app/assets/stylesheets/admin/components/save_bar.sass +++ b/app/assets/stylesheets/admin/components/save_bar.sass @@ -1,9 +1,13 @@ #save-bar position: fixed + width: 100% bottom: 0px - padding: 8px 10px + left: 0 + padding: 8px 8px font-weight: bold - background-color: #fff + background-color: #eff5fc color: #5498da h5 color: #5498da + input + margin-right: 5px diff --git a/app/assets/stylesheets/admin/openfoodnetwork.css.scss b/app/assets/stylesheets/admin/openfoodnetwork.css.scss index 17d43ff3a5..1fc95face8 100644 --- a/app/assets/stylesheets/admin/openfoodnetwork.css.scss +++ b/app/assets/stylesheets/admin/openfoodnetwork.css.scss @@ -37,6 +37,7 @@ text-angular .ta-editor { input.red { background-color: #DA5354; + margin-right: 5px; } input.search { diff --git a/app/views/admin/order_cycles/_form.html.haml b/app/views/admin/order_cycles/_form.html.haml index c447d35d58..ed2d3acbc2 100644 --- a/app/views/admin/order_cycles/_form.html.haml +++ b/app/views/admin/order_cycles/_form.html.haml @@ -52,14 +52,10 @@ .actions - if @order_cycle.new_record? = f.submit 'Create', 'ng-click' => "submit('#{main_app.admin_order_cycles_path}')", 'ng-disabled' => '!loaded()' - - else - = f.submit 'Update', 'ng-click' => "submit(null)", 'ng-disabled' => '!loaded()' - = f.submit 'Update and Close', 'ng-click' => "submit('#{main_app.admin_order_cycles_path}')", 'ng-disabled' => '!loaded()' + %span{'ng-show' => 'loaded()'} - or = link_to 'Cancel', main_app.admin_order_cycles_path %span{'ng-hide' => 'loaded()'} Loading... - = render 'spree/admin/shared/status_message' - unless Rails.env.production? diff --git a/app/views/admin/order_cycles/_simple_form.html.haml b/app/views/admin/order_cycles/_simple_form.html.haml index 4dc64a012b..9364d080ff 100644 --- a/app/views/admin/order_cycles/_simple_form.html.haml +++ b/app/views/admin/order_cycles/_simple_form.html.haml @@ -23,12 +23,7 @@ .actions - if @order_cycle.new_record? = f.submit 'Create', 'ng-click' => "submit('#{main_app.admin_order_cycles_path}')", 'ng-disabled' => '!loaded()' - - else - = f.submit 'Update', 'ng-click' => "submit(null)", 'ng-disabled' => '!loaded()' - = f.submit 'Update and Close', 'ng-click' => "submit('#{main_app.admin_order_cycles_path}')", 'ng-disabled' => '!loaded()' %span{'ng-show' => 'loaded()'} - or = link_to 'Cancel', main_app.admin_order_cycles_path %span{'ng-hide' => 'loaded()'} Loading... - = render 'spree/admin/shared/status_message' diff --git a/app/views/admin/order_cycles/edit.html.haml b/app/views/admin/order_cycles/edit.html.haml index f3b0bdb721..9f85261224 100644 --- a/app/views/admin/order_cycles/edit.html.haml +++ b/app/views/admin/order_cycles/edit.html.haml @@ -27,7 +27,10 @@ - ng_controller = order_cycles_simple_form ? 'AdminSimpleEditOrderCycleCtrl' : 'AdminEditOrderCycleCtrl' -= form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller} do |f| += form_for [main_app, :admin, @order_cycle], :url => '', :html => {:class => 'ng order_cycle', 'ng-app' => 'admin.orderCycles', 'ng-controller' => ng_controller, name: 'order_cycle_form'} do |f| + + %save-bar{ buttons: "[{ text: 'Update', action: submit, param: null, class: 'red' }, { text: 'Update and Close', action: submit, param: '#{main_app.admin_order_cycles_path}', class: 'red' }, { text: 'Cancel', action: cancel, param: '#{main_app.admin_order_cycles_path}', class: '' }]", form: "order_cycle_form" } + - if order_cycles_simple_form = render 'simple_form', f: f - else diff --git a/app/views/admin/variant_overrides/_products.html.haml b/app/views/admin/variant_overrides/_products.html.haml index c17e4c189a..f255d86e0b 100644 --- a/app/views/admin/variant_overrides/_products.html.haml +++ b/app/views/admin/variant_overrides/_products.html.haml @@ -1,5 +1,5 @@ %form{ name: 'variant_overrides_form', ng: { show: "views.inventory.visible" } } - %save-bar{ save: "update()", form: "variant_overrides_form" } + %save-bar{ form: "variant_overrides_form", buttons: "[{ text: 'Save Changes', action: update, class: 'red' }]" } %table.index.bulk#variant-overrides %col.producer{ width: "20%", ng: { show: 'columns.producer.visible' } } %col.product{ width: "20%", ng: { show: 'columns.product.visible' } } diff --git a/app/views/spree/admin/orders/bulk_management.html.haml b/app/views/spree/admin/orders/bulk_management.html.haml index 43983e87ea..d8228b5c83 100644 --- a/app/views/spree/admin/orders/bulk_management.html.haml +++ b/app/views/spree/admin/orders/bulk_management.html.haml @@ -10,7 +10,7 @@ = render :partial => 'spree/admin/shared/order_sub_menu' %div{ ng: { controller: 'LineItemsCtrl' } } - %save-bar{ save: "submit()", form: "bulk_order_form" } + %save-bar{ form: "bulk_order_form", buttons: "[{ text: 'Save Changes', action: submit, class: 'red' }]" } .filters{ :class => "sixteen columns alpha" } .date_filter{ :class => "two columns alpha" } %label{ :for => 'start_date_filter' } diff --git a/spec/features/admin/order_cycles_spec.rb b/spec/features/admin/order_cycles_spec.rb index aafaa5ee77..cd5ef0a07e 100644 --- a/spec/features/admin/order_cycles_spec.rb +++ b/spec/features/admin/order_cycles_spec.rb @@ -267,6 +267,9 @@ feature %q{ scenario "updating an order cycle", js: true do + # Make the page long enough to avoid the save bar overlaying the form + page.driver.resize(1280, 3600) + # Given an order cycle with all the settings oc = create(:order_cycle) initial_variants = oc.variants.sort_by &:id @@ -359,6 +362,8 @@ feature %q{ select 'Distributor fee 2', from: 'order_cycle_outgoing_exchange_2_enterprise_fees_0_enterprise_fee_id' # And I click Update + expect(page).to have_selector "#save-bar" + save_screenshot('abc.png') click_button 'Update and Close' # Then my order cycle should have been updated @@ -607,10 +612,6 @@ feature %q{ page.all('tr.supplier').count.should == 3 page.all('tr.distributor').count.should == 3 - # When I save, then those exchanges should remain - click_button 'Update' - page.should have_content "Your order cycle has been updated." - oc.reload oc.suppliers.should match_array [supplier_managed, supplier_permitted, supplier_unmanaged] oc.coordinator.should == distributor_managed @@ -618,6 +619,9 @@ feature %q{ end scenario "editing an order cycle" do + # Make the page long enough to avoid the save bar overlaying the form + page.driver.resize(1280, 3600) + oc = create(:simple_order_cycle, { suppliers: [supplier_managed, supplier_permitted, supplier_unmanaged], coordinator: distributor_managed, distributors: [distributor_managed, distributor_permitted, distributor_unmanaged], name: 'Order Cycle 1' } ) visit edit_admin_order_cycle_path(oc) @@ -627,6 +631,7 @@ feature %q{ page.find("tr.supplier-#{supplier_permitted.id} a.remove-exchange").click page.find("tr.distributor-#{distributor_managed.id} a.remove-exchange").click page.find("tr.distributor-#{distributor_permitted.id} a.remove-exchange").click + click_button 'Update' # Then the exchanges should be removed @@ -698,10 +703,6 @@ feature %q{ # I should be able to see but not toggle v2, because I don't have permission expect(page).to have_field "order_cycle_outgoing_exchange_0_variants_#{v2.id}", disabled: true - # When I save, any exchanges that I can't manage remain - click_button 'Update' - page.should have_content "Your order cycle has been updated." - oc.reload oc.suppliers.should match_array [supplier_managed, supplier_permitted, supplier_unmanaged] oc.coordinator.should == distributor_managed @@ -751,10 +752,6 @@ feature %q{ # I should be able to see but not toggle v2, because I don't have permission expect(page).to have_field "order_cycle_incoming_exchange_0_variants_#{v2.id}", disabled: true - # When I save, any exchange that I can't manage remains - click_button 'Update' - page.should have_content "Your order cycle has been updated." - oc.reload oc.suppliers.should match_array [supplier_managed, supplier_permitted, supplier_unmanaged] oc.coordinator.should == distributor_managed @@ -868,6 +865,9 @@ feature %q{ end scenario "updating an order cycle" do + # Make the page long enough to avoid the save bar overlaying the form + page.driver.resize(1280, 3600) + # Given an order cycle with pickup time and instructions fee1 = create(:enterprise_fee, name: 'my fee', enterprise: enterprise) fee2 = create(:enterprise_fee, name: 'that fee', enterprise: enterprise) @@ -902,6 +902,7 @@ feature %q{ # When I update, or update and close, both work click_button 'Update' page.should have_content 'Your order cycle has been updated.' + click_button 'Update and Close' # Then my order cycle should have been updated diff --git a/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee b/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee index dbad5a9f05..f5ccd25aac 100644 --- a/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee +++ b/spec/javascripts/unit/admin/order_cycles/controllers/simple_edit.js.coffee @@ -10,7 +10,8 @@ describe "AdminSimpleEditOrderCycleCtrl", -> outgoing_exchange = {} beforeEach -> - scope = {} + scope = + $watch: jasmine.createSpy('$watch') location = absUrl: -> 'example.com/admin/order_cycles/27/edit' diff --git a/spec/javascripts/unit/order_cycle_spec.js.coffee b/spec/javascripts/unit/order_cycle_spec.js.coffee index 973b348383..b66acfcb1d 100644 --- a/spec/javascripts/unit/order_cycle_spec.js.coffee +++ b/spec/javascripts/unit/order_cycle_spec.js.coffee @@ -169,7 +169,9 @@ describe 'OrderCycle controllers', -> EnterpriseFee = null beforeEach -> - scope = {} + scope = + order_cycle_form: jasmine.createSpyObj('order_cycle_form', ['$dirty', '$setPristine']) + $watch: jasmine.createSpy('$watch') event = preventDefault: jasmine.createSpy('preventDefault') location = @@ -292,6 +294,7 @@ describe 'OrderCycle controllers', -> scope.removeExchange(event, 'exchange') expect(event.preventDefault).toHaveBeenCalled() expect(OrderCycle.removeExchange).toHaveBeenCalledWith('exchange') + expect(scope.order_cycle_form.$dirty).toEqual true it 'Adds coordinator fees', -> scope.addCoordinatorFee(event) @@ -320,6 +323,7 @@ describe 'OrderCycle controllers', -> it 'Submits the order cycle via OrderCycle update', -> scope.submit('/admin/order_cycles') expect(OrderCycle.update).toHaveBeenCalledWith('/admin/order_cycles') + expect(scope.order_cycle_form.$setPristine.calls.length).toEqual 1 describe 'OrderCycle services', ->