mirror of
https://github.com/openfoodfoundation/openfoodnetwork
synced 2026-02-27 01:43:22 +00:00
Merge pull request #13436 from chahmedejaz/task/13432-decommission-old-products-screen
Decommission Old Products UI and Related Code
This commit is contained in:
@@ -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
|
||||
@@ -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()
|
||||
@@ -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)
|
||||
@@ -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'
|
||||
})
|
||||
@@ -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)
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
@@ -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}" }
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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'
|
||||
@@ -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}}
|
||||
'
|
||||
@@ -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'
|
||||
@@ -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
|
||||
@@ -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) }
|
||||
@@ -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) }
|
||||
@@ -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()'}
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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";
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 ; }
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
@import "../css/admin/all.scss";
|
||||
@import "../../../node_modules/trix/dist/trix.css";
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
class ActivateAdminStyleV3ForNewUsers < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
Flipper.enable_group(:admin_style_v3, :new_2024_07_03)
|
||||
end
|
||||
end
|
||||
@@ -1,5 +0,0 @@
|
||||
class EnableFeatureAdminStyleV3ForAdmins < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
Flipper.enable_group(:admin_style_v3, :admins)
|
||||
end
|
||||
end
|
||||
@@ -1,7 +0,0 @@
|
||||
class EnableAdminStyleV3ByDefault < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
if Rails.env.development?
|
||||
Flipper.enable(:admin_style_v3)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +0,0 @@
|
||||
class ActivateAdminStyleV3For25PCentUsers < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
Flipper.enable_percentage_of_actors(:admin_style_v3, 25)
|
||||
end
|
||||
end
|
||||
@@ -1,5 +0,0 @@
|
||||
class ActivateAdminStyleV3For50PcUsers < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
Flipper.enable_percentage_of_actors(:admin_style_v3, 50)
|
||||
end
|
||||
end
|
||||
@@ -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
|
||||
@@ -1,5 +0,0 @@
|
||||
class FullyEnableAdminStyleV3Flag < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
Flipper.enable(:admin_style_v3)
|
||||
end
|
||||
end
|
||||
@@ -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|
|
||||
|
||||
@@ -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) }
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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()
|
||||
Reference in New Issue
Block a user