diff --git a/CHANGELOG.md b/CHANGELOG.md
index af20b6b7..23325814 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,11 +18,14 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
- `searchListPredicate` property: Allows to filter the complete list of search options at once.
- Following optional BlueprintJs properties are forwarded now to override default behaviour: `noResults`, `createNewItemRenderer` and `itemRenderer`
- `isValidNewOption` property: Checks if an input string is or can be turned into a valid new option.
+- `ActivityControlWidge`
+ - Support `badge` on activity control menu button.
### Fixed
- ``
- border of the BlueprintJS `Tag` elements were fixed
+- `extendedTooltip` of a handle in the ReactFlow (v12) component does not show the tooltip.
### Changed
diff --git a/src/cmem/ActivityControl/ActivityControlWidget.tsx b/src/cmem/ActivityControl/ActivityControlWidget.tsx
index 4663a108..c7fc36e1 100644
--- a/src/cmem/ActivityControl/ActivityControlWidget.tsx
+++ b/src/cmem/ActivityControl/ActivityControlWidget.tsx
@@ -93,6 +93,8 @@ export interface ActivityControlWidgetProps extends TestableComponent {
interface IActivityContextMenu extends TestableComponent {
// Tooltip for the context menu
tooltip?: string;
+ // Optional badge shown on the context menu button.
+ badge?: string | number;
// The entries of the context menu
menuItems: IActivityMenuAction[];
}
@@ -228,6 +230,15 @@ export function ActivityControlWidget(props: ActivityControlWidgetProps) {
+ }
>
{activityContextMenu.menuItems.map((menuAction, idx) => {
return (
diff --git a/src/cmem/ActivityControl/tests/ActivityControlWidget.test.tsx b/src/cmem/ActivityControl/tests/ActivityControlWidget.test.tsx
index 5df29c6d..b3a63dea 100644
--- a/src/cmem/ActivityControl/tests/ActivityControlWidget.test.tsx
+++ b/src/cmem/ActivityControl/tests/ActivityControlWidget.test.tsx
@@ -96,4 +96,25 @@ describe("ActivityControlWidget", () => {
fireEvent.click(customButton);
expect(mockAction).toHaveBeenCalledTimes(1);
});
+
+ it("renders a badge on the context menu trigger", () => {
+ const { container } = render(
+ ,
+ );
+
+ expect(container.querySelector("button[title='More options']")).toHaveTextContent("3");
+ });
});
diff --git a/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx b/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
index a23bb963..8f36a512 100644
--- a/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
+++ b/src/cmem/react-flow/ReactFlow/ReactFlow.stories.tsx
@@ -97,7 +97,7 @@ const nodeExamples = {
content: "Example content.",
minimalShape: "none",
},
- position: { x: 400, y: 200 },
+ position: { x: 400, y: 100 },
},
{
id: "linking-3",
@@ -141,6 +141,16 @@ const nodeExamples = {
},
position: { x: 50, y: 300 },
},
+ {
+ id: "linking-6",
+ type: "ruleblock",
+ data: {
+ label: "Rule block",
+ content: "Example content.",
+ minimalShape: "none",
+ },
+ position: { x: 400, y: 200 },
+ },
],
edges: [
{
diff --git a/src/cmem/react-flow/_handles.scss b/src/cmem/react-flow/_handles.scss
index a753b745..92021c33 100644
--- a/src/cmem/react-flow/_handles.scss
+++ b/src/cmem/react-flow/_handles.scss
@@ -30,5 +30,6 @@
@include handletypestyles("sourcepath");
@include handletypestyles("targetpath");
@include handletypestyles("transformation");
+@include handletypestyles("ruleblock");
@include handletypestyles("comparator");
@include handletypestyles("aggregator");
diff --git a/src/cmem/react-flow/_minimap.scss b/src/cmem/react-flow/_minimap.scss
index 864d932b..2b4078eb 100644
--- a/src/cmem/react-flow/_minimap.scss
+++ b/src/cmem/react-flow/_minimap.scss
@@ -44,5 +44,6 @@
@include mapnodestyles("sourcepath");
@include mapnodestyles("targetpath");
@include mapnodestyles("transformation");
+@include mapnodestyles("ruleblock");
@include mapnodestyles("comparator");
@include mapnodestyles("aggregator");
diff --git a/src/cmem/react-flow/configuration/_colors-linking.scss b/src/cmem/react-flow/configuration/_colors-linking.scss
index c9e47d42..7d2acfc6 100644
--- a/src/cmem/react-flow/configuration/_colors-linking.scss
+++ b/src/cmem/react-flow/configuration/_colors-linking.scss
@@ -5,6 +5,8 @@
--#{$eccgui}-targetpath-node-bright: #{eccgui-color-var("layout", "petrol", 300)};
--#{$eccgui}-transformation-node: #{eccgui-color-var("layout", "pink", 700)};
--#{$eccgui}-transformation-node-bright: #{eccgui-color-var("layout", "pink", 300)};
+ --#{$eccgui}-ruleblock-node: #{eccgui-color-var("layout", "vermilion", 700)};
+ --#{$eccgui}-ruleblock-node-bright: #{eccgui-color-var("layout", "vermilion", 300)};
--#{$eccgui}-comparator-node: #{eccgui-color-var("layout", "teal", 700)};
--#{$eccgui}-comparator-node-bright: #{eccgui-color-var("layout", "teal", 300)};
--#{$eccgui}-aggregator-node: #{eccgui-color-var("layout", "cyan", 700)};
diff --git a/src/cmem/react-flow/configuration/linking.ts b/src/cmem/react-flow/configuration/linking.ts
index d7635614..3fd23323 100644
--- a/src/cmem/react-flow/configuration/linking.ts
+++ b/src/cmem/react-flow/configuration/linking.ts
@@ -19,6 +19,7 @@ const nodeTypes: Record> = {
sourcepath: NodeDefault,
targetpath: NodeDefault,
transformation: NodeDefault,
+ ruleblock: NodeDefault,
comparator: NodeDefault,
aggregator: NodeDefault,
stickynote: StickyNoteNode,
diff --git a/src/cmem/react-flow/configuration/typing.ts b/src/cmem/react-flow/configuration/typing.ts
index 0f01eae2..5719ad1e 100644
--- a/src/cmem/react-flow/configuration/typing.ts
+++ b/src/cmem/react-flow/configuration/typing.ts
@@ -4,6 +4,7 @@ export enum LINKING_NODE_TYPES {
sourcepath = "sourcepath",
targetpath = "targetpath",
transformation = "transformation",
+ ruleblock = "ruleblock",
comparator = "comparator",
aggregator = "aggregator",
stickynote = "stickynote",
diff --git a/src/cmem/react-flow/nodes/_colors.scss b/src/cmem/react-flow/nodes/_colors.scss
index e5d1950f..6ab1cdab 100644
--- a/src/cmem/react-flow/nodes/_colors.scss
+++ b/src/cmem/react-flow/nodes/_colors.scss
@@ -62,5 +62,6 @@
@include nodetypestyles("sourcepath");
@include nodetypestyles("targetpath");
@include nodetypestyles("transformation");
+@include nodetypestyles("ruleblock");
@include nodetypestyles("comparator");
@include nodetypestyles("aggregator");
diff --git a/src/components/Icon/canonicalIconNames.tsx b/src/components/Icon/canonicalIconNames.tsx
index d253a0bd..00a04599 100644
--- a/src/components/Icon/canonicalIconNames.tsx
+++ b/src/components/Icon/canonicalIconNames.tsx
@@ -63,6 +63,7 @@ const canonicalIcons = {
"artefact-report": icons.Report,
"artefact-task": icons.Script,
"artefact-transform": icons.DataRefinery,
+ "artefact-ruleblock": transform(icons.Fragments, 90),
"artefact-uncategorized": icons.Unknown,
"artefact-workflow": icons.ModelBuilder,
diff --git a/src/extensions/react-flow/handles/HandleContent.tsx b/src/extensions/react-flow/handles/HandleContent.tsx
index 5a1b8836..48c89adb 100644
--- a/src/extensions/react-flow/handles/HandleContent.tsx
+++ b/src/extensions/react-flow/handles/HandleContent.tsx
@@ -21,7 +21,7 @@ export const HandleContent = memo(
{children}
) : extendedTooltip ? (
-
+
) : (
<>>
);
@@ -33,6 +33,7 @@ export const HandleContent = memo(
autoFocus={false}
enforceFocus={false}
openOnTargetFocus={false}
+ usePlaceholder={false}
{...tooltipProps}
>
{handleContent}
diff --git a/src/extensions/react-flow/handles/HandleDefault.tsx b/src/extensions/react-flow/handles/HandleDefault.tsx
index 621bf9c9..1d08ff96 100644
--- a/src/extensions/react-flow/handles/HandleDefault.tsx
+++ b/src/extensions/react-flow/handles/HandleDefault.tsx
@@ -80,7 +80,7 @@ export const HandleDefault = memo(
offset: {
enabled: true,
options: {
- offset: [3, 20],
+ offset: [0, 20],
},
},
},
@@ -89,21 +89,15 @@ export const HandleDefault = memo(
isOpen: extendedTooltipDisplayed,
};
- const handleContentProps = React.useMemo(
- () => ({
- ...data,
- tooltipProps: {
- ...handleContentTooltipProps,
- ...data?.tooltipProps,
- } as TooltipProps,
- }),
- [intent, category, handleProps.isConnectable],
- );
+ const handleContentProps = {
+ ...data,
+ tooltipProps: {
+ ...handleContentTooltipProps,
+ ...data?.tooltipProps,
+ } as TooltipProps,
+ };
- const handleContent = React.useMemo(
- () => {children},
- [],
- );
+ const handleContent = {children};
let switchTooltipTimerOn: ReturnType;
let switchToolsTimerOff: ReturnType;
@@ -119,7 +113,7 @@ export const HandleDefault = memo(
if (handleProps.onClick) {
handleProps.onClick(e);
}
- if (toolsTarget.length > 0 && e.target === handleDefaultRef.current) {
+ if (toolsTarget.length > 0 && e.currentTarget === handleDefaultRef.current) {
setExtendedTooltipDisplayed(false);
(toolsTarget[0] as HTMLElement).click();
}
@@ -127,7 +121,7 @@ export const HandleDefault = memo(
"data-category": category,
onMouseEnter: (e: React.MouseEvent) => {
if (switchToolsTimerOff) clearTimeout(switchToolsTimerOff);
- if (e.target === handleDefaultRef.current) {
+ if (e.currentTarget === handleDefaultRef.current) {
switchTooltipTimerOn = setTimeout(
() => setExtendedTooltipDisplayed(true),
data?.tooltipProps?.hoverOpenDelay ?? 500,
@@ -142,7 +136,16 @@ export const HandleDefault = memo(
setExtendedTooltipDisplayed(false);
},
}),
- [intent, category, tooltip, handleProps.isConnectable, handleProps.style],
+ [
+ intent,
+ category,
+ tooltip,
+ flowVersionCheck,
+ handleProps.isConnectable,
+ handleProps.style,
+ handleProps.onClick,
+ data?.tooltipProps?.hoverOpenDelay,
+ ],
);
switch (flowVersionCheck) {
diff --git a/src/extensions/react-flow/handles/_handles.scss b/src/extensions/react-flow/handles/_handles.scss
index 7f276267..e1c0018e 100644
--- a/src/extensions/react-flow/handles/_handles.scss
+++ b/src/extensions/react-flow/handles/_handles.scss
@@ -146,7 +146,14 @@ div.react-flow__handle {
position: absolute;
inset: 0;
overflow: hidden;
- cursor: help;
+}
+
+.#{$eccgui}-graphviz__handle__content--extendedTooltip {
+ inset: unset;
+ top: 50%;
+ left: 50%;
+ height: 0;
+ width: 0;
}
div.react-flow__handle-right {
diff --git a/src/extensions/react-flow/handles/tests/HandleDefault.test.tsx b/src/extensions/react-flow/handles/tests/HandleDefault.test.tsx
new file mode 100644
index 00000000..53f2f563
--- /dev/null
+++ b/src/extensions/react-flow/handles/tests/HandleDefault.test.tsx
@@ -0,0 +1,60 @@
+import React from "react";
+import { fireEvent, render, screen } from "@testing-library/react";
+import { OverlaysProvider } from "@blueprintjs/core";
+import "@testing-library/jest-dom";
+
+import { HandleDefault } from "../HandleDefault";
+
+jest.mock("react-flow-renderer", () => {
+ const React = require("react");
+ return {
+ Handle: React.forwardRef(
+ ({ children, isConnectable, position, type, ...props }: any, ref: React.Ref) => (
+
+ {children}
+
+ ),
+ ),
+ };
+});
+
+jest.mock("@xyflow/react", () => {
+ const React = require("react");
+ return {
+ Handle: React.forwardRef(
+ ({ children, isConnectable, position, type, ...props }: any, ref: React.Ref) => (
+
+ {children}
+
+ ),
+ ),
+ };
+});
+
+jest.mock("../../versionsupport", () => ({
+ useReactFlowVersion: () => "v9",
+}));
+
+describe("HandleDefault", () => {
+ it("shows the extended tooltip on handle hover", async () => {
+ render(
+
+
+ ,
+ );
+
+ fireEvent.mouseEnter(screen.getByTestId("handle"));
+
+ expect(await screen.findByText("This is another Tooltip")).toBeVisible();
+ });
+});