Преглед изворни кода

feat(core): Implement facet duplicator

Relates to #627
Michael Bromley пре 1 година
родитељ
комит
8d208473ce

+ 67 - 0
packages/core/e2e/duplicate-entity.e2e-spec.ts

@@ -35,6 +35,7 @@ import {
     CREATE_ROLE,
     GET_COLLECTION,
     GET_COLLECTIONS,
+    GET_FACET_WITH_VALUES,
     GET_PRODUCT_WITH_VARIANTS,
     UPDATE_PRODUCT_VARIANTS,
 } from './graphql/shared-definitions';
@@ -645,6 +646,72 @@ describe('Duplicating entities', () => {
                 expect(collection?.filters).toEqual(testCollection.filters);
             });
         });
+
+        describe('Facet duplicator', () => {
+            let newFacetId: string;
+
+            it('duplicate facet', async () => {
+                const { duplicateEntity } = await adminClient.query<
+                    Codegen.DuplicateEntityMutation,
+                    Codegen.DuplicateEntityMutationVariables
+                >(DUPLICATE_ENTITY, {
+                    input: {
+                        entityName: 'Facet',
+                        entityId: 'T_1',
+                        duplicatorInput: {
+                            code: 'facet-duplicator',
+                            arguments: [
+                                {
+                                    name: 'includeFacetValues',
+                                    value: 'true',
+                                },
+                            ],
+                        },
+                    },
+                });
+
+                duplicateEntityGuard.assertSuccess(duplicateEntity);
+
+                expect(duplicateEntity.newEntityId).toBe('T_2');
+                newFacetId = duplicateEntity.newEntityId;
+            });
+
+            it('facet name is suffixed', async () => {
+                const { facet } = await adminClient.query<
+                    Codegen.GetFacetWithValuesQuery,
+                    Codegen.GetFacetWithValuesQueryVariables
+                >(GET_FACET_WITH_VALUES, {
+                    id: newFacetId,
+                });
+
+                expect(facet?.name).toBe('category (copy)');
+            });
+
+            it('is initially private', async () => {
+                const { facet } = await adminClient.query<
+                    Codegen.GetFacetWithValuesQuery,
+                    Codegen.GetFacetWithValuesQueryVariables
+                >(GET_FACET_WITH_VALUES, {
+                    id: newFacetId,
+                });
+
+                expect(facet?.isPrivate).toBe(true);
+            });
+
+            it('facet values are duplicated', async () => {
+                const { facet } = await adminClient.query<
+                    Codegen.GetFacetWithValuesQuery,
+                    Codegen.GetFacetWithValuesQueryVariables
+                >(GET_FACET_WITH_VALUES, {
+                    id: newFacetId,
+                });
+
+                expect(facet?.values.map(v => v.name).sort()).toEqual([
+                    'computers (copy)',
+                    'electronics (copy)',
+                ]);
+            });
+        });
     });
 });
 

+ 3 - 12
packages/core/e2e/facet.e2e-spec.ts

@@ -5,9 +5,9 @@ import path from 'path';
 import { afterAll, beforeAll, describe, expect, it } from 'vitest';
 
 import { initialData } from '../../../e2e-common/e2e-initial-data';
-import { testConfig, TEST_SETUP_TIMEOUT_MS } from '../../../e2e-common/test-config';
+import { TEST_SETUP_TIMEOUT_MS, testConfig } from '../../../e2e-common/test-config';
 
-import { FACET_VALUE_FRAGMENT, FACET_WITH_VALUES_FRAGMENT } from './graphql/fragments';
+import { FACET_VALUE_FRAGMENT } from './graphql/fragments';
 import * as Codegen from './graphql/generated-e2e-admin-types';
 import {
     ChannelFragment,
@@ -15,7 +15,6 @@ import {
     DeletionResult,
     FacetWithValuesFragment,
     GetFacetWithValueListDocument,
-    GetFacetWithValuesDocument,
     LanguageCode,
 } from './graphql/generated-e2e-admin-types';
 import {
@@ -24,6 +23,7 @@ import {
     CREATE_FACET,
     GET_FACET_LIST,
     GET_FACET_LIST_SIMPLE,
+    GET_FACET_WITH_VALUES,
     GET_PRODUCT_WITH_VARIANTS,
     UPDATE_FACET,
     UPDATE_PRODUCT,
@@ -810,15 +810,6 @@ describe('Facet resolver', () => {
     });
 });
 
-export const GET_FACET_WITH_VALUES = gql`
-    query GetFacetWithValues($id: ID!) {
-        facet(id: $id) {
-            ...FacetWithValues
-        }
-    }
-    ${FACET_WITH_VALUES_FRAGMENT}
-`;
-
 export const GET_FACET_WITH_VALUE_LIST = gql`
     query GetFacetWithValueList($id: ID!) {
         facet(id: $id) {

+ 9 - 0
packages/core/e2e/graphql/shared-definitions.ts

@@ -1054,3 +1054,12 @@ export const GET_COLLECTION = gql`
     }
     ${COLLECTION_FRAGMENT}
 `;
+
+export const GET_FACET_WITH_VALUES = gql`
+    query GetFacetWithValues($id: ID!) {
+        facet(id: $id) {
+            ...FacetWithValues
+        }
+    }
+    ${FACET_WITH_VALUES_FRAGMENT}
+`;

+ 1 - 1
packages/core/src/config/entity/entity-duplicators/collection-duplicator.ts

@@ -33,7 +33,7 @@ export const collectionDuplicator = new EntityDuplicator({
         connection = injector.get(TransactionalConnection);
         collectionService = injector.get(CollectionService);
     },
-    async duplicate({ ctx, id, args }) {
+    async duplicate({ ctx, id }) {
         const collection = await connection.getEntityOrThrow(ctx, Collection, id, {
             relations: {
                 featuredAsset: true,

+ 84 - 0
packages/core/src/config/entity/entity-duplicators/facet-duplicator.ts

@@ -0,0 +1,84 @@
+import {
+    CreateFacetInput,
+    FacetTranslationInput,
+    LanguageCode,
+    Permission,
+} from '@vendure/common/lib/generated-types';
+
+import { Injector } from '../../../common/index';
+import { TransactionalConnection } from '../../../connection/index';
+import { Facet } from '../../../entity/index';
+import { FacetService, FacetValueService } from '../../../service/index';
+import { EntityDuplicator } from '../entity-duplicator';
+
+let connection: TransactionalConnection;
+let facetService: FacetService;
+let facetValueService: FacetValueService;
+
+/**
+ * @description
+ * Duplicates a Facet
+ */
+export const facetDuplicator = new EntityDuplicator({
+    code: 'facet-duplicator',
+    description: [
+        {
+            languageCode: LanguageCode.en,
+            value: 'Default duplicator for Facets',
+        },
+    ],
+    requiresPermission: [Permission.CreateFacet, Permission.CreateCatalog],
+    forEntities: ['Facet'],
+    args: {
+        includeFacetValues: {
+            type: 'boolean',
+            defaultValue: true,
+            label: [{ languageCode: LanguageCode.en, value: 'Include facet values' }],
+        },
+    },
+    init(injector: Injector) {
+        connection = injector.get(TransactionalConnection);
+        facetService = injector.get(FacetService);
+        facetValueService = injector.get(FacetValueService);
+    },
+    async duplicate({ ctx, id, args }) {
+        const facet = await connection.getEntityOrThrow(ctx, Facet, id, {
+            relations: {
+                values: true,
+            },
+        });
+        const translations: FacetTranslationInput[] = facet.translations.map(translation => {
+            return {
+                name: translation.name + ' (copy)',
+                languageCode: translation.languageCode,
+                customFields: translation.customFields,
+            };
+        });
+        const facetInput: CreateFacetInput = {
+            isPrivate: true,
+            translations,
+            customFields: facet.customFields,
+            code: facet.code + '-copy',
+        };
+
+        const duplicatedFacet = await facetService.create(ctx, facetInput);
+        if (args.includeFacetValues) {
+            if (facet.values.length) {
+                for (const value of facet.values) {
+                    const newValue = await facetValueService.create(ctx, duplicatedFacet, {
+                        code: value.code + '-copy',
+                        translations: value.translations.map(translation => ({
+                            name: translation.name + ' (copy)',
+                            languageCode: translation.languageCode,
+                            customFields: translation.customFields,
+                        })),
+                        facetId: duplicatedFacet.id,
+                        customFields: value.customFields,
+                    });
+                    duplicatedFacet.values.push(newValue);
+                }
+            }
+        }
+        return duplicatedFacet;
+    },
+});

+ 2 - 1
packages/core/src/config/entity/entity-duplicators/index.ts

@@ -1,4 +1,5 @@
 import { collectionDuplicator } from './collection-duplicator';
+import { facetDuplicator } from './facet-duplicator';
 import { productDuplicator } from './product-duplicator';
 
-export const defaultEntityDuplicators = [productDuplicator, collectionDuplicator];
+export const defaultEntityDuplicators = [productDuplicator, collectionDuplicator, facetDuplicator];