From de7015e19c3c07c32c02cef8c11404f56d7d151c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Jos=C3=A9=20dos=20Santos?= Date: Thu, 21 Nov 2024 11:23:13 -0300 Subject: [PATCH] kie-issues#208: Renaming any "NamedElement" on the DMN Editor should update all references to the old name --- .../dmn-editor/src/dataTypes/DataTypeName.tsx | 93 +++++++++++++++++-- .../src/mutations/renameItemDefinition.ts | 18 ++-- .../src/refactor/IdentifiersRefactor.ts | 4 +- .../refactor/IdentifiersRefactor.test.ts | 2 - 4 files changed, 97 insertions(+), 20 deletions(-) diff --git a/packages/dmn-editor/src/dataTypes/DataTypeName.tsx b/packages/dmn-editor/src/dataTypes/DataTypeName.tsx index 832ca2fe33b..651c8aea668 100644 --- a/packages/dmn-editor/src/dataTypes/DataTypeName.tsx +++ b/packages/dmn-editor/src/dataTypes/DataTypeName.tsx @@ -18,8 +18,11 @@ */ import * as React from "react"; -import { useCallback, useMemo } from "react"; -import { DMN15__tItemDefinition } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types"; +import { useCallback, useMemo, useState } from "react"; +import { + DMN15__tDefinitions, + DMN15__tItemDefinition, +} from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types"; import { Normalized } from "@kie-tools/dmn-marshaller/dist/normalization/normalize"; import { Flex } from "@patternfly/react-core/dist/js/layouts/Flex"; import { EditableNodeLabel, useEditableNodeLabel } from "../diagram/nodes/EditableNodeLabel"; @@ -33,6 +36,11 @@ import { useExternalModels } from "../includedModels/DmnEditorDependenciesContex import { State } from "../store/Store"; import { DmnBuiltInDataType } from "@kie-tools/boxed-expression-component/dist/api"; import { DmnLatestModel } from "@kie-tools/dmn-marshaller"; +import { + isIdentifierReferencedInSomeExpression, + RefactorConfirmationDialog, +} from "../refactor/RefactorConfirmationDialog"; +import { DataTypeIndex } from "./DataTypes"; export function DataTypeName({ isReadOnly, @@ -75,7 +83,7 @@ export function DataTypeName({ (s) => s.computed(s).getDirectlyIncludedExternalModelsByNamespace(externalModelsByNamespace).dmns ); - const externalModelsByNamespaceMap = useMemo(() => { + const externalDmnModelsByNamespaceMap = useMemo(() => { const externalModels = new Map>(); for (const [key, externalDmn] of externalDmnsByNamespace) { @@ -84,29 +92,94 @@ export function DataTypeName({ return externalModels; }, [externalDmnsByNamespace]); + const _shouldCommitOnBlur = shouldCommitOnBlur ?? true; // Defaults to true + + const [isRefactorModalOpen, setIsRefactorModalOpen] = useState(false); + const [newName, setNewName] = useState(""); + const identifierId = useMemo(() => itemDefinition["@_id"], [itemDefinition]); + const oldName = useMemo(() => itemDefinition["@_name"], [itemDefinition]); + + const applyRename = useCallback( + (args: { + definitions: Normalized; + newName: string; + shouldRenameReferencedExpressions: boolean; + allDataTypesById: DataTypeIndex; + }) => { + renameItemDefinition({ + ...args, + itemDefinitionId: itemDefinition["@_id"]!, + externalDmnModelsByNamespaceMap, + }); + }, + [externalDmnModelsByNamespaceMap, itemDefinition] + ); + const onRenamed = useCallback( (newName) => { - if (isReadOnly) { + if (isReadOnly || newName === oldName) { return; } dmnEditorStoreApi.setState((state) => { - renameItemDefinition({ + if ( + isIdentifierReferencedInSomeExpression({ + identifierUuid: identifierId, + dmnDefinitions: state.dmn.model.definitions, + externalDmnModelsByNamespaceMap, + }) + ) { + setNewName(newName); + setIsRefactorModalOpen(true); + } else { + applyRename({ + definitions: state.dmn.model.definitions, + newName, + shouldRenameReferencedExpressions: false, + allDataTypesById: state.computed(state).getDataTypes(externalModelsByNamespace).allDataTypesById, + }); + } + }); + }, + [ + applyRename, + dmnEditorStoreApi, + externalDmnModelsByNamespaceMap, + externalModelsByNamespace, + identifierId, + isReadOnly, + oldName, + ] + ); + + const confirmRename = useCallback( + (shouldRenameReferencedExpressions: boolean) => { + setIsRefactorModalOpen(false); + dmnEditorStoreApi.setState((state) => { + applyRename({ definitions: state.dmn.model.definitions, newName, - itemDefinitionId: itemDefinition["@_id"]!, + shouldRenameReferencedExpressions, allDataTypesById: state.computed(state).getDataTypes(externalModelsByNamespace).allDataTypesById, - externalModelsByNamespaceMap, }); }); }, - [dmnEditorStoreApi, externalModelsByNamespace, externalModelsByNamespaceMap, isReadOnly, itemDefinition] + [applyRename, dmnEditorStoreApi, externalModelsByNamespace, newName] ); - const _shouldCommitOnBlur = shouldCommitOnBlur ?? true; // Defaults to true - return ( <> + { + confirmRename(true); + }} + onConfirmRenameOnly={() => { + confirmRename(false); + }} + isRefactorModalOpen={isRefactorModalOpen} + fromName={oldName} + toName={newName} + /> {editMode === "hover" && ( ; newName: string; itemDefinitionId: string; allDataTypesById: DataTypeIndex; - externalModelsByNamespaceMap: Map>; + externalDmnModelsByNamespaceMap: Map>; + shouldRenameReferencedExpressions: boolean; }) { const dataType = allDataTypesById.get(itemDefinitionId); if (!dataType) { @@ -90,12 +92,14 @@ export function renameItemDefinition({ // Not top-level.. meaning that we need to update FEEL expressions referencing it else { - const identifiersRefactor = new IdentifiersRefactor({ - writeableDmnDefinitions: definitions, - _readonly_externalDmnModelsByNamespaceMap: externalModelsByNamespaceMap, - }); + if (shouldRenameReferencedExpressions) { + const identifiersRefactor = new IdentifiersRefactor({ + writeableDmnDefinitions: definitions, + _readonly_externalDmnModelsByNamespaceMap: externalDmnModelsByNamespaceMap, + }); - identifiersRefactor.rename({ identifierUuid: itemDefinitionId, newName: trimmedNewName }); + identifiersRefactor.rename({ identifierUuid: itemDefinitionId, newName: trimmedNewName }); + } } itemDefinition["@_name"] = trimmedNewName; diff --git a/packages/dmn-language-service/src/refactor/IdentifiersRefactor.ts b/packages/dmn-language-service/src/refactor/IdentifiersRefactor.ts index fe3f2cab231..173045984e0 100644 --- a/packages/dmn-language-service/src/refactor/IdentifiersRefactor.ts +++ b/packages/dmn-language-service/src/refactor/IdentifiersRefactor.ts @@ -127,7 +127,9 @@ export class IdentifiersRefactor { public getExpressionsThatUseTheIdentifier(identifierId: string) { const identifierContext = this.repository.identifiers.get(identifierId); if (!identifierContext) { - return []; + return ( + this.repository.dataTypeIndexedByUuid.get(identifierId)?.source.expressionsThatUseTheIdentifier.values() ?? [] + ); } return identifierContext.identifier.expressionsThatUseTheIdentifier.values(); diff --git a/packages/dmn-language-service/tests/refactor/IdentifiersRefactor.test.ts b/packages/dmn-language-service/tests/refactor/IdentifiersRefactor.test.ts index 39946b867f2..5dcd227452e 100644 --- a/packages/dmn-language-service/tests/refactor/IdentifiersRefactor.test.ts +++ b/packages/dmn-language-service/tests/refactor/IdentifiersRefactor.test.ts @@ -77,7 +77,6 @@ describe("Refactor renamed identifiers", () => { newName: "MON", }); - // id="_4a4d01be-fe97-49a2-8c4c-3a49ff27968d" name="Tax" // Rename the "Tax" property of "Monthly" data type to "The Tax" identifiersRefactor.rename({ identifierUuid: "_4a4d01be-fe97-49a2-8c4c-3a49ff27968d", @@ -193,7 +192,6 @@ describe("Refactor renamed identifiers", () => { ).toEqual("x > 2"); }); - // test("rename decision service element - should update referenced expressions", async () => {}); test("rename included model - should update referenced expressions", async () => { const identifiersRefactor = new IdentifiersRefactor({ writeableDmnDefinitions: getDefinitions(includeMathModelDmn()),