diff --git a/src/Controller/Frontend/ViewMoreController.php b/src/Controller/Frontend/ViewMoreController.php index 5ffb0b7..8625a83 100644 --- a/src/Controller/Frontend/ViewMoreController.php +++ b/src/Controller/Frontend/ViewMoreController.php @@ -43,7 +43,7 @@ public function __construct( } /** - * @Route("/filter_view_more", name="gally_filter_view_more", methods={"GET"}) + * @Route("/filter_view_more", name="gally_filter_view_more", methods={"GET"}, options={"expose"=true}) * * @AclAncestor("oro_product_frontend_view") */ diff --git a/src/DependencyInjection/GallyOroExtension.php b/src/DependencyInjection/GallyOroExtension.php index 09e7222..e6eae5b 100644 --- a/src/DependencyInjection/GallyOroExtension.php +++ b/src/DependencyInjection/GallyOroExtension.php @@ -15,7 +15,6 @@ namespace Gally\OroPlugin\DependencyInjection; use Oro\Bundle\ConfigBundle\DependencyInjection\SettingsBuilder; -use Oro\Bundle\WarehouseBundle\Provider\EnabledWarehousesProvider; use Symfony\Component\Config\FileLocator; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader; @@ -32,7 +31,7 @@ public function load(array $configs, ContainerBuilder $container) $loader->load('services.yml'); $loader->load('controllers.yml'); - if (class_exists(EnabledWarehousesProvider::class)) { + if (class_exists('Oro\Bundle\WarehouseBundle\Provider\EnabledWarehousesProvider')) { $loader->load('services/enterprise.yml'); } } diff --git a/src/Resources/public/default/scss/gally-style.scss b/src/Resources/public/default/scss/gally-style.scss new file mode 100644 index 0000000..9283006 --- /dev/null +++ b/src/Resources/public/default/scss/gally-style.scss @@ -0,0 +1,3 @@ +.dropdown-menu.loading { + position: absolute; +} diff --git a/src/Resources/public/js/filter/gally-filter.js b/src/Resources/public/js/filter/gally-filter.js index 2135abd..62ec5d2 100644 --- a/src/Resources/public/js/filter/gally-filter.js +++ b/src/Resources/public/js/filter/gally-filter.js @@ -2,6 +2,7 @@ define(function(require) { 'use strict'; const $ = require('jquery'); + const _ = require('underscore'); const routing = require('routing'); const MultiSelectFilter = require('oro/filter/multiselect-filter'); const LoadingMaskView = require('oroui/js/app/views/loading-mask-view'); @@ -24,8 +25,6 @@ define(function(require) { */ initialize: function (options) { GallyFilter.__super__.initialize.call(this, options); - const viewMoreLabel = __('gally.filter.showMore.label'); - this.showMoreLink = $('', {href: '#', html: viewMoreLabel, click: this.showMore.bind(this)}); }, /** @@ -34,14 +33,80 @@ define(function(require) { render: function() { GallyFilter.__super__.render.call(this); - if (this.custom_data.hasMore) { - this.selectWidget.multiselect('open'); - this.selectWidget.getWidget().append(this.showMoreLink); - this.selectWidget.multiselect('close'); + // Defers the view more link rendering to be sure it is displayed after the filter options. + setTimeout(function () { + if (!this.showMoreLink) { + const viewMoreLabel = __('gally.filter.showMore.label'); + this.showMoreLink = $('', {href: '#', html: viewMoreLabel, click: this.showMore.bind(this)}); + this.selectWidget.multiselect('open'); + this.selectWidget.getWidget().append(this.showMoreLink); + if (!this.subview('loading')) { + this.subview('loading', new LoadingMaskView({container: this.selectWidget.getWidget()})); + } + this.selectWidget.multiselect('close'); + this.showMoreLink.hide(); + } + + if (this.custom_data.hasMore) { + this.showMoreLink.show(); + } else { + this.showMoreLink.hide(); + } + + }.bind(this), 100); + + }, + + onMetadataLoaded: function(metadata) { + this.custom_data = metadata.custom_data; + this.choices = metadata.choices; + GallyFilter.__super__.onMetadataLoaded.call(this, metadata); + }, + + filterTemplateData: function(data) { + if (this.counts === null) { + return data; + } else if (_.isEmpty(this.counts)) { + this.counts = Object.create(null); } - if (!this.subview('loading')) { - this.subview('loading', new LoadingMaskView({container: this.$el})); + + let options = $.extend(true, {}, this.choices || {}); + const filterOptions = option => { + if (this.isDisableFiltersEnabled && _.has(this.countsWithoutFilters, option.value)) { + option.disabled = true; + } else { + options = _.without(options, option); + } + }; + + _.each(options, option => { + this.counts[option.value] = option.count; + // option.count = this.counts[option.value] || 0; + option.disabled = false; + if (option.count === 0 && + !_.contains(data.selected.value, option.value) + ) { + filterOptions(option); + } + }); + + const nonZeroOptions = _.filter(options, option => { + return option.count > 0; + }); + if (nonZeroOptions.length === 1) { + _.each(options, option => { + if (option.count === this.totalRecordsCount && + !_.contains(data.selected.value, option.value) + ) { + filterOptions(option); + } + }); } + + this.visible = !_.isEmpty(options); + data.options = options; + + return data; }, showMore: function() { diff --git a/src/Resources/public/js/filters-manager.js b/src/Resources/public/js/filters-manager.js new file mode 100644 index 0000000..304d918 --- /dev/null +++ b/src/Resources/public/js/filters-manager.js @@ -0,0 +1,45 @@ +define(function(require, exports, module) { + 'use strict'; + + const _ = require('underscore'); + const BaseFilterManager = require('orofilter/js/filters-manager'); + + /** + * View that represents all grid filters + * + * @export orofilter/js/filters-manager + * @class orofilter.FiltersManager + * @extends BaseView + * + * @event updateList on update of filter list + * @event updateFilter on update data of specific filter + * @event disableFilter on disable specific filter + */ + return BaseFilterManager.extend({ + + /** + * @param {orodatagrid.datagrid.Grid} grid + */ + updateFilters: function(grid) { + + let metadataFilters = {}; + _.each(grid.metadata.filters, metadata => metadataFilters[metadata.name] = metadata); + + _.each(this.filters, function(filter, name) { + let metadata = metadataFilters[name]; + if (metadata) { + filter.visible = true; + filter.setRenderMode(this.renderMode); + filter.trigger('total-records-count-updated', this.collection.state.totalRecords); + filter.trigger('metadata-loaded', metadata); + } else { + filter.visible = false; + } + + delete metadataFilters[name]; + }, this); + + this.checkFiltersVisibility(); + } + }); +}); diff --git a/src/Resources/views/layouts/default/config/assets.yml b/src/Resources/views/layouts/default/config/assets.yml new file mode 100644 index 0000000..7b524e7 --- /dev/null +++ b/src/Resources/views/layouts/default/config/assets.yml @@ -0,0 +1,3 @@ +styles: + inputs: + - 'bundles/gallyoro/default/scss/gally-style.scss' diff --git a/src/Resources/views/layouts/default/config/jsmodules.yml b/src/Resources/views/layouts/default/config/jsmodules.yml index bd17933..d672900 100644 --- a/src/Resources/views/layouts/default/config/jsmodules.yml +++ b/src/Resources/views/layouts/default/config/jsmodules.yml @@ -6,4 +6,7 @@ dynamic-imports: - oro/filter/gally-filter map: '*': - oroproduct/templates/search-autocomplete.html: gallyoro/default/templates/search-autocomplete.html + orofilter/js/filters-manager: 'gallyoro/js/filters-manager' + oroproduct/templates/search-autocomplete.html: 'gallyoro/default/templates/search-autocomplete.html' + 'gallyoro/js/filters-manager': + 'orofilter/js/filters-manager': 'orofilter/js/filters-manager' diff --git a/src/Search/Extension/GallyDataGridExtension.php b/src/Search/Extension/GallyDataGridExtension.php index 13d6f10..e505e27 100644 --- a/src/Search/Extension/GallyDataGridExtension.php +++ b/src/Search/Extension/GallyDataGridExtension.php @@ -85,6 +85,7 @@ private function addFilterFieldsFromGallyConfiguration(DatagridConfiguration $co 'visible' => false, 'disabled' => false, 'renderable' => true, + 'choices' => [], ]; // @see \Gally\Search\Decoration\GraphQl\AddAggregationsData::formatAggregation @@ -180,7 +181,7 @@ private function addFiltersFromGallyResult(DatagridConfiguration $config): void $filters = []; foreach ($currentFilters as $code => $filter) { - if (\in_array($code, ['sku', 'names'], true)) { + if (\in_array($code, ['sku', 'names'], true) || 'gally-select' === $filter['type']) { $filters[$code] = $filter; } } @@ -201,6 +202,9 @@ private function addFiltersFromGallyResult(DatagridConfiguration $config): void $filter['type'] = 'boolean'; $filters[$gallyFilter['field']] = $filter; } else { + foreach ($gallyFilter['options'] as $index => $option) { + $gallyFilter['options'][$index]['data'] = $option['value']; + } $filter['choices'] = $gallyFilter['options']; $filter['options']['gally_options'] = $gallyFilter['options']; $filter['options']['has_more'] = $gallyFilter['hasMore']; diff --git a/src/Search/Filter/SelectFilter.php b/src/Search/Filter/SelectFilter.php index 7b21d85..9a89fc7 100644 --- a/src/Search/Filter/SelectFilter.php +++ b/src/Search/Filter/SelectFilter.php @@ -87,10 +87,14 @@ public function getMetadata(): array { $metadata = parent::getMetadata(); - $metadata['custom_data'] = [ - 'hasMore' => $this->hasMore, - 'hasMoreUrl' => '', - ]; + $metadata['custom_data'] = ['hasMore' => $this->hasMore]; + $metadata['isDisableFiltersEnabled'] = true; + $metadata['counts'] = []; + $metadata['countsWithoutFilters'] = []; + foreach ($metadata['choices'] ?? [] as $choice) { + $metadata['counts'][$choice['value']] = $choice['count']; + $metadata['countsWithoutFilters'][$choice['value']] = $choice['count']; + } return $metadata; }