diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx index c24b5736b06..1cdfe5ba660 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx @@ -89,12 +89,15 @@ const AddNodeMenu = ({ schemaPointer }: AddNodeMenuProps) => { }; const useAddNodeMenuItems = (schemaPointer: string): AddNodeMenuItemProps[] => { - const { setSelectedUniquePointer } = useSchemaEditorAppContext(); + const { setSelectedUniquePointer, schemaModel } = useSchemaEditorAppContext(); const addNode = useAddProperty(); const addAndSelectNode = (...params: Parameters) => { const newPointer = addNode(...params); - if (newPointer) setSelectedUniquePointer(newPointer); + if (newPointer) { + const newUniquePointer = schemaModel.getUniquePointer(newPointer); + setSelectedUniquePointer(newUniquePointer); + } }; return [ diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.ts b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.ts index 80e7dc719ba..14d8d6817a5 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.ts +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.ts @@ -6,7 +6,7 @@ import { useSavableSchemaModel } from '../../../hooks/useSavableSchemaModel'; import { useSchemaEditorAppContext } from '@altinn/schema-editor/hooks/useSchemaEditorAppContext'; export const useAddReference = (): HandleAdd => { - const { setSelectedUniquePointer } = useSchemaEditorAppContext(); + const { setSelectedUniquePointer, schemaModel } = useSchemaEditorAppContext(); const savableModel = useSavableSchemaModel(); return useCallback( (reference: string, position: ItemPosition) => { @@ -15,8 +15,9 @@ export const useAddReference = (): HandleAdd => { const schemaPointer = savableModel.getFinalNode(target.parentPointer).schemaPointer; const refName = savableModel.generateUniqueChildName(schemaPointer, 'ref'); const ref = savableModel.addReference(refName, reference, target); - setSelectedUniquePointer(ref.schemaPointer); + const uniquePointer = schemaModel.getUniquePointer(ref.schemaPointer); + setSelectedUniquePointer(uniquePointer); }, - [savableModel, setSelectedUniquePointer], + [savableModel, setSelectedUniquePointer, schemaModel], ); }; diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.test.ts b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.test.ts index d743a8e2b2b..4a0501a5384 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.test.ts +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.test.ts @@ -7,13 +7,17 @@ import { ROOT_POINTER, SchemaModel, validateTestUiSchema, + UNIQUE_POINTER_PREFIX, + Keyword, } from '@altinn/schema-model'; import { + childOfReferredNodeMock, combinationNodeMock, fieldNode1Mock, nodeWithSameNameAsObjectChildMock, objectChildMock, objectNodeMock, + referenceNodeMock, rootNodeMock, toggableNodeMock, uiSchemaNodesMock, @@ -21,6 +25,8 @@ import { import type { SavableSchemaModel } from '../../../classes/SavableSchemaModel'; import { ArrayUtils } from '@studio/pure-functions'; +const uniquePointerOfRoot = UNIQUE_POINTER_PREFIX + ROOT_POINTER; + describe('useMoveProperty', () => { const setup = (schemaEditorAppContextProps?: Partial) => { const save = jest.fn(); @@ -32,7 +38,7 @@ describe('useMoveProperty', () => { }; const { result } = renderHookWithProviders({ appContextProps })(useMoveProperty); const move: HandleMove = result.current; - return { move, save }; + return { move, save, schemaModel }; }; it('Moves a property to the given position', () => { @@ -56,7 +62,7 @@ describe('useMoveProperty', () => { const { move, save } = setup(); const pointerOfNodeToMove = fieldNode1Mock.schemaPointer; const indexInNewParent = 1; - const target: ItemPosition = { parentId: ROOT_POINTER, index: indexInNewParent }; + const target: ItemPosition = { parentId: uniquePointerOfRoot, index: indexInNewParent }; move(pointerOfNodeToMove, target); expect(save).toHaveBeenCalledTimes(1); const savedModel: SavableSchemaModel = save.mock.lastCall[0]; @@ -71,7 +77,7 @@ describe('useMoveProperty', () => { it('Moves a property to the given position when it is on the root and the target index is 0', () => { const { move, save } = setup(); const pointerOfNodeToMove = fieldNode1Mock.schemaPointer; - const target: ItemPosition = { parentId: ROOT_POINTER, index: 0 }; + const target: ItemPosition = { parentId: uniquePointerOfRoot, index: 0 }; move(pointerOfNodeToMove, target); expect(save).toHaveBeenCalledTimes(1); const savedModel: SavableSchemaModel = save.mock.lastCall[0]; @@ -87,7 +93,7 @@ describe('useMoveProperty', () => { const { move, save } = setup(); const pointerOfNodeToMove = fieldNode1Mock.schemaPointer; const index = rootNodeMock.children.length; - const target: ItemPosition = { parentId: ROOT_POINTER, index }; + const target: ItemPosition = { parentId: uniquePointerOfRoot, index }; move(pointerOfNodeToMove, target); expect(save).toHaveBeenCalledTimes(1); const savedModel: SavableSchemaModel = save.mock.lastCall[0]; @@ -103,7 +109,7 @@ describe('useMoveProperty', () => { const { move, save } = setup(); const pointerOfNodeToMove = objectNodeMock.schemaPointer; const index = -1; - const target: ItemPosition = { parentId: ROOT_POINTER, index }; + const target: ItemPosition = { parentId: uniquePointerOfRoot, index }; move(pointerOfNodeToMove, target); expect(save).toHaveBeenCalledTimes(1); const savedModel: SavableSchemaModel = save.mock.lastCall[0]; @@ -154,37 +160,73 @@ describe('useMoveProperty', () => { expect(save).toHaveBeenCalledTimes(0); }); - it('Updates the selected node pointer if moving a node that is selected into an object', () => { - const setSelectedNodePointerMock = jest.fn(); + it('Updates the selected unique node pointer if moving a node that is selected into an object', () => { + const setSelectedUniquePointerMock = jest.fn(); const { move, save } = setup({ - selectedUniquePointer: fieldNode1Mock.schemaPointer, - setSelectedUniquePointer: setSelectedNodePointerMock, + selectedUniquePointer: `${UNIQUE_POINTER_PREFIX}${fieldNode1Mock.schemaPointer}`, + setSelectedUniquePointer: setSelectedUniquePointerMock, }); - const pointerOfNodeToMove = fieldNode1Mock.schemaPointer; + const pointerOfNodeToMove = `${UNIQUE_POINTER_PREFIX}${fieldNode1Mock.schemaPointer}`; const index = rootNodeMock.children.length; const target: ItemPosition = { parentId: ROOT_POINTER, index }; move(pointerOfNodeToMove, target); - expect(setSelectedNodePointerMock).toHaveBeenCalledTimes(1); + expect(setSelectedUniquePointerMock).toHaveBeenCalledTimes(1); const savedModel: SavableSchemaModel = save.mock.lastCall[0]; const rootChildren = savedModel.getRootChildren(); const addedRootChild = rootChildren[index]; - expect(setSelectedNodePointerMock).toHaveBeenCalledWith(addedRootChild.schemaPointer); + expect(setSelectedUniquePointerMock).toHaveBeenCalledWith( + `${UNIQUE_POINTER_PREFIX}${addedRootChild.schemaPointer}`, + ); }); - it('Updates the selected node pointer if moving a node that is selected into a combination node', () => { - const setSelectedNodePointerMock = jest.fn(); + it('Updates the selected unique node pointer if moving a node that is selected into a combination node', () => { + const setSelectedUniquePointerMock = jest.fn(); + const pointerOfNodeToMove = UNIQUE_POINTER_PREFIX + toggableNodeMock.schemaPointer; const { move } = setup({ - selectedUniquePointer: toggableNodeMock.schemaPointer, - setSelectedUniquePointer: setSelectedNodePointerMock, + selectedUniquePointer: pointerOfNodeToMove, + setSelectedUniquePointer: setSelectedUniquePointerMock, }); - const pointerOfNodeToMove = toggableNodeMock.schemaPointer; - const pointerOfNewParent = combinationNodeMock.schemaPointer; + const pointerOfNewParent = `${UNIQUE_POINTER_PREFIX}${combinationNodeMock.schemaPointer}`; const indexInNewParent = 0; const target: ItemPosition = { parentId: pointerOfNewParent, index: indexInNewParent }; move(pointerOfNodeToMove, target); - expect(setSelectedNodePointerMock).toHaveBeenCalledTimes(1); - expect(setSelectedNodePointerMock).toHaveBeenCalledWith( - `${combinationNodeMock.schemaPointer}/anyOf/${indexInNewParent}`, + expect(setSelectedUniquePointerMock).toHaveBeenCalledTimes(1); + expect(setSelectedUniquePointerMock).toHaveBeenCalledWith( + `${pointerOfNewParent}/anyOf/${indexInNewParent}`, ); }); + + it('Updates the selected unique node pointer when moving a node that is selected out of a referenced object', () => { + const setSelectedUniquePointerMock = jest.fn(); + const schemaPointerOfNodeToMove = childOfReferredNodeMock.schemaPointer; + const nameOfNodeToMove = extractNameFromPointer(schemaPointerOfNodeToMove); + const uniquePointerOfParent = UNIQUE_POINTER_PREFIX + referenceNodeMock.schemaPointer; + const uniquePointerOfNodeToMove = `${uniquePointerOfParent}/${Keyword.Properties}/${nameOfNodeToMove}`; + const expectedFinalUniquePointer = `${uniquePointerOfRoot}/${Keyword.Properties}/${nameOfNodeToMove}`; + const { move } = setup({ + selectedUniquePointer: uniquePointerOfNodeToMove, + setSelectedUniquePointer: setSelectedUniquePointerMock, + }); + const target: ItemPosition = { parentId: uniquePointerOfRoot, index: 0 }; + move(uniquePointerOfNodeToMove, target); + expect(setSelectedUniquePointerMock).toHaveBeenCalledTimes(1); + expect(setSelectedUniquePointerMock).toHaveBeenCalledWith(expectedFinalUniquePointer); + }); + + it('Updates the selected unique node pointer when moving a node that is selected into a referenced object', () => { + const setSelectedUniquePointerMock = jest.fn(); + const schemaPointerOfNodeToMove = objectNodeMock.schemaPointer; + const nameOfNodeToMove = extractNameFromPointer(schemaPointerOfNodeToMove); + const uniquePointerOfNodeToMove = `${uniquePointerOfRoot}/${Keyword.Properties}/${nameOfNodeToMove}`; + const uniquePointerOfTargetParent = UNIQUE_POINTER_PREFIX + referenceNodeMock.schemaPointer; + const expectedFinalUniquePointer = `${uniquePointerOfTargetParent}/${Keyword.Properties}/${nameOfNodeToMove}`; + const { move } = setup({ + selectedUniquePointer: uniquePointerOfNodeToMove, + setSelectedUniquePointer: setSelectedUniquePointerMock, + }); + const target: ItemPosition = { parentId: uniquePointerOfTargetParent, index: 0 }; + move(uniquePointerOfNodeToMove, target); + expect(setSelectedUniquePointerMock).toHaveBeenCalledTimes(1); + expect(setSelectedUniquePointerMock).toHaveBeenCalledWith(expectedFinalUniquePointer); + }); }); diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.ts b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.ts index 83c62a086e9..3afbd23b4ae 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.ts +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.ts @@ -11,9 +11,6 @@ export const useMoveProperty = (): HandleMove => { const savableModel = useSavableSchemaModel(); const { selectedUniquePointer, setSelectedUniquePointer } = useSchemaEditorAppContext(); const { t } = useTranslation(); - const selectedSchemaPointer = selectedUniquePointer - ? savableModel.getSchemaPointerByUniquePointer(selectedUniquePointer) - : null; const areThereCollidingNames = useCallback( (schemaPointer: string, schemaParentPointer: string): boolean => { const currentParent = savableModel.getParentNode(schemaPointer); @@ -40,11 +37,15 @@ export const useMoveProperty = (): HandleMove => { alert(t('schema_editor.move_node_same_name_error', { name, parent })); } else { const movedNode = savableModel.moveNode(schemaPointer, target); - if (selectedSchemaPointer === schemaPointer) { - setSelectedUniquePointer(movedNode.schemaPointer); + if (selectedUniquePointer === uniquePointer) { + const movedUniquePointer = savableModel.getUniquePointer( + movedNode.schemaPointer, + position.parentId, + ); + setSelectedUniquePointer(movedUniquePointer); } } }, - [savableModel, t, areThereCollidingNames, selectedSchemaPointer, setSelectedUniquePointer], + [savableModel, t, areThereCollidingNames, selectedUniquePointer, setSelectedUniquePointer], ); }; diff --git a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx index eb05966ba98..ea829d602dc 100644 --- a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx @@ -31,8 +31,11 @@ export const AddPropertyMenu = ({ schemaPointer, uniquePointer }: AddPropertyMen const addPropertyAndClose = (kind: ObjectKind, fieldType?: FieldType) => { const childPointer = addProperty(kind, fieldType, schemaPointer); - setSelectedUniquePointer(savableModel.getUniquePointer(childPointer, uniquePointer)); - closeDropdown(); + if (childPointer) { + const uniqueChildPointer = savableModel.getUniquePointer(childPointer, uniquePointer); + setSelectedUniquePointer(uniqueChildPointer); + closeDropdown(); + } }; const closeDropdown = () => setIsAddDropdownOpen(false); diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx index aa9d34f0414..cd653d53d5d 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx @@ -25,7 +25,8 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { const setSelectedType = (schemaPointer: string) => { setSelectedTypePointer(schemaPointer); - setSelectedUniquePointer(schemaPointer); + const uniquePointer = schemaModel.getUniquePointer(schemaPointer); + setSelectedUniquePointer(uniquePointer); }; const handleAddDefinition = (e: MouseEvent) => { diff --git a/frontend/packages/schema-editor/test/mocks/uiSchemaMock.ts b/frontend/packages/schema-editor/test/mocks/uiSchemaMock.ts index 0fa819fc421..ace53c3a21e 100644 --- a/frontend/packages/schema-editor/test/mocks/uiSchemaMock.ts +++ b/frontend/packages/schema-editor/test/mocks/uiSchemaMock.ts @@ -19,6 +19,7 @@ const stringDefinitionNodePointer = '#/$defs/def2'; const nodeWithSameNameAsObjectChildPointer = '#/properties/someNode'; const referenceNodePointer = '#/properties/referenceNode'; const referredNodePointer = '#/$defs/referredNode'; +const childOfReferredNodePointer = '#/$defs/referredNode/properties/childOfReferredNode'; export const nodeMockBase: FieldNode = { objectKind: ObjectKind.Field, @@ -43,7 +44,14 @@ export const referenceNodeMock: ReferenceNode = { export const referredNodeMock: FieldNode = { ...nodeMockBase, + fieldType: FieldType.Object, schemaPointer: referredNodePointer, + children: [childOfReferredNodePointer], +}; + +export const childOfReferredNodeMock: FieldNode = { + ...nodeMockBase, + schemaPointer: childOfReferredNodePointer, }; export const rootNodeMock: FieldNode = { @@ -137,6 +145,7 @@ export const uiSchemaNodesMock: UiSchemaNodes = [ fieldNode2Mock, referenceNodeMock, referredNodeMock, + childOfReferredNodeMock, nodeWithCustomPropsMock, toggableNodeMock, objectNodeMock, diff --git a/frontend/packages/schema-model/src/index.ts b/frontend/packages/schema-model/src/index.ts index bb51af0a0f4..67b3c24154e 100644 --- a/frontend/packages/schema-model/src/index.ts +++ b/frontend/packages/schema-model/src/index.ts @@ -1,6 +1,6 @@ export { buildJsonSchema } from './lib/build-json-schema'; export { buildUiSchema } from './lib/build-ui-schema'; -export { ROOT_POINTER } from './lib/constants'; +export { ROOT_POINTER, UNIQUE_POINTER_PREFIX } from './lib/constants'; export type { UiSchemaNode, UiSchemaNodes } from './types'; export type { FieldNode } from './types/FieldNode'; export type { CombinationNode } from './types/CombinationNode'; diff --git a/frontend/packages/schema-model/src/lib/SchemaModel.test.ts b/frontend/packages/schema-model/src/lib/SchemaModel.test.ts index 3259b8387a4..566e8271a1f 100644 --- a/frontend/packages/schema-model/src/lib/SchemaModel.test.ts +++ b/frontend/packages/schema-model/src/lib/SchemaModel.test.ts @@ -40,7 +40,7 @@ import type { FieldNode } from '../types/FieldNode'; import type { ReferenceNode } from '../types/ReferenceNode'; import { extractNameFromPointer } from './pointerUtils'; import { isArray, isDefinition } from './utils'; -import { ROOT_POINTER } from './constants'; +import { ROOT_POINTER, UNIQUE_POINTER_PREFIX } from './constants'; import type { CombinationNode } from '../types/CombinationNode'; import { ArrayUtils } from '@studio/pure-functions'; @@ -116,27 +116,25 @@ describe('SchemaModel', () => { }); describe('getNodeByUniquePointer', () => { - it('Returns the node when pointer it is the root pointer', () => { - expect(schemaModel.getNodeByUniquePointer(rootNodeMock.schemaPointer)).toEqual(rootNodeMock); + it('Returns the node when unique pointer is the root', () => { + const uniqueRootPointer = `${UNIQUE_POINTER_PREFIX}${rootNodeMock.schemaPointer}`; + expect(schemaModel.getNodeByUniquePointer(uniqueRootPointer)).toEqual(rootNodeMock); }); - it('Returns the node when pointer is a property node', () => { - expect(schemaModel.getNodeByUniquePointer(parentNodeMock.schemaPointer)).toEqual( - parentNodeMock, - ); - expect(schemaModel.getNodeByUniquePointer(defNodeMock.schemaPointer)).toEqual(defNodeMock); - expect(schemaModel.getNodeByUniquePointer(allOfNodeMock.schemaPointer)).toEqual( - allOfNodeMock, - ); - expect(schemaModel.getNodeByUniquePointer(stringNodeMock.schemaPointer)).toEqual( - stringNodeMock, - ); + it('Returns the node when unique pointer is a property node', () => { + const uniqueParentPointer = `${UNIQUE_POINTER_PREFIX}${parentNodeMock.schemaPointer}`; + expect(schemaModel.getNodeByUniquePointer(uniqueParentPointer)).toEqual(parentNodeMock); + const uniqueDefPointer = `${UNIQUE_POINTER_PREFIX}${defNodeMock.schemaPointer}`; + expect(schemaModel.getNodeByUniquePointer(uniqueDefPointer)).toEqual(defNodeMock); + const uniqueAllOfPointer = `${UNIQUE_POINTER_PREFIX}${allOfNodeMock.schemaPointer}`; + expect(schemaModel.getNodeByUniquePointer(uniqueAllOfPointer)).toEqual(allOfNodeMock); + const uniqueStringPointer = `${UNIQUE_POINTER_PREFIX}${stringNodeMock.schemaPointer}`; + expect(schemaModel.getNodeByUniquePointer(uniqueStringPointer)).toEqual(stringNodeMock); }); it('Returns the node reflecting the path to a given unique pointer in a reference', () => { - const uniqueChildPointer = '#/properties/referenceToParent/properties/child'; - const uniqueGrandchildPointer = - '#/properties/referenceToParent/properties/child/properties/grandchild'; + const uniqueChildPointer = `${UNIQUE_POINTER_PREFIX}${ROOT_POINTER}/properties/referenceToParent/properties/child`; + const uniqueGrandchildPointer = `${UNIQUE_POINTER_PREFIX}${ROOT_POINTER}/properties/referenceToParent/properties/child/properties/grandchild`; expect(schemaModel.getNodeByUniquePointer(uniqueChildPointer)).toEqual( defNodeWithChildrenChildMock, @@ -148,10 +146,10 @@ describe('SchemaModel', () => { }); describe('getSchemaPointerByUniquePointer', () => { - it('Returns the schema pointer for a given unique pointer to an object', () => { - const uniqueGrandChildPointer = - '#/properties/referenceToParent/properties/child/properties/grandchild'; - const uniqueChildPointer = '#/properties/referenceToParent/properties/child'; + const uniqueGrandChildPointer = `${UNIQUE_POINTER_PREFIX}${ROOT_POINTER}/properties/referenceToParent/properties/child/properties/grandchild`; + const uniqueChildPointer = `${UNIQUE_POINTER_PREFIX}${ROOT_POINTER}/properties/referenceToParent/properties/child`; + + it('Returns the schema pointer for a given unique pointer', () => { expect(schemaModel.getSchemaPointerByUniquePointer(uniqueChildPointer)).toEqual( defNodeWithChildrenChildMock.schemaPointer, ); @@ -169,42 +167,44 @@ describe('SchemaModel', () => { }); describe('getUniquePointer', () => { - it('Returns the pointer as is when called on the root node', () => { + it('Returns the unique pointer when called on the root node', () => { + const expectedUniqueRootPointer = `${UNIQUE_POINTER_PREFIX}${ROOT_POINTER}`; expect(schemaModel.getUniquePointer(rootNodeMock.schemaPointer)).toEqual( - rootNodeMock.schemaPointer, + expectedUniqueRootPointer, ); }); - it('Returns the pointer as is when called on a property node', () => { + it('Returns the unique pointer when called on a property node', () => { + const expectedUniquePointer = `${UNIQUE_POINTER_PREFIX}${referenceToObjectNodeMock.schemaPointer}`; + expect(schemaModel.getUniquePointer(referenceToObjectNodeMock.schemaPointer)).toEqual( - referenceToObjectNodeMock.schemaPointer, + expectedUniquePointer, ); }); - it('Returns a pointer reflecting the path to a given node in a reference to an object', () => { - const expectedChildPointer = '#/properties/referenceToParent/properties/child'; - const expectedGrandchildPointer = - '#/properties/referenceToParent/properties/child/properties/grandchild'; + it('Returns a unique pointer reflecting the path to a given node in a reference to an object', () => { + const expectedUniqueChildPointer = `${UNIQUE_POINTER_PREFIX}${ROOT_POINTER}/properties/referenceToParent/properties/child`; + const expectedUniqueGrandchildPointer = `${UNIQUE_POINTER_PREFIX}${ROOT_POINTER}/properties/referenceToParent/properties/child/properties/grandchild`; expect( schemaModel.getUniquePointer( defNodeWithChildrenChildMock.schemaPointer, referenceToObjectNodeMock.schemaPointer, ), - ).toEqual(expectedChildPointer); + ).toEqual(expectedUniqueChildPointer); expect( schemaModel.getUniquePointer( defNodeWithChildrenGrandchildMock.schemaPointer, - expectedChildPointer, + expectedUniqueChildPointer, ), - ).toEqual(expectedGrandchildPointer); + ).toEqual(expectedUniqueGrandchildPointer); }); it('Returns a pointer reflecting the path to a given node in a reference to a combination', () => { const { schemaPointer } = combinationDefNodeChild1Mock; const uniquePointerOfParent = referenceToCombinationDefNodeMock.schemaPointer; const result = schemaModel.getUniquePointer(schemaPointer, uniquePointerOfParent); - const expectedResult = '#/properties/referenceToCombinationDef/oneOf/0'; + const expectedResult = `${UNIQUE_POINTER_PREFIX}#/properties/referenceToCombinationDef/oneOf/0`; expect(result).toEqual(expectedResult); }); }); diff --git a/frontend/packages/schema-model/src/lib/SchemaModel.ts b/frontend/packages/schema-model/src/lib/SchemaModel.ts index eabf91f7154..1255b3d132e 100644 --- a/frontend/packages/schema-model/src/lib/SchemaModel.ts +++ b/frontend/packages/schema-model/src/lib/SchemaModel.ts @@ -23,9 +23,9 @@ import { moveArrayItem, replaceItemsByValue, } from 'app-shared/utils/arrayUtils'; -import { ROOT_POINTER } from './constants'; +import { ROOT_POINTER, UNIQUE_POINTER_PREFIX } from './constants'; import type { ReferenceNode } from '../types/ReferenceNode'; -import { ObjectUtils, ArrayUtils } from '@studio/pure-functions'; +import { ObjectUtils, ArrayUtils, StringUtils } from '@studio/pure-functions'; import { replaceStart } from 'app-shared/utils/stringUtils'; import { createDefinitionPointer, @@ -85,11 +85,12 @@ export class SchemaModel { } public getSchemaPointerByUniquePointer(uniquePointer: string): string { - if (this.hasNode(uniquePointer)) return uniquePointer; + const pointer = this.removeUniquePointerPrefix(uniquePointer); + if (this.hasNode(pointer)) return pointer; - const parentNodePointer = this.getParentSchemaPointerByUniquePointer(uniquePointer); + const parentSchemaPointer = this.getParentSchemaPointerByUniquePointer(pointer); return makePointerFromArray([ - parentNodePointer, + parentSchemaPointer, extractCategoryFromPointer(uniquePointer), extractNameFromPointer(uniquePointer), ]); @@ -107,10 +108,16 @@ export class SchemaModel { return this.getNodeByUniquePointer(parentUniquePointer); } + private removeUniquePointerPrefix(uniquePointer: string): string { + return StringUtils.removeStart(uniquePointer, UNIQUE_POINTER_PREFIX); + } + public getUniquePointer(schemaPointer: string, uniqueParentPointer?: string): string { - if (!uniqueParentPointer || !isDefinitionPointer(schemaPointer)) return schemaPointer; + if (!uniqueParentPointer || !isDefinitionPointer(schemaPointer)) + return `${UNIQUE_POINTER_PREFIX}${schemaPointer}`; const category = extractCategoryFromPointer(schemaPointer); - return `${uniqueParentPointer}/${category}/${extractNameFromPointer(schemaPointer)}`; + const parentPointer = this.removeUniquePointerPrefix(uniqueParentPointer); + return `${UNIQUE_POINTER_PREFIX}${parentPointer}/${category}/${extractNameFromPointer(schemaPointer)}`; } public hasNode(schemaPointer: string): boolean { diff --git a/frontend/packages/schema-model/src/lib/constants.ts b/frontend/packages/schema-model/src/lib/constants.ts index 825c373d711..ace09930068 100644 --- a/frontend/packages/schema-model/src/lib/constants.ts +++ b/frontend/packages/schema-model/src/lib/constants.ts @@ -1,2 +1,3 @@ export const META_SCHEMA_ID = 'https://json-schema.org/draft/2020-12/schema'; export const ROOT_POINTER = '#'; +export const UNIQUE_POINTER_PREFIX = 'uniquePointer-';