Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,15 @@
.dec-root .react-flow__pane:active {
cursor: grabbing !important;
}

/* hide handles in read-only mode */
.dec-root .read-only .react-flow__handle {
visibility: hidden !important;
width: 0 !important;
height: 0 !important;
min-width: 0 !important;
min-height: 0 !important;
}
}

/* custom nodes */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export type DiagramProps = {

export const Diagram = ({ divRef, ref, colorMode = "light" }: DiagramProps) => {
const reactFlowInstance: RF.ReactFlowInstance = RF.useReactFlow();
const { model, nodes, edges, setNodes, setEdges } = useDiagramEditorContext();
const { model, nodes, edges, isReadOnly, setNodes, setEdges } = useDiagramEditorContext();

const [minimapVisible, setMinimapVisible] = React.useState(false);

Expand Down Expand Up @@ -126,7 +126,13 @@ export const Diagram = ({ divRef, ref, colorMode = "light" }: DiagramProps) => {
}, [model, reactFlowInstance, setNodes, setEdges]);

return (
<div ref={divRef} className="dec:h-full dec:relative" data-testid={"diagram-container"}>
<div
ref={divRef}
className={["dec:h-full", "dec:relative", isReadOnly && "read-only"]
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we are mixing strings and boolean in the same array.
if we are only conditionally adding read-only , can we use a ternary condition to make it more readable?

.filter(Boolean)
.join(" ")}
data-testid={"diagram-container"}
>
Comment thread
handreyrc marked this conversation as resolved.
<RF.ReactFlow
nodeTypes={ReactFlowNodeTypes}
nodes={nodes}
Expand All @@ -151,6 +157,8 @@ export const Diagram = ({ divRef, ref, colorMode = "light" }: DiagramProps) => {
},
}}
data-testid={"react-flow-canvas"}
nodesDraggable={!isReadOnly}
nodesConnectable={!isReadOnly}
>
{minimapVisible && <RF.MiniMap pannable zoomable position={"top-right"} />}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,35 @@ import { en } from "../../../src/i18n/locales/en";
import { ReactFlowProvider } from "@xyflow/react";
import * as autoLayoutModule from "../../../src/react-flow/diagram/autoLayout";

/**
* Helper function to render the Diagram component with all required providers
* @param options - Configuration options for the diagram
* @param options.isReadOnly - Whether the diagram should be in read-only mode
* @param options.content - The workflow content to render
* @param options.locale - The locale to use for i18n
*/
function renderDiagram({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering is it worth moving this to common render-helpers file, there is some crossover with providers there taht could be used or you think thats overkill and should just stay here, wdyt?

isReadOnly = true,
content = "",
locale = "en",
}: {
isReadOnly?: boolean;
content?: string;
locale?: string;
} = {}) {
return render(
<ReactFlowProvider>
<DiagramEditorContextProvider content={content} isReadOnly={isReadOnly} locale={locale}>
<I18nProvider locale="en" dictionaries={{ en }}>
<SidebarProvider>
<Diagram />
</SidebarProvider>
</I18nProvider>
</DiagramEditorContextProvider>
</ReactFlowProvider>,
);
}

describe("Diagram Component", () => {
let applyAutoLayoutSpy: ReturnType<typeof vi.spyOn>;

Expand All @@ -40,17 +69,7 @@ describe("Diagram Component", () => {
});

it("render Diagram component and canvas", async () => {
render(
<ReactFlowProvider>
<DiagramEditorContextProvider content={""} isReadOnly={true} locale={"en"}>
<I18nProvider locale="en" dictionaries={{ en }}>
<SidebarProvider>
<Diagram />
</SidebarProvider>
</I18nProvider>
</DiagramEditorContextProvider>
</ReactFlowProvider>,
);
renderDiagram({ isReadOnly: true });

const diagram = screen.getByTestId("diagram-container");
const canvas = screen.getByTestId("react-flow-canvas");
Expand All @@ -63,4 +82,75 @@ describe("Diagram Component", () => {
expect(applyAutoLayoutSpy).toHaveBeenCalled();
});
});

it("should apply read-only class when isReadOnly is true", async () => {
renderDiagram({ isReadOnly: true });

const diagram = screen.getByTestId("diagram-container");

// Verify that the read-only class is applied
expect(diagram).toHaveClass("read-only");

await waitFor(() => {
expect(applyAutoLayoutSpy).toHaveBeenCalled();
});
});

it("should not apply read-only class when isReadOnly is false", async () => {
renderDiagram({ isReadOnly: false });

const diagram = screen.getByTestId("diagram-container");

// Verify that the read-only class is not applied
expect(diagram).not.toHaveClass("read-only");

await waitFor(() => {
expect(applyAutoLayoutSpy).toHaveBeenCalled();
});
});

it("should disable node interaction when isReadOnly is true", async () => {
renderDiagram({ isReadOnly: true });

const diagram = screen.getByTestId("diagram-container");

// Verify that the read-only class is applied
// This class applies CSS rule: .read-only .react-flow__handle { visibility: hidden !important; }
expect(diagram).toHaveClass("read-only");

// Verify ReactFlow canvas is rendered
const canvas = screen.getByTestId("react-flow-canvas");
expect(canvas).toBeInTheDocument();

// Note: The actual CSS visibility of handles cannot be tested in JSDOM as it doesn't apply stylesheets.
// The read-only behavior is enforced through:
// 1. CSS class "read-only" which hides .react-flow__handle elements
// 2. ReactFlow props nodesDraggable={false} and nodesConnectable={false}
// For full verification of handle visibility, use e2e tests where CSS is applied.

await waitFor(() => {
expect(applyAutoLayoutSpy).toHaveBeenCalled();
});
});

it("should enable node interaction when isReadOnly is false", async () => {
renderDiagram({ isReadOnly: false });

const diagram = screen.getByTestId("diagram-container");

// Verify that the read-only class is not applied
expect(diagram).not.toHaveClass("read-only");

// Verify ReactFlow canvas is rendered
const canvas = screen.getByTestId("react-flow-canvas");
expect(canvas).toBeInTheDocument();

// Note: When read-only class is not present, handles are visible via CSS
// and ReactFlow props nodesDraggable={true} and nodesConnectable={true} enable interaction.
// For full verification of handle visibility and interaction, use e2e tests.

await waitFor(() => {
expect(applyAutoLayoutSpy).toHaveBeenCalled();
});
});
});
Loading