diff --git a/app/assets/javascripts/admin/bulk_product_update.js.coffee b/app/assets/javascripts/admin/bulk_product_update.js.coffee deleted file mode 100644 index ab62e3f321..0000000000 --- a/app/assets/javascripts/admin/bulk_product_update.js.coffee +++ /dev/null @@ -1,390 +0,0 @@ -angular.module("ofn.admin").controller "AdminProductEditCtrl", ($scope, $timeout, $filter, $http, $window, $location, BulkProducts, DisplayProperties, DirtyProducts, VariantUnitManager, StatusMessage, producers, Taxons, Columns, tax_categories, RequestMonitor, SortOptions, ErrorsParser, ProductFiltersUrl) -> - $scope.StatusMessage = StatusMessage - - $scope.columns = Columns.columns - - $scope.variant_unit_options = VariantUnitManager.variantUnitOptions() - - $scope.RequestMonitor = RequestMonitor - $scope.pagination = BulkProducts.pagination - $scope.per_page_options = [ - {id: 15, name: t('js.admin.orders.index.per_page', results: 15)}, - {id: 50, name: t('js.admin.orders.index.per_page', results: 50)}, - {id: 100, name: t('js.admin.orders.index.per_page', results: 100)} - ] - - $scope.q = { - producerFilter: "" - categoryFilter: "" - importDateFilter: "" - query: "" - sorting: "" - } - - $scope.sorting = "name asc" - $scope.producers = producers - $scope.taxons = Taxons.all - $scope.tax_categories = tax_categories - $scope.page = 1 - $scope.per_page = 15 - $scope.products = BulkProducts.products - $scope.DisplayProperties = DisplayProperties - - $scope.sortOptions = SortOptions - - $scope.initialise = -> - $scope.q = ProductFiltersUrl.loadFromUrl($location.search()) - $scope.fetchProducts() - - $scope.$watchCollection '[q.query, q.producerFilter, q.categoryFilter, q.importDateFilter, per_page]', -> - $scope.page = 1 # Reset page when changing filters for new search - - $scope.changePage = (newPage) -> - $scope.page = newPage - $scope.fetchProducts() - - $scope.fetchProducts = -> - removeClearedValues() - params = { - 'q[name_cont]': $scope.q.query, - 'q[variants_supplier_id_eq]': $scope.q.producerFilter, - 'q[variants_primary_taxon_id_eq]': $scope.q.categoryFilter, - 'q[s]': $scope.sorting, - import_date: $scope.q.importDateFilter, - page: $scope.page, - per_page: $scope.per_page - } - RequestMonitor.load(BulkProducts.fetch(params).$promise).then -> - # update url with the filters used - $location.search(ProductFiltersUrl.generate($scope.q)) - $scope.resetProducts() - - removeClearedValues = -> - delete $scope.q.producerFilter if $scope.q.producerFilter == "0" - delete $scope.q.categoryFilter if $scope.q.categoryFilter == "0" - delete $scope.q.importDateFilter if $scope.q.importDateFilter == "0" - - $timeout -> - if $scope.showLatestImport - $scope.q.importDateFilter = $scope.importDates[1].id - - $scope.resetProducts = -> - DirtyProducts.clear() - StatusMessage.clear() - - $scope.updateOnHand = (product) -> - on_demand_variants = [] - if product.variants - on_demand_variants = (variant for id, variant of product.variants when variant.on_demand) - - unless product.on_demand || on_demand_variants.length > 0 - product.on_hand = $scope.onHand(product) - - - $scope.onHand = (product) -> - onHand = 0 - if product.hasOwnProperty("variants") and product.variants instanceof Object - for id, variant of product.variants - onHand = onHand + parseInt(if variant.on_hand > 0 then variant.on_hand else 0) - else - onHand = "error" - onHand - - $scope.shiftTab = (tab) -> - $scope.visibleTab.visible = false unless $scope.visibleTab == tab || $scope.visibleTab == undefined - tab.visible = !tab.visible - $scope.visibleTab = tab - - $scope.resetSelectFilters = -> - $scope.q.query = "" - $scope.q.producerFilter = "0" - $scope.q.categoryFilter = "0" - $scope.q.importDateFilter = "0" - $scope.fetchProducts() - - $scope.$watch 'sortOptions', (sort) -> - return unless sort && sort.predicate != "" - - $scope.sorting = sort.getSortingExpr(defaultDirection: "asc") - $scope.fetchProducts() - , true - - confirm_unsaved_changes = () -> - (DirtyProducts.count() > 0 and confirm(t("unsaved_changes_confirmation"))) or (DirtyProducts.count() == 0) - - editProductUrl = (product, variant) -> - "/admin/products/" + product.id + ((if variant then "/variants/" + variant.id else "")) + "/edit" - - $scope.editWarn = (product, variant) -> - if confirm_unsaved_changes() - $window.location.href = ProductFiltersUrl.buildUrl(editProductUrl(product, variant), $scope.q) - - $scope.toggleShowAllVariants = -> - showVariants = !DisplayProperties.showVariants 0 - $scope.products.forEach (product) -> - DisplayProperties.setShowVariants product.id, showVariants - DisplayProperties.setShowVariants 0, showVariants - - $scope.addVariant = (product) -> - # Set new variant category to same as last product variant category to keep compactibility with deleted variant callback to set new variant category - newVariantId = $scope.nextVariantId(); - newVariantCategoryId = product.variants[product.variants.length - 1]?.category_id - product.variants.push - id: newVariantId - unit_value: null - unit_description: null - on_demand: false - display_as: null - display_name: null - on_hand: null - price: null - tax_category_id: null - category_id: newVariantCategoryId - DisplayProperties.setShowVariants product.id, true - DirtyProducts.addVariantProperty(product.id, newVariantId, 'category_id', newVariantCategoryId) - - - $scope.nextVariantId = -> - $scope.variantIdCounter = 0 unless $scope.variantIdCounter? - $scope.variantIdCounter -= 1 - $scope.variantIdCounter - - $scope.deleteProduct = (product) -> - if confirm(t('are_you_sure')) - $http( - method: "DELETE" - url: "/api/v0/products/" + product.id - ).then (response) -> - $scope.products.splice $scope.products.indexOf(product), 1 - DirtyProducts.deleteProduct product.id - $scope.displayDirtyProducts() - - - $scope.deleteVariant = (product, variant) -> - if product.variants.length > 1 - if !$scope.variantSaved(variant) - $scope.removeVariant(product, variant) - else - if confirm(t("are_you_sure")) - $http( - method: "DELETE" - url: "/api/v0/products/" + product.id + "/variants/" + variant.id - ).then (response) -> - $scope.removeVariant(product, variant) - else - alert(t("delete_product_variant")) - - $scope.removeVariant = (product, variant) -> - product.variants.splice product.variants.indexOf(variant), 1 - DirtyProducts.deleteVariant product.id, variant.id - $scope.displayDirtyProducts() - - - $scope.cloneProduct = (product) -> - BulkProducts.cloneProduct product - - $scope.hasVariants = (product) -> - product.variants.length > 0 - - - $scope.hasUnit = (variant) -> - variant.variant_unit_with_scale? - - $scope.variantSaved = (variant) -> - variant.hasOwnProperty('id') && variant.id > 0 - - - $scope.hasOnDemandVariants = (product) -> - (variant for id, variant of product.variants when variant.on_demand).length > 0 - - - $scope.submitProducts = -> - # Pack pack $scope.products, so they will match the list returned from the server, - # then pack $scope.dirtyProducts, ensuring that the correct product info is sent to the server. - $scope.packProduct product for id, product of $scope.products - $scope.packProduct product for id, product of DirtyProducts.all() - - productsToSubmit = filterSubmitProducts(DirtyProducts.all()) - if productsToSubmit.length > 0 - $scope.updateProducts productsToSubmit # Don't submit an empty list - else - StatusMessage.display 'alert', t("products_change") - - - $scope.updateProducts = (productsToSubmit) -> - $scope.displayUpdating() - $http( - method: "POST" - url: "/admin/products/bulk_update" - data: - products: productsToSubmit - filters: - 'q[name_cont]': $scope.q.query - 'q[variants_supplier_id_eq]': $scope.q.producerFilter - 'q[variants_primary_taxon_id_eq]': $scope.q.categoryFilter - 'q[s]': $scope.sorting - import_date: $scope.q.importDateFilter - page: $scope.page - per_page: $scope.per_page - ).then((response) -> - DirtyProducts.clear() - BulkProducts.updateVariantLists(response.data.products || []) - $timeout -> $scope.displaySuccess() - ).catch (response) -> - if response.status == 400 && response.data.errors? - errorsString = ErrorsParser.toString(response.data.errors, response.status) - $scope.displayFailure t("products_update_error") + "\n" + errorsString - else - $scope.displayFailure t("products_update_error_data") + response.status - - $scope.cancel = (destination) -> - $window.location = destination - - $scope.packProduct = (product) -> - if product.variants - for id, variant of product.variants - $scope.packVariant variant - - - $scope.packVariant = (variant) -> - if variant.variant_unit_with_scale - match = variant.variant_unit_with_scale.match(/^([^_]+)_([\d\.]+)$/) - if match - variant.variant_unit = match[1] - variant.variant_unit_scale = parseFloat(match[2]) - else - variant.variant_unit = variant.variant_unit_with_scale - variant.variant_unit_scale = null - - if variant.hasOwnProperty("unit_value_with_description") - match = variant.unit_value_with_description.match(/^([\d\.\,]+(?= |$)|)( |)(.*)$/) - if match - variant.unit_value = parseFloat(match[1].replace(",", ".")) - variant.unit_value = null if isNaN(variant.unit_value) - if variant.unit_value && variant.variant_unit_scale - variant.unit_value = parseFloat(window.bigDecimal.multiply(variant.unit_value, variant.variant_unit_scale, 2)) - variant.unit_description = match[3] - - $scope.incrementLimit = -> - if $scope.limit < $scope.products.length - $scope.limit = $scope.limit + 5 - - - $scope.displayUpdating = -> - StatusMessage.display 'progress', t("saving") - - - $scope.displaySuccess = -> - StatusMessage.display 'success',t("products_changes_saved") - $scope.bulk_product_form.$setPristine() - - - $scope.displayFailure = (failMessage) -> - StatusMessage.display 'failure', t("products_update_error_msg") + " #{failMessage}" - - - $scope.displayDirtyProducts = -> - count = DirtyProducts.count() - switch count - when 0 then StatusMessage.clear() - when 1 then StatusMessage.display 'notice', t("one_product_unsaved") - else StatusMessage.display 'notice', t("products_unsaved", n: count) - - -filterSubmitProducts = (productsToFilter) -> - filteredProducts = [] - if productsToFilter instanceof Object - angular.forEach productsToFilter, (product) -> - if product.hasOwnProperty("id") - filteredProduct = {id: product.id} - filteredVariants = [] - hasUpdatableProperty = false - - if product.hasOwnProperty("variants") - angular.forEach product.variants, (variant) -> - result = filterSubmitVariant variant - filteredVariant = result.filteredVariant - variantHasUpdatableProperty = result.hasUpdatableProperty - filteredVariants.push filteredVariant if variantHasUpdatableProperty - - if product.hasOwnProperty("name") - filteredProduct.name = product.name - hasUpdatableProperty = true - if product.hasOwnProperty("price") - filteredProduct.price = product.price - hasUpdatableProperty = true - if product.hasOwnProperty("on_hand") and filteredVariants.length == 0 #only update if no variants present - filteredProduct.on_hand = product.on_hand - hasUpdatableProperty = true - if product.hasOwnProperty("on_demand") and filteredVariants.length == 0 #only update if no variants present - filteredProduct.on_demand = product.on_demand - hasUpdatableProperty = true - if product.hasOwnProperty("inherits_properties") - filteredProduct.inherits_properties = product.inherits_properties - hasUpdatableProperty = true - if filteredVariants.length > 0 # Note that the name of the property changes to enable mass assignment of variants attributes with rails - filteredProduct.variants_attributes = filteredVariants - hasUpdatableProperty = true - filteredProducts.push filteredProduct if hasUpdatableProperty - - filteredProducts - - -filterSubmitVariant = (variant) -> - hasUpdatableProperty = false - filteredVariant = {} - if not variant.deleted_at? and variant.hasOwnProperty("id") - filteredVariant.id = variant.id unless variant.id <= 0 - if variant.hasOwnProperty("sku") - filteredVariant.sku = variant.sku - hasUpdatableProperty = true - if variant.hasOwnProperty("on_hand") - filteredVariant.on_hand = variant.on_hand - hasUpdatableProperty = true - if variant.hasOwnProperty("on_demand") - filteredVariant.on_demand = variant.on_demand - hasUpdatableProperty = true - if variant.hasOwnProperty("price") - filteredVariant.price = variant.price - hasUpdatableProperty = true - if variant.hasOwnProperty("unit_value") - filteredVariant.unit_value = variant.unit_value - hasUpdatableProperty = true - if variant.hasOwnProperty("unit_description") - filteredVariant.unit_description = variant.unit_description - hasUpdatableProperty = true - if variant.hasOwnProperty("display_name") - filteredVariant.display_name = variant.display_name - hasUpdatableProperty = true - if variant.hasOwnProperty("tax_category_id") - filteredVariant.tax_category_id = variant.tax_category_id - hasUpdatableProperty = true - if variant.hasOwnProperty("category_id") - filteredVariant.primary_taxon_id = variant.category_id - hasUpdatableProperty = true - if variant.hasOwnProperty("display_as") - filteredVariant.display_as = variant.display_as - hasUpdatableProperty = true - if variant.hasOwnProperty("producer_id") - filteredVariant.supplier_id = variant.producer_id - hasUpdatableProperty = true - if variant.hasOwnProperty("variant_unit_with_scale") - filteredVariant.variant_unit = variant.variant_unit - filteredVariant.variant_unit_scale = variant.variant_unit_scale - hasUpdatableProperty = true - if variant.hasOwnProperty("variant_unit_name") - filteredVariant.variant_unit_name = variant.variant_unit_name - hasUpdatableProperty = true - - {filteredVariant: filteredVariant, hasUpdatableProperty: hasUpdatableProperty} - - -toObjectWithIDKeys = (array) -> - object = {} - - for i of array - if array[i] instanceof Object and array[i].hasOwnProperty("id") - object[array[i].id] = angular.copy(array[i]) - object[array[i].id].variants = toObjectWithIDKeys(array[i].variants) if array[i].hasOwnProperty("variants") and array[i].variants instanceof Array - - object diff --git a/app/assets/javascripts/admin/products/controllers/product_image_controller.js.coffee b/app/assets/javascripts/admin/products/controllers/product_image_controller.js.coffee deleted file mode 100644 index fb447208e2..0000000000 --- a/app/assets/javascripts/admin/products/controllers/product_image_controller.js.coffee +++ /dev/null @@ -1,8 +0,0 @@ -angular.module("ofn.admin").controller "ProductImageCtrl", ($scope, ProductImageService) -> - $scope.imageUploader = ProductImageService.imageUploader - $scope.imagePreview = ProductImageService.imagePreview - - $scope.$watch 'product.image_url', (newValue, oldValue) -> - if newValue != oldValue - $scope.imagePreview = newValue - $scope.uploadModal.close() diff --git a/app/assets/javascripts/admin/products/directives/image_modal.js.coffee b/app/assets/javascripts/admin/products/directives/image_modal.js.coffee deleted file mode 100644 index 69ca1731fd..0000000000 --- a/app/assets/javascripts/admin/products/directives/image_modal.js.coffee +++ /dev/null @@ -1,6 +0,0 @@ -angular.module("ofn.admin").directive "imageModal", ($modal, ProductImageService) -> - restrict: 'C' - link: (scope, elem, attrs, ctrl) -> - elem.on "click", (ev) => - scope.uploadModal = $modal.open(templateUrl: 'admin/modals/image_upload.html', controller: ctrl, scope: scope, windowClass: 'simple-modal') - ProductImageService.configure(scope.product) diff --git a/app/assets/javascripts/admin/resources/resources/product_resource.js.coffee b/app/assets/javascripts/admin/resources/resources/product_resource.js.coffee deleted file mode 100644 index 7d842d8eed..0000000000 --- a/app/assets/javascripts/admin/resources/resources/product_resource.js.coffee +++ /dev/null @@ -1,6 +0,0 @@ -angular.module("admin.resources").factory 'ProductResource', ($resource) -> - $resource('/admin/product/:id/:action.json', {}, { - 'index': - url: '/api/v0/products/bulk_products.json' - method: 'GET' - }) diff --git a/app/assets/javascripts/admin/services/bulk_products.js.coffee b/app/assets/javascripts/admin/services/bulk_products.js.coffee deleted file mode 100644 index a2823bf997..0000000000 --- a/app/assets/javascripts/admin/services/bulk_products.js.coffee +++ /dev/null @@ -1,76 +0,0 @@ -angular.module("ofn.admin").factory "BulkProducts", (ProductResource, dataFetcher, $http) -> - new class BulkProducts - products: [] - pagination: {} - - fetch: (params) -> - ProductResource.index params, (data) => - @products.length = 0 - @addProducts data.products - angular.extend(@pagination, data.pagination) - - cloneProduct: (product) -> - $http.post("/api/v0/products/" + product.id + "/clone").then (response) => - dataFetcher("/api/v0/products/" + response.data.id + "?template=bulk_show").then (newProduct) => - @unpackProduct newProduct - @insertProductAfter(product, newProduct) - - updateVariantLists: (serverProducts) -> - for server_product in serverProducts - product = @findProductInList(server_product.id, @products) - product.variants = server_product.variants - @loadVariantUnitValues product.variants - - find: (id) -> - @findProductInList id, @products - - findProductInList: (id, product_list) -> - products = (product for product in product_list when product.id == id) - if products.length == 0 then null else products[0] - - addProducts: (products) -> - for product in products - @unpackProduct product - @products.push product - - insertProductAfter: (product, newProduct) -> - index = @products.indexOf(product) - @products.splice(index + 1, 0, newProduct) - - unpackProduct: (product) -> - @loadVariantUnit product - - loadVariantUnit: (product) -> - @loadVariantUnitValues product.variants if product.variants - - loadVariantUnitValues: (variants) -> - for variant in variants - @loadVariantUnitValue variant - - loadVariantUnitValue: (variant) -> - variant.variant_unit_with_scale = - if variant.variant_unit && variant.variant_unit_scale && variant.variant_unit != 'items' - "#{variant.variant_unit}_#{variant.variant_unit_scale}" - else if variant.variant_unit - variant.variant_unit - else - null - - unit_value = @variantUnitValue variant - unit_value = if unit_value? then unit_value else '' - variant.unit_value_with_description = "#{unit_value} #{variant.unit_description || ''}".trim() - - variantUnitValue: (variant) -> - if variant.unit_value? - if variant.variant_unit_scale - variant_unit_value = @divideAsInteger variant.unit_value, variant.variant_unit_scale - parseFloat(window.bigDecimal.round(variant_unit_value, 2)) - else - variant.unit_value - else - null - - # forces integer division to avoid javascript floating point imprecision - # using one billion as the multiplier so that it works for numbers with up to 9 decimal places - divideAsInteger: (a, b) -> - (a * 1000000000) / (b * 1000000000) diff --git a/app/controllers/spree/admin/products_controller.rb b/app/controllers/spree/admin/products_controller.rb index f51ba5503e..2e036ffdb6 100644 --- a/app/controllers/spree/admin/products_controller.rb +++ b/app/controllers/spree/admin/products_controller.rb @@ -19,11 +19,6 @@ module Spree before_action :load_spree_api_key, only: [:index, :variant_overrides] before_action :strip_new_properties, only: [:create, :update] - def index - @current_user = spree_current_user - @show_latest_import = params[:latest_import] || false - end - def show session[:return_to] ||= request.referer redirect_to( action: :edit ) @@ -65,28 +60,6 @@ module Spree end end - def bulk_update - product_set = product_set_from_params - - product_set.collection.each { |p| authorize! :update, p } - - if product_set.save - redirect_to main_app.bulk_products_api_v0_products_path(bulk_index_query) - elsif product_set.errors.present? - render json: { errors: product_set.errors }, status: :bad_request - else - render body: nil, status: :internal_server_error - end - end - - def clone - @new = @product.duplicate - raise "Clone failed" unless @new.save - - flash[:success] = t('.success') - redirect_to spree.admin_products_url - end - def group_buy_options @url_filters = ::ProductFilters.new.extract(request.query_parameters) end diff --git a/app/helpers/admin/products_helper.rb b/app/helpers/admin/products_helper.rb index b2f7beada9..d7b8a2086f 100644 --- a/app/helpers/admin/products_helper.rb +++ b/app/helpers/admin/products_helper.rb @@ -32,12 +32,8 @@ module Admin [precised_unit_value, variant.unit_description].compact_blank.join(" ") end - def products_return_to_url(url_filters) - if feature?(:admin_style_v3, spree_current_user) - return session[:products_return_to_url] || admin_products_url - end - - "#{admin_products_path}#{url_filters.empty? ? '' : "#?#{url_filters.to_query}"}" + def products_return_to_url + session[:products_return_to_url] || admin_products_url end # if user hasn't saved any preferences on products page and there's only one producer; diff --git a/app/helpers/spree/admin/navigation_helper.rb b/app/helpers/spree/admin/navigation_helper.rb index 7b408e5ef5..ccb141043f 100644 --- a/app/helpers/spree/admin/navigation_helper.rb +++ b/app/helpers/spree/admin/navigation_helper.rb @@ -29,13 +29,7 @@ module Spree scope: [:admin, :tab]).capitalize css_classes = [] - - if options[:icon] && !feature?(:admin_style_v3, spree_current_user) - link = link_to_with_icon(options[:icon], titleized_label, destination_url) - css_classes << 'tab-with-icon' - else - link = link_to(titleized_label, destination_url) - end + link = link_to(titleized_label, destination_url) selected = if options[:match_path] PathChecker diff --git a/app/views/admin/products_v3/_table.html.haml b/app/views/admin/products_v3/_table.html.haml index 5226461c94..15d7646c6c 100644 --- a/app/views/admin/products_v3/_table.html.haml +++ b/app/views/admin/products_v3/_table.html.haml @@ -1,4 +1,4 @@ -= form_with url: bulk_update_admin_products_path, method: :post, id: "products-form", += form_with url: admin_products_bulk_update_path, method: :post, id: "products-form", builder: BulkFormBuilder, html: { data: { 'turbo-frame': "_self", controller: "bulk-form", diff --git a/app/views/admin/shared/_stimulus_pagination.html.haml b/app/views/admin/shared/_stimulus_pagination.html.haml index ec73ecb92b..632b766653 100644 --- a/app/views/admin/shared/_stimulus_pagination.html.haml +++ b/app/views/admin/shared/_stimulus_pagination.html.haml @@ -3,10 +3,7 @@ .pagination{ "data-controller": "search" } - if pagy.prev %button.page.prev{ data: { action: 'click->search#changePage', page: pagy.prev } } - - if feature?(:admin_style_v3, spree_current_user) - %i.icon-chevron-left{ data: { action: 'click->search#changePage', page: pagy.prev } } - - else - != pagy_t('pagy.prev') + %i.icon-chevron-left{ data: { action: 'click->search#changePage', page: pagy.prev } } - else %button.page.disabled{disabled: "disabled"}!= pagy_t('pagy.prev') @@ -22,9 +19,6 @@ - if pagy.next %button.page.next{ data: { action: 'click->search#changePage', page: pagy.next } } - - if feature?(:admin_style_v3, spree_current_user) - %i.icon-chevron-right{ data: { action: 'click->search#changePage', page: pagy.next } } - - else - != pagy_t('pagy.next') + %i.icon-chevron-right{ data: { action: 'click->search#changePage', page: pagy.next } } - else %button.page.disabled.pagination-next{disabled: "disabled"}!= pagy_t('pagy.next') diff --git a/app/views/spree/admin/products/edit.html.haml b/app/views/spree/admin/products/edit.html.haml index 003a35eee6..7f6df174db 100644 --- a/app/views/spree/admin/products/edit.html.haml +++ b/app/views/spree/admin/products/edit.html.haml @@ -1,7 +1,7 @@ = admin_inject_available_units - content_for :page_actions do - %li= button_link_to t('admin.products.back_to_products_list'), products_return_to_url(@url_filters), :icon => 'icon-arrow-left' + %li= button_link_to t('admin.products.back_to_products_list'), products_return_to_url, :icon => 'icon-arrow-left' %li#new_product_link = button_link_to t(:new_product), new_object_url, { :icon => 'icon-plus', :id => 'admin_new_product' } @@ -18,6 +18,6 @@ = button t(:update), 'icon-refresh' - = button_link_to t(:cancel), products_return_to_url(@url_filters), icon: 'icon-remove' + = button_link_to t(:cancel), products_return_to_url, icon: 'icon-remove' #product-preview-modal-container diff --git a/app/views/spree/admin/products/index.html.haml b/app/views/spree/admin/products/index.html.haml deleted file mode 100644 index b78c73cb4f..0000000000 --- a/app/views/spree/admin/products/index.html.haml +++ /dev/null @@ -1,14 +0,0 @@ -= render 'spree/admin/products/index/header' -= render 'spree/admin/products/index/data' -= admin_inject_available_units - -%div{ "ng-app": 'ofn.admin', "ng-controller": 'AdminProductEditCtrl', "ng-init": 'initialise()' } - - = render 'spree/admin/products/index/filters' - %div{ 'ng-cloak' => true } - = render 'spree/admin/products/index/actions' - = render 'spree/admin/products/index/indicators' - = render 'spree/admin/products/index/products' - - %div{'ng-show' => "!RequestMonitor.loading && products.length > 0" } - = render partial: 'admin/shared/angular_pagination' diff --git a/app/views/spree/admin/products/index/_actions.html.haml b/app/views/spree/admin/products/index/_actions.html.haml deleted file mode 100644 index aea4ebeb61..0000000000 --- a/app/views/spree/admin/products/index/_actions.html.haml +++ /dev/null @@ -1,11 +0,0 @@ -.controls.sixteen.columns.alpha{ 'ng-hide' => 'RequestMonitor.loading || products.length == 0' } - .ten.columns.alpha.index-controls - .per-page{'ng-show' => '!RequestMonitor.loading && products.length > 0'} - %input.per-page-select.ofn-select2{type: 'number', data: 'per_page_options', 'min-search' => 999, 'ng-model' => 'per_page', 'ng-change' => 'fetchProducts()'} - - %span.per-page-feedback - {{ 'spree.admin.orders.index.results_found' | t:{number: pagination.results} }} - {{ 'spree.admin.orders.index.viewing' | t:{start: ((pagination.page -1) * pagination.per_page) +1, end: ((pagination.page -1) * pagination.per_page) + products.length} }} - - .six.columns.omega - %columns-dropdown{ action: "#{controller_name}_#{action_name}" } diff --git a/app/views/spree/admin/products/index/_data.html.haml b/app/views/spree/admin/products/index/_data.html.haml deleted file mode 100644 index 13a6dc780e..0000000000 --- a/app/views/spree/admin/products/index/_data.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -= admin_inject_producers(@producers) -= admin_inject_taxons(@taxons) -= admin_inject_tax_categories(@tax_categories) -= admin_inject_spree_api_key(@spree_api_key) -= admin_inject_column_preferences diff --git a/app/views/spree/admin/products/index/_filters.html.haml b/app/views/spree/admin/products/index/_filters.html.haml deleted file mode 100644 index 57615eb09e..0000000000 --- a/app/views/spree/admin/products/index/_filters.html.haml +++ /dev/null @@ -1,33 +0,0 @@ -%fieldset - %legend{align: 'center'}= t(:search) - - .filters.sixteen.columns.alpha.omega - .quick_search.three.columns.alpha - %label{ for: 'quick_filter' } - %br - %input.quick-search.fullwidth{ name: "quick_filter", type: 'text', placeholder: t('admin.quick_search'), "ng-keypress": "$event.keyCode === 13 && fetchProducts()", "ng-model": 'q.query' } - .one.columns   - .filter_select.three.columns - %label{ for: 'producer_filter' }= t 'producer' - %br - %select.fullwidth{ id: 'producer_filter', "ofn-select2-min-search": 5, "ng-model": 'q.producerFilter', "ng-options": 'producer.id as producer.name for producer in producers' } - .filter_select.three.columns - %label{ for: 'category_filter' }= t 'category' - %br - %select.fullwidth{ id: 'category_filter', "ofn-select2-min-search": 5, "ng-model": 'q.categoryFilter', "ng-options": 'taxon.id as taxon.name for taxon in taxons' } - .filter_select.three.columns - %label{ for: 'import_filter' }= t 'import_date' - %br - %select.fullwidth{ id: 'import_date_filter', "ofn-select2-min-search": 5, "ng-model": 'q.importDateFilter', "ng-init": "importDates = #{@import_dates}; showLatestImport = #{@show_latest_import}", "ng-options": 'date.id as date.name for date in importDates' } - - .filter_clear.three.columns.omega - %label{ for: 'clear_all_filters' } - %br - %input.fullwidth.red{ :type => 'button', :id => 'clear_all_filters', :value => t('admin.clear_filters'), 'ng-click' => "resetSelectFilters()" } - - .clearfix - - .actions.filter-actions - %div - %a.button.icon-search{'ng-click' => 'fetchProducts()'} - = t(:filter_results) diff --git a/app/views/spree/admin/products/index/_header.html.haml b/app/views/spree/admin/products/index/_header.html.haml deleted file mode 100644 index f3314a1a39..0000000000 --- a/app/views/spree/admin/products/index/_header.html.haml +++ /dev/null @@ -1,10 +0,0 @@ -- content_for :page_title do - = t('.title') - -- content_for :page_actions do - %div{ :class => "toolbar" } - %ul{ :class => "actions header-action-links inline-menu" } - %li#new_product_link - = button_link_to t(:new_product), new_object_url, { :icon => 'icon-plus', :id => 'admin_new_product' } - -= render partial: 'spree/admin/shared/product_sub_menu' diff --git a/app/views/spree/admin/products/index/_indicators.html.haml b/app/views/spree/admin/products/index/_indicators.html.haml deleted file mode 100644 index 2907c04074..0000000000 --- a/app/views/spree/admin/products/index/_indicators.html.haml +++ /dev/null @@ -1,14 +0,0 @@ -.sixteen.columns.alpha#loading{ 'ng-if' => 'RequestMonitor.loading' } - = render partial: "components/admin_spinner" - %h1 - = t('.title') - -.sixteen.columns.alpha{ 'ng-show' => '!RequestMonitor.loading && products.length == 0 && q.query.length == 0' } - %h1#no_results= t('.no_products') - -.sixteen.columns.alpha{ 'ng-show' => '!RequestMonitor.loading && products.length == 0 && q.query.length != 0' } - %h1#no_results - = t('.no_results') - ' - {{q.query}} - ' diff --git a/app/views/spree/admin/products/index/_products.html.haml b/app/views/spree/admin/products/index/_products.html.haml deleted file mode 100644 index 032c783e7f..0000000000 --- a/app/views/spree/admin/products/index/_products.html.haml +++ /dev/null @@ -1,14 +0,0 @@ -.sixteen.columns.alpha{ 'ng-hide' => 'RequestMonitor.loading || products.length == 0' } - %form{ name: 'bulk_product_form', autocomplete: "off" } - %save-bar{ dirty: "bulk_product_form.$dirty", persist: "false" } - %input.red{ type: "button", value: t(:save_changes), "ng-click": "submitProducts()", "ng-disabled": "!bulk_product_form.$dirty" } - %input{ type: "button", value: t(:close), 'ng-click' => "cancel('#{admin_products_path}')" } - - %table.index#listing_products.bulk - - = render 'spree/admin/products/index/products_head' - - %tbody{ 'ng-repeat' => 'product in products', 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'" } - - = render 'spree/admin/products/index/products_product' - = render 'spree/admin/products/index/products_variant' diff --git a/app/views/spree/admin/products/index/_products_head.html.haml b/app/views/spree/admin/products/index/_products_head.html.haml deleted file mode 100644 index 9e6d7e7065..0000000000 --- a/app/views/spree/admin/products/index/_products_head.html.haml +++ /dev/null @@ -1,41 +0,0 @@ -%colgroup - %col.actions - %col.image{ "ng-show": 'columns.image.visible' } - %col.producer{ "ng-show": 'columns.producer.visible' } - %col.sku{ "ng-show": 'columns.sku.visible' } - %col.name{ "ng-show": 'columns.name.visible' } - %col.unit{ "ng-show": 'columns.unit.visible' } - %col.display_as{ "ng-show": 'columns.unit.visible' } - %col.price{ "ng-show": 'columns.price.visible' } - %col.on_hand{ "ng-show": 'columns.on_hand.visible' } - %col.on_demand{ "ng-show": 'columns.on_demand.visible' } - %col.category{ "ng-show": 'columns.category.visible' } - %col.tax_category{ "ng-show": 'columns.tax_category.visible' } - %col.inherits_properties{ "ng-show": 'columns.inherits_properties.visible' } - %col.import_date{ "ng-show": 'columns.import_date.visible' } - %col.actions - %col.actions - %col.actions - -%thead - %tr{ "ng-controller": "ColumnsCtrl" } - %th.left-actions - %a{ 'ng-click' => 'toggleShowAllVariants()', :style => 'color: red; cursor: pointer' } - = t(:expand_all) - %th.image{ 'ng-show' => 'columns.image.visible' } - %th.producer{ 'ng-show' => 'columns.producer.visible' }=t('admin.producer') - %th.sku{ 'ng-show' => 'columns.sku.visible' }=t('admin.sku') - %th.name{ 'ng-show' => 'columns.name.visible' } - = render partial: 'spree/admin/shared/sortable_header', locals: {column_name: 'name'} - %th.unit{ 'ng-show' => 'columns.unit.visible' }=t('.unit') - %th.display_as{ 'ng-show' => 'columns.unit.visible' }=t('.display_as') - %th.price{ 'ng-show' => 'columns.price.visible' }=t('admin.price') - %th.on_hand{ 'ng-show' => 'columns.on_hand.visible' }=t('admin.on_hand') - %th.on_demand{ 'ng-show' => 'columns.on_demand.visible' }=t('admin.on_demand?') - %th.category{ 'ng-show' => 'columns.category.visible' }=t('.category') - %th.tax_category{ 'ng-show' => 'columns.tax_category.visible' }=t('.tax_category') - %th.inherits_properties{ 'ng-show' => 'columns.inherits_properties.visible' }=t('.inherits_properties?') - %th.import_date{ 'ng-show' => 'columns.import_date.visible' }=t('.import_date') - %th.actions - %th.actions - %th.actions diff --git a/app/views/spree/admin/products/index/_products_product.html.haml b/app/views/spree/admin/products/index/_products_product.html.haml deleted file mode 100644 index aa10e5e29a..0000000000 --- a/app/views/spree/admin/products/index/_products_product.html.haml +++ /dev/null @@ -1,33 +0,0 @@ -%tr.product{ :id => "p_{{product.id}}" } - %td.left-actions - %a{ 'ofn-toggle-variants' => 'true', :class => "view-variants", 'ng-show' => 'hasVariants(product)' } - %a{ :class => "add-variant icon-plus-sign", 'ng-click' => "addVariant(product)", 'ng-show' => "!hasVariants(product) && hasUnit(product)" } - %td.image{ 'ng-show' => 'columns.image.visible' } - %a{class: 'image-modal'} - %img{'ng-src' => '{{ product.thumb_url }}'} - %td.producer{ 'ng-show' => 'columns.producer.visible' } - %td.sku{ 'ng-show' => 'columns.sku.visible' } - %input{ 'ng-model' => "product.sku", :name => 'product_sku', 'ofn-track-product' => 'sku', :type => 'text' } - %td.name{ 'ng-show' => 'columns.name.visible' } - %input{ 'ng-model' => "product.name", :name => 'product_name', 'ofn-track-product' => 'name', :type => 'text' } - %td.unit{ 'ng-show' => 'columns.unit.visible' } - %td.display_as{ 'ng-show' => 'columns.unit.visible' } - %td.price{ 'ng-show' => 'columns.price.visible' } - %input{ 'ng-model' => 'product.price', 'ofn-decimal' => :true, :name => 'price', 'ofn-track-product' => 'price', :type => 'text', 'ng-hide' => 'hasVariants(product)' } - %td.on_hand{ 'ng-show' => 'columns.on_hand.visible' } - %span{ 'ng-bind' => 'product.on_hand', :name => 'on_hand', 'ng-if' => '!hasOnDemandVariants(product) && (hasVariants(product) || product.on_demand)' } - %input.field{ 'ng-model' => 'product.on_hand', :name => 'on_hand', 'ofn-track-product' => 'on_hand', 'ng-if' => '!(hasVariants(product) || product.on_demand)', :type => 'number' } - %td.on_demand{ 'ng-show' => 'columns.on_demand.visible' } - %input.field{ 'ng-model' => 'product.on_demand', :name => 'on_demand', 'ofn-track-product' => 'on_demand', :type => 'checkbox', 'ng-hide' => 'hasVariants(product)' } - %td.category{ 'ng-if' => 'columns.category.visible' } - %td.tax_category{ 'ng-if' => 'columns.tax_category.visible' } - %td.inherits_properties{ 'ng-show' => 'columns.inherits_properties.visible' } - %input{ 'ng-model' => 'product.inherits_properties', :name => 'inherits_properties', 'ofn-track-product' => 'inherits_properties', type: "checkbox" } - %td.import_date{ 'ng-show' => 'columns.import_date.visible' } - %span {{(product.import_date | date:"MMMM dd, yyyy HH:mm") || ""}} - %td.actions - %a{ 'ng-click' => 'editWarn(product)', :class => "edit-product icon-edit no-text", 'ofn-with-tip' => t(:edit) } - %td.actions - %a{ 'ng-click' => 'cloneProduct(product)', :class => "clone-product icon-copy no-text", 'ofn-with-tip' => t(:clone) } - %td.actions - %a{ 'ng-click' => 'deleteProduct(product)', :class => "delete-product icon-trash no-text", 'ofn-with-tip' => t(:remove) } diff --git a/app/views/spree/admin/products/index/_products_variant.html.haml b/app/views/spree/admin/products/index/_products_variant.html.haml deleted file mode 100644 index 4aa5e13f78..0000000000 --- a/app/views/spree/admin/products/index/_products_variant.html.haml +++ /dev/null @@ -1,39 +0,0 @@ -%tr.variant{ :id => "v_{{variant.id}}", 'ng-repeat' => 'variant in product.variants', 'ng-show' => 'DisplayProperties.showVariants(product.id)', 'ng-class-even' => "'even'", 'ng-class-odd' => "'odd'" } - %td.left-actions - %a{ :class => "variant-item icon-caret-right", 'ng-hide' => "$last" } - %a{ :class => "add-variant icon-plus-sign", 'ng-click' => "addVariant(product)", 'ng-show' => "$last", 'ofn-with-tip' => t('.new_variant') } - %td{ 'ng-show' => 'columns.image.visible' } - %td{ 'ng-show' => 'columns.producer.visible' } - %select.fullwidth{ "data-controller": "tom-select", 'ng-model' => 'variant.producer_id', :name => 'producer_id', 'ofn-track-variant' => 'producer_id', 'ng-options' => 'producer.id as producer.name for producer in producers' } - %td{ 'ng-show' => 'columns.sku.visible' } - %input{ 'ng-model' => "variant.sku", :name => 'variant_sku', 'ofn-track-variant' => 'sku', :type => 'text' } - %td{ 'ng-show' => 'columns.name.visible' } - %input{ 'ng-model' => 'variant.display_name', :name => 'variant_display_name', 'ofn-track-variant' => 'display_name', :type => 'text', placeholder: "{{ product.name }}" } - %td.unit_value{ 'ng-show' => 'columns.unit.visible' } - %select.no-search{ "data-controller": "tom-select", 'ng-model' => 'variant.variant_unit_with_scale', :name => 'variant_unit_with_scale', 'ofn-track-variant' => 'variant_unit_with_scale', 'ng-options' => 'unit[1] as unit[0] for unit in variant_unit_options' } - %input{ 'ng-model' => 'variant.unit_value_with_description', :name => 'variant_unit_value_with_description', 'ofn-track-variant' => 'unit_value_with_description', :type => 'text', :placeholder => 'value', 'ng-show' => "hasUnit(variant)" } - %input{ 'ng-model' => 'variant.variant_unit_name', :name => 'variant_unit_name', 'ofn-track-variant' => 'variant_unit_name', :placeholder => 'unit', 'ng-show' => "variant.variant_unit_with_scale == 'items'", :type => 'text' } - %td.display_as{ 'ng-show' => 'columns.unit.visible' } - %input{ 'ofn-display-as' => 'variant', 'ng-model' => 'variant.display_as', name: 'variant_display_as', 'ofn-track-variant' => 'display_as', type: 'text', placeholder: '{{ placeholder_text }}' } - %td{ 'ng-show' => 'columns.price.visible' } - %input{ 'ng-model' => 'variant.price', 'ofn-decimal' => :true, :name => 'variant_price', 'ofn-track-variant' => 'price', :type => 'text' } - %td{ 'ng-show' => 'columns.on_hand.visible' } - %input.field{ 'ng-model' => 'variant.on_hand', 'ng-change' => 'updateOnHand(product)', :name => 'variant_on_hand', 'ng-if' => '!variant.on_demand', 'ofn-track-variant' => 'on_hand', :type => 'number' } - %span{ :name => 'variant_on_hand', 'ng-if' => 'variant.on_demand' } - = t(:on_demand) - %td{ 'ng-show' => 'columns.on_demand.visible' } - %input.field{ 'ng-model' => 'variant.on_demand', :name => 'variant_on_demand', 'ofn-track-variant' => 'on_demand', :type => 'checkbox' } - %td{ 'ng-show' => 'columns.category.visible' } - %input.fullwidth{ type: 'text', id: "p{{product.id}}_category_id", 'ng-model' => 'variant.category_id', 'ofn-taxon-autocomplete' => '', 'ofn-track-variant' => 'category_id', 'multiple-selection' => 'false', placeholder: 'Category' } - %td{ 'ng-show' => 'columns.tax_category.visible' } - %select.select2{ name: 'variant_tax_category_id', "ofn-track-variant": 'tax_category_id', "ng-model": 'variant.tax_category_id', "ng-options": 'tax_category.id as tax_category.name for tax_category in tax_categories' } - %option{ value: '' }= t(:none) - %td{ 'ng-show' => 'columns.inherits_properties.visible' } - %td{ 'ng-show' => 'columns.import_date.visible' } - %span {{variant.import_date | date:"MMMM dd, yyyy HH:mm"}} - %td.actions - %a{ 'ng-click' => 'editWarn(product,variant)', :class => "edit-variant icon-edit no-text", 'ng-show' => "variantSaved(variant)", 'ofn-with-tip' => t(:edit) } - %td.actions - %span.icon-warning-sign{ 'ng-if' => 'variant.variant_overrides_count > 0', 'ofn-with-tip' => "{{ 'spree.admin.products.index.products_variant.variant_has_n_overrides' | t:{n: variant.variant_overrides_count} }}" } - %td.actions - %a{ 'ng-click' => 'deleteVariant(product,variant)', "ng-class" => '{disabled: product.variants.length < 2}', :class => "delete-variant icon-trash no-text", 'ofn-with-tip' => t(:remove) } diff --git a/app/views/spree/admin/products/index/_save_button_row.html.haml b/app/views/spree/admin/products/index/_save_button_row.html.haml deleted file mode 100644 index 8818bf84b3..0000000000 --- a/app/views/spree/admin/products/index/_save_button_row.html.haml +++ /dev/null @@ -1,3 +0,0 @@ -.sixteen.columns.alpha{ 'ng-hide' => 'RequestMonitor.loading || products.length == 0', style: "margin-bottom: 10px" } - .four.columns.alpha - %input.four.columns.alpha{ :type => 'button', :value => t(:save_changes), 'ng-click' => 'submitProducts()'} diff --git a/app/views/spree/admin/shared/_head.html.haml b/app/views/spree/admin/shared/_head.html.haml index e1b987232c..5da4963871 100644 --- a/app/views/spree/admin/shared/_head.html.haml +++ b/app/views/spree/admin/shared/_head.html.haml @@ -14,12 +14,7 @@ = " - OFN #{t(:administration)}" %link{:href => "https://fonts.googleapis.com/css?family=Open+Sans:400italic,600italic,400,600&subset=latin,cyrillic,greek,vietnamese", :rel => "stylesheet", :type => "text/css"} - -- if feature?(:admin_style_v3, spree_current_user) - = stylesheet_pack_tag 'admin-style-v3', media: "screen, print" -- else - = stylesheet_pack_tag 'admin-styles', media: "screen, print" - += stylesheet_pack_tag 'admin-style-v3', media: "screen, print" = render "layouts/bugsnag_js" - if content_for? :minimal_js diff --git a/app/views/spree/admin/shared/_product_sub_menu.html.haml b/app/views/spree/admin/shared/_product_sub_menu.html.haml index 91fc3e6bc5..7fe1ccc3ed 100644 --- a/app/views/spree/admin/shared/_product_sub_menu.html.haml +++ b/app/views/spree/admin/shared/_product_sub_menu.html.haml @@ -1,6 +1,6 @@ - content_for :sub_menu do %ul#sub_nav.inline-menu - = tab :products, :products_v3 + = tab :products, :products_v3, url: admin_products_path = tab :properties = tab :variant_overrides, url: main_app.admin_inventory_path, match_path: '/inventory' if feature?(:inventory, spree_current_user.enterprises) = tab :import, url: main_app.admin_product_import_path, match_path: '/product_import' diff --git a/app/views/spree/admin/shared/_tabs.html.haml b/app/views/spree/admin/shared/_tabs.html.haml index 3ad1a1d53a..ebe1c422ba 100644 --- a/app/views/spree/admin/shared/_tabs.html.haml +++ b/app/views/spree/admin/shared/_tabs.html.haml @@ -1,11 +1,11 @@ -= tab :overview, label: 'dashboard', url: spree.admin_dashboard_path, icon: 'icon-dashboard' -= tab :products, :properties, :inventory, :product_import, :images, :variants, :product_properties, :group_buy_options, :seo, :products_v3, :variant_overrides, url: admin_products_path, icon: 'icon-th-large' -= tab :order_cycles, url: main_app.admin_order_cycles_path, icon: 'icon-refresh' -= tab :orders, :subscriptions, :customer_details, :adjustments, :payments, :return_authorizations, url: admin_orders_path, icon: 'icon-shopping-cart' -= tab :reports, url: main_app.admin_reports_path, icon: 'icon-file' -= tab :general_settings, :terms_of_service_files, :mail_methods, :tax_categories, :tax_rates, :tax_settings, :zones, :countries, :states, :payment_methods, :taxons, :shipping_methods, :shipping_categories, :enterprise_fees, :contents, :invoice_settings, :matomo_settings, :stripe_connect_settings, :connected_app_settings, label: 'configuration', icon: 'icon-wrench', url: edit_admin_general_settings_path += tab :overview, label: 'dashboard', url: spree.admin_dashboard_path += tab :products, :properties, :inventory, :product_import, :images, :variants, :product_properties, :group_buy_options, :seo, :products_v3, :variant_overrides, url: admin_products_path += tab :order_cycles, url: main_app.admin_order_cycles_path += tab :orders, :subscriptions, :customer_details, :adjustments, :payments, :return_authorizations, url: admin_orders_path += tab :reports, url: main_app.admin_reports_path += tab :general_settings, :terms_of_service_files, :mail_methods, :tax_categories, :tax_rates, :tax_settings, :zones, :countries, :states, :payment_methods, :taxons, :shipping_methods, :shipping_categories, :enterprise_fees, :contents, :invoice_settings, :matomo_settings, :stripe_connect_settings, :connected_app_settings, label: 'configuration', url: edit_admin_general_settings_path = tab :enterprises, :enterprise_relationships, :vouchers, :oidc_settings, url: main_app.admin_enterprises_path = tab :customers, url: main_app.admin_customers_path = tab :enterprise_groups, url: main_app.admin_enterprise_groups_path, label: 'groups' - if can? :admin, Spree::User - = tab(:users, :enterprise_roles, url: spree.admin_users_path, icon: 'icon-user') + = tab(:users, :enterprise_roles, url: spree.admin_users_path) diff --git a/app/webpacker/css/admin/all.scss b/app/webpacker/css/admin/all.scss deleted file mode 100644 index a63e543f90..0000000000 --- a/app/webpacker/css/admin/all.scss +++ /dev/null @@ -1,125 +0,0 @@ -@import "vendor/assets/stylesheets/normalize"; -@import "vendor/assets/stylesheets/responsive-tables"; -@import "vendor/assets/stylesheets/jquery.powertip"; -@import "~jquery-ui/themes/base/core"; -@import "~jquery-ui/themes/base/button"; -@import "~jquery-ui/themes/base/resizable"; -@import "vendor/assets/stylesheets/jquery-ui-theme"; -@import "~jquery-ui/themes/base/dialog"; -@import "../shared/ng-tags-input.min"; -@import "vendor/assets/stylesheets/select2.css.scss"; -@import "~flatpickr/dist/flatpickr"; -@import "~flatpickr/dist/themes/material_blue"; -@import "~shortcut-buttons-flatpickr/dist/themes/light"; - -@import "globals/functions"; -@import "globals/palette"; -@import "globals/variables"; -@import "globals/mixins"; - -@import "plugins/font-awesome"; - -@import "../shared/variables/layout"; -@import "../shared/variables/variables"; -@import "../shared/utilities"; -@import "shared/typography"; -@import "shared/tables"; -@import "shared/icons"; -@import "shared/forms"; -@import "shared/layout"; -@import "shared/scroll_bar"; - -@import "../shared/trix"; - -@import "plugins/flatpickr-customization"; -@import "plugins/powertip"; -@import "plugins/select2"; - -@import "sections/orders"; -@import "sections/products"; - -@import "hacks/mozilla"; -@import "hacks/opera"; -@import "hacks/ie"; - -@import "components/actions"; -@import "components/alert-box"; -@import "components/alert_row"; -@import "components/buttons"; -@import "components/date-picker"; -@import "components/dialogs"; -@import "components/input"; -@import "components/jquery_dialog"; -@import "components/messages"; -@import "components/navigation"; -@import "components/ng-cloak"; -@import "components/page_actions"; -@import "components/pagination"; -@import "components/per_page_controls"; -@import "components/product_autocomplete"; -@import "components/progress"; -@import "components/save_bar"; -@import "components/sidebar"; -@import "components/simple_modal"; -@import "components/states"; -@import "components/stripe_connect_button"; -@import "components/subscriptions_states"; -@import "components/table-filter"; -@import "components/table_loading"; -@import "components/timepicker"; -@import "components/todo"; -@import "components/tooltip"; -@import "components/wizard_progress"; - -@import "pages/enterprise_form"; -@import "pages/subscription_form"; -@import "pages/subscription_line_items"; -@import "pages/subscription_review"; - -@import "advanced_settings"; -@import "alert"; -@import "animations"; -@import "change_type_form"; -@import "connected_apps"; -@import "customers"; -@import "dashboard_item"; -@import "dashboard-single-ent"; -@import "dialog"; -@import "disabled"; -@import "dropdown"; -@import "enterprise_index_panels"; -@import "enterprises"; -@import "filters_and_controls"; -@import "grid"; -@import "icons"; -@import "index_panel_buttons"; -@import "index_panels"; -@import "modals"; -@import "offsets"; -@import "openfoodnetwork"; -@import "order_cycles"; -@import "orders"; -@import "product_import"; -@import "products"; -@import "question-mark-tooltip"; -@import "relationships"; -@import "reports"; -@import "select2"; -@import "sidebar-item"; -@import "side_menu"; -@import "tables"; -@import "tag_rules"; -@import "terms_of_service_banner"; -@import "terms_of_service_files"; -@import "validation"; -@import "variant_overrides"; -@import "welcome"; - -@import "../shared/question-mark-icon"; -@import "question-mark-tooltip"; - -@import "~tom-select/src/scss/tom-select.default"; -@import "components/tom_select"; - -@import "app/components/modal_component/modal_component"; -@import "app/webpacker/css/admin/trix.scss"; diff --git a/app/webpacker/css/admin/components/actions.scss b/app/webpacker/css/admin/components/actions.scss deleted file mode 100644 index c766a284ac..0000000000 --- a/app/webpacker/css/admin/components/actions.scss +++ /dev/null @@ -1,31 +0,0 @@ -table tbody tr { - &.highlight { - @each $action in $actions { - &.action-#{$action} td { - background-color: get-value($actions, $actions-bg-colors, $action); - border-color: get-value($actions, $actions-brd-colors, $action); - } - } - - &.action-remove td, - &.action-void td { - text-decoration: line-through; - - &.actions { - text-decoration: none; - } - } - } - - &.before-highlight { - @each $action in $actions { - &.action-#{$action} td { - border-bottom-color: get-value($actions, $actions-brd-colors, $action); - } - } - } - - td.actions { - background-color: transparent !important; - } -} diff --git a/app/webpacker/css/admin/components/buttons.scss b/app/webpacker/css/admin/components/buttons.scss deleted file mode 100644 index 1291d04e15..0000000000 --- a/app/webpacker/css/admin/components/buttons.scss +++ /dev/null @@ -1,93 +0,0 @@ -input[type="submit"], -input[type="button"]:not(.trix-button), -button:not(.plain):not(.trix-button), -.button { - position: relative; - cursor: pointer; - font-size: 85%; - @include border-radius($border-radius); - display: inline-block; - padding: 8px 15px; - border: none; - background-color: $color-btn-bg; - color: $color-btn-text; - text-transform: uppercase; - font-weight: 600 !important; - - &:before { - font-weight: normal !important; - } - - &:visited, - &:active, - &:focus { - color: $color-btn-text; - } - - &:hover { - background-color: $color-btn-hover-bg; - color: $color-btn-hover-text; - } - - &:active:focus { - box-shadow: 0 0 8px 0 darken($color-btn-hover-bg, 5) inset; - } - - &.fullwidth { - width: 100%; - text-align: center; - } - - &.secondary { - background-color: transparent; - border: 1px solid $color-btn-bg; - color: $color-btn-bg; - - &:hover, - &:active, - &:focus { - background-color: #ebf3fb; - } - - &:active:focus { - box-shadow: none; - } - } - - .badge { - position: absolute; - top: 0; - right: 0; - transform: translateY(-50%); - font-size: 10px; - text-transform: capitalize; - padding: 0px 5px; - border-radius: 3px; - - &:before { - padding: 0; - } - - &.danger { - background-color: $color-warning; - } - &.success { - background-color: $spree-green; - } - } -} - -input.red, -a.button.red, -button.red { - background-color: $color-warning; - margin-right: 5px; - color: #ffffff; -} - -a.button.red { - &:not(:hover) { - color: #fff; - background-color: $color-warning; - } -} diff --git a/app/webpacker/css/admin/components/date-picker.scss b/app/webpacker/css/admin/components/date-picker.scss deleted file mode 100644 index a35b5a970e..0000000000 --- a/app/webpacker/css/admin/components/date-picker.scss +++ /dev/null @@ -1,20 +0,0 @@ -// scss-lint:disable QualifyingElement - -input.datetimepicker { - min-width: 12.9em; -} - -.container input[readonly].flatpickr-input, -.container input[readonly].datepicker, -.container input[readonly].datetimepicker { - background-color: $white; - cursor: pointer; -} - -img.ui-datepicker-trigger { - margin-left: -1.75em; - position: absolute; - margin-top: 0.5em; -} - -// scss-lint:enable QualifyingElement diff --git a/app/webpacker/css/admin/components/messages.scss b/app/webpacker/css/admin/components/messages.scss deleted file mode 100644 index f92498a599..0000000000 --- a/app/webpacker/css/admin/components/messages.scss +++ /dev/null @@ -1,76 +0,0 @@ -.errorExplanation { - padding: 10px; - border: 1px solid very-light($color-error, 12); - background-color: very-light($color-error, 6); - border-radius: 3px; - color: $color-error; - margin-bottom: 15px; - - h2 { - font-size: 140%; - color: $color-error; - margin-bottom: 5px; - } - - p { - padding: 10px 0; - } - - ul { - list-style-position: inside; - - li { - font-weight: $font-weight-bold; - } - } -} - -.flash-container { - position: fixed; - top: 0; - left: 0; - width: 100%; - z-index: 1000; - - .flash { - padding: 18px; - text-align: center; - font-size: 120%; - color: $color-1; - font-weight: 600; - margin-top: 0; - - &.notice { - background-color: rgba($color-notice, 0.8); - } - &.success { - background-color: rgba($color-success, 0.8); - } - &.error { - background-color: rgba($color-error, 0.8); - } - - // Adjust heights to fit main layout dimension (header, navbar...) - &:nth-child(2) { - padding: 24px; - } - &:nth-child(3) { - padding: 20px; - } - - .actions { - display: none; /* avoid adding new button on old design */ - } - } -} - -.notice:not(.flash) { - padding: 1rem; - margin-bottom: 1.5rem; - background-color: $spree-light-blue; - border-radius: $border-radius; - - a { - font-weight: bold; - } -} diff --git a/app/webpacker/css/admin/components/navigation.scss b/app/webpacker/css/admin/components/navigation.scss deleted file mode 100644 index 2aeb3a8a30..0000000000 --- a/app/webpacker/css/admin/components/navigation.scss +++ /dev/null @@ -1,174 +0,0 @@ -// Navigation -//--------------------------------------------------- -.inline-menu { - margin: 0; - -webkit-margin-before: 0; - -webkit-padding-start: 0; -} - -nav.menu { - ul { - list-style: none; - - li { - a { - padding: 10px 0; - display: block; - position: relative; - text-align: left; - border: 1px solid transparent; - text-transform: uppercase; - font-weight: 600; - font-size: 90%; - } - - &.active a { - color: $color-2; - border-left-width: 0; - border-bottom-color: $color-2; - } - - &:hover a { - color: $color-2; - } - } - } -} - -.admin-login-navigation-bar { - ul { - text-align: right; - - li { - padding: 5px 0 5px 10px; - text-align: right; - font-size: 90%; - color: $color-link; - margin-top: 8px; - - &.user-logged-in-as { - width: 50%; - color: $color-body-text; - } - - &:hover { - i { - color: $color-2; - } - } - } - } -} - -#admin-menu { - background-color: $color-3; - - ul { - display: flex; - } - - li { - min-width: 90px; - flex-grow: 1; - - a { - display: block; - padding: 25px 5px; - color: $color-1 !important; - text-transform: uppercase; - position: relative; - text-align: center; - font-weight: 600; - - i { - display: inline; - } - - &:hover { - background-color: $color-2; - - &:after { - content: ""; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 5px solid $color-2; - bottom: 0px; - margin-bottom: -5px; - left: 50%; - margin-left: -10px; - z-index: 1; - } - } - - span.text { - font-weight: 600; - } - } - - a::before { - font-weight: normal; - padding-top: 0; - } - - .dropdown { - width: 300px; - background-color: $color-3; - width: 200px; - z-index: 100000; - - > li { - width: 200px !important; - - a:after { - display: none; - } - } - } - - &.selected a { - @extend a, :hover; - } - } -} - -#sub-menu { - background-color: $color-2; - padding-bottom: 0; - - li { - a { - display: block; - padding: 12px 20px; - color: $color-1; - text-align: center; - text-transform: uppercase; - position: relative; - font-size: 85%; - } - - &.selected a, - a:hover { - &:after { - content: ""; - position: absolute; - border-left: 10px solid transparent; - border-right: 10px solid transparent; - border-top: 5px solid $color-2; - bottom: 0px; - margin-bottom: -5px; - left: 50%; - margin-left: -10px; - z-index: 0; - } - } - } -} - -#header figure { - margin: 0.25em 0; -} - -#login-nav { - line-height: 1.75em; -} diff --git a/app/webpacker/css/admin/components/pagination.scss b/app/webpacker/css/admin/components/pagination.scss deleted file mode 100644 index 730abe8888..0000000000 --- a/app/webpacker/css/admin/components/pagination.scss +++ /dev/null @@ -1,32 +0,0 @@ -.pagination { - text-align: center; - margin: 2em 0 1em; - padding: 10px 0; - - .page { - padding: 5px 8px; - text-align: center; - display: inline-block; - text-align: center; - - &.current { - background-color: $color-2; - border-radius: 3px; - color: $color-1; - } - } - - button { - margin: 0 0.35em; - - &.active { - background-color: darken($spree-blue, 15%); - cursor: default; - } - - &.disabled { - background-color: $color-btn-disabled-bg; - cursor: default; - } - } -} diff --git a/app/webpacker/css/admin/components/sidebar.scss b/app/webpacker/css/admin/components/sidebar.scss deleted file mode 100644 index 960de96ab0..0000000000 --- a/app/webpacker/css/admin/components/sidebar.scss +++ /dev/null @@ -1,26 +0,0 @@ -// Sidebar -//--------------------------------------------------- -#sidebar { - overflow: visible; - border-top: 1px solid $color-border; - margin-top: 17px; - - .sidebar-title { - color: $color-2; - text-transform: uppercase; - text-align: center; - font-size: 14px; - font-weight: 600; - - > span { - display: inline; - background: #fff; - padding: 5px 10px; - position: relative; - top: -14px; - - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - } - } -} diff --git a/app/webpacker/css/admin/components/tom_select.scss b/app/webpacker/css/admin/components/tom_select.scss deleted file mode 100644 index 0783795e6e..0000000000 --- a/app/webpacker/css/admin/components/tom_select.scss +++ /dev/null @@ -1,141 +0,0 @@ -.ts-wrapper { - min-height: initial; -} - -.ts-wrapper.multi { - .ts-control { - box-shadow: none; - border-color: $pale-blue; - - &:focus { - border-color: $spree-green; - } - - [data-value] { - text-shadow: none; - background-image: none; - background-repeat: initial; - box-shadow: none; - background-color: $spree-blue; - } - } - - .ts-control > div { - border: none; - background-color: $spree-blue; - } -} - -.ts-wrapper.plugin-remove_button .item .remove { - font-weight: bold; -} - -.ts-dropdown { - margin-top: 0; - - .option { - min-height: 2.25em; - display: block; - } -} - -.ts-wrapper.single .ts-control, -.ts-dropdown.single { - border-color: $color-tbl-border; -} - -.ts-control, -.ts-wrapper.single.input-active .ts-control { - cursor: pointer; - padding: 6px 8px; - outline: 0 !important; - min-height: 2.5em; -} - -.ts-wrapper.single .ts-control { - padding-right: 2rem; -} - -.ts-wrapper.inline, -.ts-wrapper.inline.input-active { - width: fit-content; - - .ts-control { - padding-right: 2rem; - } -} - -.ts-wrapper.single .ts-control { - box-shadow: none; - background-image: none; - background-color: $white; -} - -.ts-wrapper.primary.focus .ts-control, -.ts-wrapper.primary .ts-control { - background-color: $spree-blue; - border-color: $spree-blue; - color: $white; - - &:after { - border-color: $white transparent transparent transparent; - } -} - -.ts-wrapper .select-multiple { - cursor: pointer; -} - -.ts-wrapper.dropdown-active.primary .ts-control { - background-color: $spree-green; - border-color: $spree-green; - color: $white; - - &:after { - border-color: transparent transparent $white transparent; - } -} - -.dropdown-input-wrap { - padding: 0.2em; - position: relative; - - &:before { - @extend [class^="icon-"]; - @extend .icon-search; - - position: absolute; - opacity: 0.4; - line-height: 2em; - left: 0.75em; - } - - .dropdown-input { - outline: 0; - padding: 4px 6px; - border: 1px solid $spree-green; - border-radius: 0.3em; - padding-left: 1.75em; - } -} - -.ts-wrapper.no-search { - .dropdown-input-wrap { - display: none; - } -} - -.ts-dropdown .create:hover, -.ts-dropdown #admin-menu li.selected a.create, -#admin-menu li.selected .ts-dropdown a.create, -.ts-dropdown .option:hover, -.ts-dropdown #admin-menu li.selected a.option, -#admin-menu li.selected .ts-dropdown a.option, -.ts-dropdown .active { - background-color: $spree-blue; - color: $white; -} - -.ts-dropdown [data-selectable] .highlight { - background: rgba(149, 180, 255, 0.26); -} diff --git a/app/webpacker/css/admin/globals/variables.scss b/app/webpacker/css/admin/globals/variables.scss deleted file mode 100644 index f35788dc5f..0000000000 --- a/app/webpacker/css/admin/globals/variables.scss +++ /dev/null @@ -1,156 +0,0 @@ -// ------------------------------------------------------------- -// Variables used in all other files -//-------------------------------------------------------------- - -// Fonts -//-------------------------------------------------------------- -$base-font-family: "Open Sans", "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; - -// Colors -//-------------------------------------------------------------- - -// Body base colors -$color-body-bg: $color-1 !default; -$color-body-text: $color-4 !default; -$color-headers: $color-4 !default; -$color-link: $color-3 !default; -$color-link-hover: $color-2 !default; -$color-link-active: $color-2 !default; -$color-link-focus: $color-2 !default; -$color-link-visited: $color-3 !default; -$color-border: very-light($color-3, 12) !default; - -// Basic flash colors -$color-success: $color-2 !default; -$color-notice: $color-6 !default; -$color-warning: $color-5 !default; -$color-error: $color-5 !default; - -// Table colors -$color-tbl-odd: $color-1 !default; -$color-tbl-even: very-light($color-3, 4) !default; -$color-tbl-thead: very-light($color-3, 4) !default; -$color-tbl-border: $pale-blue !default; - -// Button colors -$color-btn-bg: $color-3 !default; -$color-btn-text: $color-1 !default; -$color-btn-hover-bg: $color-2 !default; -$color-btn-hover-text: $color-1 !default; -$color-btn-disabled-bg: $light-grey !default; - -// Actions colors -$color-action-edit-bg: very-light($color-success, 5 ) !default; -$color-action-edit-brd: very-light($color-success, 20 ) !default; -$color-action-clone-bg: very-light($color-notice, 5 ) !default; -$color-action-clone-brd: very-light($color-notice, 15 ) !default; -$color-action-remove-bg: very-light($color-error, 5 ) !default; -$color-action-remove-brd: very-light($color-error, 10 ) !default; -$color-action-void-bg: very-light($color-error, 10 ) !default; -$color-action-void-brd: very-light($color-error, 20 ) !default; -$color-action-cancel-bg: very-light($color-notice, 10 ) !default; -$color-action-cancel-brd: very-light($color-notice, 20 ) !default; -$color-action-capture-bg: very-light($color-success, 5 ) !default; -$color-action-capture-brd: very-light($color-success, 20 ) !default; -$color-action-save-bg: very-light($color-success, 5 ) !default; -$color-action-save-brd: very-light($color-success, 20 ) !default; -$color-action-mail-bg: very-light($color-success, 5 ) !default; -$color-action-mail-brd: very-light($color-success, 20 ) !default; - -// Select2 select field colors -$color-sel-bg: $color-3 !default; -$color-sel-text: $color-1 !default; -$color-sel-hover-bg: $color-2 !default; -$color-sel-hover-text: $color-1 !default; - -// Text inputs colors -$color-txt-brd: $color-border !default; -$color-txt-text: $color-3 !default; -$color-txt-hover-brd: $color-2 !default; -$vpadding-txt: 7px; -$hpadding-txt: 10px; - -// Modal colors -$color-modal-close-btn: $color-5 !default; -$color-modal-close-btn-hover: darken($color-5, 5%) !default; - -// States label colors -$color-ste-complete-bg: $color-success !default; -$color-ste-complete-text: $color-1 !default; -$color-ste-completed-bg: $color-success !default; -$color-ste-completed-text: $color-1 !default; -$color-ste-sold-bg: $color-success !default; -$color-ste-sold-text: $color-1 !default; -$color-ste-pending-bg: $color-notice !default; -$color-ste-pending-text: $color-1 !default; -$color-ste-requires_authorization-bg: $color-notice !default; -$color-ste-requires_authorization-text: $color-1 !default; -$color-ste-awaiting_return-bg: $color-notice !default; -$color-ste-awaiting_return-text: $color-1 !default; -$color-ste-returned-bg: $color-notice !default; -$color-ste-returned-text: $color-1 !default; -$color-ste-credit_owed-bg: $color-notice !default; -$color-ste-credit_owed-text: $color-1 !default; -$color-ste-paid-bg: $color-success !default; -$color-ste-paid-text: $color-1 !default; -$color-ste-shipped-bg: $color-success !default; -$color-ste-shipped-text: $color-1 !default; -$color-ste-balance_due-bg: $color-notice !default; -$color-ste-balance_due-text: $color-1 !default; -$color-ste-backorder-bg: $color-notice !default; -$color-ste-backorder-text: $color-1 !default; -$color-ste-none-bg: $color-error !default; -$color-ste-none-text: $color-1 !default; -$color-ste-ready-bg: $color-success !default; -$color-ste-ready-text: $color-1 !default; -$color-ste-void-bg: $color-error !default; -$color-ste-void-text: $color-1 !default; -$color-ste-canceled-bg: $color-error !default; -$color-ste-canceled-text: $color-1 !default; -$color-ste-address-bg: $color-error !default; -$color-ste-address-text: $color-1 !default; -$color-ste-checkout-bg: $color-notice !default; -$color-ste-checkout-text: $color-1 !default; -$color-ste-cart-bg: $color-notice !default; -$color-ste-cart-text: $color-1 !default; -$color-ste-payment-bg: $color-error !default; -$color-ste-payment-text: $color-1 !default; -$color-ste-delivery-bg: $color-success !default; -$color-ste-delivery-text: $color-1 !default; -$color-ste-confirmation-bg: $color-error !default; -$color-ste-confirmation-text: $color-1 !default; -$color-ste-active-bg: $color-success !default; -$color-ste-active-text: $color-1 !default; -$color-ste-inactive-bg: $color-notice !default; -$color-ste-inactive-text: $color-1 !default; - -// Available states -$states: completed, complete, sold, pending, awaiting_return, returned, credit_owed, paid, shipped, balance_due, backorder, checkout, cart, address, delivery, payment, confirmation, canceled, ready, void, requires_authorization, active, inactive !default; -$states-bg-colors: $color-ste-completed-bg, $color-ste-complete-bg, $color-ste-sold-bg, $color-ste-pending-bg, $color-ste-awaiting_return-bg, $color-ste-returned-bg, $color-ste-credit_owed-bg, $color-ste-paid-bg, $color-ste-shipped-bg, $color-ste-balance_due-bg, $color-ste-backorder-bg, $color-ste-checkout-bg, $color-ste-cart-bg, $color-ste-address-bg, $color-ste-delivery-bg, $color-ste-payment-bg, $color-ste-confirmation-bg, $color-ste-canceled-bg, $color-ste-ready-bg, $color-ste-void-bg, $color-ste-requires_authorization-bg, $color-ste-active-bg, $color-ste-inactive-bg !default; -$states-text-colors: $color-ste-completed-text, $color-ste-complete-text, $color-ste-sold-text, $color-ste-pending-text, $color-ste-awaiting_return-text, $color-ste-returned-text, $color-ste-credit_owed-text, $color-ste-paid-text, $color-ste-shipped-text, $color-ste-balance_due-text, $color-ste-backorder-text, $color-ste-checkout-text, $color-ste-cart-text, $color-ste-address-text, $color-ste-delivery-text, $color-ste-payment-text, $color-ste-confirmation-text, $color-ste-canceled-text, $color-ste-ready-text, $color-ste-void-text, $color-ste-requires_authorization-text, $color-ste-active-text, $color-ste-inactive-text !default; - -// Available actions -$actions: edit, clone, remove, void, capture, save, cancel, mail !default; -$actions-bg-colors: $color-action-edit-bg, $color-action-clone-bg, $color-action-remove-bg, $color-action-void-bg, $color-action-capture-bg, $color-action-save-bg, $color-action-cancel-bg, $color-action-mail-bg !default; -$actions-brd-colors: $color-action-edit-brd, $color-action-clone-brd, $color-action-remove-brd, $color-action-void-brd, $color-action-capture-brd, $color-action-save-brd, $color-action-cancel-brd, $color-action-mail-brd !default; - -// Sizes -//-------------------------------------------------------------- -$body-font-size: 13px !default; - -$h6-size: $body-font-size + 2 !default; -$h5-size: $h6-size + 2 !default; -$h4-size: $h5-size + 2 !default; -$h3-size: $h4-size + 2 !default; -$h2-size: $h3-size + 2 !default; -$h1-size: $h2-size + 2 !default; - -$border-radius: 3px !default; -$border-input: 1px solid #2e3132; // Copied over from admin_v3 variables as a temporary solution - -$font-weight-bold: 600 !default; -$font-weight-normal: 400 !default; - -// z-index -//-------------------------------------------------------------- -$tos-banner-z-index: 102; diff --git a/app/webpacker/css/admin/plugins/flatpickr-customization.scss b/app/webpacker/css/admin/plugins/flatpickr-customization.scss deleted file mode 100644 index 79bc735d4d..0000000000 --- a/app/webpacker/css/admin/plugins/flatpickr-customization.scss +++ /dev/null @@ -1,68 +0,0 @@ -$background-grey: #eceef1; -$background-blue: $color-3; - -// scss-lint:disable SelectorFormat - -.flatpickr-calendar { - border-radius: 0; - - // Disable animation - &.animate.open { - animation: none; - } - - &.arrowBottom::after { - border-top-color: $background-grey; - } - - &.arrowTop::after { - border-bottom-color: $background-blue; - } - - .flatpickr-months .flatpickr-month { - border-radius: 0; - } - - .flatpickr-months .flatpickr-month, - .flatpickr-current-month .flatpickr-monthDropdown-months { - background: $background-blue; - } - - .flatpickr-weekdays { - background: $background-blue; - - .flatpickr-weekday { - background: $background-blue; - } - } - - .flatpickr-day.selected, - .flatpickr-day.startRange, - .flatpickr-day.endRange, - .flatpickr-day.selected.inRange, - .flatpickr-day.startRange.inRange, - .flatpickr-day.endRange.inRange, - .flatpickr-day.selected:focus, - .flatpickr-day.startRange:focus, - .flatpickr-day.endRange:focus, - .flatpickr-day.selected:hover, - .flatpickr-day.startRange:hover, - .flatpickr-day.endRange:hover, - .flatpickr-day.selected.prevMonthDay, - .flatpickr-day.startRange.prevMonthDay, - .flatpickr-day.endRange.prevMonthDay, - .flatpickr-day.selected.nextMonthDay, - .flatpickr-day.startRange.nextMonthDay, - .flatpickr-day.endRange.nextMonthDay { - background: $background-blue; - border-color: $background-blue; - } -} - -// scss-lint:enable SelectorFormat - -// customization for shortcut-buttons -.shortcut-buttons-flatpickr-wrapper > .shortcut-buttons-flatpickr-buttons { - justify-content: space-between; - flex-grow: 1; -} diff --git a/app/webpacker/css/admin/plugins/powertip.scss b/app/webpacker/css/admin/plugins/powertip.scss deleted file mode 100644 index 4afc7dfddb..0000000000 --- a/app/webpacker/css/admin/plugins/powertip.scss +++ /dev/null @@ -1,118 +0,0 @@ -#powerTip { - background-color: $color-3; - padding: 5px 15px; - @include border-radius($border-radius); - - &.n:before, - &.ne:before, - &.nw:before { - border-top-width: 5px; - border-top-color: $color-3; - bottom: -5px; - } - - &.e:before { - border-right-width: 5px; - border-right-color: $color-3; - left: -5px; - } - &.s:before, - &.se:before, - &.sw:before { - border-bottom-width: 5px; - border-bottom-color: $color-3; - top: -5px; - } - &.w:before { - border-left-width: 5px; - border-left-color: $color-3; - right: -5px; - } - &.ne:before, - &.se:before { - border-right-width: 5px; - border-right-color: $color-3; - left: -5px; - } - &.nw:before, - &.sw:before { - border-left-width: 5px; - border-right-color: $color-3; - right: -5px; - } - - &.clone, - &.yellow, - &.cancel { - background-color: $color-notice; - - &.n:before, - &.ne:before, - &.nw:before { - border-top-color: $color-notice; - } - &.e:before, - &.nw:before, - &.sw:before { - border-right-color: $color-notice; - } - &.s:before, - &.se:before, - &.sw:before { - border-bottom-color: $color-notice; - } - &.w:before { - border-left-color: $color-notice; - } - } - &.edit, - &.green, - &.capture, - &.save, - &.add { - background-color: $color-success; - - &.n:before, - &.ne:before, - &.nw:before { - border-top-color: $color-success; - } - &.e:before, - &.nw:before, - &.sw:before { - border-right-color: $color-success; - } - &.s:before, - &.se:before, - &.sw:before { - border-bottom-color: $color-success; - } - &.w:before { - border-left-color: $color-success; - } - } - &.remove, - &.red, - &.void { - background-color: $color-error; - - &.n:before, - &.ne:before, - &.nw:before { - border-top-color: $color-error; - } - &.e:before, - &.nw:before, - &.sw:before { - border-right-color: $color-error; - } - &.s:before, - &.se:before, - &.sw:before { - border-bottom-color: $color-error; - } - &.w:before { - border-left-color: $color-error; - } - } -} diff --git a/app/webpacker/css/admin/sections/orders.scss b/app/webpacker/css/admin/sections/orders.scss deleted file mode 100644 index e6e45309d3..0000000000 --- a/app/webpacker/css/admin/sections/orders.scss +++ /dev/null @@ -1,65 +0,0 @@ -// Customize orders filter -.admin-orders-index-search { - select[data-placeholder="Status"] { - width: 100%; - } - - .select2-container { - width: 100% !important; - } -} - -// Order-total -.order-details-total { - text-align: center; - - .order-total { - font-size: 35px; - font-weight: 600; - color: $color-success; - } -} - -.admin-order-form-fields { - legend.stock-location { - color: $color-body-text; - - .shipment-number { - color: $color-success; - } - .stock-location-name { - color: $color-success; - } - } -} - -.insufficient-stock-items { - legend { - color: $color-error; - } - - table tr:last-child th { - border-bottom: 1px solid $color-tbl-border; - } -} - -// Customize orduct add fieldset -#add-line-item { - fieldset { - padding: 10px 0; - - .field { - margin-bottom: 0; - - input[type="text"], - input[type="number"] { - width: 100%; - } - } - .actions { - .button { - margin-top: 28px; - } - } - } -} diff --git a/app/webpacker/css/admin/shared/forms.scss b/app/webpacker/css/admin/shared/forms.scss deleted file mode 100644 index 03bee63048..0000000000 --- a/app/webpacker/css/admin/shared/forms.scss +++ /dev/null @@ -1,261 +0,0 @@ -$text-inputs: "input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel]"; - -#{$text-inputs}, -input[type="date"], -input[type="datetime"], -input[type="time"], -input[type="number"], -textarea, -fieldset { - @include border-radius($border-radius); - padding: $vpadding-txt $hpadding-txt; - border: 1px solid $color-txt-brd; - color: $color-txt-text; - font-size: 90%; - - &:focus { - outline: none; - border-color: $color-txt-hover-brd; - } - - &[disabled] { - opacity: 0.7; - } -} - -textarea { - line-height: 19px; -} - -.fullwidth { - width: 100%; -} - -label { - font-weight: 600; - text-transform: uppercase; - font-size: 85%; - display: inline; - margin-bottom: 5px; - color: $color-4; - - &.inline { - display: inline-block !important; - } - - &.block { - display: block !important; - } -} - -.label-block label { - display: block; -} - -span.info { - font-style: italic; - font-size: 85%; - color: lighten($color-body-text, 15); - display: block; - line-height: 20px; - margin: 5px 0; -} - -.field { - padding: 10px 0; - - &.checkbox { - min-height: 70px; - - input[type="checkbox"] { - display: inline-block; - width: auto; - } - - label { - cursor: pointer; - display: block; - } - } - - ul { - border-top: 1px solid $color-border; - list-style: none; - padding-top: 5px; - - li { - display: inline-block; - padding-right: 10px; - - label { - font-weight: normal; - text-transform: none; - } - &.white-space-nowrap { - white-space: nowrap; - } - } - } - - // Errors described by default form builder - .field_with_errors { - label { - color: $color-error; - } - - input { - border-color: $color-error; - } - } - // Errors described by Spree::Admin::BaseHelper - .formError { - color: $color-error; - font-style: italic; - font-size: 85%; - } -} - -fieldset { - box-shadow: none; - box-sizing: border-box; - border-color: $color-border; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - margin-left: 0; - margin-right: 0; - position: relative; - margin-bottom: 35px; - padding: 10px 0 15px 0; - background-color: transparent; - border-left: none; - border-right: none; - border-radius: 0; - - &.no-border-bottom { - border-bottom: none; - margin-bottom: 0; - } - - &.no-border-top { - border-top: none; - padding-top: 0; - } - - legend { - background-color: $color-1; - color: $color-2; - font-size: 14px; - font-weight: 600; - text-transform: uppercase; - text-align: center; - padding: 8px 15px; - margin: 0 auto; - - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - - i { - color: $color-link; - } - } - - label { - color: lighten($color-body-text, 8); - } - - .filter-actions { - margin-bottom: -32px; - margin-top: 15px; - text-align: center; - - form { - display: inline-block; - } - - button, - .button, - input[type="submit"], - input[type="button"], - span.or { - @include border-radius($border-radius); - - -webkit-box-shadow: 0 0 0 15px $color-1; - -moz-box-shadow: 0 0 0 15px $color-1; - -ms-box-shadow: 0 0 0 15px $color-1; - -o-box-shadow: 0 0 0 15px $color-1; - box-shadow: 0 0 0 15px $color-1; - - &:hover { - border-color: $color-1; - } - - &:first-of-type { - margin-right: 1.25em; - } - } - - span.or { - background-color: $color-1; - border-width: 5px; - margin-left: 5px; - margin-right: 5px; - position: relative; - - -webkit-box-shadow: 0 0 0 5px $color-1; - -moz-box-shadow: 0 0 0 5px $color-1; - -ms-box-shadow: 0 0 0 5px $color-1; - -o-box-shadow: 0 0 0 5px $color-1; - box-shadow: 0 0 0 5px $color-1; - } - } - - &.labels-inline { - .field { - margin-bottom: 0; - display: table; - width: 100%; - - label, - input { - display: table-cell !important; - } - input { - width: 100%; - } - - &.checkbox { - input { - width: auto !important; - } - } - } - .actions { - padding: 0; - text-align: right; - } - } -} - -.form-buttons { - text-align: center; -} - -select { - @extend input, [type="text"]; - background-color: white; -} - -.inline-checkbox { - display: inline-flex; - align-items: center; - margin-top: 3px; - - input, - label { - cursor: pointer; - } - label { - margin: 0; - padding-left: 0.4rem; - } -} diff --git a/app/webpacker/css/admin/shared/icons.scss b/app/webpacker/css/admin/shared/icons.scss deleted file mode 100644 index 2e581b209b..0000000000 --- a/app/webpacker/css/admin/shared/icons.scss +++ /dev/null @@ -1,25 +0,0 @@ -// Some fixes for fontwesome stylesheets -[class^="icon-"], [class*=" icon-"] { - &:before { - padding-right: 5px; - } - - &.button, &.icon_link { - width: auto; - - &:before { - padding-top: 3px; - } - } -} - -.icon-email:before { @extend .icon-envelope, :before; } -.icon-resend_authorization_email:before { @extend .icon-envelope, :before; } -.icon-resume:before { @extend .icon-refresh, :before; } - -.icon-cancel:before, -.icon-void:before { @extend .icon-remove, :before; } - -.icon-capture, -.icon-capture_and_complete_order { @extend .icon-ok } -.icon-credit:before { @extend .icon-ok, :before ; } diff --git a/app/webpacker/css/admin/shared/layout.scss b/app/webpacker/css/admin/shared/layout.scss deleted file mode 100644 index 35d4c2613d..0000000000 --- a/app/webpacker/css/admin/shared/layout.scss +++ /dev/null @@ -1,134 +0,0 @@ -// Basics -//--------------------------------------------------- -* { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; -} - -.admin { - &__section-header { - padding: 15px 0; - background-color: very-light($color-3, 4); - border-bottom: 1px solid $color-border; - - .ofn-drop-down { - border: 0; - background-color: $spree-blue; - color: $color-1; - float: none; - margin-left: 3px; - &:hover, - &.expanded { - border: 0; - color: $color-1; - } - } - - &__content { - display: flex; - align-items: center; - justify-content: space-between; - flex-wrap: wrap; - @media all and (min-width: $tablet_breakpoint) { - flex-wrap: nowrap; - } - } - - &__title { - width: 100%; - margin-bottom: 10px; - @media all and (min-width: $tablet_breakpoint) { - margin-bottom: 0; - } - } - - &__actions { - display: flex; - flex: 1 0 auto; - align-items: center; - list-style: none; - @media all and (min-width: $tablet_breakpoint) { - justify-content: flex-end; - } - > li { - display: flex; - margin-right: 10px; - &:empty { - display: none; - } - &:last-child { - margin-right: 0; - } - } - } - } -} - -.hidden { - display: none; -} - -.float-right { - float: right; -} - -.float-left { - float: left; -} - -.mr-0 { - margin-right: 0 !important; -} - -.ml-0 { - margin-left: 0 !important; -} - -@media print { - .print-hidden { - display: none !important; - } -} - -// Header -//--------------------------------------------------- -#header { - background-color: $color-1; - padding: 5px 0; -} - -#logo { - height: 40px; -} - -.page-title { - i { - color: $color-2; - } -} - -// Content -//--------------------------------------------------- -#content { - background-color: $color-1; - position: relative; - z-index: 0; - padding: 0; - margin-top: 15px; -} - -// Footer -//--------------------------------------------------- -#footer { - margin-top: 15px; - border-top: 1px solid $color-border; - padding: 10px 0; -} - -@media print { - header, - nav { - display: none; - } -} diff --git a/app/webpacker/css/admin/shared/tables.scss b/app/webpacker/css/admin/shared/tables.scss deleted file mode 100644 index a518f223b1..0000000000 --- a/app/webpacker/css/admin/shared/tables.scss +++ /dev/null @@ -1,208 +0,0 @@ -table { - width: 100%; - margin-bottom: 15px; - border-collapse: separate; - - th, td { - padding: 7px 5px; - border-right: 1px solid $color-border; - border-bottom: 1px solid $color-border; - vertical-align: middle; - text-overflow: ellipsis; - - img { - border: 1px solid transparent; - } - - &:first-child { - border-left: 1px solid $color-border; - } - - a { - border-bottom: 1px dotted lighten($color-link, 10); - - &:hover { - border-color: lighten($color-link-hover, 10); - } - } - - .handle { - display: block !important; - text-align: center; - padding-right: 0; - } - - &.actions { - background-color: transparent; - border: none !important; - text-align: center; - - span.text { - font-size: $body-font-size; - } - - [class*='icon-'].no-text { - font-size: 120%; - background-color: very-light($color-3); - border: 1px solid $color-border; - border-radius: 15px; - width: 29px; - height: 29px; - display: inline-block; - padding-top: 2px; - - &:before { - text-align: center !important; - width: 27px; - display: inline-block; - } - - &:hover { - border-color: transparent; - } - } - - button[class*='icon-'] { - color: $color-link; - padding: 0 !important; - } - - .icon-envelope-alt, .icon-eye-open { - color: $color-link; - padding-left: 0px; - - &:hover { - background-color: $color-3; - color: $color-1; - } - } - .icon-trash:hover, .icon-void:hover { - background-color: $color-error; - color: $color-1; - } - .icon-cancel:hover { - background-color: $color-notice; - color: $color-1; - } - .icon-edit:hover, .icon-capture:hover, .icon-capture_and_complete_order:hover, .icon-ok:hover, .icon-plus:hover, .icon-road:hover { - background-color: $color-success; - color: $color-1; - } - .icon-copy:hover { - background-color: $color-notice; - color: $color-1; - } - } - - input[type="number"], - input[type="text"] { - width: 100%; - } - - &.no-border { - border-right: none; - } - - .handle { - @extend .icon-reorder; - font-family: FontAwesome; - text-decoration: inherit; - display: inline-block; - speak: none; - cursor: move; - } - - } - - &.no-borders { - td, th { - border: none !important; - } - - } - - thead { - th { - padding: 10px; - border-top: 1px solid $color-border; - border-bottom: none; - background-color: $color-tbl-thead; - text-transform: uppercase; - font-size: 85%; - font-weight: $font-weight-bold; - } - } - - tbody { - tr { - &:first-child th, - &:first-child td { - border-top: 1px solid $color-border; - } - &.even td { - background-color: $color-tbl-even; - - img { - border: 1px solid very-light($color-3, 6); - } - } - - &:hover td { - background-color: very-light($color-3, 5); - - img { - border: 1px solid $color-border; - } - } - - &.deleted td { - background-color: very-light($color-error, 6); - border-color: very-light($color-error, 15); - } - - &.ui-sortable-placeholder td { - border: 1px solid $color-2 !important; - visibility: visible !important; - - &.actions { - background-color: transparent; - border-right: none !important; - border-top: none !important; - border-bottom: none !important; - border-left: 1px solid $color-2 !important; - } - } - - &.ui-sortable-helper { - width: 100%; - - td { - background-color: lighten($color-3, 33); - border-bottom: 1px solid $color-border; - - &.actions { - display: none; - } - } - } - } - - &.no-border-top tr:first-child td { - border-top: none; - } - - &.grand-total { - td { - border-color: $color-2 !important; - text-transform: uppercase; - font-size: 110%; - font-weight: 600; - background-color: lighten($color-2, 50); - } - .total { - background-color: $color-2; - color: $color-1; - } - } - } -} diff --git a/app/webpacker/css/admin/shared/typography.scss b/app/webpacker/css/admin/shared/typography.scss deleted file mode 100644 index 4435933458..0000000000 --- a/app/webpacker/css/admin/shared/typography.scss +++ /dev/null @@ -1,158 +0,0 @@ -// Base -//-------------------------------------------------------------- -body, div, dl, dt, dd, ul, ol, li, h1, h2, h3, h4, h5, h6, pre, form, p, blockquote, th, td { margin: 0; padding: 0; font-size: $body-font-size; } - -body { - font-family: $base-font-family; - font-size: $body-font-size; - font-weight: 400; - color: $color-body-text; - text-rendering: optimizeLegibility; -} - -hr { - border-top: 1px solid $color-border; - border-bottom: 1px solid white; - border-left: none; -} - -strong, b { - font-weight: 600; -} - -// links -//-------------------------------------------------------------- -a { - color: $color-link; - text-decoration: none; - line-height: inherit; - - &, &:hover, &:active, &:visited, &:focus { - outline: none; - } - - &:visited { - color: $color-link-visited; - } - &:focus { - color: $color-link-focus; - } - &:active { - color: $color-link-active; - } - &:hover { - color: $color-link-hover; - } -} - -// Headings -//-------------------------------------------------------------- - -h1,h2,h3,h4,h5,h6 { - font-weight: 600; - color: $color-headers; - line-height: 1.1; -} - -h1 { font-size: $h1-size; line-height: $h1-size + 6 } -h2 { font-size: $h2-size; line-height: $h1-size + 4 } -h3 { font-size: $h3-size; line-height: $h1-size + 2 } -h4 { font-size: $h4-size; line-height: $h1-size } -h5 { font-size: $h5-size; line-height: $h1-size } -h6 { font-size: $h6-size; line-height: $h1-size } - - -// Lists -//-------------------------------------------------------------- -ul { - &.inline-menu { - li { - display: inline-block; - } - } - &.fields { - list-style: none; - padding: 0; - margin: 0; - } -} - -dl { - width: 100%; - overflow: hidden; - margin: 5px 0; - color: lighten($color-body-text, 15); - - dt, dd { - float: left; - line-height: 16px; - padding: 5px; - text-align: justify; - } - - dt { - width: 40%; - font-weight: 600; - padding-left: 0; - text-transform: uppercase; - font-size: 85%; - } - - dd { - width: 60%; - padding-right: 0; - } - - dd:after { - content: ''; - clear: both; - } - -} - -// Helpers -.align-center { text-align: center } -.align-right { text-align: right } -.align-left { text-align: left } -.align-justify { text-align: justify } - -.uppercase { text-transform: uppercase } - -.green { color: $color-2 } -.blue { color: $color-3 } -.red { color: $color-5 } -.yellow { color: $color-6 } - -.no-objects-found { - text-align: center; - font-size: 120%; - text-transform: uppercase; - padding: 40px 0px; - color: lighten($color-body-text, 15); -} - -.text-normal { - font-size: 1rem; - font-weight: 300; -} - -.text-big { - font-size: 1.2rem; - font-weight: 300; -} - -.text-red { - color: $color-warning; -} - -input.text-big { - font-size: 1.1rem; -} - -.pad-top { - padding-top: 1em; -} - -.white-space-nowrap { - white-space: nowrap; -} diff --git a/app/webpacker/css/admin/terms_of_service_banner.scss b/app/webpacker/css/admin/terms_of_service_banner.scss deleted file mode 100644 index ca23f9b763..0000000000 --- a/app/webpacker/css/admin/terms_of_service_banner.scss +++ /dev/null @@ -1,27 +0,0 @@ -#banner-container { - position: fixed; - bottom: 0px; - left: 0; - width: 100%; - z-index: $tos-banner-z-index; - - .terms-of-service-banner { - padding: 18px; - text-align: center; - font-size: 120%; - color: white; - font-weight: 600; - margin-top: 0; - background-color: rgba($color-notice, 0.8); - display: flex; - - .column-left { - width: 70%; - } - - .column-right { - width: 30%; - text-align: center; - } - } -} diff --git a/app/webpacker/packs/admin-styles.scss b/app/webpacker/packs/admin-styles.scss deleted file mode 100644 index 32d33f37b6..0000000000 --- a/app/webpacker/packs/admin-styles.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import "../css/admin/all.scss"; -@import "../../../node_modules/trix/dist/trix.css"; diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 9c3eb66324..9b844fcfd0 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -73,17 +73,13 @@ Openfoodnetwork::Application.routes.draw do post :import, on: :collection end - constraints FeatureToggleConstraint.new(:admin_style_v3) do - # This might be easier to arrange once we rename the controller to plain old "products" - post '/products/bulk_update', to: 'products_v3#bulk_update' - get '/products', to: 'products_v3#index' - # we already have DELETE admin/products/:id here - delete 'products_v3/:id', to: 'products_v3#destroy', as: 'product_destroy' - delete 'products_v3/destroy_variant/:id', to: 'products_v3#destroy_variant', as: 'destroy_variant' - post 'clone/:id', to: 'products_v3#clone', as: 'clone_product' - - resources :product_preview, only: [:show] - end + # This might be easier to arrange once we rename the controller to plain old "products" + post '/products/bulk_update', to: 'products_v3#bulk_update', as: 'products_bulk_update' + get '/products', to: 'products_v3#index', as: 'products' + delete 'products_v3/:id', to: 'products_v3#destroy', as: 'product_destroy' + delete 'products_v3/destroy_variant/:id', to: 'products_v3#destroy_variant', as: 'destroy_variant' + post 'clone/:id', to: 'products_v3#clone', as: 'clone_product' + resources :product_preview, only: [:show] resources :variant_overrides do post :bulk_update, on: :collection diff --git a/config/routes/spree.rb b/config/routes/spree.rb index c6c84fddbe..512f708b14 100644 --- a/config/routes/spree.rb +++ b/config/routes/spree.rb @@ -50,16 +50,8 @@ Spree::Core::Engine.routes.draw do resources :users - constraints FeatureToggleConstraint.new(:admin_style_v3, negate: true) do - # Show old bulk products screen - resources :products, :index do - post :bulk_update, :on => :collection, :as => :bulk_update - end - end - - resources :products, except: :index do + resources :products, except: [:index, :destroy] do member do - get :clone get :group_buy_options get :seo end @@ -83,11 +75,6 @@ Spree::Core::Engine.routes.draw do end end - if Rails.env.development? - # duplicate old path for reference when admin_style_v3 enabled - resources :products_old, to: 'products#index', only: :index - end - get '/variants/search', :to => "variants#search", :as => :search_variants resources :properties diff --git a/db/migrate/20240625024328_activate_admin_style_v3_for_new_users.rb b/db/migrate/20240625024328_activate_admin_style_v3_for_new_users.rb deleted file mode 100644 index 55fb41febd..0000000000 --- a/db/migrate/20240625024328_activate_admin_style_v3_for_new_users.rb +++ /dev/null @@ -1,5 +0,0 @@ -class ActivateAdminStyleV3ForNewUsers < ActiveRecord::Migration[7.0] - def up - Flipper.enable_group(:admin_style_v3, :new_2024_07_03) - end -end diff --git a/db/migrate/20240710013128_enable_feature_admin_style_v3_for_admins.rb b/db/migrate/20240710013128_enable_feature_admin_style_v3_for_admins.rb deleted file mode 100644 index 9d04164719..0000000000 --- a/db/migrate/20240710013128_enable_feature_admin_style_v3_for_admins.rb +++ /dev/null @@ -1,5 +0,0 @@ -class EnableFeatureAdminStyleV3ForAdmins < ActiveRecord::Migration[7.0] - def up - Flipper.enable_group(:admin_style_v3, :admins) - end -end diff --git a/db/migrate/20240715103415_enable_admin_style_v3_by_default.rb b/db/migrate/20240715103415_enable_admin_style_v3_by_default.rb deleted file mode 100644 index 29099bcb0f..0000000000 --- a/db/migrate/20240715103415_enable_admin_style_v3_by_default.rb +++ /dev/null @@ -1,7 +0,0 @@ -class EnableAdminStyleV3ByDefault < ActiveRecord::Migration[7.0] - def up - if Rails.env.development? - Flipper.enable(:admin_style_v3) - end - end -end diff --git a/db/migrate/20240718150852_activate_admin_style_v3_for_25_p_cent_users.rb b/db/migrate/20240718150852_activate_admin_style_v3_for_25_p_cent_users.rb deleted file mode 100644 index 066a18745f..0000000000 --- a/db/migrate/20240718150852_activate_admin_style_v3_for_25_p_cent_users.rb +++ /dev/null @@ -1,5 +0,0 @@ -class ActivateAdminStyleV3For25PCentUsers < ActiveRecord::Migration[7.0] - def up - Flipper.enable_percentage_of_actors(:admin_style_v3, 25) - end -end diff --git a/db/migrate/20240731065321_activate_admin_style_v3_for50_pc_users.rb b/db/migrate/20240731065321_activate_admin_style_v3_for50_pc_users.rb deleted file mode 100644 index 0cde1950fb..0000000000 --- a/db/migrate/20240731065321_activate_admin_style_v3_for50_pc_users.rb +++ /dev/null @@ -1,5 +0,0 @@ -class ActivateAdminStyleV3For50PcUsers < ActiveRecord::Migration[7.0] - def up - Flipper.enable_percentage_of_actors(:admin_style_v3, 50) - end -end diff --git a/db/migrate/20240810150912_activate_admin_style_v3_for75_pc_users.rb b/db/migrate/20240810150912_activate_admin_style_v3_for75_pc_users.rb deleted file mode 100644 index cc412c0b58..0000000000 --- a/db/migrate/20240810150912_activate_admin_style_v3_for75_pc_users.rb +++ /dev/null @@ -1,9 +0,0 @@ -class ActivateAdminStyleV3For75PcUsers < ActiveRecord::Migration[7.0] - def up - Flipper.enable_percentage_of_actors(:admin_style_v3, 75) - end - - def down - Flipper.enable_percentage_of_actors(:admin_style_v3, 50) - end -end diff --git a/db/migrate/20240828203544_fully_enable_admin_style_v3_flag.rb b/db/migrate/20240828203544_fully_enable_admin_style_v3_flag.rb deleted file mode 100644 index db2fd6007f..0000000000 --- a/db/migrate/20240828203544_fully_enable_admin_style_v3_flag.rb +++ /dev/null @@ -1,5 +0,0 @@ -class FullyEnableAdminStyleV3Flag < ActiveRecord::Migration[7.0] - def up - Flipper.enable(:admin_style_v3) - end -end diff --git a/lib/open_food_network/feature_toggle.rb b/lib/open_food_network/feature_toggle.rb index a373917ea3..daef91de47 100644 --- a/lib/open_food_network/feature_toggle.rb +++ b/lib/open_food_network/feature_toggle.rb @@ -8,16 +8,10 @@ module OpenFoodNetwork # module FeatureToggle def self.conditional_features - features = {} - if Rails.env.development? - features.merge!({ - "admin_style_v3" => <<~DESC, - Test the work-in-progress design updates. - DESC - }); - end + # Returns environment-specific features that are conditionally available + # Currently empty but can be used to add features based on environment - features + {} end # Please add your new feature here to appear in the Flipper UI. @@ -76,9 +70,6 @@ module OpenFoodNetwork ACTIVE_BY_DEFAULT = { # Copy features here that were activated in a migration so that new # instances, development and test environments have the feature active. - "admin_style_v3" => <<~DESC, - Test the work-in-progress design updates. - DESC }.freeze def self.setup! @@ -97,9 +88,6 @@ module OpenFoodNetwork # Checks weather a feature is enabled for any of the given actors. def self.enabled?(feature_name, *actors) - # TODO: Need to remove these checks when we fully remove the toggle from development as well - # need this check as Flipper won't recognize 'admin_style_v3' as it is removed for server envs - return true if !Rails.env.development? && feature_name == :admin_style_v3 return Flipper.enabled?(feature_name) if actors.empty? actors.any? do |actor| diff --git a/spec/controllers/spree/admin/products_controller_spec.rb b/spec/controllers/spree/admin/products_controller_spec.rb index af89e197fc..f57392aa81 100644 --- a/spec/controllers/spree/admin/products_controller_spec.rb +++ b/spec/controllers/spree/admin/products_controller_spec.rb @@ -3,130 +3,6 @@ require 'spec_helper' RSpec.describe Spree::Admin::ProductsController do - describe 'bulk_update' do - context "updating a product we do not have access to" do - let(:s_managed) { create(:enterprise) } - let(:s_unmanaged) { create(:enterprise) } - let(:product) do - create(:simple_product, supplier_id: s_unmanaged.id, name: 'Peas') - end - - before do - controller_login_as_enterprise_user [s_managed] - spree_post :bulk_update, - "products" => [{ "id" => product.id, "name" => "Pine nuts" }] - end - - it "denies access" do - expect(response).to redirect_to unauthorized_path - end - - it "does not update any product" do - expect(product.reload.name).not_to eq("Pine nuts") - end - end - - context "when changing a product's variant_unit" do - let(:producer) { create(:enterprise) } - let!(:product) do - create( - :simple_product, - supplier_id: producer.id, - variant_unit: 'items', - variant_unit_scale: nil, - variant_unit_name: 'bunches', - unit_value: nil, - unit_description: 'some description' - ) - end - - before { controller_login_as_enterprise_user([producer]) } - - it 'succeeds' do - spree_post :bulk_update, - "products" => [ - { - "id" => product.id, - "variant_unit" => "weight", - "variant_unit_scale" => 1 - } - ] - - expect(response).to have_http_status(:found) - end - - it 'does not redirect to bulk_products' do - spree_post :bulk_update, - "products" => [ - { - "id" => product.id, - "variant_unit" => "weight", - "variant_unit_scale" => 1 - } - ] - - expect(response).to redirect_to( - '/api/v0/products/bulk_products' - ) - end - end - - context 'when passing empty variants_attributes' do - let(:producer) { create(:enterprise) } - let!(:product) do - create( - :simple_product, - supplier_id: producer.id, - variant_unit: 'items', - variant_unit_scale: nil, - variant_unit_name: 'bunches', - unit_value: nil, - unit_description: 'bunches' - ) - end - let!(:another_product) do - create( - :simple_product, - supplier_id: producer.id, - variant_unit: 'weight', - variant_unit_scale: 1000, - variant_unit_name: nil - ) - end - let!(:taxon) { create(:taxon) } - - before { controller_login_as_enterprise_user([producer]) } - - it 'does not fail' do - spree_post :bulk_update, - "products" => [ - { - "id" => another_product.id, - "variants_attributes" => [{}] - }, - { - "id" => product.id, - "variants_attributes" => [ - { - "on_hand" => 2, - "price" => "5.0", - "unit_value" => 4, - "variant_unit" => "weight", - "variant_unit_scale" => "1", - "unit_description" => "", - "display_name" => "name", - "primary_taxon_id" => taxon.id, - "supplier_id" => producer.id - } - ] - } - ] - - expect(response).to have_http_status(:found) - end - end - end - context "creating a new product" do let(:supplier) { create(:supplier_enterprise) } let(:taxon) { create(:taxon) } diff --git a/spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee b/spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee deleted file mode 100644 index 532f569d69..0000000000 --- a/spec/javascripts/unit/admin/bulk_product_update_spec.js.coffee +++ /dev/null @@ -1,1080 +0,0 @@ -describe "filtering products for submission to database", -> - it "accepts an object or an array and only returns an array", -> - expect(filterSubmitProducts([])).toEqual [] - expect(filterSubmitProducts({})).toEqual [] - expect(filterSubmitProducts(1: - id: 1 - name: "lala" - )).toEqual [ - id: 1 - name: "lala" - ] - expect(filterSubmitProducts([ - id: 1 - name: "lala" - ])).toEqual [ - id: 1 - name: "lala" - ] - expect(filterSubmitProducts(1)).toEqual [] - expect(filterSubmitProducts("2")).toEqual [] - expect(filterSubmitProducts(null)).toEqual [] - - it "only returns products which have an id property", -> - expect(filterSubmitProducts([ - { - id: 1 - name: "p1" - } - { - notanid: 2 - name: "p2" - } - ])).toEqual [ - id: 1 - name: "p1" - ] - - it "does not return a product object for products which have no propeties other than an id", -> - expect(filterSubmitProducts([ - { - id: 1 - someunwantedproperty: "something" - } - { - id: 2 - name: "p2" - } - ])).toEqual [ - id: 2 - name: "p2" - ] - - it "does not return an on_hand count when a product has variants", -> - testProduct = - id: 1 - on_hand: 5 - variants: [ - id: 1 - on_hand: 5 - price: 12.0 - ] - - expect(filterSubmitProducts([testProduct])).toEqual [ - id: 1 - variants_attributes: [ - id: 1 - on_hand: 5 - price: 12.0 - ] - ] - - it "returns variants as variants_attributes", -> - testProduct = - id: 1 - variants: [ - id: 1 - on_hand: 5 - price: 12.0 - unit_value: 250 - unit_description: "(bottle)" - ] - - expect(filterSubmitProducts([testProduct])).toEqual [ - id: 1 - variants_attributes: [ - id: 1 - on_hand: 5 - price: 12.0 - unit_value: 250 - unit_description: "(bottle)" - ] - ] - - it "ignores variants without an id, and those for which deleted_at is not null", -> - testProduct = - id: 1 - variants: [ - { - id: 1 - on_hand: 3 - price: 5.0 - } - { - on_hand: 1 - price: 15.0 - } - { - id: 2 - on_hand: 2 - deleted_at: new Date() - price: 20.0 - } - ] - - expect(filterSubmitProducts([testProduct])).toEqual [ - id: 1 - variants_attributes: [ - id: 1 - on_hand: 3 - price: 5.0 - ] - ] - - it "returns variants with a negative id without that id", -> - testProduct = - id: 1 - variants: [ - id: -1 - on_hand: 5 - price: 12.0 - unit_value: 250 - unit_description: "(bottle)" - ] - - expect(filterSubmitProducts([testProduct])).toEqual [ - id: 1 - variants_attributes: [ - on_hand: 5 - price: 12.0 - unit_value: 250 - unit_description: "(bottle)" - ] - ] - - it "does not return variants_attributes property if variants is an empty array", -> - testProduct = - id: 1 - price: 10 - variants: [] - - expect(filterSubmitProducts([testProduct])).toEqual [ - id: 1 - price: 10 - ] - - it "returns variant_unit_with_scale as variant_unit and variant_unit_scale", -> - testProduct = - id: 1 - variants: [ - id: 1 - variant_unit: 'weight' - variant_unit_scale: 1 - variant_unit_with_scale: 'weight_1' - ] - - expect(filterSubmitProducts([testProduct])).toEqual [ - id: 1 - variants_attributes: [ - id: 1 - variant_unit: 'weight' - variant_unit_scale: 1 - ] - ] - - it "returns stock properties of a product if no variant is provided", -> - testProduct = - id: 1 - name: "TestProduct" - on_hand: 0 - on_demand: false - - expect(filterSubmitProducts([testProduct])).toEqual [ - id: 1 - name: "TestProduct" - on_hand: 0 - on_demand: false - ] - - it "only returns the properties of products which ought to be updated", -> - testProduct = - id: 1 - name: "TestProduct" - description: "" - deleted_at: null - meta_keywords: null - shipping_category_id: null - created_at: null - updated_at: null - on_hand: 0 - on_demand: false - group_buy: null - group_buy_unit_size: null - variants: [ - id: 1 - on_hand: 2 - price: 10.0 - unit_value: 250 - tax_category_id: null - unit_description: "(bottle)" - display_as: "bottle" - display_name: "nothing" - producer_id: 5 - variant_unit: 'volume' - variant_unit_scale: 1 - variant_unit_name: 'loaf' - variant_unit_with_scale: 'volume_1' - ] - - expect(filterSubmitProducts([testProduct])).toEqual [ - id: 1 - name: "TestProduct" - variants_attributes: [ - id: 1 - on_hand: 2 - price: 10.0 - unit_value: 250 - tax_category_id: null - unit_description: "(bottle)" - display_as: "bottle" - display_name: "nothing" - supplier_id: 5 - variant_unit: 'volume' - variant_unit_scale: 1 - variant_unit_name: 'loaf' - ] - ] - -describe "AdminProductEditCtrl", -> - $ctrl = $scope = $timeout = $httpBackend = BulkProducts = DirtyProducts = DisplayProperties = ProductFiltersUrl = windowStub = null - - beforeEach -> - module "ofn.admin" - module ($provide)-> - $provide.value "producers", [] - $provide.value "taxons", [] - $provide.value "tax_categories", [] - $provide.value 'SpreeApiKey', 'API_KEY' - $provide.value 'columns', [] - null - module "admin.products" - module ($provide)-> - $provide.value "availableUnits", "g,kg,T,mL,L,kL" - null - - beforeEach inject((_$controller_, _$timeout_, $rootScope, _$httpBackend_, _BulkProducts_, _DirtyProducts_, _DisplayProperties_, _ProductFiltersUrl_) -> - $scope = $rootScope.$new() - $ctrl = _$controller_ - $timeout = _$timeout_ - $httpBackend = _$httpBackend_ - BulkProducts = _BulkProducts_ - DirtyProducts = _DirtyProducts_ - DisplayProperties = _DisplayProperties_ - ProductFiltersUrl = _ProductFiltersUrl_ - - # Stub the window object so we don't get redirected when href is updated - windowStub = {navigator: {userAgent: 'foo'}, location: {href: ''}} - - $ctrl "AdminProductEditCtrl", {$scope: $scope, $timeout: $timeout, $window: windowStub} - ) - - describe "loading data upon initialisation", -> - beforeEach -> - spyOn($scope, "fetchProducts").and.returnValue "nothing" - - it "gets a list of producers and then resets products with a list of data", -> - $scope.initialise() - expect($scope.fetchProducts.calls.count()).toBe 1 - - it "gets a list of products applying filters from the url", inject ($location) -> - query = 'lala' - producerFilter = 2 - categoryFilter = 5 - sorting = 'name desc' - importDateFilter = '2020-06-08' - $location.search({query: query, producerFilter: producerFilter, categoryFilter: categoryFilter, sorting: sorting, importDateFilter: importDateFilter}) - - $scope.initialise() - - expect($scope.q.query).toBe query - expect($scope.q.categoryFilter).toBe categoryFilter - expect($scope.q.sorting).toBe sorting - expect($scope.q.importDateFilter).toBe importDateFilter - - describe "fetching products", -> - $q = null - deferred = null - - beforeEach inject((_$q_) -> - $q = _$q_ - ) - - beforeEach -> - deferred = $q.defer() - deferred.resolve() - spyOn $scope, "resetProducts" - spyOn(BulkProducts, "fetch").and.returnValue deferred.promise - - it "calls resetProducts after data has been received", -> - $scope.fetchProducts() - $scope.$digest() - expect($scope.resetProducts).toHaveBeenCalled() - - it "updates url with filter after data has been received", inject ($location, $window) -> - query = 'lala' - producerFilter = 2 - categoryFilter = 5 - sorting = 'name desc' - importDateFilter = '2020-06-08' - - $scope.q.query = query - $scope.q.producerFilter = producerFilter - $scope.q.categoryFilter = categoryFilter - $scope.q.sorting = sorting - $scope.q.importDateFilter = importDateFilter - - $scope.fetchProducts() - $scope.$digest() - - encodedSorting = $window.encodeURIComponent(sorting) - encodedDate = $window.encodeURIComponent(importDateFilter) - expect($location.url()).toBe( - "?producerFilter=#{producerFilter}&categoryFilter=#{categoryFilter}&query=#{query}&sorting=#{encodedSorting}&importDateFilter=#{encodedDate}" - ) - - describe "resetting products", -> - beforeEach -> - spyOn DirtyProducts, "clear" - $scope.products = {} - $scope.resetProducts [ - { - id: 1 - name: "P1" - } - { - id: 3 - name: "P2" - } - ] - - it "resets dirtyProducts", -> - expect(DirtyProducts.clear).toHaveBeenCalled() - - describe "sorting products", -> - it "sorts products", -> - spyOn $scope, "fetchProducts" - - $scope.sortOptions.toggle('name') - $scope.$apply() - - expect($scope.sorting).toEqual 'name desc' - expect($scope.fetchProducts).toHaveBeenCalled() - - describe "updating the product on hand count", -> - it "updates when product is not available on demand", -> - spyOn($scope, "onHand").and.returnValue 123 - product = {on_demand: false} - $scope.updateOnHand(product) - expect(product.on_hand).toEqual 123 - - it "updates when product's variants are not available on demand", -> - spyOn($scope, "onHand").and.returnValue 123 - product = {on_demand: false, variants: [{on_demand: false}]} - $scope.updateOnHand(product) - expect(product.on_hand).toEqual 123 - - it "does nothing when the product is available on demand", -> - product = {on_demand: true} - $scope.updateOnHand(product) - expect(product.on_hand).toBeUndefined() - - it "does nothing when one of the variants is available on demand", -> - product = - on_demand: false - variants: [ - {on_demand: false, on_hand: 10} - {on_demand: true, on_hand: Infinity} - ] - $scope.updateOnHand(product) - expect(product.on_hand).toBeUndefined() - - - describe "getting on_hand counts when products have variants", -> - p1 = undefined - p2 = undefined - p3 = undefined - beforeEach -> - p1 = variants: - 1: - id: 1 - on_hand: 1 - - 2: - id: 2 - on_hand: 2 - - 3: - id: 3 - on_hand: 3 - - p2 = variants: - 4: - id: 4 - not_on_hand: 1 - - 5: - id: 5 - on_hand: 2 - - 6: - id: 6 - on_hand: 3 - - p3 = - not_variants: - 7: - id: 7 - on_hand: 1 - - 8: - id: 8 - on_hand: 2 - - variants: - 9: - id: 9 - on_hand: 3 - - it "sums variant on_hand properties", -> - expect($scope.onHand(p1)).toEqual 6 - - it "ignores items in variants without an on_hand property (adds 0)", -> - expect($scope.onHand(p2)).toEqual 5 - - it "ignores on_hand properties of objects in arrays which are not named 'variants' (adds 0)", -> - expect($scope.onHand(p3)).toEqual 3 - - it "returns 'error' if not given an object with a variants property that is an object", -> - expect($scope.onHand([])).toEqual "error" - expect($scope.onHand(not_variants: [])).toEqual "error" - - - describe "determining whether a product has variants that are available on demand", -> - it "returns true when at least one variant does", -> - product = - variants: [ - {on_demand: false} - {on_demand: true} - ] - expect($scope.hasOnDemandVariants(product)).toBe(true) - - it "returns false otherwise", -> - product = - variants: [ - {on_demand: false} - {on_demand: false} - ] - expect($scope.hasOnDemandVariants(product)).toBe(false) - - - describe "determining whether a product has variants", -> - it "returns true when it does", -> - product = - variants: [{id: 1}, {id: 2}] - expect($scope.hasVariants(product)).toBe(true) - - it "returns false when it does not", -> - product = - variants: [] - expect($scope.hasVariants(product)).toBe(false) - - - describe "determining whether a product has a unit", -> - it "returns true when it does", -> - variant ={variant_unit_with_scale: 'weight_1000'} - - expect($scope.hasUnit(variant)).toBe(true) - - it "returns false when its unit is undefined", -> - variant = {} - expect($scope.hasUnit(variant)).toBe(false) - - - describe "determining whether a variant has been saved", -> - it "returns true when it has a positive id", -> - variant = {id: 1} - expect($scope.variantSaved(variant)).toBe(true) - - it "returns false when it has no id", -> - variant = {} - expect($scope.variantSaved(variant)).toBe(false) - - it "returns false when it has a negative id", -> - variant = {id: -1} - expect($scope.variantSaved(variant)).toBe(false) - - - describe "submitting products to be updated", -> - describe "packing products", -> - beforeEach -> - window.bigDecimal = jasmine.createSpyObj "bigDecimal", ["multiply"] - window.bigDecimal.multiply.and.callFake (a, b, c) -> (a * b).toFixed(c) - - it "packs each variant", -> - spyOn $scope, "packVariant" - testVariant = {id: 1} - testProduct = - id: 1 - variants: {1: testVariant} - - $scope.packProduct(testProduct) - - expect($scope.packVariant).toHaveBeenCalledWith(testVariant) - - describe "packing variants", -> - beforeEach -> - window.bigDecimal = jasmine.createSpyObj "bigDecimal", ["multiply"] - window.bigDecimal.multiply.and.callFake (a, b, c) -> (a * b).toFixed(c) - - it "extracts variant_unit_with_scale into variant_unit and variant_unit_scale", -> - testVariant = - id: 1 - variant_unit: 'weight' - variant_unit_scale: 1 - variant_unit_with_scale: 'volume_1000' - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - id: 1 - variant_unit: 'volume' - variant_unit_scale: 1000 - variant_unit_with_scale: 'volume_1000' - - it "extracts when variant_unit_with_scale is 'items'", -> - testVariant = - id: 1 - variant_unit: 'weight' - variant_unit_scale: 1 - variant_unit_with_scale: 'items' - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - id: 1 - variant_unit: 'items' - variant_unit_scale: null - variant_unit_with_scale: 'items' - - it "extracts unit_value and unit_description from unit_value_with_description", -> - testVariant = {unit_value_with_description: "250.5 (bottle)"} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: 250.5 - unit_description: "(bottle)" - unit_value_with_description: "250.5 (bottle)" - - it "extracts into unit_value when only a number is provided", -> - testVariant = {variant_unit_scale: 1.0, unit_value_with_description: "250.5"} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: 250.5 - unit_description: '' - unit_value_with_description: "250.5" - variant_unit_scale: 1.0 - - it "extracts into unit_description when only a string is provided", -> - testVariant = {unit_value_with_description: "Medium"} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: null - unit_description: 'Medium' - unit_value_with_description: "Medium" - - it "extracts into unit_description when a string starting with a number is provided", -> - testVariant = {unit_value_with_description: "1kg"} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: null - unit_description: '1kg' - unit_value_with_description: "1kg" - - it "sets blank values when no value provided", -> - testVariant = {unit_value_with_description: ""} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: null - unit_description: '' - unit_value_with_description: "" - - it "sets nothing when the field is undefined", -> - testVariant = {} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual({}) - - it "sets zero when the field is zero", -> - testVariant = {variant_unit_scale: 1.0, unit_value_with_description: "0"} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: 0 - unit_description: '' - unit_value_with_description: "0" - variant_unit_scale: 1.0 - - it "converts value from chosen unit to base unit", -> - testVariant = {variant_unit_scale: 1000, unit_value_with_description: "250.5"} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: 250500 - unit_description: '' - unit_value_with_description: "250.5" - variant_unit_scale: 1000 - - it "does not convert value when using a non-scaled unit", -> - testVariant = {unit_value_with_description: "12"} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: 12 - unit_description: '' - unit_value_with_description: "12" - - it "converts unit_value into a float when a comma separated number is provided", -> - testVariant = {variant_unit_scale: 1.0, unit_value_with_description: "250,5"} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: 250.5 - unit_description: '' - unit_value_with_description: "250,5" - variant_unit_scale: 1.0 - - it "rounds off the unit_value upto 2 decimal places", -> - testVariant = {variant_unit_scale: 1.0, unit_value_with_description: "1234.567"} - - $scope.packVariant(testVariant) - - expect(testVariant).toEqual - unit_value: 1234.57 - unit_description: '' - unit_value_with_description: "1234.567" - variant_unit_scale: 1.0 - - - describe "filtering products", -> - beforeEach -> - spyOn $scope, "packProduct" - spyOn(window, "filterSubmitProducts").and.returnValue [ - { - id: 1 - value: 3 - } - { - id: 2 - value: 4 - } - ] - spyOn $scope, "updateProducts" - DirtyProducts.addProductProperty 1, "propName", "something" - DirtyProducts.addProductProperty 2, "propName", "something" - $scope.products = - 1: - id: 1 - 2: - id: 2 - - $scope.submitProducts() - - it "packs all products and all dirty products", -> - expect($scope.packProduct.calls.count()).toBe 4 - - it "filters returned dirty products", -> - expect(filterSubmitProducts).toHaveBeenCalledWith - 1: - id: 1 - propName: "something" - 2: - id: 2 - propName: "something" - - - it "sends dirty and filtered objects to submitProducts()", -> - expect($scope.updateProducts).toHaveBeenCalledWith [ - { - id: 1 - value: 3 - } - { - id: 2 - value: 4 - } - ] - - - describe "updating products", -> - it "submits products to be updated with a http post request to /admin/products/bulk_update", -> - $httpBackend.expectPOST("/admin/products/bulk_update").respond "list of products" - $scope.updateProducts "list of products" - $httpBackend.flush() - - it "runs displaySuccess() when post returns success", -> - spyOn $scope, "displaySuccess" - spyOn BulkProducts, "updateVariantLists" - spyOn DirtyProducts, "clear" - - $scope.bulk_product_form = jasmine.createSpyObj('bulk_product_form', ['$setPristine']) - - $scope.products = [ - { - id: 1 - name: "P1" - } - { - id: 2 - name: "P2" - } - ] - $httpBackend.expectPOST("/admin/products/bulk_update").respond 200, [ - { - id: 1 - name: "P1" - } - { - id: 2 - name: "P2" - } - ] - $scope.updateProducts "list of dirty products" - $httpBackend.flush() - $timeout.flush() - expect($scope.displaySuccess).toHaveBeenCalled() - expect($scope.bulk_product_form.$setPristine).toHaveBeenCalled - expect(DirtyProducts.clear).toHaveBeenCalled() - expect(BulkProducts.updateVariantLists).toHaveBeenCalled() - - it "runs displayFailure() when post returns an error", -> - spyOn $scope, "displayFailure" - $scope.products = "updated list of products" - $httpBackend.expectPOST("/admin/products/bulk_update").respond 500, "updated list of products" - $scope.updateProducts "updated list of products" - $httpBackend.flush() - expect($scope.displayFailure).toHaveBeenCalled() - - describe "displaying the error information when post returns 400", -> - beforeEach -> - spyOn $scope, "displayFailure" - $scope.products = "updated list of products" - - it "displays errors in an array", -> - $httpBackend.expectPOST("/admin/products/bulk_update").respond 400, { "errors": ["an error"] } - $scope.updateProducts "updated list of products" - $httpBackend.flush() - expect($scope.displayFailure).toHaveBeenCalledWith("Saving failed with the following error(s):\nan error\n") - - it "displays errors in a hash", -> - $httpBackend.expectPOST("/admin/products/bulk_update").respond 400, { "errors": { "base": ["a basic error"] } } - $scope.updateProducts "updated list of products" - $httpBackend.flush() - expect($scope.displayFailure).toHaveBeenCalledWith("Saving failed with the following error(s):\na basic error\n") - - - describe "adding variants", -> - beforeEach -> - spyOn DisplayProperties, 'setShowVariants' - - it "adds first and subsequent variants", -> - product = {id: 123, variants: [ - { - id: 1, price: 10.0, unit_value: 1, tax_category_id: null, unit_description: '1kg', - on_demand: false, on_hand: null, display_as: null, display_name: null, category_id: 2 - } - ]} - $scope.addVariant(product) - $scope.addVariant(product) - expect(product).toEqual - id: 123 - variants: [ - {id: 1, price: 10.0, unit_value: 1, tax_category_id: null, unit_description: '1kg', on_demand: false, on_hand: null, display_as: null, display_name: null, category_id: 2} - {id: -1, price: null, unit_value: null, tax_category_id: null, unit_description: null, on_demand: false, on_hand: null, display_as: null, display_name: null, category_id: 2} - {id: -2, price: null, unit_value: null, tax_category_id: null, unit_description: null, on_demand: false, on_hand: null, display_as: null, display_name: null, category_id: 2} - ] - - it "shows the variant(s)", -> - product = {id: 123, variants: []} - $scope.addVariant(product) - expect(DisplayProperties.setShowVariants).toHaveBeenCalledWith 123, true - - - describe "deleting products", -> - it "deletes products with a http delete request to /api/products/id", -> - spyOn(window, "confirm").and.returnValue true - $scope.products = [ - { - id: 9 - } - { - id: 13 - } - ] - $scope.dirtyProducts = {} - $httpBackend.expectDELETE("/api/v0/products/13").respond 200, "data" - $scope.deleteProduct $scope.products[1] - expect(window.confirm).toHaveBeenCalledWith "Are you sure?" - $httpBackend.flush() - - it "removes the specified product from both $scope.products and $scope.dirtyProducts (if it exists there)", -> - spyOn(window, "confirm").and.returnValue true - $scope.products = [ - { - id: 9 - } - { - id: 13 - } - ] - DirtyProducts.addProductProperty 9, "someProperty", "something" - DirtyProducts.addProductProperty 13, "name", "P1" - - $httpBackend.expectDELETE("/api/v0/products/13").respond 200, "data" - $scope.deleteProduct $scope.products[1] - $httpBackend.flush() - expect($scope.products).toEqual [ - id: 9 - ] - expect(DirtyProducts.all()).toEqual 9: - id: 9 - someProperty: "something" - - - - describe "deleting variants", -> - describe "when the variant is the only one left on the product", -> - it "alerts the user", -> - spyOn(window, "alert") - $scope.products = [ - {id: 1, variants: [{id: 1}]} - ] - $scope.deleteVariant $scope.products[0], $scope.products[0].variants[0] - expect(window.alert).toHaveBeenCalledWith "The last variant cannot be deleted!" - - describe "when the variant has not been saved", -> - it "removes the variant from products and dirtyProducts", -> - spyOn(window, "confirm").and.returnValue true - $scope.products = [ - {id: 1, variants: [{id: -1},{id: -2}]} - ] - DirtyProducts.addVariantProperty 1, -1, "something", "something" - DirtyProducts.addProductProperty 1, "something", "something" - $scope.deleteVariant $scope.products[0], $scope.products[0].variants[0] - expect($scope.products).toEqual([ - {id: 1, variants: [{id: -2}]} - ]) - expect(DirtyProducts.all()).toEqual - 1: { id: 1, something: 'something'} - - - describe "when the variant has been saved", -> - it "deletes variants with a http delete request to /api/products/(id)/variants/(variant_id)", -> - spyOn(window, "confirm").and.returnValue true - $scope.products = [ - { - id: 9 - variants: [{ - id: 3 - price: 12 - }, - { - id: 4 - price: 15 - } - ] - } - { - id: 13 - } - ] - $scope.dirtyProducts = {} - $httpBackend.expectDELETE("/api/v0/products/9/variants/3").respond 200, "data" - $scope.deleteVariant $scope.products[0], $scope.products[0].variants[0] - $httpBackend.flush() - - it "removes the specified variant from both the variants object and $scope.dirtyProducts (if it exists there)", -> - spyOn(window, "confirm").and.returnValue true - $scope.products = [ - { - id: 9 - variants: [ - { - id: 3 - price: 12.0 - } - { - id: 4 - price: 6.0 - } - ] - } - { - id: 13 - } - ] - DirtyProducts.addVariantProperty 9, 3, "price", 12.0 - DirtyProducts.addVariantProperty 9, 4, "price", 6.0 - DirtyProducts.addProductProperty 13, "name", "P1" - - $httpBackend.expectDELETE("/api/v0/products/9/variants/3").respond 200, "data" - $scope.deleteVariant $scope.products[0], $scope.products[0].variants[0] - $httpBackend.flush() - expect($scope.products[0].variants).toEqual [ - id: 4 - price: 6.0 - ] - expect(DirtyProducts.all()).toEqual - 9: - id: 9 - variants: - 4: - id: 4 - price: 6.0 - - 13: - id: 13 - name: "P1" - - describe "editWarn", -> - testProduct = testVariant = null - - beforeEach -> - testProduct = - id: 1 - name: "TestProduct" - description: "" - deleted_at: null - meta_keywords: null - shipping_category_id: null - created_at: null - updated_at: null - on_hand: 0 - on_demand: false - producer_id: 5 - group_buy: null - group_buy_unit_size: null - - describe 'product has variant', -> - it 'should load the edit product variant page', -> - testVariant = - id: 2 - name: "TestVariant" - - $scope.editWarn(testProduct, testVariant) - - expect(windowStub.location.href).toBe( - "/admin/products/#{testProduct.id}/variants/#{testVariant.id}/edit" - ) - - describe 'product has no variant', -> - it 'should display unsaved changes confirmation if there are any DirtyProduct', inject ($window, DirtyProducts) -> - spyOn($window, 'confirm') - spyOn(DirtyProducts, 'count').and.returnValue 2 - - $scope.editWarn(testProduct, null) - expect($window.confirm).toHaveBeenCalled() - - it 'should load the edit product page', inject -> - $scope.editWarn(testProduct, null) - - expect(windowStub.location.href).toBe( - "/admin/products/#{testProduct.id}/edit" - ) - - it 'should load edit product page including the selected filters', inject ($httpParamSerializer) -> - query = 'lala' - category = 3 - $scope.q.query = query - $scope.q.categoryFilter = category - - # use $httpParamSerializer as it will sort parameters alphabetically - expectedFilter = $httpParamSerializer({ query: query, categoryFilter: category }) - - $scope.editWarn(testProduct, null) - - expect(windowStub.location.href).toBe( - "/admin/products/#{testProduct.id}/edit?#{expectedFilter}" - ) - - describe "filtering products", -> - describe "clearing filters", -> - it "resets filter variables", -> - $scope.q.query = "lala" - $scope.q.producerFilter = "5" - $scope.q.categoryFilter = "6" - $scope.resetSelectFilters() - expect($scope.q.query).toBe "" - expect($scope.q.producerFilter).toBeUndefined - expect($scope.q.categoryFilter).toBeUndefined - - -describe "converting arrays of objects with ids to an object with ids as keys", -> - it "returns an object", -> - array = [] - expect(toObjectWithIDKeys(array)).toEqual {} - - it "adds each object in the array provided with an id to the returned object with the id as its key", -> - array = [ - { - id: 1 - } - { - id: 3 - } - ] - expect(toObjectWithIDKeys(array)).toEqual - 1: - id: 1 - - 3: - id: 3 - - - it "ignores items which are not objects and those which do not possess ids", -> - array = [ - { - id: 1 - } - "not an object" - { - notanid: 3 - } - ] - expect(toObjectWithIDKeys(array)).toEqual 1: - id: 1 - - - it "sends arrays with the key 'variants' to itself", -> - spyOn(window, "toObjectWithIDKeys").and.callThrough() - array = [ - { - id: 1 - variants: [id: 17] - } - { - id: 2 - variants: - 12: - id: 12 - } - ] - products = toObjectWithIDKeys(array) - expect(products["1"].variants).toEqual 17: - id: 17 - - expect(toObjectWithIDKeys).toHaveBeenCalledWith [id: 17] - expect(toObjectWithIDKeys).not.toHaveBeenCalledWith {12: {id: 12}} diff --git a/spec/javascripts/unit/admin/services/bulk_products_spec.js.coffee b/spec/javascripts/unit/admin/services/bulk_products_spec.js.coffee deleted file mode 100644 index ea741adc35..0000000000 --- a/spec/javascripts/unit/admin/services/bulk_products_spec.js.coffee +++ /dev/null @@ -1,188 +0,0 @@ -describe "BulkProducts service", -> - BulkProducts = $httpBackend = null - - beforeEach -> - module "ofn.admin" - window.bigDecimal = jasmine.createSpyObj "bigDecimal", ["round"] - window.bigDecimal.round.and.callFake (a, b) -> a.toFixed(b) - - beforeEach inject (_BulkProducts_, _$httpBackend_) -> - BulkProducts = _BulkProducts_ - $httpBackend = _$httpBackend_ - - describe "cloning products", -> - it "clones products using a http post request to /api/products/(id)/clone", -> - BulkProducts.products = [ - id: 13 - ] - $httpBackend.expectPOST("/api/v0/products/13/clone").respond 201, - id: 17 - $httpBackend.expectGET("/api/v0/products/17?template=bulk_show").respond 200, [ - id: 17 - ] - BulkProducts.cloneProduct BulkProducts.products[0] - $httpBackend.flush() - - it "adds the product", -> - originalProduct = - id: 16 - clonedProduct = - id: 17 - - spyOn(BulkProducts, "insertProductAfter") - spyOn(BulkProducts, "unpackProduct") - BulkProducts.products = [originalProduct] - $httpBackend.expectPOST("/api/v0/products/16/clone").respond 201, clonedProduct - $httpBackend.expectGET("/api/v0/products/17?template=bulk_show").respond 200, clonedProduct - BulkProducts.cloneProduct BulkProducts.products[0] - $httpBackend.flush() - expect(BulkProducts.unpackProduct).toHaveBeenCalledWith clonedProduct - BulkProducts.unpackProduct(clonedProduct) - expect(BulkProducts.insertProductAfter).toHaveBeenCalledWith originalProduct, clonedProduct - - - describe "preparing products", -> - beforeEach -> - spyOn BulkProducts, "loadVariantUnit" - - it "calls loadVariantUnit for the product", -> - product = {id: 123} - BulkProducts.unpackProduct product - expect(BulkProducts.loadVariantUnit).toHaveBeenCalled() - - - describe "loading variant unit", -> - describe "setting product variant_unit_with_scale field", -> - it "HERE 2 sets by combining variant_unit and variant_unit_scale", -> - product = - variants:[ - id: 10 - variant_unit: "volume" - variant_unit_scale: .001 - ] - BulkProducts.loadVariantUnit product - expect(product.variants[0].variant_unit_with_scale).toEqual "volume_0.001" - - it "sets to null when variant_unit is null", -> - product = - variants: [ - {variant_unit: null, variant_unit_scale: 1000} - ] - BulkProducts.loadVariantUnit product - - expect(product.variants[0].variant_unit_with_scale).toBeNull() - - it "sets to variant_unit when variant_unit_scale is null", -> - product = - variants: [ - {variant_unit: 'items', variant_unit_scale: null, variant_unit_name: 'foo'} - ] - BulkProducts.loadVariantUnit product - expect(product.variants[0].variant_unit_with_scale).toEqual "items" - - it "sets to variant_unit when variant_unit is 'items'", -> - product = - variants: [ - {variant_unit: 'items', variant_unit_scale: 1000, variant_unit_name: 'foo'} - ] - BulkProducts.loadVariantUnit product - expect(product.variants[0].variant_unit_with_scale).toEqual "items" - - it "loads data for variants (excl. master)", -> - spyOn BulkProducts, "loadVariantUnitValue" - - product = - variants: [ - {id: 2, variant_unit_scale: 1.0, unit_value: 2, unit_description: '(two)'} - ] - BulkProducts.loadVariantUnitValues product.variants - - expect(BulkProducts.loadVariantUnitValue).toHaveBeenCalledWith product.variants[0] - - describe "setting variant unit_value_with_description", -> - it "sets by combining unit_value and unit_description", -> - product = - variants: [ - {id: 1, variant_unit_scale: 1.0, unit_value: 1, unit_description: '(bottle)'} - ] - BulkProducts.loadVariantUnitValues product.variants - expect(product.variants[0]).toEqual - id: 1 - variant_unit_scale: 1.0, - variant_unit_with_scale: null, - unit_value: 1 - unit_description: '(bottle)' - unit_value_with_description: '1 (bottle)' - - it "uses unit_value when description is missing", -> - product = - variants: [ - {id: 1, variant_unit_scale: 1.0, unit_value: 1} - ] - BulkProducts.loadVariantUnitValues product.variants - expect(product.variants[0].unit_value_with_description).toEqual '1' - - it "uses unit_description when value is missing", -> - product = - variants: [ - {id: 1, variant_unit_scale: 1.0, unit_description: 'Small'} - ] - BulkProducts.loadVariantUnitValues product.variants - expect(product.variants[0].unit_value_with_description).toEqual 'Small' - - it "converts values from base value to chosen unit", -> - product = - variants: [ - id: 1, variant_unit_scale: 1000.0, unit_value: 2500 - ] - BulkProducts.loadVariantUnitValues product.variants - expect(product.variants[0].unit_value_with_description).toEqual '2.5' - - it "converts values from base value to chosen unit without breaking precision", -> - product = - variants: [ - {id: 1,variant_unit_scale: 0.001, unit_value: 0.35} - ] - BulkProducts.loadVariantUnitValues product.variants - expect(product.variants[0].unit_value_with_description).toEqual '350' - - it "displays a unit_value of zero", -> - product = - variants: [ - {id: 1, variant_unit_scale: 1.0, unit_value: 0} - ] - BulkProducts.loadVariantUnitValues product.variants - expect(product.variants[0].unit_value_with_description).toEqual '0' - - - describe "calculating the scaled unit value for a variant", -> - it "returns the scaled value when variant has a unit_value", -> - variant = {variant_unit_scale: 0.001, unit_value: 5} - expect(BulkProducts.variantUnitValue(variant)).toEqual 5000 - - it "returns the scaled value rounded off upto 2 decimal points", -> - variant = {variant_unit_scale: 28.35, unit_value: 1234.5} - expect(BulkProducts.variantUnitValue(variant)).toEqual 43.54 - - it "returns the unscaled value when the product has no scale", -> - variant = {unit_value: 5} - expect(BulkProducts.variantUnitValue(variant)).toEqual 5 - - it "returns zero when the value is zero", -> - variant = {unit_value: 0} - expect(BulkProducts.variantUnitValue(variant)).toEqual 0 - - it "returns null when the variant has no unit_value", -> - variant = {} - expect(BulkProducts.variantUnitValue(variant)).toEqual null - - - describe "fetching a product by id", -> - it "returns the product when it is present", -> - product = {id: 123} - BulkProducts.products = [product] - expect(BulkProducts.find(123)).toEqual product - - it "returns null when the product is not present", -> - BulkProducts.products = [] - expect(BulkProducts.find(123)).toBeNull()