This is an automated email from the ASF dual-hosted git repository.

tiagobento pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie-tools.git


The following commit(s) were added to refs/heads/main by this push:
     new b4ab570ecca kie-issues#914: On the DMN Editor, fix rendering of 
TypeRefSelector on Data Type node panel for Decision Services (#2147)
b4ab570ecca is described below

commit b4ab570ecca78149f29b16ef787d8fe2ba882fed
Author: Tiago Bento <[email protected]>
AuthorDate: Wed Feb 7 08:58:09 2024 -0500

    kie-issues#914: On the DMN Editor, fix rendering of TypeRefSelector on Data 
Type node panel for Decision Services (#2147)
---
 packages/dmn-editor/src/DmnEditor.css              |  9 +---
 packages/dmn-editor/src/dataTypes/DataTypeName.tsx |  2 +
 .../dmn-editor/src/dataTypes/TypeRefSelector.tsx   | 51 ++++++++++++++--------
 packages/dmn-editor/src/diagram/Diagram.tsx        |  4 +-
 .../src/diagram/nodes/DataTypeNodePanel.tsx        |  4 +-
 .../src/diagram/nodes/EditableNodeLabel.tsx        |  8 ++--
 packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx | 27 ++++++++++--
 packages/dmn-editor/src/diagram/nodes/Nodes.tsx    | 47 ++++++++++++++------
 8 files changed, 103 insertions(+), 49 deletions(-)

diff --git a/packages/dmn-editor/src/DmnEditor.css 
b/packages/dmn-editor/src/DmnEditor.css
index 444d2b7217c..ee68a8b6e29 100644
--- a/packages/dmn-editor/src/DmnEditor.css
+++ b/packages/dmn-editor/src/DmnEditor.css
@@ -50,6 +50,7 @@
   top: 0;
   left: 0;
   overflow: visible;
+  z-index: 10000; /* Makes the data type node panel appear correctly, on top 
of the node */
 }
 .kie-dmn-editor--node:focus {
   outline: none;
@@ -589,13 +590,7 @@ the cursor is inside it. By making it adimensional, that 
never happens.  */
 .kie-dmn-editor--data-type-node-panel 
.pf-c-select__toggle.pf-m-typeahead::before {
   border: 0;
 }
-.kie-dmn-editor--data-type-node-panel > div:hover {
-  backdrop-filter: brightness(95%);
-}
-.kie-dmn-editor--data-type-node-panel > div:active {
-  backdrop-filter: brightness(90%);
-}
-/*    edit button on decision and bkm nodes */
+/* edit button on decision and bkm nodes */
 .kie-dmn-editor--edit-expression-node-panel {
   position: absolute;
   padding: 4px 8px;
diff --git a/packages/dmn-editor/src/dataTypes/DataTypeName.tsx 
b/packages/dmn-editor/src/dataTypes/DataTypeName.tsx
index f7e7c4219bd..53b5e11ed9d 100644
--- a/packages/dmn-editor/src/dataTypes/DataTypeName.tsx
+++ b/packages/dmn-editor/src/dataTypes/DataTypeName.tsx
@@ -99,6 +99,7 @@ export function DataTypeName({
           name={feelQNameToDisplay.full}
           onRenamed={onRenamed}
           allUniqueNames={onGetAllUniqueNames}
+          enableAutoFocusing={enableAutoFocusing}
         />
       )}
       {editMode === "double-click" && (
@@ -115,6 +116,7 @@ export function DataTypeName({
           {/* Using this component here is not ideal, as we're not dealing 
with Node names, but it works well enough */}
           <EditableNodeLabel
             truncate={true}
+            enableAutoFocusing={enableAutoFocusing}
             grow={true}
             isEditing={isEditingLabel}
             setEditing={setEditingLabel}
diff --git a/packages/dmn-editor/src/dataTypes/TypeRefSelector.tsx 
b/packages/dmn-editor/src/dataTypes/TypeRefSelector.tsx
index c6021dc5155..3a05689ec9d 100644
--- a/packages/dmn-editor/src/dataTypes/TypeRefSelector.tsx
+++ b/packages/dmn-editor/src/dataTypes/TypeRefSelector.tsx
@@ -20,7 +20,7 @@
 import { DmnBuiltInDataType, generateUuid } from 
"@kie-tools/boxed-expression-component/dist/api";
 import { Select, SelectGroup, SelectOption, SelectVariant } from 
"@patternfly/react-core/dist/js/components/Select";
 import * as React from "react";
-import { useMemo, useRef, useState } from "react";
+import { useCallback, useRef, useState } from "react";
 import { TypeRefLabel } from "./TypeRefLabel";
 import { ArrowUpIcon } from 
"@patternfly/react-icons/dist/js/icons/arrow-up-icon";
 import { DmnEditorTab } from "../store/Store";
@@ -35,26 +35,45 @@ import { useExternalModels } from 
"../includedModels/DmnEditorDependenciesContex
 
 export type OnTypeRefChange = (newDataType: DmnBuiltInDataType) => void;
 export type OnCreateDataType = (newDataTypeName: string) => void;
+export type OnToggle = (isExpanded: boolean) => void;
 
 export const typeRefSelectorLimitedSpaceStyle = { maxHeight: "600px", 
boxShadow: "none", overflowY: "scroll" };
 
-export function TypeRefSelector(props: {
+export function TypeRefSelector({
+  zoom,
+  heightRef,
+  onChange,
+  typeRef,
+  isDisabled,
+  menuAppendTo,
+  onCreate,
+  onToggle,
+}: {
   zoom?: number;
   heightRef: React.RefObject<HTMLElement>;
   isDisabled?: boolean;
   typeRef: string | undefined;
   onChange: OnTypeRefChange;
   onCreate?: OnCreateDataType;
+  onToggle?: OnToggle;
   menuAppendTo?: "parent";
 }) {
   const [isOpen, setOpen] = useState(false);
   const { externalModelsByNamespace } = useExternalModels();
   const selectedDataType = useDmnEditorStore((s) =>
-    props.typeRef
-      ? 
s.computed(s).getDataTypes(externalModelsByNamespace).allTopLevelDataTypesByFeelName.get(props.typeRef)
+    typeRef
+      ? 
s.computed(s).getDataTypes(externalModelsByNamespace).allTopLevelDataTypesByFeelName.get(typeRef)
       : undefined
   );
 
+  const _onToggle = useCallback(
+    (isExpanded: boolean) => {
+      onToggle?.(isExpanded);
+      setOpen(isExpanded);
+    },
+    [onToggle]
+  );
+
   const dmnEditorStoreApi = useDmnEditorStoreApi();
 
   const { customDataTypes, externalDataTypes } = useDmnEditorStore((state) => {
@@ -78,17 +97,13 @@ export function TypeRefSelector(props: {
     return { customDataTypes, externalDataTypes };
   });
 
-  const exists = selectedDataType || (props.typeRef && 
builtInFeelTypeNames.has(props.typeRef));
+  const exists = selectedDataType || (typeRef && 
builtInFeelTypeNames.has(typeRef));
 
   const id = generateUuid();
 
   const toggleRef = useRef<HTMLButtonElement>(null);
 
-  const { maxHeight, direction } = useInViewSelect(
-    props.heightRef ?? { current: document.body },
-    toggleRef,
-    props.zoom ?? 1
-  );
+  const { maxHeight, direction } = useInViewSelect(heightRef ?? { current: 
document.body }, toggleRef, zoom ?? 1);
 
   return (
     <Flex
@@ -116,23 +131,23 @@ export function TypeRefSelector(props: {
       <Select
         toggleRef={toggleRef}
         className={!exists ? "kie-dmn-editor--type-ref-selector-invalid-value" 
: undefined}
-        isDisabled={props.isDisabled}
+        isDisabled={isDisabled}
         variant={SelectVariant.typeahead}
         typeAheadAriaLabel={DmnBuiltInDataType.Undefined}
-        onToggle={setOpen}
+        onToggle={_onToggle}
         onSelect={(e, v) => {
-          setOpen(false);
-          props.onChange(v as DmnBuiltInDataType);
+          _onToggle(false);
+          onChange(v as DmnBuiltInDataType);
         }}
-        selections={props.typeRef}
+        selections={typeRef}
         isOpen={isOpen}
         aria-labelledby={"Data types selector"}
         placeholderText={"Select a data type..."}
-        isCreatable={!!props.onCreate}
+        isCreatable={!!onCreate}
         isCreateOptionOnTop={false}
-        onCreateOption={props.onCreate}
+        onCreateOption={onCreate}
         isGrouped={true}
-        menuAppendTo={props.menuAppendTo ?? document.body}
+        menuAppendTo={menuAppendTo ?? document.body}
         maxHeight={maxHeight}
         direction={direction}
         onWheelCapture={(e) => e.stopPropagation()} // Necessary so that 
Reactflow doesn't mess with this event.
diff --git a/packages/dmn-editor/src/diagram/Diagram.tsx 
b/packages/dmn-editor/src/diagram/Diagram.tsx
index 3190545e09f..c12c9f56456 100644
--- a/packages/dmn-editor/src/diagram/Diagram.tsx
+++ b/packages/dmn-editor/src/diagram/Diagram.tsx
@@ -319,7 +319,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
               },
             });
             state.diagram._selectedNodes = [newNodeId];
-            state.focus.consumableId = id;
+            state.focus.consumableId = newNodeId;
           });
         } else if 
(e.dataTransfer.getData(MIME_TYPE_FOR_DMN_EDITOR_EXTERNAL_NODES_FROM_INCLUDED_MODELS))
 {
           e.stopPropagation();
@@ -503,7 +503,7 @@ export const Diagram = React.forwardRef<DiagramRef, { 
container: React.RefObject
           });
 
           state.diagram._selectedNodes = [newDmnObejctHref];
-          state.focus.consumableId = id;
+          state.focus.consumableId = newDmnObejctHref;
         });
 
         // Indepdent of what happens in the state mutation above, we always 
need to reset the `ongoingConnection` at the end here.
diff --git a/packages/dmn-editor/src/diagram/nodes/DataTypeNodePanel.tsx 
b/packages/dmn-editor/src/diagram/nodes/DataTypeNodePanel.tsx
index 1ce71e28e05..599cc325ae7 100644
--- a/packages/dmn-editor/src/diagram/nodes/DataTypeNodePanel.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/DataTypeNodePanel.tsx
@@ -24,7 +24,7 @@ import {
 } from "@kie-tools/dmn-marshaller/dist/schemas/dmn-1_5/ts-gen/types";
 import { DmnBuiltInDataType } from 
"@kie-tools/boxed-expression-component/dist/api";
 import { useDmnEditorStore } from "../../store/StoreContext";
-import { OnCreateDataType, OnTypeRefChange, TypeRefSelector } from 
"../../dataTypes/TypeRefSelector";
+import { OnCreateDataType, OnToggle, OnTypeRefChange, TypeRefSelector } from 
"../../dataTypes/TypeRefSelector";
 import { useDmnEditor } from "../../DmnEditorContext";
 import { useResolvedTypeRef } from "../../dataTypes/useResolvedTypeRef";
 
@@ -38,6 +38,7 @@ export function DataTypeNodePanel(props: {
   shape: DMNDI15__DMNShape | undefined;
   onChange: OnTypeRefChange;
   onCreate?: OnCreateDataType;
+  onToggle?: OnToggle;
   dmnObjectNamespace: string | undefined;
 }) {
   const enableDataTypesToolbarOnNodes = useDmnEditorStore((s) => 
s.diagram.overlays.enableDataTypesToolbarOnNodes);
@@ -70,6 +71,7 @@ export function DataTypeNodePanel(props: {
               typeRef={resolvedTypeRef}
               onChange={props.onChange}
               onCreate={props.onCreate}
+              onToggle={props.onToggle}
               menuAppendTo={"parent"}
               isDisabled={isExternalNode}
             />
diff --git a/packages/dmn-editor/src/diagram/nodes/EditableNodeLabel.tsx 
b/packages/dmn-editor/src/diagram/nodes/EditableNodeLabel.tsx
index 2503ce966f7..3c43bc3a3f9 100644
--- a/packages/dmn-editor/src/diagram/nodes/EditableNodeLabel.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/EditableNodeLabel.tsx
@@ -32,8 +32,8 @@ import { generateUuid } from 
"@kie-tools/boxed-expression-component/dist/api";
 import { useFocusableElement } from "../../focus/useFocusableElement";
 import { flushSync } from "react-dom";
 import { NodeLabelPosition } from "./NodeSvgs";
-import "./EditableNodeLabel.css";
 import { State } from "../../store/Store";
+import "./EditableNodeLabel.css";
 
 export type OnEditableNodeLabelChange = (value: string | undefined) => void;
 
@@ -52,6 +52,7 @@ export function EditableNodeLabel({
   skipValidation,
   onGetAllUniqueNames,
   fontCssProperties,
+  enableAutoFocusing,
 }: {
   id?: string;
   shouldCommitOnBlur?: boolean;
@@ -67,6 +68,7 @@ export function EditableNodeLabel({
   skipValidation?: boolean;
   onGetAllUniqueNames: (s: State) => UniqueNameIndex;
   fontCssProperties?: React.CSSProperties;
+  enableAutoFocusing?: boolean;
 }) {
   const displayValue = useDmnEditorStore((s) => {
     if (!value) {
@@ -199,7 +201,7 @@ export function EditableNodeLabel({
 
   useFocusableElement(
     ref,
-    id ?? namedElement?.["@_id"],
+    enableAutoFocusing ?? true ? id ?? namedElement?.["@_id"] : undefined,
     useCallback(
       (cb) => {
         setTimeout(() => {
@@ -207,7 +209,7 @@ export function EditableNodeLabel({
             setEditing(true);
           });
           cb();
-        });
+        }, 100);
       },
       [setEditing]
     )
diff --git a/packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx 
b/packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx
index 5fbc941da67..ec66ae7148b 100644
--- a/packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/NodeSvgs.tsx
@@ -67,7 +67,17 @@ export function normalize<T extends NodeSvgProps>(_props: T) 
{
 }
 
 export function InputDataNodeSvg(__props: NodeSvgProps & { isCollection?: 
boolean }) {
-  const { strokeWidth, x, y, width, height, fillColor, strokeColor, props } = 
normalize(__props);
+  const {
+    strokeWidth,
+    x,
+    y,
+    width,
+    height,
+    fillColor,
+    strokeColor,
+    props: { isCollection, ...props },
+  } = normalize(__props);
+
   const rx =
     typeof height === "number"
       ? height / 2
@@ -97,13 +107,22 @@ export function InputDataNodeSvg(__props: NodeSvgProps & { 
isCollection?: boolea
         rx={rx}
         ry={ry}
       />
-      {props.isCollection && <NodeCollectionMarker {...__props} 
anchor={"bottom"} />}
+      {isCollection && <NodeCollectionMarker {...__props} anchor={"bottom"} />}
     </>
   );
 }
 
 export function DecisionNodeSvg(__props: NodeSvgProps & { isCollection?: 
boolean }) {
-  const { strokeWidth, x, y, width, height, fillColor, strokeColor, props } = 
normalize(__props);
+  const {
+    strokeWidth,
+    x,
+    y,
+    width,
+    height,
+    fillColor,
+    strokeColor,
+    props: { isCollection, ...props },
+  } = normalize(__props);
 
   return (
     <>
@@ -118,7 +137,7 @@ export function DecisionNodeSvg(__props: NodeSvgProps & { 
isCollection?: boolean
         strokeLinejoin={"round"}
         {...props}
       />
-      {props.isCollection && <NodeCollectionMarker {...__props} anchor="top" 
/>}
+      {isCollection && <NodeCollectionMarker {...__props} anchor="top" />}
     </>
   );
 }
diff --git a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx 
b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
index 09174032ce6..102898856e7 100644
--- a/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
+++ b/packages/dmn-editor/src/diagram/nodes/Nodes.tsx
@@ -33,7 +33,7 @@ import { XmlQName } from 
"@kie-tools/xml-parser-ts/dist/qNames";
 import { drag } from "d3-drag";
 import { select } from "d3-selection";
 import * as React from "react";
-import { useCallback, useEffect, useMemo, useRef } from "react";
+import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } 
from "react";
 import * as RF from "reactflow";
 import { OnCreateDataType, OnTypeRefChange } from 
"../../dataTypes/TypeRefSelector";
 import { addTopLevelItemDefinition } from 
"../../mutations/addTopLevelItemDefinition";
@@ -69,6 +69,7 @@ import { NODE_TYPES } from "./NodeTypes";
 import { OutgoingStuffNodePanel } from "./OutgoingStuffNodePanel";
 import { propsHaveSameValuesDeep } from "../memoization/memoization";
 import { useExternalModels } from 
"../../includedModels/DmnEditorDependenciesContext";
+import { NODE_LAYERS } from "../../store/computed/computeDiagramData";
 
 export type ElementFilter<E extends { __$$element: string }, Filter extends 
string> = E extends any
   ? E["__$$element"] extends Filter
@@ -120,6 +121,7 @@ export const InputDataNode = React.memo(
 
     const { isEditingLabel, setEditingLabel, triggerEditing, 
triggerEditingIfEnter } = useEditableNodeLabel(id);
     useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, 
selected, isEditingLabel);
+    const [isDataTypesPanelExpanded, setDataTypePanelExpanded] = 
useState(false);
 
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
@@ -203,6 +205,7 @@ export const InputDataNode = React.memo(
             edgeTypes={outgoingStructure[NODE_TYPES.inputData].edges}
           />
           <EditableNodeLabel
+            id={id}
             namedElement={inputData}
             namedElementQName={dmnObjectQName}
             isEditing={isEditingLabel}
@@ -229,6 +232,7 @@ export const InputDataNode = React.memo(
             shape={shape}
             onCreate={onCreateDataType}
             onChange={onTypeRefChange}
+            onToggle={setDataTypePanelExpanded}
           />
         </div>
       </>
@@ -263,6 +267,7 @@ export const DecisionNode = React.memo(
       decision["@_id"]
     );
     useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, 
selected, isEditingLabel);
+    const [isDataTypesPanelExpanded, setDataTypePanelExpanded] = 
useState(false);
 
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
@@ -349,6 +354,7 @@ export const DecisionNode = React.memo(
             edgeTypes={outgoingStructure[NODE_TYPES.decision].edges}
           />
           <EditableNodeLabel
+            id={id}
             namedElement={decision}
             namedElementQName={dmnObjectQName}
             isEditing={isEditingLabel}
@@ -375,6 +381,7 @@ export const DecisionNode = React.memo(
             shape={shape}
             onChange={onTypeRefChange}
             onCreate={onCreateDataType}
+            onToggle={setDataTypePanelExpanded}
           />
         </div>
       </>
@@ -409,6 +416,7 @@ export const BkmNode = React.memo(
       bkm["@_id"]
     );
     useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, 
selected, isEditingLabel);
+    const [isDataTypesPanelExpanded, setDataTypePanelExpanded] = 
useState(false);
 
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
@@ -479,6 +487,7 @@ export const BkmNode = React.memo(
             edgeTypes={outgoingStructure[NODE_TYPES.bkm].edges}
           />
           <EditableNodeLabel
+            id={id}
             namedElement={bkm}
             namedElementQName={dmnObjectQName}
             isEditing={isEditingLabel}
@@ -505,6 +514,7 @@ export const BkmNode = React.memo(
             shape={shape}
             onChange={onTypeRefChange}
             onCreate={onCreateDataType}
+            onToggle={setDataTypePanelExpanded}
           />
         </div>
       </>
@@ -596,6 +606,7 @@ export const KnowledgeSourceNode = React.memo(
             edgeTypes={outgoingStructure[NODE_TYPES.knowledgeSource].edges}
           />
           <EditableNodeLabel
+            id={id}
             namedElement={knowledgeSource}
             namedElementQName={dmnObjectQName}
             position={getNodeLabelPosition(type as NodeType)}
@@ -706,7 +717,7 @@ export const TextAnnotationNode = React.memo(
             edgeTypes={outgoingStructure[NODE_TYPES.textAnnotation].edges}
           />
           <EditableNodeLabel
-            id={textAnnotation["@_id"]}
+            id={id}
             namedElement={undefined}
             namedElementQName={undefined}
             position={getNodeLabelPosition(type as NodeType)}
@@ -762,6 +773,8 @@ export const DecisionServiceNode = React.memo(
       decisionService["@_id"]
     );
     useHoveredNodeAlwaysOnTop(ref, zIndex, shouldActLikeHovered, dragging, 
selected, isEditingLabel);
+    const [isDataTypesPanelExpanded, setDataTypePanelExpanded] = 
useState(false);
+
     const dmnEditorStoreApi = useDmnEditorStoreApi();
 
     const { isTargeted, isValidConnectionTarget } = 
useConnectionTargetStatus(id, shouldActLikeHovered);
@@ -897,6 +910,7 @@ export const DecisionServiceNode = React.memo(
             edgeTypes={outgoingStructure[NODE_TYPES.decisionService].edges}
           />
           <EditableNodeLabel
+            id={id}
             namedElement={decisionService}
             namedElementQName={dmnObjectQName}
             position={getNodeLabelPosition(type as NodeType)}
@@ -924,6 +938,7 @@ export const DecisionServiceNode = React.memo(
             shape={shape}
             onCreate={onCreateDataType}
             onChange={onTypeRefChange}
+            onToggle={setDataTypePanelExpanded}
           />
         </div>
       </>
@@ -1033,7 +1048,7 @@ export const GroupNode = React.memo(
             edgeTypes={outgoingStructure[NODE_TYPES.group].edges}
           />
           <EditableNodeLabel
-            id={group["@_id"]}
+            id={id}
             namedElement={undefined}
             namedElementQName={undefined}
             position={getNodeLabelPosition(type as NodeType)}
@@ -1102,6 +1117,7 @@ export const UnknownNode = React.memo(
           <InfoNodePanel isVisible={!isTargeted && shouldActLikeHovered} />
 
           <EditableNodeLabel
+            id={id}
             namedElement={undefined}
             namedElementQName={undefined}
             position={getNodeLabelPosition(type as NodeType)}
@@ -1193,22 +1209,25 @@ function useNodeDimensions(
 
 function useHoveredNodeAlwaysOnTop(
   ref: React.RefObject<HTMLDivElement | SVGElement>,
-  layer: number,
+  zIndex: number,
   shouldActLikeHovered: boolean,
   dragging: boolean,
   selected: boolean,
   isEditing: boolean
 ) {
-  useEffect(() => {
-    setTimeout(() => {
-      if (selected && !isEditing) {
-        ref.current?.focus();
-      }
-      if (ref.current) {
-        ref.current.parentElement!.style.zIndex = `${shouldActLikeHovered || 
dragging ? layer + 1000 + 1 : layer}`;
-      }
-    }, 0);
-  }, [dragging, shouldActLikeHovered, ref, selected, layer, isEditing]);
+  useLayoutEffect(() => {
+    const r = ref.current;
+
+    if (selected && !isEditing) {
+      r?.focus();
+    }
+
+    if (r) {
+      r.parentElement!.style.zIndex = `${
+        shouldActLikeHovered || dragging ? zIndex + NODE_LAYERS.NESTED_NODES + 
1 : zIndex
+      }`;
+    }
+  }, [dragging, shouldActLikeHovered, ref, zIndex, selected, isEditing]);
 }
 
 export function useConnection(nodeId: string) {


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to