From cf625d2e0bfe86fec6581966998547330a1bf949 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 6 Apr 2020 14:31:42 +0200 Subject: [PATCH 01/37] add fastly module --- src/modules/fastly/README.md | 27 +++++++++++++++++++++++++++ src/modules/fastly/server.ts | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 src/modules/fastly/README.md create mode 100644 src/modules/fastly/server.ts diff --git a/src/modules/fastly/README.md b/src/modules/fastly/README.md new file mode 100644 index 0000000000..7e8d750f00 --- /dev/null +++ b/src/modules/fastly/README.md @@ -0,0 +1,27 @@ +# VSF Cache Fastly +This module extends default caching docs/guide/basics/ssr-cache.md to allow using fastly as cache provider. + +## How to install +Add to config: +```json +"fastly": { + "enabled": true, + "serviceId": "xyz", // (https://docs.fastly.com/en/guides/finding-and-managing-your-account-info#finding-your-service-id) + "token": "xyz" // fastly api token (https://docs.fastly.com/api/auth#tokens) +} +``` + +Change those values in `server` section: +```json +"useOutputCacheTagging": true, +"useOutputCache": true +``` + +## How to purge cache? +Open: +``` +http://localhost:3000/invalidate?key=aeSu7aip&tag=home +``` + +## Problems +Please be aware that you can send maximum 256 keys per request, more info https://docs.fastly.com/api/purge#purge_db35b293f8a724717fcf25628d713583 diff --git a/src/modules/fastly/server.ts b/src/modules/fastly/server.ts new file mode 100644 index 0000000000..475ba34889 --- /dev/null +++ b/src/modules/fastly/server.ts @@ -0,0 +1,36 @@ +import { serverHooks } from '@vue-storefront/core/server/hooks' +import fetch from 'isomorphic-fetch' +import config from 'config' + +serverHooks.beforeOutputRenderedResponse(({ output, res, context }) => { + if (!config.get('fastly.enabled')) { + return output + } + + const tagsArray = Array.from(context.output.cacheTags) + const cacheTags = tagsArray.join(' ') + res.setHeader('Surrogate-Key', cacheTags) + + return output +}) + +serverHooks.beforeCacheInvalidated(async ({ tags }) => { + if (!config.get('fastly.enabled') || !config.get('server.useOutputCache') || !config.get('server.useOutputCacheTagging')) { + return + } + + console.log('Invalidating Fastly Surrogate-Key') + const surrogate_keys = tags.filter((tag) => + config.server.availableCacheTags.indexOf(tag) >= 0 || + config.server.availableCacheTags.find(t => tag.indexOf(t) === 0) + ) + console.log(surrogate_keys) + + const response = await fetch(`https://api.fastly.com/service/${config.get('fastly.serviceId')}/purge`, { + method: 'POST', + headers: { 'Fastly-Key': config.get('fastly.token') }, + body: JSON.stringify({ surrogate_keys }) + }) + const text = await response.text() + console.log(text) +}) From f2ab3106d40040c4da9e459f0bb2239164961b0a Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 6 Apr 2020 14:33:17 +0200 Subject: [PATCH 02/37] clean code --- src/modules/fastly/server.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/modules/fastly/server.ts b/src/modules/fastly/server.ts index 475ba34889..f37069b15a 100644 --- a/src/modules/fastly/server.ts +++ b/src/modules/fastly/server.ts @@ -24,7 +24,6 @@ serverHooks.beforeCacheInvalidated(async ({ tags }) => { config.server.availableCacheTags.indexOf(tag) >= 0 || config.server.availableCacheTags.find(t => tag.indexOf(t) === 0) ) - console.log(surrogate_keys) const response = await fetch(`https://api.fastly.com/service/${config.get('fastly.serviceId')}/purge`, { method: 'POST', From 821d545985e1f152b83dc46e458bb635b73f994d Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 6 Apr 2020 14:57:19 +0200 Subject: [PATCH 03/37] split requests into chunks --- src/modules/fastly/README.md | 3 --- src/modules/fastly/server.ts | 22 +++++++++++++--------- 2 files changed, 13 insertions(+), 12 deletions(-) diff --git a/src/modules/fastly/README.md b/src/modules/fastly/README.md index 7e8d750f00..50293a731d 100644 --- a/src/modules/fastly/README.md +++ b/src/modules/fastly/README.md @@ -22,6 +22,3 @@ Open: ``` http://localhost:3000/invalidate?key=aeSu7aip&tag=home ``` - -## Problems -Please be aware that you can send maximum 256 keys per request, more info https://docs.fastly.com/api/purge#purge_db35b293f8a724717fcf25628d713583 diff --git a/src/modules/fastly/server.ts b/src/modules/fastly/server.ts index f37069b15a..474c5525a6 100644 --- a/src/modules/fastly/server.ts +++ b/src/modules/fastly/server.ts @@ -2,6 +2,8 @@ import { serverHooks } from '@vue-storefront/core/server/hooks' import fetch from 'isomorphic-fetch' import config from 'config' +const chunk = require('lodash/chunk') + serverHooks.beforeOutputRenderedResponse(({ output, res, context }) => { if (!config.get('fastly.enabled')) { return output @@ -20,16 +22,18 @@ serverHooks.beforeCacheInvalidated(async ({ tags }) => { } console.log('Invalidating Fastly Surrogate-Key') - const surrogate_keys = tags.filter((tag) => + const tagsChunks = chunk(tags.filter((tag) => config.server.availableCacheTags.indexOf(tag) >= 0 || config.server.availableCacheTags.find(t => tag.indexOf(t) === 0) - ) + ), 256) // we can send maximum 256 keys per request, more info https://docs.fastly.com/api/purge#purge_db35b293f8a724717fcf25628d713583 - const response = await fetch(`https://api.fastly.com/service/${config.get('fastly.serviceId')}/purge`, { - method: 'POST', - headers: { 'Fastly-Key': config.get('fastly.token') }, - body: JSON.stringify({ surrogate_keys }) - }) - const text = await response.text() - console.log(text) + for (const tagsChunk of tagsChunks) { + const response = await fetch(`https://api.fastly.com/service/${config.get('fastly.serviceId')}/purge`, { + method: 'POST', + headers: { 'Fastly-Key': config.get('fastly.token') }, + body: JSON.stringify({ surrogate_keys: tagsChunk }) + }) + const text = await response.text() + console.log(text) + } }) From 432840f9d0c276b9b7777d0c22899900cd106209 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Mon, 6 Apr 2020 15:17:12 +0200 Subject: [PATCH 04/37] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a858b5aa2..eaa74928b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Product Page Schema implementation as JSON-LD - @Michal-Dziedzinski (#3704) - Add `/cache-version.json` route to get current cache version - Built-in module for detecting device type based on UserAgent with SSR support - @Fifciu +- Adds module which handles cache invalidation for Fastly. - @gibkigonzo (#4096) ### Fixed From 1f6075ff5ea9be5edf8daf92458378012695e729 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 7 Apr 2020 08:24:17 +0200 Subject: [PATCH 05/37] move graphql search adapter from core to src --- src/search/adapter/.gitkeep | 0 {core/lib => src}/search/adapter/graphql/gqlQuery.js | 0 .../lib => src}/search/adapter/graphql/processor/processType.ts | 0 {core/lib => src}/search/adapter/graphql/queries/categories.gql | 0 {core/lib => src}/search/adapter/graphql/queries/cmsBlock.gql | 0 .../lib => src}/search/adapter/graphql/queries/cmsHierarchy.gql | 0 {core/lib => src}/search/adapter/graphql/queries/cmsPage.gql | 0 .../search/adapter/graphql/queries/customAttributeMetadata.gql | 0 {core/lib => src}/search/adapter/graphql/queries/products.gql | 0 {core/lib => src}/search/adapter/graphql/queries/reviews.gql | 0 {core/lib => src}/search/adapter/graphql/queries/taxrule.gql | 0 {core/lib => src}/search/adapter/graphql/searchAdapter.ts | 2 +- 12 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 src/search/adapter/.gitkeep rename {core/lib => src}/search/adapter/graphql/gqlQuery.js (100%) rename {core/lib => src}/search/adapter/graphql/processor/processType.ts (100%) rename {core/lib => src}/search/adapter/graphql/queries/categories.gql (100%) rename {core/lib => src}/search/adapter/graphql/queries/cmsBlock.gql (100%) rename {core/lib => src}/search/adapter/graphql/queries/cmsHierarchy.gql (100%) rename {core/lib => src}/search/adapter/graphql/queries/cmsPage.gql (100%) rename {core/lib => src}/search/adapter/graphql/queries/customAttributeMetadata.gql (100%) rename {core/lib => src}/search/adapter/graphql/queries/products.gql (100%) rename {core/lib => src}/search/adapter/graphql/queries/reviews.gql (100%) rename {core/lib => src}/search/adapter/graphql/queries/taxrule.gql (100%) rename {core/lib => src}/search/adapter/graphql/searchAdapter.ts (99%) diff --git a/src/search/adapter/.gitkeep b/src/search/adapter/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/core/lib/search/adapter/graphql/gqlQuery.js b/src/search/adapter/graphql/gqlQuery.js similarity index 100% rename from core/lib/search/adapter/graphql/gqlQuery.js rename to src/search/adapter/graphql/gqlQuery.js diff --git a/core/lib/search/adapter/graphql/processor/processType.ts b/src/search/adapter/graphql/processor/processType.ts similarity index 100% rename from core/lib/search/adapter/graphql/processor/processType.ts rename to src/search/adapter/graphql/processor/processType.ts diff --git a/core/lib/search/adapter/graphql/queries/categories.gql b/src/search/adapter/graphql/queries/categories.gql similarity index 100% rename from core/lib/search/adapter/graphql/queries/categories.gql rename to src/search/adapter/graphql/queries/categories.gql diff --git a/core/lib/search/adapter/graphql/queries/cmsBlock.gql b/src/search/adapter/graphql/queries/cmsBlock.gql similarity index 100% rename from core/lib/search/adapter/graphql/queries/cmsBlock.gql rename to src/search/adapter/graphql/queries/cmsBlock.gql diff --git a/core/lib/search/adapter/graphql/queries/cmsHierarchy.gql b/src/search/adapter/graphql/queries/cmsHierarchy.gql similarity index 100% rename from core/lib/search/adapter/graphql/queries/cmsHierarchy.gql rename to src/search/adapter/graphql/queries/cmsHierarchy.gql diff --git a/core/lib/search/adapter/graphql/queries/cmsPage.gql b/src/search/adapter/graphql/queries/cmsPage.gql similarity index 100% rename from core/lib/search/adapter/graphql/queries/cmsPage.gql rename to src/search/adapter/graphql/queries/cmsPage.gql diff --git a/core/lib/search/adapter/graphql/queries/customAttributeMetadata.gql b/src/search/adapter/graphql/queries/customAttributeMetadata.gql similarity index 100% rename from core/lib/search/adapter/graphql/queries/customAttributeMetadata.gql rename to src/search/adapter/graphql/queries/customAttributeMetadata.gql diff --git a/core/lib/search/adapter/graphql/queries/products.gql b/src/search/adapter/graphql/queries/products.gql similarity index 100% rename from core/lib/search/adapter/graphql/queries/products.gql rename to src/search/adapter/graphql/queries/products.gql diff --git a/core/lib/search/adapter/graphql/queries/reviews.gql b/src/search/adapter/graphql/queries/reviews.gql similarity index 100% rename from core/lib/search/adapter/graphql/queries/reviews.gql rename to src/search/adapter/graphql/queries/reviews.gql diff --git a/core/lib/search/adapter/graphql/queries/taxrule.gql b/src/search/adapter/graphql/queries/taxrule.gql similarity index 100% rename from core/lib/search/adapter/graphql/queries/taxrule.gql rename to src/search/adapter/graphql/queries/taxrule.gql diff --git a/core/lib/search/adapter/graphql/searchAdapter.ts b/src/search/adapter/graphql/searchAdapter.ts similarity index 99% rename from core/lib/search/adapter/graphql/searchAdapter.ts rename to src/search/adapter/graphql/searchAdapter.ts index 9a6b1141a8..704b8eb2fe 100644 --- a/core/lib/search/adapter/graphql/searchAdapter.ts +++ b/src/search/adapter/graphql/searchAdapter.ts @@ -1,5 +1,5 @@ import { prepareQueryVars } from './gqlQuery' -import { currentStoreView, prepareStoreView } from '../../../multistore' +import { currentStoreView, prepareStoreView } from '@vue-storefront/core/lib/multistore' import fetch from 'isomorphic-fetch' import {processESResponseType, processProductsType, processCmsType} from './processor/processType' import { SearchQuery } from 'storefront-query-builder' From 7ec94e64018e7be84ea2ac7f2f8e9c45b3d215c7 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 7 Apr 2020 08:33:17 +0200 Subject: [PATCH 06/37] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eff44ea75..704fd0ba5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -59,6 +59,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Removed `product/loadConfigurableAttributes` calls - @andrzejewsky, @gibkigonzo (#3336) - Disable `mapFallback` url by default - @gibkigonzo(#4092) - Include token in pricing sync - @carlokok (#4156) +- Move 'graphql' search adapter from core to src (deprecated) - @gibkigonzo (#4214) ## [1.11.2] - 2020.03.10 From c171b071344019d80e717c5623409534169a4280 Mon Sep 17 00:00:00 2001 From: Carlo Kok Date: Tue, 7 Apr 2020 09:36:08 +0200 Subject: [PATCH 07/37] Allow parent_ids field on product as an alternative to urlpath based breadcrumb navigation and fixes breadcrumbs to support string category ids --- CHANGELOG.md | 1 + core/modules/catalog-next/store/category/actions.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eff44ea75..a0341badd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [1.12.0-rc1] - UNRELEASED ### Added +- Allow parent_ids field on product as an alternative to urlpath based breadcrumb navigation (#4219) - Pass the original item_id when updating/deleting a cart entry @carlokok (#4218) - Separating endpoints for CSR/SSR - @Fifciu (#2861) - Added short hands for version and help flags - @jamesgeorge007 (#3946) diff --git a/core/modules/catalog-next/store/category/actions.ts b/core/modules/catalog-next/store/category/actions.ts index 5f8e52ea73..4bffe47289 100644 --- a/core/modules/catalog-next/store/category/actions.ts +++ b/core/modules/catalog-next/store/category/actions.ts @@ -156,7 +156,7 @@ const actions: ActionTree = { Vue.prototype.$cacheTags.add(`C${category.id}`) }) } - const notFoundCategories = searchedIds.filter(categoryId => !categories.some(cat => cat.id === parseInt(categoryId))) + const notFoundCategories = searchedIds.filter(categoryId => !categories.some(cat => cat.id === parseInt(categoryId) || cat.id === categoryId)) commit(types.CATEGORY_ADD_CATEGORIES, categories) commit(types.CATEGORY_ADD_NOT_FOUND_CATEGORY_IDS, notFoundCategories) @@ -216,7 +216,7 @@ const actions: ActionTree = { }, async loadCategoryBreadcrumbs ({ dispatch, getters }, { category, currentRouteName, omitCurrent = false }) { if (!category) return - const categoryHierarchyIds = _prepareCategoryPathIds(category) // getters.getCategoriesHierarchyMap.find(categoryMapping => categoryMapping.includes(category.id)) + const categoryHierarchyIds = category.parent_ids ? [...category.parent_ids, category.id] : _prepareCategoryPathIds(category) // getters.getCategoriesHierarchyMap.find(categoryMapping => categoryMapping.includes(category.id)) const categoryFilters = Object.assign({ 'id': categoryHierarchyIds }, cloneDeep(config.entities.category.breadcrumbFilterFields)) const categories = await dispatch('loadCategories', { filters: categoryFilters, reloadAll: Object.keys(config.entities.category.breadcrumbFilterFields).length > 0 }) const sorted = [] From 528d38150b9d0b4f631b0c1ddf5903ccc6b4a952 Mon Sep 17 00:00:00 2001 From: cewald Date: Wed, 8 Apr 2020 09:13:46 +0000 Subject: [PATCH 08/37] Update `storefront-query-builder`object in unit tests --- core/modules/cart/test/unit/store/productActions.spec.ts | 2 +- core/modules/cms/test/unit/createHierarchyLoadQuery.spec.ts | 2 +- core/modules/cms/test/unit/createLoadingBlockQuery.spec.ts | 2 +- core/modules/cms/test/unit/createPageLoadingQuery.spec.ts | 2 +- core/modules/cms/test/unit/createSingleBlockQuery.spec.ts | 2 +- core/modules/cms/test/unit/createSinglePageLoadQuery.spec.ts | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/modules/cart/test/unit/store/productActions.spec.ts b/core/modules/cart/test/unit/store/productActions.spec.ts index 5f8a9d90fe..bf51b81ac1 100644 --- a/core/modules/cart/test/unit/store/productActions.spec.ts +++ b/core/modules/cart/test/unit/store/productActions.spec.ts @@ -76,7 +76,7 @@ describe('Cart productActions', () => { (contextMock.dispatch as jest.Mock).mockImplementationOnce(() => ({ items: [serverItem] })); const result = await (cartActions as any).findProductOption(contextMock, { serverItem }); - expect(contextMock.dispatch).toBeCalledWith('product/list', { query: { _appliedFilters: [{ attribute: 'configurable_children.sku', options: Object, scope: 'default', value: { eq: 1 } }], _availableFilters: [], _searchText: '' }, size: 1, start: 0, updateState: false }, { root: true }) + expect(contextMock.dispatch).toBeCalledWith('product/list', { query: { _appliedFilters: [{ attribute: 'configurable_children.sku', options: Object, scope: 'default', value: { eq: 1 } }], _availableFilters: [], _appliedSort: [], _searchText: '' }, size: 1, start: 0, updateState: false }, { root: true }) expect(result).toEqual({ childSku: 1, sku: 1 }) }); diff --git a/core/modules/cms/test/unit/createHierarchyLoadQuery.spec.ts b/core/modules/cms/test/unit/createHierarchyLoadQuery.spec.ts index bd9e32df6d..b21c9494a0 100644 --- a/core/modules/cms/test/unit/createHierarchyLoadQuery.spec.ts +++ b/core/modules/cms/test/unit/createHierarchyLoadQuery.spec.ts @@ -20,6 +20,6 @@ describe('createHierarchyLoadQuery', () => { const filter = { id: null } let hierarchyLoadQuery = createHierarchyLoadQuery(filter) - expect(hierarchyLoadQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _searchText: '' }) + expect(hierarchyLoadQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _appliedSort: [], _searchText: '' }) }) }) diff --git a/core/modules/cms/test/unit/createLoadingBlockQuery.spec.ts b/core/modules/cms/test/unit/createLoadingBlockQuery.spec.ts index 625d2393cf..4673de015a 100644 --- a/core/modules/cms/test/unit/createLoadingBlockQuery.spec.ts +++ b/core/modules/cms/test/unit/createLoadingBlockQuery.spec.ts @@ -15,6 +15,6 @@ describe('createLoadingBlockQuery', () => { const filter = { filterField: 'test', filterValues: undefined } let loadingBlockQuery = createLoadingBlockQuery(filter) - expect(loadingBlockQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _searchText: '' }) + expect(loadingBlockQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _appliedSort: [], _searchText: '' }) }) }) diff --git a/core/modules/cms/test/unit/createPageLoadingQuery.spec.ts b/core/modules/cms/test/unit/createPageLoadingQuery.spec.ts index 4876ae4f27..471fe1ac59 100644 --- a/core/modules/cms/test/unit/createPageLoadingQuery.spec.ts +++ b/core/modules/cms/test/unit/createPageLoadingQuery.spec.ts @@ -15,6 +15,6 @@ describe('createPageLoadingQuery', () => { const filter = { filterField: 'test', filterValues: undefined } let pageLoadingQuery = createPageLoadingQuery(filter) - expect(pageLoadingQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _searchText: '' }) + expect(pageLoadingQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _appliedSort: [], _searchText: '' }) }) }) diff --git a/core/modules/cms/test/unit/createSingleBlockQuery.spec.ts b/core/modules/cms/test/unit/createSingleBlockQuery.spec.ts index 1b5964a329..feca385fa9 100644 --- a/core/modules/cms/test/unit/createSingleBlockQuery.spec.ts +++ b/core/modules/cms/test/unit/createSingleBlockQuery.spec.ts @@ -15,6 +15,6 @@ describe('createSingleBlockLoadQuery should', () => { const argsMock = { key: 'test', value: undefined } let mockSingleBlockQuery = createSingleBlockQuery(argsMock) - expect(mockSingleBlockQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _searchText: '' }) + expect(mockSingleBlockQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _appliedSort: [], _searchText: '' }) }) }) diff --git a/core/modules/cms/test/unit/createSinglePageLoadQuery.spec.ts b/core/modules/cms/test/unit/createSinglePageLoadQuery.spec.ts index cbc0f630da..343b3d4b4a 100644 --- a/core/modules/cms/test/unit/createSinglePageLoadQuery.spec.ts +++ b/core/modules/cms/test/unit/createSinglePageLoadQuery.spec.ts @@ -15,6 +15,6 @@ describe('createSinglePageLoadQuery should', () => { const filter = { key: 'test', value: undefined } let singlePageMockQuery = createSinglePageLoadQuery(filter) - expect(singlePageMockQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _searchText: '' }) + expect(singlePageMockQuery).toEqual({ _availableFilters: [], _appliedFilters: [], _appliedSort: [], _searchText: '' }) }) }) From 658990894fb02dfe76eafd7aae4ac5638664a1ac Mon Sep 17 00:00:00 2001 From: cewald Date: Wed, 8 Apr 2020 09:51:47 +0000 Subject: [PATCH 09/37] Update to `storefront-query-builder` version `1.0.0` --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 42bba80a67..ccd48aa423 100644 --- a/package.json +++ b/package.json @@ -79,7 +79,7 @@ "redis-tag-cache": "^1.2.1", "reflect-metadata": "^0.1.12", "register-service-worker": "^1.5.2", - "storefront-query-builder": "^0.0.9", + "storefront-query-builder": "^1.0.0", "ts-node": "^8.6.2", "vue": "^2.6.11", "vue-analytics": "^5.16.1", From 260aec4c249116c8534f59f29c1dfb3ea43b17ad Mon Sep 17 00:00:00 2001 From: cewald Date: Wed, 8 Apr 2020 09:58:14 +0000 Subject: [PATCH 10/37] Update `api-search-query` search-adapter to support new `storefront-query-builder` sorting --- core/lib/search/adapter/api-search-query/searchAdapter.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/core/lib/search/adapter/api-search-query/searchAdapter.ts b/core/lib/search/adapter/api-search-query/searchAdapter.ts index 551e13b58c..326ccf95ab 100644 --- a/core/lib/search/adapter/api-search-query/searchAdapter.ts +++ b/core/lib/search/adapter/api-search-query/searchAdapter.ts @@ -42,6 +42,11 @@ export class SearchAdapter { if (Request.hasOwnProperty('groupToken') && Request.groupToken !== null) { rawQueryObject['groupToken'] = Request.groupToken } + if (Request.sort) { + const [ field, options ] = Request.sort.split(':') + rawQueryObject.applySort({ field, options }) + delete Request.sort + } const storeView = (Request.store === null) ? currentStoreView() : await prepareStoreView(Request.store) Request.index = storeView.elasticsearch.index From e8fdd76c56b2043ea71b2b3c308f4f579f2408f9 Mon Sep 17 00:00:00 2001 From: cewald Date: Wed, 8 Apr 2020 10:01:57 +0000 Subject: [PATCH 11/37] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b4b986b05a..892191309a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Product Page Schema implementation as JSON-LD - @Michal-Dziedzinski (#3704) - Add `/cache-version.json` route to get current cache version - Built-in module for detecting device type based on UserAgent with SSR support - @Fifciu +- Update to `storefront-query-builder` version `1.0.0` - @cewald (#4234) ### Fixed From a21febe344b2313878d5f11d84e1c8bd8e661112 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 8 Apr 2020 14:59:42 +0200 Subject: [PATCH 12/37] add generate-file script to dockerfile --- docker/vue-storefront/vue-storefront.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/vue-storefront/vue-storefront.sh b/docker/vue-storefront/vue-storefront.sh index a6db7c8673..920b5c52ba 100755 --- a/docker/vue-storefront/vue-storefront.sh +++ b/docker/vue-storefront/vue-storefront.sh @@ -3,7 +3,7 @@ set -e yarn install || exit $? -yarn build:client && yarn build:server && yarn build:sw || exit $? +yarn generate-files && yarn build:client && yarn build:server && yarn build:sw || exit $? if [ "$VS_ENV" = 'dev' ]; then yarn dev From 397f7c1b17807b585659d2bf1bd11143103ef66b Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 8 Apr 2020 15:06:31 +0200 Subject: [PATCH 13/37] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0eff44ea75..ea0e324723 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Product Page Schema implementation as JSON-LD - @Michal-Dziedzinski (#3704) - Add `/cache-version.json` route to get current cache version - Built-in module for detecting device type based on UserAgent with SSR support - @Fifciu +- Move generating files from webpack config to script @gibkigonzo (#4236) ### Fixed From 877fd7ab8edd96c79f7bb280b8a712178d0b3588 Mon Sep 17 00:00:00 2001 From: cewald Date: Wed, 8 Apr 2020 14:26:36 +0000 Subject: [PATCH 14/37] Add cookbook recipe for extending the query builder to docs --- docs/guide/cookbook/module.md | 100 ++++++++++++++++++++++++++++++++-- 1 file changed, 94 insertions(+), 6 deletions(-) diff --git a/docs/guide/cookbook/module.md b/docs/guide/cookbook/module.md index 3ec015afef..45f50decd2 100644 --- a/docs/guide/cookbook/module.md +++ b/docs/guide/cookbook/module.md @@ -678,10 +678,98 @@ It's hands down no-brainer to bootstrap a module _manually_ because the skeleton ### 2. Recipe ### 3. Peep into the kitchen (what happens internally) ### 4. Chef's secret (protip) -
-
-## 6. Anti-patterns & Common pitfalls +## 6. Extend Elasticsearch request body using `storefront-query-builder` + +If you're using the new [`storefront-query-builder`](https://github.com/DivanteLtd/storefront-query-builder) and the `api-search-query` search-adapter ([introduced with v1.1.12](/guide/upgrade-notes/#_1-11-1-12)) it is now possible to extend it by new filters, or even overwrite a existing filter, to customize your Elasticsearch request-bodies. + +So, this way you can add custom Elasticsearch queries to the query-chain and still use the notation of `SearchQuery` in the Vue Storefront. + +> **Note:** This will only work from `storefront-query-builder` version `1.0.0` and `vue-storefront` version `1.12.2`. + +### Usecases + +One usecases where this feature would come in handy is for example if you like to add complex queries on multiple points in your source code. Using the following technique you can just add a custom filter to your `SearchQuery` in a single line inside your VSF source-code using the `query.applyFilter(...)` method and then add the complex logic into your custom-filter inside the API. + +### Registering a new filter + +The `vue-storefront-api` will only try to load filters that are registered in the configs. The extension/module, that contains the filter, must be enabled and the new filter module-classes needs to be registered in its extension config inside the `catalogFilter` array. The filter files must be located inside `filter/catalog/` of your module folder. + +For example: If you have a module called `extend-catalog` with a filter called `StockFilter`, the file path to filter would be `src/api/extensions/extend-catalog/filter/catalog/StockFilter.ts` and the config would look like: +``` +{ + "registeredExtensions": [ "extend-catalog" ], + "extensions": { + "extend-catalog": { + "catalogFilter": [ "StockFilter" ] + } + } +} +``` + +### Filter module-class properties + +The filter can contain four different properties. Followed a short explaination, what they are doing. + +* `check` – This method checks the condition that be must matched to execute the filter. The first valid filter is executed – all afterwards are ignored. +* `priority` – This is the priority in which the filters are going to be called. The sort is lower to higher. +* `mutator` – The mutator method is in charge of prehandling the filter value, to e.g. set defaults or check and change the type. +* `filter` – This method contains the query logic we wan't to add and mutates the `bodybuilder` query-chain. + +### Example + +Lets assume we like to add a possibility to add a default set of product-attribute filters we can apply to each `SearchQuery` without repeating ourselfs in source-code. So, for example, it should filter for two `color`'s and a specific `cut` to supply a filter for spring-coloured short's we implement at several places in our VSF. + +#### Changes in `vue-storefront` repository + +The query in the VSF code would look like this (that's it on the VSF side): +```js +import { SearchQuery } from 'storefront-query-builder' +import { quickSearchByQuery } from '@vue-storefront/core/lib/search' + +//... + +const query = new SearchQuery() +query.applyFilter({ key: 'spring-shorts', value: 'male', scope: 'default' }) +const products = await dispatch('product/list', { query, size: 5 }) +``` + +#### Changes in `vue-storefront-api` repository + +In the `vue-storefront-api` we are going to add the real filter/query magic. +There is already an example module called `example-custom-filter` which we are going to use for our filter. + +As you look inside its module folder `src/api/extensions/example-custom-filter/`, you will find a child folder `filter/catalog/` with all existing custom filters for this module. Inside this folder we are going to duplicate the existing `SampleFilter.ts` into another one called `SpringShorts.ts` – this is our new custom filter module-class. + +This file needs to be registered in the config JSON to let the API know that there is a new custom filter inside our extension. +Therefore you open your `default.json` or specific config JSON file and add our new filename `SpringShorts` to the config node `extensions.example-custom-filter.catalogFilter` array. + +Our `SpringShorts.ts` contains an object that contains [four properties](#filter-module-class-properties): `priority`, `check`, `filter`, `mutator`. We don't need a `mutator` nor `priority`, so we can remove these lines. `check` and `filter` needs to be changed to fulfill our needs. So, this is how our filter finally looks like: + +```js +import { FilterInterface } from 'storefront-query-builder' + +const filter: FilterInterface = { + check: ({ attribute }) => attribute === 'spring-shorts', + filter ({ value, attribute, operator, queryChain }) { + return queryChain + .filter('terms', 'pants', [ 'shorts' ]) + .filter('terms', 'cut', [ 1, 2 ]) + .filter('terms', 'color', [ 3, 4 ]) + .filter('terms', 'gender', [ value ]) + } +} + +export default filter +``` + +Inside `check` we tell the filter to just be applied if the attribute is named exactly `spring-shorts`. + +Inside `filter` we extend the Elasticsearch query-chain by our desired filters, using the `bodybuilder` library syntax. + +That's it, now we are able to filter by a complex query in only one line inside VSF. + +## 7. Anti-patterns & Common pitfalls ### 1. Preparation ### 2. Recipe @@ -699,7 +787,7 @@ _[INSERT VIDEO HERE]_

-## 7. Building a module from A to Z in an iteration +## 8. Building a module from A to Z in an iteration ### 1. Preparation @@ -709,7 +797,7 @@ _[INSERT VIDEO HERE]_

-## 8. Deprecated legacy of Modules +## 9. Deprecated legacy of Modules In this recipe, we will take a review of how to deal with modules in an old fashioned way , just in case you really need it. ### 1. Preparation @@ -720,7 +808,7 @@ In this recipe, we will take a review of how to deal with modules in an old fash
-## 9. Converting old modules to new modules +## 10. Converting old modules to new modules There are useful modules out there already developed in the old way. ### 1. Preparation From 47e836fb7ed93f473114293f8540a05733e2f886 Mon Sep 17 00:00:00 2001 From: cewald Date: Thu, 9 Apr 2020 11:54:56 +0000 Subject: [PATCH 15/37] Update `yarn.lock` --- yarn.lock | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index e16452b6af..dac8412f70 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2321,6 +2321,16 @@ "@typescript-eslint/typescript-estree" "1.13.0" eslint-scope "^4.0.0" +"@typescript-eslint/experimental-utils@2.27.0": + version "2.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-2.27.0.tgz#801a952c10b58e486c9a0b36cf21e2aab1e9e01a" + integrity sha512-vOsYzjwJlY6E0NJRXPTeCGqjv5OHgRU1kzxHKWJVPjDYGbPgLudBXjIlc+OD1hDBZ4l1DLbOc5VjofKahsu9Jw== + dependencies: + "@types/json-schema" "^7.0.3" + "@typescript-eslint/typescript-estree" "2.27.0" + eslint-scope "^5.0.0" + eslint-utils "^2.0.0" + "@typescript-eslint/parser@^1.7.1-alpha.17": version "1.13.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-1.13.0.tgz#61ac7811ea52791c47dc9fd4dd4a184fae9ac355" @@ -2331,6 +2341,16 @@ "@typescript-eslint/typescript-estree" "1.13.0" eslint-visitor-keys "^1.0.0" +"@typescript-eslint/parser@^2.26.0": + version "2.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-2.27.0.tgz#d91664335b2c46584294e42eb4ff35838c427287" + integrity sha512-HFUXZY+EdwrJXZo31DW4IS1ujQW3krzlRjBrFRrJcMDh0zCu107/nRfhk/uBasO8m0NVDbBF5WZKcIUMRO7vPg== + dependencies: + "@types/eslint-visitor-keys" "^1.0.0" + "@typescript-eslint/experimental-utils" "2.27.0" + "@typescript-eslint/typescript-estree" "2.27.0" + eslint-visitor-keys "^1.1.0" + "@typescript-eslint/typescript-estree@1.13.0": version "1.13.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-1.13.0.tgz#8140f17d0f60c03619798f1d628b8434913dc32e" @@ -2339,6 +2359,19 @@ lodash.unescape "4.0.1" semver "5.5.0" +"@typescript-eslint/typescript-estree@2.27.0": + version "2.27.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-2.27.0.tgz#a288e54605412da8b81f1660b56c8b2e42966ce8" + integrity sha512-t2miCCJIb/FU8yArjAvxllxbTiyNqaXJag7UOpB5DVoM3+xnjeOngtqlJkLRnMtzaRcJhe3CIR9RmL40omubhg== + dependencies: + debug "^4.1.1" + eslint-visitor-keys "^1.1.0" + glob "^7.1.6" + is-glob "^4.0.1" + lodash "^4.17.15" + semver "^6.3.0" + tsutils "^3.17.1" + "@vue/babel-helper-vue-jsx-merge-props@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-jsx-merge-props/-/babel-helper-vue-jsx-merge-props-1.0.0.tgz#048fe579958da408fb7a8b2a3ec050b50a661040" @@ -6751,6 +6784,14 @@ eslint-scope@^4.0.0, eslint-scope@^4.0.3: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-scope@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.0.0.tgz#e87c8887c73e8d1ec84f1ca591645c358bfc8fb9" + integrity sha512-oYrhJW7S0bxAFDvWqzvMPRm6pcgcnWc4QnofCAqRTRfQC0JcwenzGglTtsLyIuuWFfkqDG9vz67cnttSd53djw== + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + eslint-utils@^1.3.1: version "1.4.3" resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" @@ -6758,6 +6799,13 @@ eslint-utils@^1.3.1: dependencies: eslint-visitor-keys "^1.1.0" +eslint-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.0.0.tgz#7be1cc70f27a72a76cd14aa698bcabed6890e1cd" + integrity sha512-0HCPuJv+7Wv1bACm8y5/ECVfYdfsAm9xmVb7saeFlxjPYALefjhbYoCkBjPdPzGH8wWyTpAez82Fh3VKYEZ8OA== + dependencies: + eslint-visitor-keys "^1.1.0" + eslint-visitor-keys@^1.0.0, eslint-visitor-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.1.0.tgz#e2a82cea84ff246ad6fb57f9bde5b46621459ec2" @@ -14607,11 +14655,12 @@ stealthy-require@^1.1.1: resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= -storefront-query-builder@^0.0.9: - version "0.0.9" - resolved "https://registry.yarnpkg.com/storefront-query-builder/-/storefront-query-builder-0.0.9.tgz#e2733851d08dd98566d4f81281326658c74d660a" - integrity sha512-c6zIRyJwFQJtlLG1R+qlrHHDea1Z4O/EJbTvjbGRHIrsMKav2XfX5GzEai7SWU4+GomySU9eIR/M2YAJhVo5rw== +storefront-query-builder@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/storefront-query-builder/-/storefront-query-builder-1.0.0.tgz#8bab0b6bd61a574dfa913cad5c2fdd17858f8b07" + integrity sha512-j0JhHOYhcfDcsBUMYWVJ0UApQDOem5zo20XikxJcxfFEcM5Et1Z16674wx3++KrWCbU5raEMgHvqEPxkDFajdw== dependencies: + "@typescript-eslint/parser" "^2.26.0" clone-deep "^4.0.1" stream-browserify@^2.0.1: @@ -15443,7 +15492,7 @@ tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== -tsutils@^3.7.0: +tsutils@^3.17.1, tsutils@^3.7.0: version "3.17.1" resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.17.1.tgz#ed719917f11ca0dee586272b2ac49e015a2dd759" integrity sha512-kzeQ5B8H3w60nFY2g8cJIuH7JDpsALXySGtwGJ0p2LSjLgay3NdIpqq5SoOBe46bKDW2iq25irHCr8wjomUS2g== From 4d0b8cd67ef97708a27b1b028053fc02d48130f1 Mon Sep 17 00:00:00 2001 From: cewald Date: Sat, 11 Apr 2020 09:09:32 +0200 Subject: [PATCH 16/37] Add correct type matching to `getConfigurationMatchLevel` * There are usecase where the property values are either strings or numbers * By consolidate the type, using `toString` we can prevent that no configurable item is found because the option property type doesn't match --- core/modules/catalog/helpers/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/modules/catalog/helpers/index.ts b/core/modules/catalog/helpers/index.ts index b62bea2197..5bdaaaa8ed 100644 --- a/core/modules/catalog/helpers/index.ts +++ b/core/modules/catalog/helpers/index.ts @@ -62,7 +62,7 @@ const getConfigurationMatchLevel = (configuration, variant): number => { return [].concat(configuration[configProperty]) .map(f => toString(f.id)) - .includes(variantPropertyId) + .includes(toString(variantPropertyId)) }) .filter(Boolean) .length From dcfe972cfe2afe861d6cccd064c0eec4e1c00af2 Mon Sep 17 00:00:00 2001 From: cewald Date: Sat, 11 Apr 2020 09:13:10 +0200 Subject: [PATCH 17/37] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 05b2c425d7..4445b4e226 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Built-in module for detecting device type based on UserAgent with SSR support - @Fifciu - Update to `storefront-query-builder` version `1.0.0` - @cewald (#4234) - Move generating files from webpack config to script @gibkigonzo (#4236) +- Add correct type matching to `getConfigurationMatchLevel` - @cewald (#4241) ### Fixed From 3d7efe1c1d284efb90a87ded102cbb018196992a Mon Sep 17 00:00:00 2001 From: cewald Date: Sat, 11 Apr 2020 14:03:22 +0200 Subject: [PATCH 18/37] Remove unnecessary custom `api-search-query` search adapter --- .../adapter/api-search-query/searchAdapter.ts | 86 ------------------- 1 file changed, 86 deletions(-) delete mode 100644 src/search/adapter/api-search-query/searchAdapter.ts diff --git a/src/search/adapter/api-search-query/searchAdapter.ts b/src/search/adapter/api-search-query/searchAdapter.ts deleted file mode 100644 index d90d2d5ffa..0000000000 --- a/src/search/adapter/api-search-query/searchAdapter.ts +++ /dev/null @@ -1,86 +0,0 @@ -import fetch from 'isomorphic-fetch' -import { processURLAddress } from '@vue-storefront/core/helpers' -import queryString from 'query-string' -import { currentStoreView, prepareStoreView } from '@vue-storefront/core/lib/multistore' -import { SearchQuery } from 'storefront-query-builder' -import HttpQuery from '@vue-storefront/core/types/search/HttpQuery' -import config from 'config' -import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl' - -import { Logger } from '@vue-storefront/core/lib/logger' -import { SearchAdapter as OrgSearchAdapter } from '@vue-storefront/core/lib/search/adapter/api-search-query/searchAdapter' - -export class SearchAdapter extends OrgSearchAdapter { - public async search (Request) { - const rawQueryObject: SearchQuery = Request.searchQuery - const response_format = 'compact' - let request_format = 'search-query' - - if (!this.entities[Request.type]) { - throw new Error('No entity type registered for ' + Request.type) - } - if (!(Request.searchQuery instanceof SearchQuery)) { - request_format = 'dsl' - Logger.warn('You are using a DSL query in `search-query` api.', 'api-search-query')() - } - if (Request.hasOwnProperty('groupId') && Request.groupId !== null) { - rawQueryObject['groupId'] = Request.groupId - } - if (Request.hasOwnProperty('groupToken') && Request.groupToken !== null) { - rawQueryObject['groupToken'] = Request.groupToken - } - // Added our custom sorting here - if (Request.sort && typeof rawQueryObject.applySort === 'function') { - const [ field, options ] = Request.sort.split(':') - rawQueryObject.applySort({ field, options }) - delete Request.sort - } - const storeView = (Request.store === null) ? currentStoreView() : await prepareStoreView(Request.store) - Request.index = storeView.elasticsearch.index - - let url = processURLAddress(getApiEndpointUrl(storeView.elasticsearch, 'host')) - - if (this.entities[Request.type].url) { - url = getApiEndpointUrl(this.entities[Request.type], 'url') - } - - const httpQuery: HttpQuery = { - size: Request.size, - from: Request.from, - sort: Request.sort, - request_format, - response_format - } - - if (Request._sourceExclude) { - httpQuery._source_exclude = Request._sourceExclude.join(',') - } - if (Request._sourceInclude) { - httpQuery._source_include = Request._sourceInclude.join(',') - } - if (Request.q) { - httpQuery.q = Request.q - } - - if (!Request.index || !Request.type) { - throw new Error('Query.index and Query.type are required arguments for executing ElasticSearch query') - } - if (config.elasticsearch.queryMethod === 'GET') { - httpQuery.request = JSON.stringify(rawQueryObject) - } - url = url + '/' + encodeURIComponent(Request.index) + '/' + encodeURIComponent(Request.type) + '/_search' - url = url + '?' + queryString.stringify(httpQuery) - return fetch(url, { method: config.elasticsearch.queryMethod, - mode: 'cors', - headers: { - 'Accept': 'application/json', - 'Content-Type': 'application/json' - }, - body: config.elasticsearch.queryMethod === 'POST' ? JSON.stringify(rawQueryObject) : null - }) - .then(resp => { return resp.json() }) - .catch(error => { - throw new Error('FetchError in request to API: ' + error.toString()) - }) - } -} From 31b4061276513624e589284e0ee9b52dfafea4e9 Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Mon, 13 Apr 2020 11:55:13 +0200 Subject: [PATCH 19/37] Add our custom filter to `SearchPanel` component for custom search (#281) * Add our custom filter to `SearchPanel` component for custom search * Improve some `applyFilter` commands (remove `scope`) * Increase page-size of search-results in `SearchPanel` component --- .../store/category/actions/index.ts | 4 ++-- src/modules/icmaa-category/store/actions.ts | 2 +- .../icmaa-recommendations/helpers/Rules.ts | 2 +- .../core/blocks/SearchPanel/SearchPanel.vue | 19 +++++++++++++++---- 4 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/modules/icmaa-catalog/store/category/actions/index.ts b/src/modules/icmaa-catalog/store/category/actions/index.ts index fd68e25a40..821d0b5f80 100644 --- a/src/modules/icmaa-catalog/store/category/actions/index.ts +++ b/src/modules/icmaa-catalog/store/category/actions/index.ts @@ -36,7 +36,7 @@ const actions: ActionTree = { // Add our custom category filter // @see DivanteLtd/vue-storefront#4111 - filterQr.applyFilter({ key: 'stock', value: '', scope: 'default' }) + filterQr.applyFilter({ key: 'stock', value: '' }) if (!searchQuery.sort) { filterQr.applySort({ field: 'is_in_sale', options: { 'missing': '_first' } }) } @@ -78,7 +78,7 @@ const actions: ActionTree = { // Add our custom category filter // @see DivanteLtd/vue-storefront#4111 - filterQr.applyFilter({ key: 'stock', value: '', scope: 'default' }) + filterQr.applyFilter({ key: 'stock', value: '' }) if (!searchQuery.sort) { filterQr.applySort({ field: 'is_in_sale', options: { 'missing': '_first' } }) } diff --git a/src/modules/icmaa-category/store/actions.ts b/src/modules/icmaa-category/store/actions.ts index 3aad5e6eb4..4c8734f2b0 100644 --- a/src/modules/icmaa-category/store/actions.ts +++ b/src/modules/icmaa-category/store/actions.ts @@ -48,7 +48,7 @@ const actions: ActionTree = { let query = new SearchQuery() query - .applyFilter({ key: 'stock', value: '', scope: 'default' }) + .applyFilter({ key: 'stock', value: '' }) .applyFilter({ key: 'visibility', value: { in: [2, 3, 4] } }) .applyFilter({ key: 'status', value: { in: [0, 1] } }) .applyFilter({ key: 'category_ids', value: { in: [categoryId] } }) diff --git a/src/modules/icmaa-recommendations/helpers/Rules.ts b/src/modules/icmaa-recommendations/helpers/Rules.ts index 61738be841..a5e8554020 100644 --- a/src/modules/icmaa-recommendations/helpers/Rules.ts +++ b/src/modules/icmaa-recommendations/helpers/Rules.ts @@ -180,7 +180,7 @@ class Rules { */ protected addDefaultFilter (): this { this.query - .applyFilter({ key: 'stock', value: '', scope: 'default' }) + .applyFilter({ key: 'stock', value: '' }) .applyFilter({ key: 'visibility', value: { in: [2, 3, 4] } }) .applyFilter({ key: 'status', value: { in: [0, 1] } }) diff --git a/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue b/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue index 7e72b2a825..185ea5ff43 100644 --- a/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue +++ b/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue @@ -39,7 +39,7 @@ import i18n from '@vue-storefront/i18n' import { mapGetters } from 'vuex' import { required, minLength } from 'vuelidate/lib/validators' import { disableBodyScroll, clearAllBodyScrollLocks } from 'body-scroll-lock' -import { prepareQuickSearchQuery } from '@vue-storefront/core/modules/catalog/queries/searchPanel' +import { SearchQuery } from 'storefront-query-builder' import { Logger } from '@vue-storefront/core/lib/logger' import debounce from 'lodash-es/debounce' import uniq from 'lodash-es/uniq' @@ -66,7 +66,7 @@ export default { searchString: '', searchAlias: '', products: [], - size: 12, + size: 24, start: 0, placeholder: i18n.t('Type what you are looking for...'), emptyResults: true, @@ -158,7 +158,7 @@ export default { }, search: debounce(async function () { if (!this.$v.searchString.$invalid) { - let query = prepareQuickSearchQuery( + let query = this.prepareQuickSearchQuery( this.searchAlias = await this.getAlias(this.searchString) ) @@ -180,7 +180,7 @@ export default { }, 350), async loadMoreProducts () { if (!this.$v.searchString.$invalid) { - let query = prepareQuickSearchQuery(await this.getAlias(this.searchString)) + let query = this.prepareQuickSearchQuery(await this.getAlias(this.searchString)) this.loadingProducts = true this.$store.dispatch('product/list', { query, start: this.start, size: this.size, updateState: false }).then((resp) => { let page = Math.floor(resp.total / this.size) @@ -201,6 +201,17 @@ export default { this.emptyResults = true } }, + prepareQuickSearchQuery (value) { + let searchQuery = new SearchQuery() + + searchQuery = searchQuery + .applyFilter({ key: 'search-text', value }) + .applyFilter({ key: 'stock', value: '' }) + .applyFilter({ key: 'visibility', value: {'in': [3, 4]} }) + .applyFilter({ key: 'status', value: {'in': [0, 1]} }) + + return searchQuery + }, closeSidebar () { this.$store.dispatch('ui/setSearchpanel', false) } From 8115de0c36c5529d4ff424c5c6ff33544bfcf851 Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Mon, 13 Apr 2020 17:27:25 +0200 Subject: [PATCH 20/37] #197501 Improve `SearchPanel` category results (#282) * Populate available categories from aggregation instead of the result products to show all possible products categories not just those who are on the current result page --- .../core/blocks/SearchPanel/SearchPanel.vue | 46 +++++++++++-------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue b/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue index 185ea5ff43..4ddb0dd873 100644 --- a/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue +++ b/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue @@ -12,7 +12,7 @@ {{ $t(getNoResultsMessage) }} - +
@@ -66,7 +66,8 @@ export default { searchString: '', searchAlias: '', products: [], - size: 24, + categoryAggs: [], + size: 12, start: 0, placeholder: i18n.t('Type what you are looking for...'), emptyResults: true, @@ -90,18 +91,9 @@ export default { } return productList }, - categoryFilters () { - const categoriesMap = {} - this.products.forEach(product => { - [...product.category].forEach(category => { - categoriesMap[category.category_id] = category - }) - }) - return Object.keys(categoriesMap).map(categoryId => categoriesMap[categoryId]) - }, categories () { const splitChars = [' ', '-', ','] - return this.categoryFilters.filter(category => { + return this.categoryAggs.filter(category => { let searchStrings = [] const strings = [this.searchString, this.searchAlias] strings.forEach(s => splitChars.forEach(c => searchStrings.push(...s.split(c).filter(s => s.length >= 3)))) @@ -126,7 +118,7 @@ export default { } }, watch: { - categories () { + categoryAggs () { this.selectedCategoryIds = [] } }, @@ -166,10 +158,13 @@ export default { this.moreProducts = true this.loadingProducts = true this.$store.dispatch('product/list', { query, start: this.start, configuration: {}, size: this.size, updateState: false }).then(resp => { - this.products = resp.items + const { items, aggregations } = resp + this.products = items this.start += this.size - this.emptyResults = resp.items.length < 1 + this.emptyResults = items.length < 1 this.loadingProducts = false + + this.populateCategoryAggregations(aggregations) }).catch((err) => { Logger.error(err, 'components-search')() }) @@ -183,12 +178,13 @@ export default { let query = this.prepareQuickSearchQuery(await this.getAlias(this.searchString)) this.loadingProducts = true this.$store.dispatch('product/list', { query, start: this.start, size: this.size, updateState: false }).then((resp) => { - let page = Math.floor(resp.total / this.size) - let exceeed = resp.total - this.size * page - if (resp.start === resp.total - exceeed) { + const { items, aggregations, total, start } = resp + let page = Math.floor(total / this.size) + let exceeed = total - this.size * page + if (start === total - exceeed) { this.moreProducts = false } - this.products = this.products.concat(resp.items) + this.products = this.products.concat(items) this.start += this.size this.emptyResults = this.products.length < 1 this.loadingProducts = false @@ -212,6 +208,18 @@ export default { return searchQuery }, + populateCategoryAggregations (aggr) { + // This is a massive nested aggregation object which we crawl and collect all + // available categories of all results not just those who are on results page + this.categoryAggs = [] + if (aggr.categories_found && aggr.categories_found.doc_count > 0) { + const { categories_found } = aggr + const categories = categories_found.categories.buckets + categories.forEach(bucket => { + this.categoryAggs.push(bucket.hits.hits.hits[0]._source.category) + }) + } + }, closeSidebar () { this.$store.dispatch('ui/setSearchpanel', false) } From e2c46536519aab0828e9462aab1fdcbbcb5de238 Mon Sep 17 00:00:00 2001 From: cewald Date: Tue, 14 Apr 2020 06:02:50 +0000 Subject: [PATCH 21/37] Support `useSpecificImagePaths` with `useExactUrlsNoProxy` and add `pathType` to `afterProductThumbnailPathGenerate` hook --- core/helpers/index.ts | 14 +++++++------- core/hooks.ts | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/core/helpers/index.ts b/core/helpers/index.ts index e278d39ccd..9fd9f2ab38 100644 --- a/core/helpers/index.ts +++ b/core/helpers/index.ts @@ -47,14 +47,14 @@ export function slugify (text) { * @returns {string} */ export function getThumbnailPath (relativeUrl: string, width: number = 0, height: number = 0, pathType: string = 'product'): string { + if (config.images.useSpecificImagePaths) { + const path = config.images.paths[pathType] !== undefined ? config.images.paths[pathType] : '' + relativeUrl = path + relativeUrl + } + if (config.images.useExactUrlsNoProxy) { - return coreHooksExecutors.afterProductThumbnailPathGenerate({ path: relativeUrl, sizeX: width, sizeY: height }).path // this is exact url mode + return coreHooksExecutors.afterProductThumbnailPathGenerate({ path: relativeUrl, sizeX: width, sizeY: height, pathType }).path // this is exact url mode } else { - if (config.images.useSpecificImagePaths) { - const path = config.images.paths[pathType] !== undefined ? config.images.paths[pathType] : '' - relativeUrl = path + relativeUrl - } - let resultUrl if (relativeUrl && (relativeUrl.indexOf('://') > 0 || relativeUrl.indexOf('?') > 0 || relativeUrl.indexOf('&') > 0)) relativeUrl = encodeURIComponent(relativeUrl) // proxyUrl is not a url base path but contains {{url}} parameters and so on to use the relativeUrl as a template value and then do the image proxy opertions @@ -69,7 +69,7 @@ export function getThumbnailPath (relativeUrl: string, width: number = 0, height } const path = relativeUrl && relativeUrl.indexOf('no_selection') < 0 ? resultUrl : config.images.productPlaceholder || '' - return coreHooksExecutors.afterProductThumbnailPathGenerate({ path, sizeX: width, sizeY: height }).path + return coreHooksExecutors.afterProductThumbnailPathGenerate({ path, sizeX: width, sizeY: height, pathType }).path } } diff --git a/core/hooks.ts b/core/hooks.ts index 8e0c083685..733309fcfc 100644 --- a/core/hooks.ts +++ b/core/hooks.ts @@ -23,7 +23,7 @@ const { const { hook: afterProductThumbnailPathGeneratedHook, executor: afterProductThumbnailPathGeneratedExecutor -} = createMutatorHook<{ path: string, sizeX: number, sizeY: number }, { path: string }>() +} = createMutatorHook<{ path: string, pathType: string, sizeX: number, sizeY: number }, { path: string }>() /** Only for internal usage in core */ const coreHooksExecutors = { From 6975fdabee29a09a1f2993ec302aeb0fcebd1c2d Mon Sep 17 00:00:00 2001 From: cewald Date: Tue, 14 Apr 2020 06:26:54 +0000 Subject: [PATCH 22/37] Update CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4445b4e226..cfaa5496a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update to `storefront-query-builder` version `1.0.0` - @cewald (#4234) - Move generating files from webpack config to script @gibkigonzo (#4236) - Add correct type matching to `getConfigurationMatchLevel` - @cewald (#4241) +- Support `useSpecificImagePaths` with `useExactUrlsNoProxy` - @cewald (#4243) ### Fixed From 57bb936a3413043b72e45b5ce9ece1bbf99a8163 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 14 Apr 2020 09:39:38 +0200 Subject: [PATCH 23/37] add vsf-cache-nginx and vsf-cache-varnish modules --- .gitmodules | 8 ++++++++ src/modules/vsf-cache-nginx | 1 + src/modules/vsf-cache-varnish | 1 + 3 files changed, 10 insertions(+) create mode 100644 .gitmodules create mode 160000 src/modules/vsf-cache-nginx create mode 160000 src/modules/vsf-cache-varnish diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000000..1e12f2aaed --- /dev/null +++ b/.gitmodules @@ -0,0 +1,8 @@ +[submodule "src/modules/vsf-cache-nginx"] + path = src/modules/vsf-cache-nginx + url = git@github.com:new-fantastic/vsf-cache-nginx.git + branch = master +[submodule "src/modules/vsf-cache-varnish"] + path = src/modules/vsf-cache-varnish + url = git@github.com:new-fantastic/vsf-cache-varnish.git + branch = master diff --git a/src/modules/vsf-cache-nginx b/src/modules/vsf-cache-nginx new file mode 160000 index 0000000000..c2c07879ca --- /dev/null +++ b/src/modules/vsf-cache-nginx @@ -0,0 +1 @@ +Subproject commit c2c07879ca261b88c7cc76c45eaa49519bfcfc87 diff --git a/src/modules/vsf-cache-varnish b/src/modules/vsf-cache-varnish new file mode 160000 index 0000000000..09cc48f65e --- /dev/null +++ b/src/modules/vsf-cache-varnish @@ -0,0 +1 @@ +Subproject commit 09cc48f65ee174dc39eec809cb5f816fd3f039fa From 39d9d66753a073cc5d20407d10b06396b1beb525 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Tue, 14 Apr 2020 09:41:36 +0200 Subject: [PATCH 24/37] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4445b4e226..9383afdd16 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Update to `storefront-query-builder` version `1.0.0` - @cewald (#4234) - Move generating files from webpack config to script @gibkigonzo (#4236) - Add correct type matching to `getConfigurationMatchLevel` - @cewald (#4241) +- Add vsf-cache-nginx and vsf-cache-varnish modules - @gibkigonzo (#4096) ### Fixed From 33b3ba55f1230070819bc6dfb42f25c3ac80bf90 Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Tue, 14 Apr 2020 14:58:06 +0200 Subject: [PATCH 25/37] #187376 Bugfix for GTM tracking (#283) * Add new cookie-handler to `icmaa-external-checkout` to handle guest conversions * Load last-order by JWT-Order-ID-Token stored inside a cookie when user returns from external checkout * Connected to https://github.com/icmaa/vue-storefront-api/pull/60 & https://github.com/icmaa/shop-impericon/pull/1056 --- src/modules/icmaa-external-checkout/index.ts | 11 +++++++- .../pages/ExternalSuccess.vue | 14 ++++++++-- .../icmaa-user/data-resolver/UserService.ts | 26 +++++++++++++++++++ src/modules/icmaa-user/store/actions.ts | 25 ++++++++++++++++++ 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 src/modules/icmaa-user/data-resolver/UserService.ts diff --git a/src/modules/icmaa-external-checkout/index.ts b/src/modules/icmaa-external-checkout/index.ts index 5d80de186b..aaa5a9e2bf 100755 --- a/src/modules/icmaa-external-checkout/index.ts +++ b/src/modules/icmaa-external-checkout/index.ts @@ -26,12 +26,14 @@ export const IcmaaExternalCheckoutModule: StorefrontModule = function ({ router, EventBus.$on('session-after-nonauthorized', async () => { const customerToken = Vue.$cookies.get('vsf_token_customer') const quoteToken = Vue.$cookies.get('vsf_token_quote') + const lastOrderToken = Vue.$cookies.get('vsf_token_lastorder') - if (!store.getters['user/isLoggedIn'] && (customerToken || quoteToken)) { + if (!store.getters['user/isLoggedIn'] && (customerToken || quoteToken || lastOrderToken)) { if (customerToken) { Logger.info('Customer token found in cookie – try to login:', 'external-checkout', customerToken)() store.dispatch('user/startSessionWithToken', customerToken).then(() => { Vue.$cookies.remove('vsf_token_customer', undefined, getCookieHostname()) + Vue.$cookies.remove('vsf_token_lastorder', undefined, getCookieHostname()) }) } @@ -41,6 +43,13 @@ export const IcmaaExternalCheckoutModule: StorefrontModule = function ({ router, Vue.$cookies.remove('vsf_token_quote', undefined, getCookieHostname()) }) } + + if (!customerToken && lastOrderToken) { + Logger.info('Last-order token found in cookie – try to load last order:', 'external-checkout', lastOrderToken)() + store.dispatch('user/loadLastOrderToHistory', { token: lastOrderToken }).then(() => { + Vue.$cookies.remove('vsf_token_lastorder', undefined, getCookieHostname()) + }) + } } }) diff --git a/src/modules/icmaa-external-checkout/pages/ExternalSuccess.vue b/src/modules/icmaa-external-checkout/pages/ExternalSuccess.vue index d3c33d957e..456a5efe7c 100755 --- a/src/modules/icmaa-external-checkout/pages/ExternalSuccess.vue +++ b/src/modules/icmaa-external-checkout/pages/ExternalSuccess.vue @@ -54,8 +54,11 @@ export default { * logged in when the beforeMount event hook is called. Otherwise the `checkout-success-last-order-loaded` * event won't ever be fired on first request because `isLoggedIn` is false. */ - isLoggedIn (isLoggedIn) { - this.onLogin(isLoggedIn) + isLoggedIn (value) { + this.onLogin(value) + }, + lastOrder () { + this.guestOrder() } }, methods: { @@ -69,6 +72,13 @@ export default { if (value || this.isLoggedIn) { await this.$store.dispatch('user/refreshOrdersHistory', { resolvedFromCache: false }) this.$bus.$emit('checkout-success-last-order-loaded', this.lastOrder) + } else if (!value && !this.isLoggedIn) { + await this.$store.dispatch('user/loadLastOrderFromCache') + } + }, + async guestOrder () { + if (!this.isLoggedIn && this.lastOrder) { + this.$bus.$emit('checkout-success-last-order-loaded', this.lastOrder) } } } diff --git a/src/modules/icmaa-user/data-resolver/UserService.ts b/src/modules/icmaa-user/data-resolver/UserService.ts new file mode 100644 index 0000000000..38c706619d --- /dev/null +++ b/src/modules/icmaa-user/data-resolver/UserService.ts @@ -0,0 +1,26 @@ +import { processLocalizedURLAddress } from '@vue-storefront/core/helpers' +import { TaskQueue } from '@vue-storefront/core/lib/sync' +import Task from '@vue-storefront/core/lib/sync/types/Task' +import config from 'config' +import getApiEndpointUrl from '@vue-storefront/core/helpers/getApiEndpointUrl' + +const headers = { + 'Accept': 'application/json, text/plain, */*', + 'Content-Type': 'application/json' +} + +const getLastOrder = async (token: string): Promise => + TaskQueue.execute({ + url: processLocalizedURLAddress( + getApiEndpointUrl(config.users, 'last_order').replace('{{token}}', token) + ), + payload: { + method: 'GET', + mode: 'cors', + headers + } + }) + +export const UserService: any = { + getLastOrder +} diff --git a/src/modules/icmaa-user/store/actions.ts b/src/modules/icmaa-user/store/actions.ts index 971891dc0e..3420ea8596 100644 --- a/src/modules/icmaa-user/store/actions.ts +++ b/src/modules/icmaa-user/store/actions.ts @@ -4,6 +4,7 @@ import RootState from '@vue-storefront/core/types/RootState' import UserState from '../types/UserState' import { UserProfile } from '@vue-storefront/core/modules/user/types/UserProfile' import { UserService } from '@vue-storefront/core/data-resolver' +import { UserService as IcmaaUserService } from '../data-resolver/UserService' import * as types from './mutation-types' import * as userTypes from '@vue-storefront/core/modules/user/store/mutation-types' import { SearchQuery } from 'storefront-query-builder' @@ -95,6 +96,30 @@ const actions: ActionTree = { return resp }, + async loadLastOrderToHistory ({ commit, dispatch }, { token }) { + const resp = await IcmaaUserService.getLastOrder(token) + + if (resp.code === 200) { + const order = await dispatch('loadOrderProducts', { order: resp.result, history: [ resp.result ] }) + + commit(userTypes.USER_ORDERS_HISTORY_LOADED, { items: [ order ] }) + EventBus.$emit('user-after-loaded-orders', resp.result) + } + + return resp + }, + async loadLastOrderFromCache ({ dispatch }) { + let resolvedFromCache = false + const ordersHistory = await dispatch('loadOrdersFromCache') + if (ordersHistory) { + Logger.log('Current user order history served from cache', 'user')() + resolvedFromCache = true + } + + if (!resolvedFromCache) { + Promise.resolve(null) + } + }, async loadOrderProducts ({ dispatch }, { order, history }) { const index = history.findIndex(o => o.id === order.id) if (history[index] && history[index].products) { From 87765b03ffd84f672f51cb511e12ce4b9bda89f2 Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Tue, 14 Apr 2020 17:51:00 +0200 Subject: [PATCH 26/37] fix: removed possible memory leak in ssr When current currentStoreView() is saved in an variable outside of the export it is not clean up automatically on the SSR side. --- .../components/InstantCheckout.vue | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/modules/instant-checkout/components/InstantCheckout.vue b/src/modules/instant-checkout/components/InstantCheckout.vue index 86f4f9d2b9..81e1f4b194 100644 --- a/src/modules/instant-checkout/components/InstantCheckout.vue +++ b/src/modules/instant-checkout/components/InstantCheckout.vue @@ -15,8 +15,6 @@ import { currentStoreView } from '@vue-storefront/core/lib/multistore' import { registerModule } from '@vue-storefront/core/lib/modules' import { OrderModule } from '@vue-storefront/core/modules/order' -const storeView = currentStoreView() - export default { name: 'InstantCheckoutButton', beforeCreate () { @@ -25,7 +23,7 @@ export default { data () { return { supported: false, - country: rootStore.state.checkout.shippingDetails.country ? rootStore.state.checkout.shippingDetails.country : storeView.tax.defaultCountry, + country: rootStore.state.checkout.shippingDetails.country ? rootStore.state.checkout.shippingDetails.country : currentStoreView().tax.defaultCountry, paymentMethods: [ { supportedMethods: ['basic-card'], @@ -56,7 +54,7 @@ export default { bucket.push({ label: product.name, amount: { - currency: storeView.i18n.currencyCode, + currency: currentStoreView().i18n.currencyCode, value: this.getProductPrice(product) } }) @@ -67,7 +65,7 @@ export default { if (this.selectedShippingOption.length > 0) { bucket.push({ label: i18n.t('Shipping'), - amount: { currency: storeView.i18n.currencyCode, value: this.selectedShippingOption[0].amount.value } + amount: { currency: currentStoreView().i18n.currencyCode, value: this.selectedShippingOption[0].amount.value } }) } @@ -81,7 +79,7 @@ export default { if (shipping.length > 0) { bucket.push({ label: shipping[0].title, - amount: { currency: storeView.i18n.currencyCode, value: shipping[0].value } + amount: { currency: currentStoreView().i18n.currencyCode, value: shipping[0].value } }) } @@ -107,7 +105,7 @@ export default { return { label: i18n.t('Grand total'), - amount: { currency: storeView.i18n.currencyCode, value: subtotal } + amount: { currency: currentStoreView().i18n.currencyCode, value: subtotal } } } @@ -118,7 +116,7 @@ export default { if (total.length > 0) { return { label: total[0].title, - amount: { currency: storeView.i18n.currencyCode, value: total[0].value } + amount: { currency: currentStoreView().i18n.currencyCode, value: total[0].value } } } @@ -231,7 +229,7 @@ export default { label: method.method_title, selected: setDefault ? this.$store.getters['checkout/getShippingMethods'][0].method_code === method.method_code : false, amount: { - currency: storeView.i18n.currencyCode, + currency: currentStoreView().i18n.currencyCode, value: method.price_incl_tax } }) From e5dfd7c787a33648f80f58ec6e3ac25f44757c0e Mon Sep 17 00:00:00 2001 From: ResuBaka Date: Tue, 14 Apr 2020 17:56:44 +0200 Subject: [PATCH 27/37] docs(changelog): added new entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4445b4e226..6c06662ab4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -49,6 +49,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Fixed `cart/isVirtualCart` to return `false` when cart is empty - @haelbichalex(#4182) - Use `setProductGallery` in `product/setCurrent` to use logic of the action - @cewald (#4153) - Use same data format in getConfigurationMatchLevel - @gibkigonzo (#4208) +- removed possible memory leak in ssr - @resubaka (#4247) ### Changed / Improved From 87679473943e5c10d65f376e2552fe3cc37352c2 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 15 Apr 2020 09:51:25 +0200 Subject: [PATCH 28/37] update config --- config/default.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/default.json b/config/default.json index d86b01da69..5a565276ae 100644 --- a/config/default.json +++ b/config/default.json @@ -581,5 +581,11 @@ "enableMapFallbackUrl": false, "endpoint": "/api/url", "map_endpoint": "/api/url/map" + }, + "nginx": { + "enabled":false + }, + "varnish": { + "enabled":false } } From 48f07c8953345fe83f48debdf654a49f7beb0d14 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 15 Apr 2020 09:54:36 +0200 Subject: [PATCH 29/37] update config --- config/default.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config/default.json b/config/default.json index d86b01da69..7b771edd4c 100644 --- a/config/default.json +++ b/config/default.json @@ -581,5 +581,8 @@ "enableMapFallbackUrl": false, "endpoint": "/api/url", "map_endpoint": "/api/url/map" + }, + "fastly": { + "enabled":false } } From f0bf090ffc3e2c1f81286b033272679c044db1b8 Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 15 Apr 2020 10:11:20 +0200 Subject: [PATCH 30/37] remove empty package --- packages/cli/vue-storefront | 1 - 1 file changed, 1 deletion(-) delete mode 160000 packages/cli/vue-storefront diff --git a/packages/cli/vue-storefront b/packages/cli/vue-storefront deleted file mode 160000 index 3af5a1a152..0000000000 --- a/packages/cli/vue-storefront +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 3af5a1a152489f7335aff49c9f1d29d92a45da2f From 280276e3cdf1255c5dbf04e5dbc98b7b8ddfa58e Mon Sep 17 00:00:00 2001 From: tkostuch Date: Wed, 15 Apr 2020 10:18:09 +0200 Subject: [PATCH 31/37] update .gitmodules --- .gitmodules | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitmodules b/.gitmodules index 1e12f2aaed..2e81d78770 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,8 +1,8 @@ [submodule "src/modules/vsf-cache-nginx"] path = src/modules/vsf-cache-nginx - url = git@github.com:new-fantastic/vsf-cache-nginx.git + url = https://github.com/new-fantastic/vsf-cache-nginx.git branch = master [submodule "src/modules/vsf-cache-varnish"] path = src/modules/vsf-cache-varnish - url = git@github.com:new-fantastic/vsf-cache-varnish.git + url = https://github.com/new-fantastic/vsf-cache-varnish.git branch = master From 00b659b1b4565f12b83b2de0a86c810bbf8f7944 Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Wed, 15 Apr 2020 11:55:23 +0200 Subject: [PATCH 32/37] Bugfix for build exception in Node v13.13+ (#287) After the update to `@babel/preset-env` `^7.8.6"` I faced the exception during the build on a plain machine: ``` ERROR in ./core/service-worker/index.js Module build failed (from ./node_modules/babel-loader/lib/index.js): Error: Cannot find module '@babel/compat-data/corejs3-shipped-proposals' ``` I've found this issue mentioned in the latest commits of the `babel` plugin and upgraded to `7.9.0` as recommended: https://github.com/babel/babel/pull/11283 and https://github.com/nodejs/node/issues/32852 --- package.json | 2 +- yarn.lock | 129 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 146b526c27..64f7fc3578 100644 --- a/package.json +++ b/package.json @@ -103,7 +103,7 @@ "@babel/core": "^7.8.6", "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/polyfill": "^7.8.3", - "@babel/preset-env": "^7.8.6", + "@babel/preset-env": "^7.9.0", "@types/jest": "^25.1.3", "@types/node": "^13.7.7", "@typescript-eslint/eslint-plugin": "^1.7.1-alpha.17", diff --git a/yarn.lock b/yarn.lock index fff9316ea2..ffc5deea83 100644 --- a/yarn.lock +++ b/yarn.lock @@ -192,6 +192,15 @@ "@babel/template" "^7.8.3" "@babel/types" "^7.8.3" +"@babel/helper-function-name@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.9.5.tgz#2b53820d35275120e1874a82e5aabe1376920a5c" + integrity sha512-JVcQZeXM59Cd1qanDUxv9fgJpt3NeKUaqBqUEvfmQ+BCOKq2xUgaWZW2hr0dkbyJgezYuplEoh5knmrnS68efw== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/template" "^7.8.3" + "@babel/types" "^7.9.5" + "@babel/helper-get-function-arity@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.8.3.tgz#b894b947bd004381ce63ea1db9f08547e920abd5" @@ -306,6 +315,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.0.tgz#ad53562a7fc29b3b9a91bbf7d10397fd146346ed" integrity sha512-6G8bQKjOh+of4PV/ThDm/rRqlU7+IGoJuofpagU5GlEl29Vv0RGqqt86ZGRV8ZuSOY3o+8yXl5y782SMcG7SHw== +"@babel/helper-validator-identifier@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.9.5.tgz#90977a8e6fbf6b431a7dc31752eee233bf052d80" + integrity sha512-/8arLKUFq882w4tWGj9JYzRpAlZgiWUJ+dtteNTDqrRBz9Iguck9Rn3ykuBDoUwh2TO4tSAJlrxDUOXWklJe4g== + "@babel/helper-wrap-function@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.8.3.tgz#9dbdb2bb55ef14aaa01fe8c99b629bd5352d8610" @@ -427,6 +441,15 @@ "@babel/helper-plugin-utils" "^7.8.3" "@babel/plugin-syntax-object-rest-spread" "^7.8.0" +"@babel/plugin-proposal-object-rest-spread@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.9.5.tgz#3fd65911306d8746014ec0d0cf78f0e39a149116" + integrity sha512-VP2oXvAf7KCYTthbUHwBlewbl1Iq059f6seJGsxMizaCdgHIeczOr7FBqELhSqfkIl04Fi8okzWzl63UKbQmmg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-transform-parameters" "^7.9.5" + "@babel/plugin-proposal-optional-catch-binding@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.8.3.tgz#9dee96ab1650eed88646ae9734ca167ac4a9c5c9" @@ -610,6 +633,20 @@ "@babel/helper-split-export-declaration" "^7.8.3" globals "^11.1.0" +"@babel/plugin-transform-classes@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.9.5.tgz#800597ddb8aefc2c293ed27459c1fcc935a26c2c" + integrity sha512-x2kZoIuLC//O5iA7PEvecB105o7TLzZo8ofBVhP79N+DO3jaX+KYfww9TQcfBEZD0nikNyYcGB1IKtRq36rdmg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.8.3" + "@babel/helper-define-map" "^7.8.3" + "@babel/helper-function-name" "^7.9.5" + "@babel/helper-optimise-call-expression" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/helper-replace-supers" "^7.8.6" + "@babel/helper-split-export-declaration" "^7.8.3" + globals "^11.1.0" + "@babel/plugin-transform-computed-properties@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.8.3.tgz#96d0d28b7f7ce4eb5b120bb2e0e943343c86f81b" @@ -624,6 +661,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.3" +"@babel/plugin-transform-destructuring@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.9.5.tgz#72c97cf5f38604aea3abf3b935b0e17b1db76a50" + integrity sha512-j3OEsGel8nHL/iusv/mRd5fYZ3DrOxWC82x0ogmdN/vHfAP4MYw+AFKYanzWlktNwikKvlzUV//afBW5FTp17Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-dotall-regex@^7.4.4", "@babel/plugin-transform-dotall-regex@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.8.3.tgz#c3c6ec5ee6125c6993c5cbca20dc8621a9ea7a6e" @@ -796,6 +840,14 @@ "@babel/helper-get-function-arity" "^7.8.3" "@babel/helper-plugin-utils" "^7.8.3" +"@babel/plugin-transform-parameters@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.9.5.tgz#173b265746f5e15b2afe527eeda65b73623a0795" + integrity sha512-0+1FhHnMfj6lIIhVvS4KGQJeuhe1GI//h5uptK4PvLt+BGBxsoUJbd3/IW002yk//6sZPlFgsG1hY6OHLcy6kA== + dependencies: + "@babel/helper-get-function-arity" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-transform-property-literals@^7.8.3": version "7.8.3" resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.8.3.tgz#33194300d8539c1ed28c62ad5087ba3807b98263" @@ -953,7 +1005,7 @@ levenary "^1.1.1" semver "^5.5.0" -"@babel/preset-env@^7.8.4", "@babel/preset-env@^7.8.6": +"@babel/preset-env@^7.8.4": version "7.8.6" resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.8.6.tgz#2a0773b08589ecba4995fc71b1965e4f531af40b" integrity sha512-M5u8llV9DIVXBFB/ArIpqJuvXpO+ymxcJ6e8ZAmzeK3sQeBNOD1y+rHvHCGG4TlEmsNpIrdecsHGHT8ZCoOSJg== @@ -1016,6 +1068,72 @@ levenary "^1.1.1" semver "^5.5.0" +"@babel/preset-env@^7.9.0": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.9.5.tgz#8ddc76039bc45b774b19e2fc548f6807d8a8919f" + integrity sha512-eWGYeADTlPJH+wq1F0wNfPbVS1w1wtmMJiYk55Td5Yu28AsdR9AsC97sZ0Qq8fHqQuslVSIYSGJMcblr345GfQ== + dependencies: + "@babel/compat-data" "^7.9.0" + "@babel/helper-compilation-targets" "^7.8.7" + "@babel/helper-module-imports" "^7.8.3" + "@babel/helper-plugin-utils" "^7.8.3" + "@babel/plugin-proposal-async-generator-functions" "^7.8.3" + "@babel/plugin-proposal-dynamic-import" "^7.8.3" + "@babel/plugin-proposal-json-strings" "^7.8.3" + "@babel/plugin-proposal-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-proposal-numeric-separator" "^7.8.3" + "@babel/plugin-proposal-object-rest-spread" "^7.9.5" + "@babel/plugin-proposal-optional-catch-binding" "^7.8.3" + "@babel/plugin-proposal-optional-chaining" "^7.9.0" + "@babel/plugin-proposal-unicode-property-regex" "^7.8.3" + "@babel/plugin-syntax-async-generators" "^7.8.0" + "@babel/plugin-syntax-dynamic-import" "^7.8.0" + "@babel/plugin-syntax-json-strings" "^7.8.0" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.0" + "@babel/plugin-syntax-numeric-separator" "^7.8.0" + "@babel/plugin-syntax-object-rest-spread" "^7.8.0" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.0" + "@babel/plugin-syntax-optional-chaining" "^7.8.0" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-transform-arrow-functions" "^7.8.3" + "@babel/plugin-transform-async-to-generator" "^7.8.3" + "@babel/plugin-transform-block-scoped-functions" "^7.8.3" + "@babel/plugin-transform-block-scoping" "^7.8.3" + "@babel/plugin-transform-classes" "^7.9.5" + "@babel/plugin-transform-computed-properties" "^7.8.3" + "@babel/plugin-transform-destructuring" "^7.9.5" + "@babel/plugin-transform-dotall-regex" "^7.8.3" + "@babel/plugin-transform-duplicate-keys" "^7.8.3" + "@babel/plugin-transform-exponentiation-operator" "^7.8.3" + "@babel/plugin-transform-for-of" "^7.9.0" + "@babel/plugin-transform-function-name" "^7.8.3" + "@babel/plugin-transform-literals" "^7.8.3" + "@babel/plugin-transform-member-expression-literals" "^7.8.3" + "@babel/plugin-transform-modules-amd" "^7.9.0" + "@babel/plugin-transform-modules-commonjs" "^7.9.0" + "@babel/plugin-transform-modules-systemjs" "^7.9.0" + "@babel/plugin-transform-modules-umd" "^7.9.0" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.8.3" + "@babel/plugin-transform-new-target" "^7.8.3" + "@babel/plugin-transform-object-super" "^7.8.3" + "@babel/plugin-transform-parameters" "^7.9.5" + "@babel/plugin-transform-property-literals" "^7.8.3" + "@babel/plugin-transform-regenerator" "^7.8.7" + "@babel/plugin-transform-reserved-words" "^7.8.3" + "@babel/plugin-transform-shorthand-properties" "^7.8.3" + "@babel/plugin-transform-spread" "^7.8.3" + "@babel/plugin-transform-sticky-regex" "^7.8.3" + "@babel/plugin-transform-template-literals" "^7.8.3" + "@babel/plugin-transform-typeof-symbol" "^7.8.4" + "@babel/plugin-transform-unicode-regex" "^7.8.3" + "@babel/preset-modules" "^0.1.3" + "@babel/types" "^7.9.5" + browserslist "^4.9.1" + core-js-compat "^3.6.2" + invariant "^2.2.2" + levenary "^1.1.1" + semver "^5.5.0" + "@babel/preset-modules@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.3.tgz#13242b53b5ef8c883c3cf7dddd55b36ce80fbc72" @@ -1098,6 +1216,15 @@ lodash "^4.17.13" to-fast-properties "^2.0.0" +"@babel/types@^7.9.5": + version "7.9.5" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.9.5.tgz#89231f82915a8a566a703b3b20133f73da6b9444" + integrity sha512-XjnvNqenk818r5zMaba+sLQjnbda31UfUURv3ei0qPQw4u+j2jMyJ5b11y8ZHYTRSI3NnInQkkkRT4fLqqPdHg== + dependencies: + "@babel/helper-validator-identifier" "^7.9.5" + lodash "^4.17.13" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" From 9f820aee8e6ba2ef8839e5c286b1b99da892b2c2 Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Wed, 15 Apr 2020 12:11:12 +0200 Subject: [PATCH 33/37] #197501 Improve `SearchPanel` component (#284) * Don't load aggregations on next pages * Update `actions/setup-node` and `bahmutov/npm-install` versions in Github-Actions --- .github/workflows/build.yml | 4 ++-- .github/workflows/tests.yml | 8 ++++---- .../core/blocks/SearchPanel/SearchPanel.vue | 12 ++++++------ 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cde415515a..9247c0dbe5 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -21,12 +21,12 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v1.4.1 with: node-version: '13.x' - name: Install - uses: bahmutov/npm-install@v1 + uses: bahmutov/npm-install@v1.1.0 - name: Get repository name, and branch name run: | diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3c9e0b894e..a43e0f65a7 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v1.4.1 with: node-version: '13.x' @@ -31,7 +31,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v1.4.1 with: node-version: '13.x' @@ -69,7 +69,7 @@ jobs: steps: - uses: actions/checkout@v2 - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v1.4.1 with: node-version: '13.x' @@ -82,7 +82,7 @@ jobs: run: rsync -r ./vue-storefront-workspace/template/vue-storefront/ ./ - name: Install - uses: bahmutov/npm-install@v1 + uses: bahmutov/npm-install@v1.1.0 - name: Build run: yarn build diff --git a/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue b/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue index 4ddb0dd873..8f4b67652e 100644 --- a/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue +++ b/src/themes/icmaa-imp/components/core/blocks/SearchPanel/SearchPanel.vue @@ -150,9 +150,8 @@ export default { }, search: debounce(async function () { if (!this.$v.searchString.$invalid) { - let query = this.prepareQuickSearchQuery( - this.searchAlias = await this.getAlias(this.searchString) - ) + this.searchAlias = await this.getAlias(this.searchString) + let query = this.prepareQuickSearchQuery(this.searchAlias) this.start = 0 this.moreProducts = true @@ -175,7 +174,7 @@ export default { }, 350), async loadMoreProducts () { if (!this.$v.searchString.$invalid) { - let query = this.prepareQuickSearchQuery(await this.getAlias(this.searchString)) + let query = this.prepareQuickSearchQuery(await this.getAlias(this.searchString), true) this.loadingProducts = true this.$store.dispatch('product/list', { query, start: this.start, size: this.size, updateState: false }).then((resp) => { const { items, aggregations, total, start } = resp @@ -197,11 +196,12 @@ export default { this.emptyResults = true } }, - prepareQuickSearchQuery (value) { + prepareQuickSearchQuery (value, plain = false) { let searchQuery = new SearchQuery() + const searchFilterKey = plain ? 'search-text-plain' : 'search-text' searchQuery = searchQuery - .applyFilter({ key: 'search-text', value }) + .applyFilter({ key: searchFilterKey, value }) .applyFilter({ key: 'stock', value: '' }) .applyFilter({ key: 'visibility', value: {'in': [3, 4]} }) .applyFilter({ key: 'status', value: {'in': [0, 1]} }) From 1c8e0dcbaf96d377da06372f9fe5f52328327123 Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Wed, 15 Apr 2020 12:22:51 +0200 Subject: [PATCH 34/37] #199077 Add `icmaa-cdn` module (#286) --- src/modules/client.ts | 2 + src/modules/icmaa-cdn/.gitignore | 2 + src/modules/icmaa-cdn/README.md | 37 +++++++++++++++++++ src/modules/icmaa-cdn/index.ts | 21 +++++++++++ src/modules/icmaa-cdn/package.json | 14 +++++++ .../icmaa-cdn/provider/ScaleCommerce.ts | 19 ++++++++++ src/modules/icmaa-cdn/types/HookTypes.ts | 14 +++++++ 7 files changed, 109 insertions(+) create mode 100644 src/modules/icmaa-cdn/.gitignore create mode 100644 src/modules/icmaa-cdn/README.md create mode 100644 src/modules/icmaa-cdn/index.ts create mode 100644 src/modules/icmaa-cdn/package.json create mode 100644 src/modules/icmaa-cdn/provider/ScaleCommerce.ts create mode 100644 src/modules/icmaa-cdn/types/HookTypes.ts diff --git a/src/modules/client.ts b/src/modules/client.ts index ad725d1ebb..11e1ab293b 100644 --- a/src/modules/client.ts +++ b/src/modules/client.ts @@ -24,6 +24,7 @@ import { IcmaaExtendedNewsletterModule } from 'icmaa-newsletter' import { IcmaaExtendedReviewRoutes } from 'icmaa-review' import { IcmaaCategoryModule } from 'icmaa-category' import { IcmaaCategoryExtrasModule } from 'icmaa-category-extras' +import { IcmaaCdnModule } from 'icmaa-cdn' import { IcmaaCmsModule } from 'icmaa-cms' import { IcmaaFormsModule } from 'icmaa-forms' import { IcmaaTeaserModule } from 'icmaa-teaser' @@ -70,6 +71,7 @@ export function registerClientModules () { registerModule(IcmaaExtendedReviewRoutes) registerModule(IcmaaCategoryModule) registerModule(IcmaaCategoryExtrasModule) + registerModule(IcmaaCdnModule) registerModule(IcmaaCmsModule) registerModule(IcmaaFormsModule) registerModule(IcmaaTeaserModule) diff --git a/src/modules/icmaa-cdn/.gitignore b/src/modules/icmaa-cdn/.gitignore new file mode 100644 index 0000000000..04c01ba7ba --- /dev/null +++ b/src/modules/icmaa-cdn/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ \ No newline at end of file diff --git a/src/modules/icmaa-cdn/README.md b/src/modules/icmaa-cdn/README.md new file mode 100644 index 0000000000..dd1daebc95 --- /dev/null +++ b/src/modules/icmaa-cdn/README.md @@ -0,0 +1,37 @@ +# `icmaa-cdn` module + +Load custom image provider to support external CDN services. + +## Configs + +* Run `yarn` to install modules dependencies. + They are defined in templates `package.json`. + +* `config.images.useExactUrlsNoProxy` must be `true` / enabled + +* Add the following configs to your `config/local.json`: + ``` + "images": { + "useExactUrlsNoProxy": true + }, + "icmaa_cdn": { + "provider": "scalecommerce", + "scalecommerce": { + "baseUrl": "https://www.base-url.com/", + "quality": 85 + } + } + ``` + +## Add a new provider + +If you wan't to add another CDN provider, you can add a new modules classes inside the `provider/NewProvider.ts`. + +You also need to add the dynamic import variable to the `providers` array in the `index.ts` like: +`newprovider: () => import(/* webpackChunkName: "vsf-icmaa-cdn-newprovider" */ './provider/NewProvider')` + +Then add your desired configs under the `icmaa_cdn` configs path. + +## Todo + +[ ] ... diff --git a/src/modules/icmaa-cdn/index.ts b/src/modules/icmaa-cdn/index.ts new file mode 100644 index 0000000000..2d49328719 --- /dev/null +++ b/src/modules/icmaa-cdn/index.ts @@ -0,0 +1,21 @@ +import { StorefrontModule } from '@vue-storefront/core/lib/modules' +import { coreHooks } from '@vue-storefront/core/hooks' +import { Logger } from '@vue-storefront/core/lib/logger' + +import { ImakeHook } from './types/HookTypes' + +const providers: { [provider: string]: () => Promise } = { + scalecommerce: () => import(/* webpackChunkName: "vsf-icmaa-cdn-scalecommerce" */ './provider/ScaleCommerce') +} + +export const IcmaaCdnModule: StorefrontModule = function ({ store, appConfig, router }) { + const cdn = appConfig.icmaa_cdn && appConfig.icmaa_cdn.provider && appConfig.icmaa_cdn.provider !== '' ? appConfig.icmaa_cdn.provider : false + if (cdn && appConfig.images.useExactUrlsNoProxy && providers.hasOwnProperty(cdn)) { + const provider = providers[cdn]() + provider.then(c => { + coreHooks.afterProductThumbnailPathGenerate(c.default) + }).catch(e => { + Logger.error('Could not load provider:', 'icmaa-cdn', cdn)() + }) + } +} diff --git a/src/modules/icmaa-cdn/package.json b/src/modules/icmaa-cdn/package.json new file mode 100644 index 0000000000..01d4d41429 --- /dev/null +++ b/src/modules/icmaa-cdn/package.json @@ -0,0 +1,14 @@ +{ + "name": "icmaa-cdn", + "version": "1.0.0", + "author": "cewald and contributors", + "main": "index.js", + "license": "MIT", + "private": true, + "devDependencies": { + "@vue-storefront/core": "^1.11.1" + }, + "peerDependencies": { + "@vue-storefront/core": "^1.11.1" + } +} diff --git a/src/modules/icmaa-cdn/provider/ScaleCommerce.ts b/src/modules/icmaa-cdn/provider/ScaleCommerce.ts new file mode 100644 index 0000000000..9cda414905 --- /dev/null +++ b/src/modules/icmaa-cdn/provider/ScaleCommerce.ts @@ -0,0 +1,19 @@ +import config from 'config' +import { ImageHookProperties, ImageHookReturn } from '../types/HookTypes' + +const afterProductThumbnailPathGenerate = ({ path, sizeX, sizeY }: ImageHookProperties): ImageHookReturn => { + let { baseUrl, quality } = config.icmaa_cdn['scalecommerce'] + + baseUrl = baseUrl.replace(/\/*$/, '') + path = path.replace(/^\/*/, '') + + if (sizeX && sizeY && sizeX > 0 && sizeY > 0) { + path = `${baseUrl}/${sizeX}x${sizeY}x${quality}/media/${path}` + } else { + path = `${baseUrl}/media/${path}` + } + + return { path } +} + +export default afterProductThumbnailPathGenerate diff --git a/src/modules/icmaa-cdn/types/HookTypes.ts b/src/modules/icmaa-cdn/types/HookTypes.ts new file mode 100644 index 0000000000..09dd7b3edf --- /dev/null +++ b/src/modules/icmaa-cdn/types/HookTypes.ts @@ -0,0 +1,14 @@ +export interface ImageHookProperties { + path: string, + pathType: string, + sizeX: number, + sizeY: number +} + +export interface ImageHookReturn { + path: string +} + +export interface ImakeHook { + default(params: ImageHookProperties): ImageHookReturn +} From e1fb8521f9ca46bc39148b2d6a464e21523d2d3d Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Thu, 16 Apr 2020 06:57:09 +0200 Subject: [PATCH 35/37] Add defaults to `sortedProductOptions` of `optionsMixin` in `icmaa-imp` theme (#290) --- src/themes/icmaa-imp/mixins/product/optionsMixin.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/themes/icmaa-imp/mixins/product/optionsMixin.ts b/src/themes/icmaa-imp/mixins/product/optionsMixin.ts index 3b4b9c7723..4af25a5a10 100644 --- a/src/themes/icmaa-imp/mixins/product/optionsMixin.ts +++ b/src/themes/icmaa-imp/mixins/product/optionsMixin.ts @@ -27,10 +27,11 @@ export default { }, sortedProductOptions () { return cloneDeep(this.product.configurable_options).map(o => { + const attribute = Object.assign({ options: [] }, this.getAttributeListByCode[o.attribute_code]) + const { options } = attribute + // Sort by attributes value `sort_order` parameter o.values = o.values.sort((a, b) => { - const attribute = this.getAttributeListByCode[o.attribute_code] - const { options } = attribute const aValue = a.value_index const bValue = b.value_index From 11345ffb736303e31d422c72662b95dd164f1329 Mon Sep 17 00:00:00 2001 From: Dierk Landmann Date: Thu, 16 Apr 2020 08:45:27 +0200 Subject: [PATCH 36/37] #196865 Add SEO-Text Component (#285) --- src/modules/icmaa-cms/components/Wrapper.vue | 14 ++++++++-- .../components/core/blocks/RichText.vue | 26 +++++++++++++++++++ src/themes/icmaa-imp/pages/Home.vue | 5 +++- 3 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 src/themes/icmaa-imp/components/core/blocks/RichText.vue diff --git a/src/modules/icmaa-cms/components/Wrapper.vue b/src/modules/icmaa-cms/components/Wrapper.vue index b87c2e9c7c..c0ef1ed17e 100644 --- a/src/modules/icmaa-cms/components/Wrapper.vue +++ b/src/modules/icmaa-cms/components/Wrapper.vue @@ -13,8 +13,9 @@ import mapKeys from 'lodash-es/mapKeys' import mapValues from 'lodash-es/mapValues' import camelCase from 'lodash-es/camelCase' -const AsyncLogoline = () => import(/* webpackPreload: true */ /* webpackChunkName: "vsf-block-logoline" */ 'theme/components/core/blocks/CategoryExtras/LogoLine') -const AsyncTeaser = () => import(/* webpackPreload: true */ /* webpackChunkName: "vsf-block-teaser" */ 'theme/components/core/blocks/Teaser/Teaser') +const AsyncLogoline = () => import(/* webpackPreload: true */ /* webpackChunkName: "vsf-content-block-logoline" */ 'theme/components/core/blocks/CategoryExtras/LogoLine') +const AsyncTeaser = () => import(/* webpackPreload: true */ /* webpackChunkName: "vsf-content-block-teaser" */ 'theme/components/core/blocks/Teaser/Teaser') +const AsyncText = () => import(/* webpackPreload: true */ /* webpackChunkName: "vsf-content-block-text" */ 'theme/components/core/blocks/RichText') export default { name: 'CmsBlockWrapper', @@ -49,6 +50,15 @@ export default { }, cssClass: 't-mb-4 lg:t-mb-6', padding: true + }, + 'component_text': { + component: AsyncText, + propsTypes: { + content: 'string' + }, + propsDefaults: {}, + cssClass: 't-mb-8', + padding: false } } }, diff --git a/src/themes/icmaa-imp/components/core/blocks/RichText.vue b/src/themes/icmaa-imp/components/core/blocks/RichText.vue new file mode 100644 index 0000000000..a869acd6a3 --- /dev/null +++ b/src/themes/icmaa-imp/components/core/blocks/RichText.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/themes/icmaa-imp/pages/Home.vue b/src/themes/icmaa-imp/pages/Home.vue index ae71a54710..2f91f13536 100755 --- a/src/themes/icmaa-imp/pages/Home.vue +++ b/src/themes/icmaa-imp/pages/Home.vue @@ -15,6 +15,7 @@ + @@ -26,13 +27,15 @@ import LazyHydrate from 'vue-lazy-hydration' import Teaser from 'theme/components/core/blocks/Teaser/Teaser' import LogoLine from 'theme/components/core/blocks/CategoryExtras/LogoLineBlock' import ProductListingWidget from 'icmaa-category/components/core/ProductListingWidget' +import CmsBlock from 'icmaa-cms/components/Block' export default { components: { LazyHydrate, Teaser, LogoLine, - ProductListingWidget + ProductListingWidget, + CmsBlock }, mounted () { if (!this.isLoggedIn && localStorage.getItem('redirect')) { From f1128d3ebf2c4a8bee5787ae2b533a001986e24a Mon Sep 17 00:00:00 2001 From: Christian Ewald Date: Thu, 16 Apr 2020 11:46:43 +0200 Subject: [PATCH 37/37] Bugfix for empty cms blocks in `icmaa-cms` block component (#292) --- src/modules/icmaa-cms/components/Block.vue | 2 +- src/modules/icmaa-cms/mixins/Block.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/icmaa-cms/components/Block.vue b/src/modules/icmaa-cms/components/Block.vue index 078fba0704..85f3428c32 100644 --- a/src/modules/icmaa-cms/components/Block.vue +++ b/src/modules/icmaa-cms/components/Block.vue @@ -1,5 +1,5 @@