feature: Add scroll detection for NodeDescription overflow and remove feature flag (#3676)

* feat: Add scroll detection for NodeDescription overflow

* style: update CSS to hide non-selected note nodes

* remove feature flag

* [autofix.ci] apply automated fixes

* refactor: update feature flags and test IDs

- Update ENABLE_MVPS flag to false in feature-flags.ts
- Update testId from "extended-disclosure" to "bundle-extended-disclosure" in extraSidebarComponent/index.tsx

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
anovazzi1 2024-09-09 13:30:36 -03:00 • committed by GitHub
commit ed3306fb7e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 79 additions and 59 deletions

View file

@ -3,7 +3,7 @@ import useFlowsManagerStore from "@/stores/flowsManagerStore";
import useFlowStore from "@/stores/flowStore"; import useFlowStore from "@/stores/flowStore";
import { handleKeyDown } from "@/utils/reactflowUtils"; import { handleKeyDown } from "@/utils/reactflowUtils";
import { cn } from "@/utils/utils"; import { cn } from "@/utils/utils";
import { useEffect, useState } from "react"; import { useEffect, useRef, useState } from "react";
import Markdown from "react-markdown"; import Markdown from "react-markdown";
export default function NodeDescription({ export default function NodeDescription({
@ -29,6 +29,27 @@ export default function NodeDescription({
const [nodeDescription, setNodeDescription] = useState(description); const [nodeDescription, setNodeDescription] = useState(description);
const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot); const takeSnapshot = useFlowsManagerStore((state) => state.takeSnapshot);
const setNode = useFlowStore((state) => state.setNode); const setNode = useFlowStore((state) => state.setNode);
const overflowRef = useRef<HTMLDivElement>(null);
const [hasScroll, sethasScroll] = useState(false);
useEffect(() => {
//timeout to wait for the dom to update
setTimeout(() => {
if (overflowRef.current) {
console.log(
overflowRef.current.clientHeight,
overflowRef.current.scrollHeight,
);
if (
overflowRef.current.clientHeight < overflowRef.current.scrollHeight
) {
sethasScroll(true);
} else {
sethasScroll(false);
}
}
}, 200);
}, [inputDescription]);
useEffect(() => { useEffect(() => {
if (!selected) { if (!selected) {
@ -45,6 +66,7 @@ export default function NodeDescription({
className={cn( className={cn(
"generic-node-desc", "generic-node-desc",
!inputDescription ? "overflow-auto" : "", !inputDescription ? "overflow-auto" : "",
hasScroll ? "nowheel" : "",
)} )}
> >
{inputDescription ? ( {inputDescription ? (
@ -109,6 +131,7 @@ export default function NodeDescription({
</> </>
) : ( ) : (
<div <div
ref={overflowRef}
className={cn( className={cn(
"nodoubleclick generic-node-desc-text h-full cursor-text word-break-break-word dark:text-note-placeholder", "nodoubleclick generic-node-desc-text h-full cursor-text word-break-break-word dark:text-note-placeholder",
description === "" || !description ? "font-light italic" : "", description === "" || !description ? "font-light italic" : "",

View file

@ -33,7 +33,6 @@ function NoteNode({
}); });
} }
}, []); }, []);
const MemoNoteToolbarComponent = useMemo( const MemoNoteToolbarComponent = useMemo(
() => ( () => (
<NodeToolbar> <NodeToolbar>
@ -69,7 +68,7 @@ function NoteNode({
ref={nodeDiv} ref={nodeDiv}
className={cn( className={cn(
"flex h-full w-full flex-col gap-3 rounded-md border border-b p-5 transition-all", "flex h-full w-full flex-col gap-3 rounded-md border border-b p-5 transition-all",
selected ? "" : "shadow-sm", selected ? "" : "-z-50 shadow-sm",
)} )}
> >
<div className="flex h-fit w-full items-center align-middle"> <div className="flex h-fit w-full items-center align-middle">
@ -92,7 +91,6 @@ function NoteNode({
width: size.width, width: size.width,
height: size.height, height: size.height,
}} }}
className="nowheel overflow-auto"
> >
<NodeDescription <NodeDescription
inputClassName="border-0 ring-transparent resize-none rounded-none shadow-none h-full w-full" inputClassName="border-0 ring-transparent resize-none rounded-none shadow-none h-full w-full"

View file

@ -475,59 +475,58 @@ export default function Page({ view }: { view?: boolean }): JSX.Element {
<Background className="" /> <Background className="" />
{!view && ( {!view && (
<Controls className="fill-foreground stroke-foreground text-primary [&>button]:border-b-border [&>button]:bg-muted hover:[&>button]:bg-border"> <Controls className="fill-foreground stroke-foreground text-primary [&>button]:border-b-border [&>button]:bg-muted hover:[&>button]:bg-border">
{ENABLE_MVPS && ( <ControlButton
<ControlButton data-testid="add_note"
data-testid="add_note" onClick={() => {
onClick={() => { const wrapper = reactFlowWrapper.current!;
const wrapper = reactFlowWrapper.current!; const viewport = reactFlowInstance?.getViewport();
const x = wrapper.getBoundingClientRect().width / 2; const x = wrapper.getBoundingClientRect().width / 2;
const y = wrapper.getBoundingClientRect().height / 2; const y = wrapper.getBoundingClientRect().height / 2;
const nodePosition = const nodePosition =
reactFlowInstance?.screenToFlowPosition({ x, y })!; reactFlowInstance?.screenToFlowPosition({ x, y })!;
const data = { const data = {
node: { node: {
description: "", description: "",
display_name: "", display_name: "",
documentation: "", documentation: "",
template: {}, template: {},
}, },
type: "note", type: "note",
}; };
const newId = getNodeId(data.type); const newId = getNodeId(data.type);
const newNode: NodeType = { const newNode: NodeType = {
id: newId,
type: "noteNode",
position: { x: 0, y: 0 },
data: {
...data,
id: newId, id: newId,
type: "noteNode", },
position: { x: 0, y: 0 }, };
data: { paste(
...data, { nodes: [newNode], edges: [] },
id: newId, {
}, x: nodePosition.x,
}; y: nodePosition?.y,
paste( paneX: wrapper.getBoundingClientRect().x,
{ nodes: [newNode], edges: [] }, paneY: wrapper.getBoundingClientRect().y,
{ },
x: nodePosition.x, );
y: nodePosition?.y, }}
paneX: wrapper.getBoundingClientRect().x, className="postion absolute -top-10 rounded-sm"
paneY: wrapper.getBoundingClientRect().y, >
}, <ShadTooltip content="Add note">
); <div>
}} <IconComponent
className="postion absolute -top-10 rounded-sm" name="SquarePen"
> aria-hidden="true"
<ShadTooltip content="Add note"> className="scale-125"
<div> />
<IconComponent </div>
name="SquarePen" </ShadTooltip>
aria-hidden="true" </ControlButton>
className="scale-125"
/>
</div>
</ShadTooltip>
</ControlButton>
)}
</Controls> </Controls>
)} )}
<SelectionMenu <SelectionMenu

View file

@ -316,7 +316,7 @@ export default function ExtraSidebar(): JSX.Element {
title: "Bundles", title: "Bundles",
Icon: nodeIconsLucide.unknown, Icon: nodeIconsLucide.unknown,
}} }}
testId="extended-disclosure" testId="bundle-extended-disclosure"
> >
{Object.keys(dataFilter) {Object.keys(dataFilter)
.sort(sortKeys) .sort(sortKeys)

View file

@ -162,3 +162,7 @@ textarea[class^="ag-"]:focus {
.react-flow__node.dragging * { .react-flow__node.dragging * {
cursor: grabbing !important; cursor: grabbing !important;
} }
.react-flow__node-noteNode:not(.selected){
z-index: -1 !important;
}

View file

@ -3,10 +3,6 @@ import { expect, test } from "@playwright/test";
import uaParser from "ua-parser-js"; import uaParser from "ua-parser-js";
test("user should be able to interact with sticky notes", async ({ page }) => { test("user should be able to interact with sticky notes", async ({ page }) => {
// prevent test from failing if feature flag is disabled
if (!ENABLE_MVPS) {
return;
}
await page.goto("/"); await page.goto("/");
await page.waitForSelector('[data-testid="mainpage_title"]', { await page.waitForSelector('[data-testid="mainpage_title"]', {
timeout: 30000, timeout: 30000,