webpack implementation fix for hints not showing (#197)

* initial commit

* initial commit

* not fixed

* hot not fix

* basic webpack implementation

* implement webpack

* implement webpack

* added fixes and mobile support

* deleated package-lock.json

* Delete yarn.lock

* adding new lines and deleated public build

* Change input to symfony form row

* GHA fix

* GHA fix

* Gha fix build->encore

* Fix spec ImageTransformer

* Gha fix node version changed to 14.x

* scrutinizer node fix

* scrutinizer node fix

* scrutinizer node fix

Co-authored-by: kuba-end <kostek660i@gmail.com>
Co-authored-by: Tomasz Grochowski <tg@urias.it>
This commit is contained in:
zalmanix
2022-02-07 09:27:18 +01:00
committed by GitHub
parent 7feed4c037
commit 056c77100e
44 changed files with 2750 additions and 88 deletions

View File

@@ -24,7 +24,7 @@ jobs:
php: ["8.0", "7.4"]
symfony: ["^4.4", "^5.2"]
sylius: ["~1.9.0", "~1.10.0"]
node: ["10.x"]
node: ["14.x"]
mysql: ["8.0"]
exclude:
@@ -157,7 +157,7 @@ jobs:
name: Prepare test application assets
run: |
(cd tests/Application && bin/console assets:install public -vvv)
(cd tests/Application && yarn build)
(cd tests/Application && yarn encore production)
-
name: Prepare test application cache

25
.gitignore vendored
View File

@@ -9,3 +9,28 @@
/behat.yml
/phpspec.yml
/vendor/
/node_modules/
package-lock.json
/etc/build/*
!/etc/build/.gitignore
tests/Application/node_modules/
tests/Application/var/
!tests/Application/var/.gitkeep
tests/Application/web/*
!tests/Application/web/favicon.ico
!tests/Application/web/app.php
!tests/Application/web/app_dev.php
!tests/Application/web/app_test.php
/tests/Application/yarn.lock
/composer.lock
/etc/build/*
!/etc/build/.gitkeep

View File

@@ -9,7 +9,9 @@
"sylius/sylius": "~1.8.0 || ~1.9.0 || ~1.10.0",
"friendsofsymfony/elastica-bundle": "^6.0",
"symfony/property-access": "^4.4 || ^5.2",
"bitbag/coding-standard": "^1.0"
"bitbag/coding-standard": "^1.0",
"symfony/orm-pack": "^2.1",
"symfony/webpack-encore-bundle": "^1.13"
},
"require-dev": {
"behat/behat": "^3.6.1",

12
package.json Normal file
View File

@@ -0,0 +1,12 @@
{
"name": "@bitbag/elasticsearch-plugin",
"description": "Elasticsearch plugin for Sylius.",
"repository": "https://github.com/BitBagCommerce/[...].git",
"license": "MIT",
"scripts": {
"dist": "yarn encore production --config-name bitbag-plugin-dist"
},
"dependencies": {
"node-sass": "7.0.1"
}
}

View File

@@ -34,7 +34,7 @@ final class ImageTransformerSpec extends ObjectBehavior
ImageInterface $productImage,
FilterService $filterService
): void {
$product->getImagesByType('thumbnail')->willReturn(new ArrayCollection([$productImage->getWrappedObject()]));
$product->getImagesByType('main')->willReturn(new ArrayCollection([$productImage->getWrappedObject()]));
$productImage->getPath()->willReturn('/path-to-image');
$filterService

View File

@@ -27,7 +27,10 @@ final class SearchBoxType extends AbstractType
SymfonySearchType::class,
[
'label' => false,
'attr' => ['placeholder' => 'bitbag_sylius_elasticsearch_plugin.ui.search_box.query.placeholder'],
'attr' => [
'placeholder' => 'bitbag_sylius_elasticsearch_plugin.ui.search_box.query.placeholder',
'class' => 'prompt app-quick-add-code-input',
],
'constraints' => [new NotBlank()],
]
)

View File

@@ -0,0 +1,2 @@
import './scss/main.scss'
import './js/'

View File

View File

@@ -0,0 +1,2 @@
import './scss/main.scss'
import './js/'

View File

@@ -0,0 +1,133 @@
export default class ElasticSearchAutocomplete {
constructor(
config = {},
) {
this.config = config;
this.defaultConfig = {
searchFields: '.searchdiv',
baseAutocompleteVariantUrl: '[data-bb-elastic-url]',
searchInput: '.app-quick-add-code-input',
resultsTarget: '.results',
resultContainerClassesArray: ['result'],
resultImageClass: 'image',
resultContentClass: 'result__content',
resultPriceClass: 'result__price',
resultTitleClass: 'js-title',
resultDescriptionClass: 'result__description',
resultLinkClass: 'result__link',
resultCategoryClass: 'result__category',
resultImageClass: 'result__image',
resultContainerClass: 'result__container',
};
this.finalConfig = {...this.defaultConfig, ...config};
this.searchFieldsSelector = document.querySelector(this.finalConfig.searchFields);
}
init() {
if (this.config && typeof this.config !== 'object') {
throw new Error('BitBag - CreateConfirmationModal - given config is not valid - expected object');
}
this._debounce();
}
_toggleModalVisibility(elements) {
document.addEventListener('variantsVisible', () => {
document.addEventListener('click', () => {
elements.forEach((element) => {
element.innerHTML = '';
element.style.display = 'none';
});
});
});
}
_modalTemplate(item, categoryStyle) {
const result = document.createElement('a');
result.classList.add(...this.finalConfig.resultContainerClassesArray, 'js-result');
result.innerHTML = `
<h3 class=${this.finalConfig.resultCategoryClass} style=${categoryStyle}>${item.taxon_name}</h3>
<a href=${item.slug} class=${this.finalConfig.resultLinkClass}>
<div class=${this.finalConfig.resultContainerClass}>
<img class=${this.finalConfig.resultImageClass} src=${item.image}>
<div class=${this.finalConfig.resultContentClass}>
<div class=${this.finalConfig.resultTitleClass}>${item.name}</div>
<div class=${this.finalConfig.resultPriceClass}>${item.price}</div>
</div>
</div>
</a>
`;
return result;
}
_assignElements(entry, data) {
const currentResults = this.searchFieldsSelector.querySelector(this.finalConfig.resultsTarget);
currentResults.innerHTML = ''
currentResults.style = 'visibility: visible';
const allResults = document.querySelectorAll(this.finalConfig.resultsTarget);
if (data.items.length === 0) {
currentResults.innerHTML = '<center class="result">no matching results</center>';
}
data.items = data.items.sort((a,b) => {
if (b.taxon_name < a.taxon_name) return 1;
if (b.taxon_name > a.taxon_name) return -1;
return 0;
});
let tempTaxonName;
data.items.forEach((item) => {
let categoryStyle = "visibility: visible"
if (tempTaxonName == item.taxon_name) {
categoryStyle = "visibility: hidden";
}
tempTaxonName = item.taxon_name;
currentResults.appendChild(this._modalTemplate(item, categoryStyle));
});
currentResults.style.display = 'block';
this._toggleModalVisibility(allResults);
const customEvent = new CustomEvent('variantsVisible');
document.dispatchEvent(customEvent);
}
async _getProducts(entry) {
const variantUrl = document.querySelector(this.finalConfig.baseAutocompleteVariantUrl).dataset.bbElasticUrl;
const url = `${variantUrl}?query=${entry.value}`;
entry.parentNode.classList.add('loading');
try {
const response = await fetch(url);
const data = await response.json();
this._assignElements(entry, data);
} catch (error) {
console.error(error);
} finally {
entry.parentNode.classList.remove('loading');
}
}
_debounce() {
const codeInputs = document.querySelectorAll(this.finalConfig.searchInput);
let timeout;
codeInputs.forEach((input) => {
input.addEventListener('input', () => {
clearTimeout(timeout);
timeout = setTimeout(() => {
this._getProducts(input);
}, 400);
});
});
}
}

View File

@@ -0,0 +1 @@
import './initAutocomleate';

View File

@@ -0,0 +1,3 @@
import ElasticSearchAutocomplete from './elasticSearchAutocomplete';
new ElasticSearchAutocomplete().init();

View File

@@ -0,0 +1,92 @@
.results {
margin-top: 0.5rem;
position: absolute;
left: 50%;
-webkit-transform: translateX(-50%);
transform: translateX(-50%);
min-width: 100%;
width: 600px;
padding: 0 1rem 0 1rem;
background-color: white;
backdrop-filter: blur(1px);
z-index: 16;
box-shadow: 0px 1px 2px 0px #d4d4d5, 0px 0px 0px 1px #d4d4d5;
visibility: hidden;
color: #050428;
max-height: 50vh;
overflow-x: auto;
@media (max-width: 767px) {
width: 300px;
}
.result {
padding: 1px;
&__category {
padding-top: 1rem;
color: #050428;
}
&__link {
padding-top: 1rem;
.result__container {
max-height: 400px;
box-shadow: 0px 1px 1px 0px #d4d4d5, 0px 0px 0px 1px #d4d4d5;
color: #050428;
display: flex;
flex-direction: row;
align-items: center;
.result__image {
max-width: 7rem;
max-height: 7rem;
width: 100%;
padding: 0.5rem;
object-fit: cover;
@media (max-width: 767px){
max-width: 6rem;
max-height: 6rem;
}
}
.result__content {
display: flex;
flex-direction: row;
justify-content: space-between;
font-weight: bold;
padding: 0.5rem 3.7rem 0 0;
@media (max-width: 767px) {
flex-direction: column;
justify-content: space-evenly;
text-align: left;
width: 100%;
padding: 1rem;
}
.result__price {
position: absolute;
right: 1.5rem;
@media (max-width: 767px) {
position: relative;
right: 0;
}
}
}
.result__description {
padding: 10px;
}
}
.result__container:hover {
background-color: rgba(250, 250, 250, 0.952);
}
}
}
}

View File

@@ -0,0 +1,2 @@
@import './elasticSearchAutocomplete.scss';

View File

@@ -0,0 +1 @@

View File

@@ -0,0 +1,111 @@
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
/***/ "./src/Resources/assets/admin/js/index.js":
/*!************************************************!*\
!*** ./src/Resources/assets/admin/js/index.js ***!
\************************************************/
/***/ (() => {
/***/ }),
/***/ "./src/Resources/assets/admin/scss/main.scss":
/*!***************************************************!*\
!*** ./src/Resources/assets/admin/scss/main.scss ***!
\***************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
"use strict";
__webpack_require__.r(__webpack_exports__);
// extracted by mini-css-extract-plugin
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/compat get default export */
/******/ (() => {
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = (module) => {
/******/ var getter = module && module.__esModule ?
/******/ () => (module['default']) :
/******/ () => (module);
/******/ __webpack_require__.d(getter, { a: getter });
/******/ return getter;
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be in strict mode.
(() => {
"use strict";
/*!*********************************************!*\
!*** ./src/Resources/assets/admin/entry.js ***!
\*********************************************/
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _scss_main_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./scss/main.scss */ "./src/Resources/assets/admin/scss/main.scss");
/* harmony import */ var _js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./js/ */ "./src/Resources/assets/admin/js/index.js");
/* harmony import */ var _js___WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_js___WEBPACK_IMPORTED_MODULE_1__);
})();
/******/ })()
;

View File

@@ -0,0 +1,64 @@
.results {
min-width: 33vw;
padding: 0 1rem 1rem 1rem;
background-color: white;
backdrop-filter: blur(1px);
position: absolute;
z-index: 16;
box-shadow: 0px 1px 2px 0px #d4d4d5, 0px 0px 0px 1px #d4d4d5;
visibility: hidden;
color: #050428;
max-height: 50vh;
overflow-x: auto;
}
.results .result {
padding: 1px;
}
.results .result .result__category {
padding-top: 1em;
color: #050428;
}
.results .result .result__link {
padding-top: 1 em;
}
.results .result .result__link .result__container {
max-height: 400px;
padding: 1 rem;
box-shadow: 0px 1px 1px 0px #d4d4d5, 0px 0px 0px 1px #d4d4d5;
color: #050428;
display: flex;
flex-direction: row;
}
.results .result .result__link .result__container .result__image {
max-width: 12vw;
max-height: 12vh;
padding: 1em;
}
.results .result .result__link .result__container .result__content {
padding-left: 1em;
display: flex;
flex-direction: row;
justify-content: space-between;
font-weight: bold;
align-items: center;
}
.results .result .result__link .result__container .result__content .result__price {
position: absolute;
right: 5%;
}
.results .result .result__link .result__container .result__description {
padding: 10px;
}
.results .result .result__link .result__container:hover {
background-color: rgba(250, 250, 250, 0.952);
}

View File

@@ -0,0 +1,319 @@
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/Resources/assets/shop/js/elastictSearchAutocomplete.js":
/*!********************************************************************!*\
!*** ./src/Resources/assets/shop/js/elastictSearchAutocomplete.js ***!
\********************************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony export */ __webpack_require__.d(__webpack_exports__, {
/* harmony export */ "default": () => (/* binding */ ElasticSearchAutocomplete)
/* harmony export */ });
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
var ElasticSearchAutocomplete = /*#__PURE__*/function () {
function ElasticSearchAutocomplete() {
var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
searchFields: '.searchdiv',
baseAutocompleteVariantUrl: '[data-bb-elastic-url]',
searchInput: '.app-quick-add-code-input',
resultsTarget: '.results',
resultContainerClassesArray: ['result'],
resultImageClass: 'image',
resultContentClass: 'result__content',
resultPriceClass: 'result__price',
resultTitleClass: 'js-title',
resultDescriptionClass: 'result__description'
};
_classCallCheck(this, ElasticSearchAutocomplete);
this.searchFieldsSelector = config.searchFields;
this.searchFields = document.querySelectorAll(config.searchFields);
this.baseAutocompleteVariantUrl = config.baseAutocompleteVariantUrl;
this.searchInput = config.searchInput;
this.resultsTarget = config.resultsTarget;
this.resultContainerClassesArray = config.resultContainerClassesArray;
this.resultImageClass = config.resultImageClass;
this.resultContentClass = config.resultContentClass;
this.resultPriceClass = config.resultPriceClass;
this.resultTitleClass = config.resultTitleClass;
this.resultDescriptionClass = config.resultDescriptionClass;
}
_createClass(ElasticSearchAutocomplete, [{
key: "_toggleModalVisibility",
value: function _toggleModalVisibility(elements) {
document.addEventListener('variantsVisible', function () {
document.addEventListener('click', function () {
elements.forEach(function (element) {
element.innerHTML = '';
element.style.display = 'none';
});
});
});
}
}, {
key: "_assignElements",
value: function _assignElements(entry, data) {
var _this = this;
var currentResults = entry.closest(this.searchFieldsSelector).querySelector(this.resultsTarget);
currentResults.innerHTML = '';
currentResults.style = 'visibility: visible';
var allResults = document.querySelectorAll(this.resultsTarget);
if (data.items.length === 0) {
currentResults.innerHTML = '<center class="result">no matching results</center>';
}
data.items = data.items.sort(function (a, b) {
if (b.taxon_name < a.taxon_name) return 1;
if (b.taxon_name > a.taxon_name) return -1;
return 0;
});
console.log(data.items);
var itemTemp;
data.items.forEach(function (item) {
var _result$classList;
var category = item.taxon_name;
var categoryStyle = "visibility: visible";
if (itemTemp == item.taxon_name) {
categoryStyle = "visibility: hidden";
}
var result = document.createElement('a');
(_result$classList = result.classList).add.apply(_result$classList, _toConsumableArray(_this.resultContainerClassesArray).concat(['js-result']));
result.innerHTML = "\n <h3 class=\"result__category\" style=".concat(categoryStyle, ">").concat(category, "</h3> \n <a href=").concat(item.slug, " class=\"result__link\">\n <div class=\"result__container\">\n <img class=\"result__image\" src=").concat(item.image, ">\n <div class=").concat(_this.resultContentClass, ">\n <div class=").concat(_this.resultTitleClass, ">").concat(item.name, "</div>\n <div class=").concat(_this.resultPriceClass, ">").concat(item.price, "</div>\n </div>\n \n </div>\n </a> \n ");
itemTemp = item.taxon_name;
currentResults.appendChild(result);
});
currentResults.style.display = 'block';
this._toggleModalVisibility(allResults);
var customEvent = new CustomEvent('variantsVisible');
document.dispatchEvent(customEvent);
}
}, {
key: "_getProducts",
value: function () {
var _getProducts2 = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(entry) {
var variantUrl, url, response, data;
return regeneratorRuntime.wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
variantUrl = document.querySelector(this.baseAutocompleteVariantUrl).dataset.bbElasticUrl;
url = "".concat(variantUrl, "?query=").concat(entry.value);
entry.parentNode.classList.add('loading');
_context.prev = 3;
_context.next = 6;
return fetch(url);
case 6:
response = _context.sent;
_context.next = 9;
return response.json();
case 9:
data = _context.sent;
this._assignElements(entry, data);
_context.next = 16;
break;
case 13:
_context.prev = 13;
_context.t0 = _context["catch"](3);
console.error(_context.t0);
case 16:
_context.prev = 16;
entry.parentNode.classList.remove('loading');
return _context.finish(16);
case 19:
case "end":
return _context.stop();
}
}
}, _callee, this, [[3, 13, 16, 19]]);
}));
function _getProducts(_x) {
return _getProducts2.apply(this, arguments);
}
return _getProducts;
}()
}, {
key: "_debounce",
value: function _debounce() {
var _this2 = this;
var codeInputs = document.querySelectorAll(this.searchInput);
var timeout;
codeInputs.forEach(function (input) {
input.addEventListener('input', function () {
clearTimeout(timeout);
timeout = setTimeout(function () {
_this2._getProducts(input);
}, 400);
});
});
}
}, {
key: "init",
value: function init() {
if (this.searchFields.length === 0) {
return;
}
this._debounce();
}
}]);
return ElasticSearchAutocomplete;
}();
/***/ }),
/***/ "./src/Resources/assets/shop/js/index.js":
/*!***********************************************!*\
!*** ./src/Resources/assets/shop/js/index.js ***!
\***********************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _initAutocomleate__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./initAutocomleate */ "./src/Resources/assets/shop/js/initAutocomleate.js");
/***/ }),
/***/ "./src/Resources/assets/shop/js/initAutocomleate.js":
/*!**********************************************************!*\
!*** ./src/Resources/assets/shop/js/initAutocomleate.js ***!
\**********************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _elastictSearchAutocomplete__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./elastictSearchAutocomplete */ "./src/Resources/assets/shop/js/elastictSearchAutocomplete.js");
new _elastictSearchAutocomplete__WEBPACK_IMPORTED_MODULE_0__["default"]().init();
/***/ }),
/***/ "./src/Resources/assets/shop/scss/main.scss":
/*!**************************************************!*\
!*** ./src/Resources/assets/shop/scss/main.scss ***!
\**************************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
__webpack_require__.r(__webpack_exports__);
// extracted by mini-css-extract-plugin
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
var __webpack_exports__ = {};
// This entry need to be wrapped in an IIFE because it need to be isolated against other modules in the chunk.
(() => {
/*!********************************************!*\
!*** ./src/Resources/assets/shop/entry.js ***!
\********************************************/
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var _scss_main_scss__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./scss/main.scss */ "./src/Resources/assets/shop/scss/main.scss");
/* harmony import */ var _js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./js/ */ "./src/Resources/assets/shop/js/index.js");
})();
/******/ })()
;

View File

@@ -1,3 +0,0 @@
#products-search .results {
width: 100%;
}

View File

@@ -0,0 +1,20 @@
{
"entrypoints": {
"bitbag-elasticsearch-shop": {
"css": [
"/public/bitbag-elasticsearch-shop.css"
],
"js": [
"/public/bitbag-elasticsearch-shop.js"
]
},
"bitbag-elasticsearch-admin": {
"css": [
"/public/bitbag-elasticsearch-admin.css"
],
"js": [
"/public/bitbag-elasticsearch-admin.js"
]
}
}
}

View File

@@ -1,52 +0,0 @@
(function ( $ ) {
'use strict';
$.fn.extend({
autocompleteSearch: function (autocompleteInputElement, apiEndpointPath) {
$(autocompleteInputElement)
.search({
type: 'category',
minCharacters: 3,
apiSettings: {
onResponse: function (autocompleteResponse) {
let
response = {
results: {}
}
;
$.each(autocompleteResponse.items, function (index, item) {
var
taxonName = item.taxon_name,
maxResults = 10
;
if (index >= maxResults) {
return false;
}
if (response.results[taxonName] === undefined) {
response.results[taxonName] = {
name: taxonName,
results: []
};
}
response.results[taxonName].results.push({
title: item.name,
description: item.description,
url: item.slug,
price: item.price,
image: item.image
});
});
return response;
},
url: apiEndpointPath
}
})
;
}
});
})( jQuery );

View File

@@ -0,0 +1,6 @@
{
"public/bitbag-elasticsearch-shop.css": "/public/bitbag-elasticsearch-shop.css",
"public/bitbag-elasticsearch-shop.js": "/public/bitbag-elasticsearch-shop.js",
"public/bitbag-elasticsearch-admin.css": "/public/bitbag-elasticsearch-admin.css",
"public/bitbag-elasticsearch-admin.js": "/public/bitbag-elasticsearch-admin.js"
}

View File

@@ -1,5 +1,13 @@
{% form_theme settings.form '@BitBagSyliusElasticsearchPlugin/Shop/Menu/_searchFormTheme.html.twig' %}
<div class="searchdiv" data-bb-elastic-url="{{ url('bitbag_sylius_elasticsearch_plugin_shop_auto_complete_product_name') }}">
<div class="ui fluid category search">
<div class="ui icon input" style="width: 100%;">
{{ form_start(settings.form, {'attr': {'class': 'ui loadable form', 'novalidate': 'novalidate'}}) }}
{{ form_row(settings.form.box) }}
{{ form_end(settings.form, {'render_rest': false}) }}
{% form_theme settings.form '@BitBagSyliusElasticsearchPlugin/Shop/Menu/_searchFormTheme.html.twig' %}
{{ form_start(settings.form, {'attr': {'class': 'ui loadable form', 'novalidate': 'novalidate'}}) }}
{{ form_row(settings.form.box) }}
{{ form_end(settings.form, {'render_rest': false}) }}
</div>
</div>
<div class="results"></div>
</div>

View File

@@ -16,7 +16,7 @@ use Sylius\Component\Core\Model\ProductInterface;
final class ImageTransformer implements TransformerInterface
{
private const SYLIUS_THUMBNAIL_TYPE = 'thumbnail';
private const SYLIUS_THUMBNAIL_TYPE = 'main';
private const SYLIUS_THUMBNAIL_FILTER = 'sylius_shop_product_thumbnail';

View File

@@ -26,4 +26,4 @@ JWT_PASSPHRASE=acme_plugin_development
# For a generic SMTP server, use: "smtp://localhost:25?encryption=&auth_mode="
# Delivery is disabled by default via "null://localhost"
MAILER_URL=smtp://localhost
###< symfony/swiftmailer-bundle ###
###< symfony/swiftmailer-bundle ###

2
tests/Application/.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1,2 @@
@ @BitBagCommerce
* @Sylius/core-team

View File

@@ -0,0 +1,195 @@
name: Build
on:
push:
branches-ignore:
- 'dependabot/**'
pull_request: ~
release:
types: [created]
schedule:
-
cron: "0 1 * * 6" # Run at 1am every Saturday
workflow_dispatch: ~
jobs:
tests:
runs-on: ubuntu-18.04
name: "Sylius ${{ matrix.sylius }}, PHP ${{ matrix.php }}, Symfony ${{ matrix.symfony }}, MySQL ${{ matrix.mysql }}"
strategy:
fail-fast: false
matrix:
php: ["8.0", "7.4"]
symfony: ["^4.4", "^5.2"]
sylius: ["~1.9.0", "~1.10.0"]
node: ["14.x"]
mysql: ["8.0"]
exclude:
- sylius: ~1.9.0
php: 8.0
- sylius: ~1.10.0
symfony: ^4.4
# friendsofsymfony/elastica-bundle - package is locking php 7.x
- sylius: ~1.10.0
php: 8.0
env:
APP_ENV: test
DATABASE_URL: "mysql://root:root@127.0.0.1/sylius?serverVersion=${{ matrix.mysql }}"
steps:
-
uses: actions/checkout@v2
-
name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: "${{ matrix.php }}"
extensions: intl
tools: symfony
coverage: none
-
name: Setup Node
uses: actions/setup-node@v1
with:
node-version: "${{ matrix.node }}"
-
name: Shutdown default MySQL
run: sudo service mysql stop
-
name: Setup MySQL
uses: mirromutth/mysql-action@v1.1
with:
mysql version: "${{ matrix.mysql }}"
mysql root password: "root"
-
name: Configure sysctl limits
run: |
sudo swapoff -a
sudo sysctl -w vm.swappiness=1
sudo sysctl -w fs.file-max=262144
sudo sysctl -w vm.max_map_count=262144
-
name: Runs Elasticsearch
uses: elastic/elastic-github-actions/elasticsearch@master
with:
stack-version: 6.8.15
-
name: Output PHP version for Symfony CLI
run: php -v | head -n 1 | awk '{ print $2 }' > .php-version
-
name: Install certificates
run: symfony server:ca:install
-
name: Run Chrome Headless
run: google-chrome-stable --enable-automation --disable-background-networking --no-default-browser-check --no-first-run --disable-popup-blocking --disable-default-apps --allow-insecure-localhost --disable-translate --disable-extensions --no-sandbox --enable-features=Metal --headless --remote-debugging-port=9222 --window-size=2880,1800 --proxy-server='direct://' --proxy-bypass-list='*' http://127.0.0.1 > /dev/null 2>&1 &
-
name: Run webserver
run: (cd tests/Application && symfony server:start --port=8080 --dir=public --daemon)
-
name: Get Composer cache directory
id: composer-cache
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
name: Cache Composer
uses: actions/cache@v2
with:
path: ${{ steps.composer-cache.outputs.dir }}
key: ${{ runner.os }}-php-${{ matrix.php }}-composer-${{ hashFiles('**/composer.json **/composer.lock') }}
restore-keys: |
${{ runner.os }}-php-${{ matrix.php }}-composer-
-
name: Restrict Symfony version
if: matrix.symfony != ''
run: |
composer global require --no-progress --no-scripts --no-plugins "symfony/flex:^1.10"
composer config extra.symfony.require "${{ matrix.symfony }}"
-
name: Restrict Sylius version
if: matrix.sylius != ''
run: composer require "sylius/sylius:${{ matrix.sylius }}" --no-update --no-scripts --no-interaction
-
name: Install PHP dependencies
run: composer install --no-interaction --no-scripts
-
name: Get Yarn cache directory
id: yarn-cache
run: echo "::set-output name=dir::$(yarn cache dir)"
-
name: Cache Yarn
uses: actions/cache@v2
with:
path: ${{ steps.yarn-cache.outputs.dir }}
key: ${{ runner.os }}-node-${{ matrix.node }}-yarn-${{ hashFiles('**/package.json **/yarn.lock') }}
restore-keys: |
${{ runner.os }}-node-${{ matrix.node }}-yarn-
-
name: Install JS dependencies
run: (cd tests/Application && yarn install)
-
name: Prepare test application database
run: |
(cd tests/Application && bin/console doctrine:database:create -vvv)
(cd tests/Application && bin/console doctrine:schema:create -vvv)
-
name: Prepare test application assets
run: |
(cd tests/Application && bin/console assets:install public -vvv)
(cd tests/Application && yarn encore production)
-
name: Prepare test application cache
run: (cd tests/Application && bin/console cache:warmup -vvv)
-
name: Load fixtures in test application
run: (cd tests/Application && bin/console sylius:fixtures:load -n)
-
name: Validate composer.json
run: composer validate --ansi --strict
-
name: Validate database schema
run: (cd tests/Application && bin/console doctrine:schema:validate)
-
name: Run PHPSpec
run: vendor/bin/phpspec run --ansi -f progress --no-interaction
-
name: Run Behat
run: vendor/bin/behat --colors --strict -vvv --no-interaction || vendor/bin/behat --colors --strict -vvv --no-interaction --rerun
-
name: Upload Behat logs
uses: actions/upload-artifact@v2
if: failure()
with:
name: Behat logs
path: etc/build/
if-no-files-found: ignore

View File

@@ -1,4 +1,5 @@
/public/assets
/public/build
/public/css
/public/js
/public/media/*
@@ -7,6 +8,7 @@
!/public/media/image/.gitignore
/node_modules
package-lock.json
###> symfony/framework-bundle ###
/.env.*.local
@@ -20,3 +22,4 @@
###> symfony/web-server-bundle ###
/.web-server-pid
###< symfony/web-server-bundle ###

View File

@@ -0,0 +1 @@
import 'sylius/bundle/AdminBundle/Resources/private/entry';

View File

@@ -0,0 +1 @@
import 'sylius/bundle/ShopBundle/Resources/private/entry';

View File

@@ -1,5 +1,8 @@
{
"name": "sylius/plugin-skeleton-test-application",
"name": "sylius/plugin-elasticsearch-test-application",
"description": "Sylius application for plugin testing purposes (composer.json needed for project dir resolving)",
"license": "MIT"
"license": "MIT",
"require": {
"symfony/webpack-encore-bundle": "^1.13"
}
}

1603
tests/Application/composer.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -57,4 +57,5 @@ return [
Lexik\Bundle\JWTAuthenticationBundle\LexikJWTAuthenticationBundle::class => ['all' => true],
Sylius\Bundle\ApiBundle\SyliusApiBundle::class => ['all' => true],
SyliusLabs\DoctrineMigrationsExtraBundle\SyliusLabsDoctrineMigrationsExtraBundle::class => ['all' => true],
Symfony\WebpackEncoreBundle\WebpackEncoreBundle::class => ['all' => true],
];

View File

@@ -0,0 +1,11 @@
framework:
assets:
packages:
shop:
json_manifest_path: '%kernel.project_dir%/public/build/shop/manifest.json'
admin:
json_manifest_path: '%kernel.project_dir%/public/build/admin/manifest.json'
elasticsearch_shop:
json_manifest_path: '%kernel.project_dir%/public/build/bitbag/elasticsearch/shop/manifest.json'
elasticsearch_admin:
json_manifest_path: '%kernel.project_dir%/public/build/bitbag/elasticsearch/admin/manifest.json'

View File

@@ -0,0 +1,8 @@
webpack_encore:
output_path: '%kernel.project_dir%/public/build/default'
builds:
shop: '%kernel.project_dir%/public/build/shop'
admin: '%kernel.project_dir%/public/build/admin'
elasticsearch_shop: '%kernel.project_dir%/public/build/bitbag/elasticsearch/shop'
elasticsearch_admin: '%kernel.project_dir%/public/build/bitbag/elasticsearch/admin'

View File

@@ -5,10 +5,13 @@
"jquery": "^3.5.0",
"jquery.dirtyforms": "^2.0.0",
"lightbox2": "^2.9.0",
"node-sass": "6.0.1",
"sass-loader": "^12.4.0",
"semantic-ui-css": "^2.2.0",
"slick-carousel": "^1.8.1"
},
"devDependencies": {
"@symfony/webpack-encore": "^1.8.1",
"babel-core": "^6.26.3",
"babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-module-resolver": "^3.1.1",
@@ -21,31 +24,14 @@
"eslint-import-resolver-babel-module": "^4.0.0",
"eslint-plugin-import": "^2.12.0",
"fast-async": "^6.3.7",
"gulp": "^4.0.0",
"gulp-chug": "^0.5",
"gulp-concat": "^2.6.0",
"gulp-debug": "^2.1.2",
"gulp-if": "^2.0.0",
"gulp-livereload": "^3.8.1",
"gulp-order": "^1.1.1",
"gulp-sass": "^4.0.1",
"gulp-sourcemaps": "^1.6.0",
"gulp-uglifycss": "^1.0.5",
"merge-stream": "^1.0.0",
"rollup": "^0.60.7",
"rollup-plugin-babel": "^3.0.4",
"rollup-plugin-commonjs": "^9.1.3",
"rollup-plugin-inject": "^2.0.0",
"rollup-plugin-node-resolve": "^3.3.0",
"rollup-plugin-uglify": "^4.0.0",
"upath": "^1.1.0",
"yargs": "^6.4.0"
},
"scripts": {
"build": "gulp build",
"gulp": "gulp build",
"lint": "yarn lint:js",
"lint:js": "eslint gulpfile.babel.js"
"dev": "yarn encore dev",
"watch": "yarn encore dev --watch",
"prod": "yarn encore prod"
},
"repository": {
"type": "git",

View File

@@ -0,0 +1,2 @@
{{ encore_entry_script_tags('admin-entry', null, 'admin') }}
{{ encore_entry_script_tags('bitbag-elasticsearch-admin', null, 'elasticsearch_admin') }}

View File

@@ -0,0 +1,2 @@
{{ encore_entry_link_tags('admin-entry', null, 'admin') }}
{{ encore_entry_link_tags('bitbag-elasticsearch-admin', null, 'elasticsearch_admin') }}

View File

@@ -0,0 +1,2 @@
{{ encore_entry_script_tags('shop-entry', null, 'shop') }}
{{ encore_entry_script_tags('bitbag-elasticsearch-shop', null, 'elasticsearch_shop') }}

View File

@@ -0,0 +1,2 @@
{{ encore_entry_link_tags('shop-entry', null, 'shop') }}
{{ encore_entry_link_tags('bitbag-elasticsearch-shop', null, 'elasticsearch_shop') }}

View File

@@ -0,0 +1,49 @@
const path = require('path');
const Encore = require('@symfony/webpack-encore');
const [bitbagElasticsearchShop, bitbagElasticsearchAdmin] = require('../../webpack.config.js')
const syliusBundles = path.resolve(__dirname, '../../vendor/sylius/sylius/src/Sylius/Bundle/');
const uiBundleScripts = path.resolve(syliusBundles, 'UiBundle/Resources/private/js/');
const uiBundleResources = path.resolve(syliusBundles, 'UiBundle/Resources/private/');
// Shop config
Encore
.setOutputPath('public/build/shop/')
.setPublicPath('/build/shop')
.addEntry('shop-entry', './assets/shop/entry.js')
.disableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
.enableSassLoader();
const shopConfig = Encore.getWebpackConfig();
shopConfig.resolve.alias['sylius/ui'] = uiBundleScripts;
shopConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources;
shopConfig.resolve.alias['sylius/bundle'] = syliusBundles;
shopConfig.name = 'shop';
Encore.reset();
// Admin config
Encore
.setOutputPath('public/build/admin/')
.setPublicPath('/build/admin')
.addEntry('admin-entry', './assets/admin/entry.js')
.disableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enableSourceMaps(!Encore.isProduction())
.enableVersioning(Encore.isProduction())
.enableSassLoader();
const adminConfig = Encore.getWebpackConfig();
adminConfig.resolve.alias['sylius/ui'] = uiBundleScripts;
adminConfig.resolve.alias['sylius/ui-resources'] = uiBundleResources;
adminConfig.resolve.alias['sylius/bundle'] = syliusBundles;
adminConfig.externals = Object.assign({}, adminConfig.externals, { window: 'window', document: 'document' });
adminConfig.name = 'admin';
module.exports = [shopConfig, adminConfig, bitbagElasticsearchShop, bitbagElasticsearchAdmin];

40
webpack.config.js Normal file
View File

@@ -0,0 +1,40 @@
const path = require('path');
const Encore = require('@symfony/webpack-encore');
const pluginName = 'elasticsearch';
const getConfig = (pluginName, type) => {
Encore.reset();
Encore
.setOutputPath(`public/build/bitbag/${pluginName}/${type}/`)
.setPublicPath(`/build/bitbag/${pluginName}/${type}/`)
.addEntry(`bitbag-${pluginName}-${type}`, path.resolve(__dirname, `./src/Resources/assets/${type}/entry.js`))
.disableSingleRuntimeChunk()
.cleanupOutputBeforeBuild()
.enableSourceMaps(!Encore.isProduction())
.enableSassLoader();
const config = Encore.getWebpackConfig();
config.name = `bitbag-${pluginName}-${type}`;
return config;
}
Encore
.setOutputPath(`src/Resources/public/`)
.setPublicPath(`/public/`)
.addEntry(`bitbag-${pluginName}-shop`, path.resolve(__dirname, `./src/Resources/assets/shop/entry.js`))
.addEntry(`bitbag-${pluginName}-admin`, path.resolve(__dirname, `./src/Resources/assets/admin/entry.js`))
.cleanupOutputBeforeBuild()
.disableSingleRuntimeChunk()
.enableSassLoader();
const distConfig = Encore.getWebpackConfig();
distConfig.name = `bitbag-plugin-dist`;
Encore.reset();
const shopConfig = getConfig(pluginName, 'shop')
const adminConfig = getConfig(pluginName, 'admin')
module.exports = [shopConfig, adminConfig, distConfig];