فهرست منبع

feat(core): Implement collection duplicator

Relates to #627
Michael Bromley 1 سال پیش
والد
کامیت
d457851de7

+ 1 - 16
packages/core/e2e/collection.e2e-spec.ts

@@ -34,6 +34,7 @@ import {
     DELETE_PRODUCT,
     DELETE_PRODUCT_VARIANT,
     GET_ASSET_LIST,
+    GET_COLLECTION,
     GET_COLLECTIONS,
     UPDATE_COLLECTION,
     UPDATE_PRODUCT,
@@ -2400,22 +2401,6 @@ describe('Collection resolver', () => {
     }
 });
 
-export const GET_COLLECTION = gql`
-    query GetCollection($id: ID, $slug: String, $variantListOptions: ProductVariantListOptions) {
-        collection(id: $id, slug: $slug) {
-            ...Collection
-            productVariants(options: $variantListOptions) {
-                items {
-                    id
-                    name
-                    price
-                }
-            }
-        }
-    }
-    ${COLLECTION_FRAGMENT}
-`;
-
 export const GET_COLLECTION_LIST = gql`
     query GetCollectionListAdmin($options: CollectionListOptions) {
         collections(options: $options) {

+ 145 - 14
packages/core/e2e/duplicate-entity.e2e-spec.ts

@@ -1,9 +1,11 @@
 /* eslint-disable @typescript-eslint/no-non-null-assertion */
+import { pick } from '@vendure/common/lib/pick';
 import {
     Collection,
     CollectionService,
     defaultEntityDuplicators,
     EntityDuplicator,
+    variantIdCollectionFilter,
     LanguageCode,
     mergeConfig,
     PermissionDefinition,
@@ -29,7 +31,9 @@ import {
 } from './graphql/generated-e2e-admin-types';
 import {
     CREATE_ADMINISTRATOR,
+    CREATE_COLLECTION,
     CREATE_ROLE,
+    GET_COLLECTION,
     GET_COLLECTIONS,
     GET_PRODUCT_WITH_VARIANTS,
     UPDATE_PRODUCT_VARIANTS,
@@ -274,13 +278,13 @@ describe('Duplicating entities', () => {
 
     it('duplicate gets created', async () => {
         const { collection } = await adminClient.query<
-            Codegen.GetDuplicatedCollectionQuery,
-            Codegen.GetDuplicatedCollectionQueryVariables
-        >(GET_DUPLICATED_COLLECTION, {
+            Codegen.GetCollectionQuery,
+            Codegen.GetCollectionQueryVariables
+        >(GET_COLLECTION, {
             id: 'T_3',
         });
 
-        expect(collection).toEqual({
+        expect(pick(collection, ['id', 'name', 'slug'])).toEqual({
             id: 'T_3',
             name: 'Plants (copy)',
             slug: 'plants-copy',
@@ -441,6 +445,17 @@ describe('Duplicating entities', () => {
                 );
             });
 
+            it('product name is suffixed', async () => {
+                const { product } = await adminClient.query<
+                    Codegen.GetProductWithVariantsQuery,
+                    Codegen.GetProductWithVariantsQueryVariables
+                >(GET_PRODUCT_WITH_VARIANTS, {
+                    id: newProduct2Id,
+                });
+
+                expect(product?.name).toBe('Laptop (copy)');
+            });
+
             it('variant SKUs are suffixed', async () => {
                 const { product } = await adminClient.query<
                     Codegen.GetProductWithVariantsQuery,
@@ -504,6 +519,132 @@ describe('Duplicating entities', () => {
                 );
             });
         });
+
+        describe('Collection duplicator', () => {
+            let testCollection: Codegen.CreateCollectionMutation['createCollection'];
+            let duplicatedCollectionId: string;
+
+            beforeAll(async () => {
+                await adminClient.asSuperAdmin();
+
+                const { createCollection } = await adminClient.query<
+                    Codegen.CreateCollectionMutation,
+                    Codegen.CreateCollectionMutationVariables
+                >(CREATE_COLLECTION, {
+                    input: {
+                        parentId: 'T_2',
+                        assetIds: ['T_1'],
+                        featuredAssetId: 'T_1',
+                        isPrivate: false,
+                        inheritFilters: false,
+                        translations: [
+                            {
+                                languageCode: LanguageCode.en,
+                                name: 'Test Collection',
+                                description: 'Test Collection description',
+                                slug: 'test-collection',
+                            },
+                        ],
+                        filters: [
+                            {
+                                code: variantIdCollectionFilter.code,
+                                arguments: [
+                                    {
+                                        name: 'variantIds',
+                                        value: '["T_1"]',
+                                    },
+                                    {
+                                        name: 'combineWithAnd',
+                                        value: 'true',
+                                    },
+                                ],
+                            },
+                        ],
+                    },
+                });
+                testCollection = createCollection;
+            });
+
+            it('duplicate collection', async () => {
+                const { duplicateEntity } = await adminClient.query<
+                    Codegen.DuplicateEntityMutation,
+                    Codegen.DuplicateEntityMutationVariables
+                >(DUPLICATE_ENTITY, {
+                    input: {
+                        entityName: 'Collection',
+                        entityId: testCollection.id,
+                        duplicatorInput: {
+                            code: 'collection-duplicator',
+                            arguments: [],
+                        },
+                    },
+                });
+
+                duplicateEntityGuard.assertSuccess(duplicateEntity);
+
+                expect(testCollection.id).toBe('T_4');
+                expect(duplicateEntity.newEntityId).toBe('T_5');
+
+                duplicatedCollectionId = duplicateEntity.newEntityId;
+            });
+
+            it('collection name is suffixed', async () => {
+                const { collection } = await adminClient.query<
+                    Codegen.GetCollectionQuery,
+                    Codegen.GetCollectionQueryVariables
+                >(GET_COLLECTION, {
+                    id: duplicatedCollectionId,
+                });
+
+                expect(collection?.name).toBe('Test Collection (copy)');
+            });
+
+            it('is initially private', async () => {
+                const { collection } = await adminClient.query<
+                    Codegen.GetCollectionQuery,
+                    Codegen.GetCollectionQueryVariables
+                >(GET_COLLECTION, {
+                    id: duplicatedCollectionId,
+                });
+
+                expect(collection?.isPrivate).toBe(true);
+            });
+
+            it('assets are duplicated', async () => {
+                const { collection } = await adminClient.query<
+                    Codegen.GetCollectionQuery,
+                    Codegen.GetCollectionQueryVariables
+                >(GET_COLLECTION, {
+                    id: duplicatedCollectionId,
+                });
+
+                expect(collection?.featuredAsset).toEqual(testCollection.featuredAsset);
+                expect(collection?.assets.length).toBe(1);
+                expect(collection?.assets).toEqual(testCollection.assets);
+            });
+
+            it('parentId matches', async () => {
+                const { collection } = await adminClient.query<
+                    Codegen.GetCollectionQuery,
+                    Codegen.GetCollectionQueryVariables
+                >(GET_COLLECTION, {
+                    id: duplicatedCollectionId,
+                });
+
+                expect(collection?.parent?.id).toBe(testCollection.parent?.id);
+            });
+
+            it('filters are duplicated', async () => {
+                const { collection } = await adminClient.query<
+                    Codegen.GetCollectionQuery,
+                    Codegen.GetCollectionQueryVariables
+                >(GET_COLLECTION, {
+                    id: duplicatedCollectionId,
+                });
+
+                expect(collection?.filters).toEqual(testCollection.filters);
+            });
+        });
     });
 });
 
@@ -536,13 +677,3 @@ const DUPLICATE_ENTITY = gql`
         }
     }
 `;
-
-export const GET_DUPLICATED_COLLECTION = gql`
-    query GetDuplicatedCollection($id: ID) {
-        collection(id: $id) {
-            id
-            name
-            slug
-        }
-    }
-`;

تفاوت فایلی نمایش داده نمی شود زیرا این فایل بسیار بزرگ است
+ 9 - 16
packages/core/e2e/graphql/generated-e2e-admin-types.ts


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

@@ -1038,3 +1038,19 @@ export const ASSIGN_COLLECTIONS_TO_CHANNEL = gql`
     }
     ${COLLECTION_FRAGMENT}
 `;
+
+export const GET_COLLECTION = gql`
+    query GetCollection($id: ID, $slug: String, $variantListOptions: ProductVariantListOptions) {
+        collection(id: $id, slug: $slug) {
+            ...Collection
+            productVariants(options: $variantListOptions) {
+                items {
+                    id
+                    name
+                    price
+                }
+            }
+        }
+    }
+    ${COLLECTION_FRAGMENT}
+`;

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

@@ -0,0 +1,69 @@
+import {
+    CreateCollectionInput,
+    CreateCollectionTranslationInput,
+    LanguageCode,
+    Permission,
+} from '@vendure/common/lib/generated-types';
+
+import { Injector } from '../../../common/index';
+import { TransactionalConnection } from '../../../connection/index';
+import { Collection } from '../../../entity/index';
+import { CollectionService } from '../../../service/index';
+import { EntityDuplicator } from '../entity-duplicator';
+
+let connection: TransactionalConnection;
+let collectionService: CollectionService;
+
+/**
+ * @description
+ * Duplicates a Collection
+ */
+export const collectionDuplicator = new EntityDuplicator({
+    code: 'collection-duplicator',
+    description: [
+        {
+            languageCode: LanguageCode.en,
+            value: 'Default duplicator for Collections',
+        },
+    ],
+    requiresPermission: [Permission.CreateCollection, Permission.CreateCatalog],
+    forEntities: ['Collection'],
+    args: {},
+    init(injector: Injector) {
+        connection = injector.get(TransactionalConnection);
+        collectionService = injector.get(CollectionService);
+    },
+    async duplicate({ ctx, id, args }) {
+        const collection = await connection.getEntityOrThrow(ctx, Collection, id, {
+            relations: {
+                featuredAsset: true,
+                assets: true,
+                channels: true,
+            },
+        });
+        const translations: CreateCollectionTranslationInput[] = collection.translations.map(translation => {
+            return {
+                name: translation.name + ' (copy)',
+                slug: translation.slug + '-copy',
+                description: translation.description,
+                languageCode: translation.languageCode,
+                customFields: translation.customFields,
+            };
+        });
+        const collectionInput: CreateCollectionInput = {
+            featuredAssetId: collection.featuredAsset.id,
+            isPrivate: true,
+            assetIds: collection.assets.map(value => value.assetId),
+            parentId: collection.parentId,
+            translations,
+            customFields: collection.customFields,
+            filters: collection.filters.map(filter => ({
+                code: filter.code,
+                arguments: filter.args,
+            })),
+        };
+
+        const duplicatedCollection = await collectionService.create(ctx, collectionInput);
+        return duplicatedCollection;
+    },
+});

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

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

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

@@ -69,7 +69,7 @@ export const productDuplicator = new EntityDuplicator({
         });
         const translations: ProductTranslationInput[] = product.translations.map(translation => {
             return {
-                name: translation.name + ' Copy',
+                name: translation.name + ' (copy)',
                 slug: translation.slug + '-copy',
                 description: translation.description,
                 languageCode: translation.languageCode,

برخی فایل ها در این مقایسه diff نمایش داده نمی شوند زیرا تعداد فایل ها بسیار زیاد است