From 3ae0421b5779442dee6f03ca913ceabe9b87b355 Mon Sep 17 00:00:00 2001 From: Nicolas Molina Monroy Date: Fri, 14 Feb 2025 18:55:31 -0400 Subject: [PATCH] chore(editor-content): Reorder items in relationship field (#31389) ### Parent Issue #31383 ### Proposed Changes This pull request includes several changes to the `dot-edit-content-relationship-field` component and its associated store and tests. The primary focus is on simplifying the data handling methods and updating the UI for better consistency. Changes to UI elements: * Updated the drag handle icon in the template from a font-awesome icon to a material icon for better visual consistency (`dot-edit-content-relationship-field.component.html`). Changes to data handling methods: * Replaced the usage of `addData` and `reorderData` methods with `setData` method to streamline data updates (`dot-edit-content-relationship-field.component.ts`). [[1]](diffhunk://#diff-5cb2225620beb3baaf219cbfa2241aa934812de8ece62e1d4f7e7747f5f15416L262-R262) [[2]](diffhunk://#diff-5cb2225620beb3baaf219cbfa2241aa934812de8ece62e1d4f7e7747f5f15416L275-R275) * Removed the `addData` and `reorderData` methods from the store, consolidating data updates into the `setData` method (`relationship-field.store.ts`). [[1]](diffhunk://#diff-a2c980da63c75c9dc2cd899475beab89cb79492b1dc0819574fc380e856e7ed1L78-R77) [[2]](diffhunk://#diff-a2c980da63c75c9dc2cd899475beab89cb79492b1dc0819574fc380e856e7ed1L101-L122) Changes to tests: * Removed tests related to the `addData` and `reorderData` methods since these methods are no longer used (`relationship-field.store.spec.ts`). [[1]](diffhunk://#diff-d2a9a6233c2b1ba38c683725d2e68092978e7023e9269dbabab2fcdfa47224e2L97-L103) [[2]](diffhunk://#diff-d2a9a6233c2b1ba38c683725d2e68092978e7023e9269dbabab2fcdfa47224e2L133-L193) ### Checklist - [ ] Tests - [ ] Translations - [ ] Security Implications Contemplated (add notes if applicable) ### Additional Info ** any additional useful context or info ** ### Screenshots Original | Updated :-------------------------:|:-------------------------: ** original screenshot ** | ** updated screenshot ** --- ...-content-relationship-field.component.html | 2 +- ...it-content-relationship-field.component.ts | 4 +- .../store/relationship-field.store.spec.ts | 68 ------------------- .../store/relationship-field.store.ts | 27 +------- .../frontend/data/defaultContentType.ts | 2 +- .../frontend/models/newContentType.model.ts | 32 ++++++--- .../frontend/pages/contentTypeForm.page.ts | 33 +++++++++ .../frontend/pages/textField.page.ts | 10 --- 8 files changed, 60 insertions(+), 118 deletions(-) delete mode 100644 e2e/dotcms-e2e-node/frontend/pages/textField.page.ts diff --git a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.html b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.html index e1bec1520a38..c7ac5a077734 100644 --- a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.html +++ b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.html @@ -49,7 +49,7 @@ - +

{{ item.title }}

diff --git a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.ts b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.ts index 5fd267db1041..3749e0e00ecf 100644 --- a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.ts +++ b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/dot-edit-content-relationship-field.component.ts @@ -259,7 +259,7 @@ export class DotEditContentRelationshipFieldComponent implements ControlValueAcc takeUntilDestroyed(this.#destroyRef) ) .subscribe((items: DotCMSContentlet[]) => { - this.store.addData(items); + this.store.setData(items); }); } @@ -272,6 +272,6 @@ export class DotEditContentRelationshipFieldComponent implements ControlValueAcc return; } - this.store.reorderData(event.dragIndex, event.dropIndex); + this.store.setData(this.store.data()); } } diff --git a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/store/relationship-field.store.spec.ts b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/store/relationship-field.store.spec.ts index 1bb7bcd0ad3e..880a7a2720b5 100644 --- a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/store/relationship-field.store.spec.ts +++ b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/store/relationship-field.store.spec.ts @@ -94,13 +94,6 @@ describe('RelationshipFieldStore', () => { }); }); - describe('addData', () => { - it('should add new data', () => { - store.addData(mockData); - expect(store.data()).toEqual(mockData); - }); - }); - describe('deleteItem', () => { it('should delete item by inode', () => { store.setData(mockData); @@ -130,67 +123,6 @@ describe('RelationshipFieldStore', () => { }); }); }); - - describe('reorderData', () => { - beforeEach(() => { - store.setData(mockData); - }); - - it('should reorder data when moving item up', () => { - const currentIndex = 1; - const newIndex = 0; - store.reorderData(currentIndex, newIndex); - - const reorderedData = store.data(); - expect(reorderedData[0].inode).toBe('inode2'); - expect(reorderedData[1].inode).toBe('inode1'); - expect(reorderedData[2].inode).toBe('inode3'); - }); - - it('should reorder data when moving item down', () => { - const currentIndex = 0; - const newIndex = 2; - store.reorderData(currentIndex, newIndex); - - const reorderedData = store.data(); - expect(reorderedData[0].inode).toBe('inode2'); - expect(reorderedData[1].inode).toBe('inode3'); - expect(reorderedData[2].inode).toBe('inode1'); - }); - - it('should not change data when current and new index are the same', () => { - const currentIndex = 1; - const newIndex = 1; - store.reorderData(currentIndex, newIndex); - - const reorderedData = store.data(); - expect(reorderedData[0].inode).toBe('inode1'); - expect(reorderedData[1].inode).toBe('inode2'); - expect(reorderedData[2].inode).toBe('inode3'); - }); - - it('should handle edge case when moving first item to last position', () => { - const currentIndex = 0; - const newIndex = mockData.length - 1; - store.reorderData(currentIndex, newIndex); - - const reorderedData = store.data(); - expect(reorderedData[0].inode).toBe('inode2'); - expect(reorderedData[1].inode).toBe('inode3'); - expect(reorderedData[2].inode).toBe('inode1'); - }); - - it('should handle edge case when moving last item to first position', () => { - const currentIndex = mockData.length - 1; - const newIndex = 0; - store.reorderData(currentIndex, newIndex); - - const reorderedData = store.data(); - expect(reorderedData[0].inode).toBe('inode3'); - expect(reorderedData[1].inode).toBe('inode1'); - expect(reorderedData[2].inode).toBe('inode2'); - }); - }); }); describe('Computed Properties', () => { diff --git a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/store/relationship-field.store.ts b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/store/relationship-field.store.ts index f553491f588e..80a186b05f2f 100644 --- a/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/store/relationship-field.store.ts +++ b/core-web/libs/edit-content/src/lib/fields/dot-edit-content-relationship-field/store/relationship-field.store.ts @@ -62,7 +62,6 @@ export const RelationshipFieldStore = signalStore( */ formattedRelationship: computed(() => { const data = state.data(); - const identifiers = data.map((item) => item.identifier).join(','); return `${identifiers}`; @@ -75,9 +74,7 @@ export const RelationshipFieldStore = signalStore( * @param {RelationshipFieldItem[]} data - The data to be set. */ setData(data: DotCMSContentlet[]) { - patchState(store, { - data - }); + patchState(store, { data: [...data] }); }, /** * Sets the cardinality of the relationship field. @@ -98,28 +95,6 @@ export const RelationshipFieldStore = signalStore( data }); }, - /** - * Adds new data to the existing data in the state. - * @param {RelationshipFieldItem[]} data - The new data to be added. - */ - addData(data: DotCMSContentlet[]) { - patchState(store, { data }); - }, - /** - * Reorders the data in the store. - * @param {number} dragIndex - The index of the item to be dragged. - * @param {number} dropIndex - The index of the item to be dropped. - */ - reorderData(dragIndex: number, dropIndex: number) { - const currentData = store.data(); - const newData = [...currentData]; - const draggedItem = newData[dragIndex]; - - newData.splice(dragIndex, 1); - newData.splice(dropIndex, 0, draggedItem); - - patchState(store, { data: newData }); - }, /** * Deletes an item from the store at the specified index. * @param index - The index of the item to delete. diff --git a/e2e/dotcms-e2e-node/frontend/data/defaultContentType.ts b/e2e/dotcms-e2e-node/frontend/data/defaultContentType.ts index 11ebf36d4b5f..6d6911120eb4 100644 --- a/e2e/dotcms-e2e-node/frontend/data/defaultContentType.ts +++ b/e2e/dotcms-e2e-node/frontend/data/defaultContentType.ts @@ -9,7 +9,7 @@ export function createDefaultContentType() { { title: "Site or Folder Field", fieldType: "siteOrFolder", - }, + } ]; return defaultTypes; } diff --git a/e2e/dotcms-e2e-node/frontend/models/newContentType.model.ts b/e2e/dotcms-e2e-node/frontend/models/newContentType.model.ts index 15c221965008..75015d71b3d5 100644 --- a/e2e/dotcms-e2e-node/frontend/models/newContentType.model.ts +++ b/e2e/dotcms-e2e-node/frontend/models/newContentType.model.ts @@ -5,6 +5,7 @@ export enum TYPES { Text = "text", SiteOrFolder = "siteOrFolder", + Relationship = "relationship", } /** @@ -13,30 +14,41 @@ export enum TYPES { */ export type Fields = `${TYPES}`; +export interface GenericField { + title: string; + fieldType: Fields; + required?: boolean; + hintText?: string; +} + /** * Interface representing a text field configuration. * @interface */ -export interface TextField { - title: string; +export interface TextField extends GenericField { fieldType: `${TYPES.Text}`; - required?: boolean; - hintText?: string; } /** * Interface representing a site or host field configuration. * @interface */ -export interface SiteorHostField { - title: string; +export interface SiteorHostField extends GenericField { fieldType: `${TYPES.SiteOrFolder}`; - required?: boolean; - hintText?: string; +} + +/** + * Interface representing a relationship field configuration. + * @interface + */ +export interface RelationshipField extends GenericField { + fieldType: `${TYPES.Relationship}`; + entityToRelate: string; + cardinality: "1-1" | "1-many" | "many-1" | "many-many"; } /** * Union type of all possible field type configurations. - * @typedef {TextField | SiteorHostField} FieldsTypes + * @typedef {TextField | SiteorHostField | RelationshipField} FieldsTypes */ -export type FieldsTypes = TextField | SiteorHostField; +export type FieldsTypes = TextField | SiteorHostField | RelationshipField; diff --git a/e2e/dotcms-e2e-node/frontend/pages/contentTypeForm.page.ts b/e2e/dotcms-e2e-node/frontend/pages/contentTypeForm.page.ts index 42122e51e663..3b97253c05fe 100644 --- a/e2e/dotcms-e2e-node/frontend/pages/contentTypeForm.page.ts +++ b/e2e/dotcms-e2e-node/frontend/pages/contentTypeForm.page.ts @@ -3,6 +3,7 @@ import { FieldsTypes, TextField, SiteorHostField, + RelationshipField, } from "@models/newContentType.model"; export class ContentTypeFormPage { @@ -16,6 +17,9 @@ export class ContentTypeFormPage { if (field.fieldType === "siteOrFolder") { return prevPromise.then(() => this.addSiteOrFolderField(field)); } + if (field.fieldType === "relationship") { + return prevPromise.then(() => this.addRelationshipField(field)); + } }, Promise.resolve()); await promise; @@ -54,4 +58,33 @@ export class ContentTypeFormPage { ); await dialogAcceptBtnLocator.click(); } + + async addRelationshipField(field: RelationshipField) { + const dropZoneLocator = this.page.getByTestId("fields-bag-0"); + const relationshipFieldItemLocator = this.page.getByTestId( + "com.dotcms.contenttype.model.field.ImmutableRelationshipField", + ); + await relationshipFieldItemLocator.waitFor(); + await relationshipFieldItemLocator.dragTo(dropZoneLocator); + + const dialogInputLocator = this.page.locator("input#name"); + await dialogInputLocator.fill(field.title); + + const selectContentTypeLocator = this.page.locator("dot-searchable-dropdown"); + await selectContentTypeLocator.click(); + + const entityToRelateLocator = this.page.getByLabel(field.entityToRelate); + await entityToRelateLocator.click(); + + const cardinalitySelectorLocator = this.page.locator("dot-cardinality-selector"); + await cardinalitySelectorLocator.click(); + + const cardinalityOptionLocator = this.page.getByLabel(field.cardinality); + await cardinalityOptionLocator.click(); + + const dialogAcceptBtnLocator = this.page.getByTestId( + "dotDialogAcceptAction", + ); + await dialogAcceptBtnLocator.click(); + } } diff --git a/e2e/dotcms-e2e-node/frontend/pages/textField.page.ts b/e2e/dotcms-e2e-node/frontend/pages/textField.page.ts deleted file mode 100644 index ad7d8e2487b1..000000000000 --- a/e2e/dotcms-e2e-node/frontend/pages/textField.page.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Page } from "@playwright/test"; - -export class TextFieldPage { - constructor(private page: Page) {} - - async fill(variableName: string, value: string) { - const input = this.page.locator(`input#${variableName}`); - await input.fill(value); - } -}