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]