closes SKY-155 - adds autopan to workflow editor (#2331)

This commit is contained in:
Shuchang Zheng
2025-05-12 12:34:00 -07:00
committed by GitHub
parent 1d1a4d72ea
commit 4889e8db24
2 changed files with 65 additions and 1 deletions

View File

@@ -30,7 +30,7 @@ import {
import "@xyflow/react/dist/style.css";
import { AxiosError } from "axios";
import { nanoid } from "nanoid";
import { useEffect, useState } from "react";
import { useEffect, useRef, useState } from "react";
import { useBlocker, useParams } from "react-router-dom";
import { stringify as convertToYAML } from "yaml";
import {
@@ -85,6 +85,7 @@ import {
startNode,
} from "./workflowEditorUtils";
import { parameterIsBitwardenCredential, ParametersState } from "./types";
import { useAutoPan } from "./useAutoPan";
function convertToParametersYAML(
parameters: ParametersState,
@@ -494,6 +495,10 @@ function FlowRenderer({
doLayout(newNodesWithUpdatedParameters, newEdges);
}
const editorElementRef = useRef<HTMLDivElement>(null);
useAutoPan(editorElementRef, nodes);
return (
<>
<Dialog
@@ -542,6 +547,7 @@ function FlowRenderer({
>
<DeleteNodeCallbackContext.Provider value={deleteNode}>
<ReactFlow
ref={editorElementRef}
nodes={nodes}
edges={edges}
onNodesChange={(changes) => {

View File

@@ -0,0 +1,58 @@
import { useReactFlow } from "@xyflow/react";
import { useLayoutEffect } from "react";
import { AppNode } from "./nodes";
/**
* Some facts:
* - the workflow editor is rendered as an infinite canvas
* - nodes in the editor can have text fields
* - users type in those text fields
* - the browser will automatically attempt to scroll to a caret position when
* the caret leaves the viewport, because it is Being A Good Browser(tm)
* - this causes layout artifacts on the infinite canvas
*
* `useAutoPan` detects when the viewport is scrolled. (But it should never have
* a scroll, as it is an infinite canvas!) If a scroll value is detected, then
* we pan the viewport to counteract the scroll, and set the scroll to 0.
*
* The end result is that:
* - if a user is typing in any textual HTML element, and they scroll beyond
* the viewport, the viewport will animate-pan to counteract the scroll
* - if the user pastes large amounts of text into any textual HTML element,
* the viewport will animate-pan to counteract the scroll
*
* `editorElementRef`: a ref to the top-level editor element (the top-level div
* for react-flow, at time of writing)
*
* `nodes`: `AppNode`s; but could be anything that carries state indicative of a
* change in the editor
*/
const useAutoPan = (
editorElementRef: React.RefObject<HTMLDivElement>,
nodes: AppNode[],
) => {
const { setViewport, getViewport } = useReactFlow();
useLayoutEffect(() => {
const editorElement = editorElementRef.current;
if (editorElement) {
const scrollTop = editorElement.scrollTop;
if (scrollTop === 0) {
return;
}
editorElement.scrollTop = 0;
const { x, y, zoom } = getViewport();
const panAmount = editorElement.clientHeight * 0.3;
setViewport(
{ x, y: y - (scrollTop + panAmount), zoom },
{ duration: 300 },
);
}
}, [nodes, editorElementRef, setViewport, getViewport]);
};
export { useAutoPan };