fix accordion rebder bug from flippable component (#3203)
This commit is contained in:
34
skyvern-frontend/src/hooks/useRerender.ts
Normal file
34
skyvern-frontend/src/hooks/useRerender.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { useState } from "react";
|
||||
|
||||
/**
|
||||
* ```tsx
|
||||
* const { bump, key } = useRerender({ delay: 40,prefix: "my-prefix" });
|
||||
*
|
||||
* <div key={key}>...</div>
|
||||
*
|
||||
* // somewhere else
|
||||
* bump();
|
||||
* ```
|
||||
*/
|
||||
const useRerender = ({
|
||||
delay = 40,
|
||||
prefix,
|
||||
}: {
|
||||
delay?: number;
|
||||
prefix: string;
|
||||
}) => {
|
||||
const [forceRenderKey, setForceRenderKey] = useState(`${prefix}-0`);
|
||||
|
||||
const bump = () => {
|
||||
setTimeout(() => {
|
||||
setForceRenderKey((prev) => `${prefix}-${prev + 1}`);
|
||||
}, delay);
|
||||
};
|
||||
|
||||
return {
|
||||
bump,
|
||||
key: forceRenderKey,
|
||||
};
|
||||
};
|
||||
|
||||
export { useRerender };
|
||||
@@ -25,6 +25,7 @@ import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { placeholders, helpTooltips } from "../../helpContent";
|
||||
import { WorkflowBlockInputTextarea } from "@/components/WorkflowBlockInputTextarea";
|
||||
import { useRerender } from "@/hooks/useRerender";
|
||||
import { BlockCodeEditor } from "@/routes/workflows/components/BlockCodeEditor";
|
||||
import { WorkflowBlockInput } from "@/components/WorkflowBlockInput";
|
||||
import { AppNode } from "..";
|
||||
@@ -77,6 +78,7 @@ function ActionNode({ id, data, type }: NodeProps<ActionNode>) {
|
||||
const thisBlockIsPlaying =
|
||||
workflowRunIsRunningOrQueued && thisBlockIsTargetted;
|
||||
const elideFromDebugging = debugStore.isDebugMode && !debuggable;
|
||||
const rerender = useRerender({ prefix: "accordian" });
|
||||
|
||||
const nodes = useNodes<AppNode>();
|
||||
const edges = useEdges();
|
||||
@@ -189,6 +191,7 @@ function ActionNode({ id, data, type }: NodeProps<ActionNode>) {
|
||||
"pointer-events-none opacity-50": thisBlockIsPlaying,
|
||||
})}
|
||||
type="single"
|
||||
onValueChange={() => rerender.bump()}
|
||||
collapsible
|
||||
>
|
||||
<AccordionItem value="advanced" className="border-b-0">
|
||||
@@ -196,7 +199,7 @@ function ActionNode({ id, data, type }: NodeProps<ActionNode>) {
|
||||
Advanced Settings
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pl-6 pr-1 pt-1">
|
||||
<div className="space-y-4">
|
||||
<div key={rerender.key} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<ModelSelector
|
||||
className="nopan w-52 text-xs"
|
||||
|
||||
@@ -40,6 +40,7 @@ import { NodeHeader } from "../components/NodeHeader";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
||||
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
||||
import { useRerender } from "@/hooks/useRerender";
|
||||
|
||||
function ExtractionNode({ id, data, type }: NodeProps<ExtractionNode>) {
|
||||
const { updateNodeData } = useReactFlow();
|
||||
@@ -70,6 +71,7 @@ function ExtractionNode({ id, data, type }: NodeProps<ExtractionNode>) {
|
||||
const nodes = useNodes<AppNode>();
|
||||
const edges = useEdges();
|
||||
const outputParameterKeys = getAvailableOutputParameterKeys(nodes, edges, id);
|
||||
const rerender = useRerender({ prefix: "accordian" });
|
||||
|
||||
const isFirstWorkflowBlock = useIsFirstBlockInWorkflow({ id });
|
||||
|
||||
@@ -161,13 +163,17 @@ function ExtractionNode({ id, data, type }: NodeProps<ExtractionNode>) {
|
||||
}}
|
||||
/>
|
||||
<Separator />
|
||||
<Accordion type="single" collapsible>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
onValueChange={() => rerender.bump()}
|
||||
>
|
||||
<AccordionItem value="advanced" className="border-b-0">
|
||||
<AccordionTrigger className="py-0">
|
||||
Advanced Settings
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pl-6 pr-1 pt-1">
|
||||
<div className="space-y-4">
|
||||
<div key={rerender.key} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<ModelSelector
|
||||
className="nopan w-52 text-xs"
|
||||
|
||||
@@ -40,6 +40,7 @@ import { NodeHeader } from "../components/NodeHeader";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
||||
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
||||
import { useRerender } from "@/hooks/useRerender";
|
||||
|
||||
const urlTooltip =
|
||||
"The URL Skyvern is navigating to. Leave this field blank to pick up from where the last block left off.";
|
||||
@@ -77,6 +78,7 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
|
||||
engine: data.engine,
|
||||
model: data.model,
|
||||
});
|
||||
const rerender = useRerender({ prefix: "accordian" });
|
||||
const nodes = useNodes<AppNode>();
|
||||
const edges = useEdges();
|
||||
const outputParameterKeys = getAvailableOutputParameterKeys(nodes, edges, id);
|
||||
@@ -171,13 +173,17 @@ function FileDownloadNode({ id, data }: NodeProps<FileDownloadNode>) {
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<Accordion type="single" collapsible>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
onValueChange={() => rerender.bump()}
|
||||
>
|
||||
<AccordionItem value="advanced" className="border-b-0">
|
||||
<AccordionTrigger className="py-0">
|
||||
Advanced Settings
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pl-6 pr-1 pt-1">
|
||||
<div className="space-y-4">
|
||||
<div key={rerender.key} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<ModelSelector
|
||||
className="nopan w-52 text-xs"
|
||||
|
||||
@@ -43,6 +43,7 @@ import { CodeIcon, PlusIcon, MagicWandIcon } from "@radix-ui/react-icons";
|
||||
import { CurlImportDialog } from "./CurlImportDialog";
|
||||
import { QuickHeadersDialog } from "./QuickHeadersDialog";
|
||||
import { MethodBadge, UrlValidator, RequestPreview } from "./HttpUtils";
|
||||
import { useRerender } from "@/hooks/useRerender";
|
||||
|
||||
const httpMethods = [
|
||||
"GET",
|
||||
@@ -83,6 +84,7 @@ function HttpRequestNode({ id, data }: NodeProps<HttpRequestNodeType>) {
|
||||
});
|
||||
const deleteNodeCallback = useDeleteNodeCallback();
|
||||
|
||||
const rerender = useRerender({ prefix: "accordian" });
|
||||
const nodes = useNodes<AppNode>();
|
||||
const edges = useEdges();
|
||||
const outputParameterKeys = getAvailableOutputParameterKeys(nodes, edges, id);
|
||||
@@ -319,12 +321,16 @@ function HttpRequestNode({ id, data }: NodeProps<HttpRequestNodeType>) {
|
||||
|
||||
<Separator />
|
||||
|
||||
<Accordion type="single" collapsible>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
onValueChange={() => rerender.bump()}
|
||||
>
|
||||
<AccordionItem value="advanced" className="border-b-0">
|
||||
<AccordionTrigger className="py-0">
|
||||
Advanced Settings
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pl-6 pr-1 pt-1">
|
||||
<AccordionContent key={rerender.key} className="pl-6 pr-1 pt-1">
|
||||
<div className="space-y-4">
|
||||
<ParametersMultiSelect
|
||||
availableOutputParameters={outputParameterKeys}
|
||||
|
||||
@@ -41,6 +41,7 @@ import { NodeHeader } from "../components/NodeHeader";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
||||
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
||||
import { useRerender } from "@/hooks/useRerender";
|
||||
|
||||
function LoginNode({ id, data, type }: NodeProps<LoginNode>) {
|
||||
const { updateNodeData } = useReactFlow();
|
||||
@@ -73,6 +74,7 @@ function LoginNode({ id, data, type }: NodeProps<LoginNode>) {
|
||||
model: data.model,
|
||||
});
|
||||
|
||||
const rerender = useRerender({ prefix: "accordian" });
|
||||
const nodes = useNodes<AppNode>();
|
||||
const edges = useEdges();
|
||||
const outputParameterKeys = getAvailableOutputParameterKeys(nodes, edges, id);
|
||||
@@ -185,12 +187,16 @@ function LoginNode({ id, data, type }: NodeProps<LoginNode>) {
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<Accordion type="single" collapsible>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
onValueChange={() => rerender.bump()}
|
||||
>
|
||||
<AccordionItem value="advanced" className="border-b-0">
|
||||
<AccordionTrigger className="py-0">
|
||||
Advanced Settings
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pl-6 pr-1 pt-1">
|
||||
<AccordionContent key={rerender.key} className="pl-6 pr-1 pt-1">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<ModelSelector
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Separator } from "@/components/ui/separator";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { WorkflowBlockInput } from "@/components/WorkflowBlockInput";
|
||||
import { WorkflowBlockInputTextarea } from "@/components/WorkflowBlockInputTextarea";
|
||||
import { useRerender } from "@/hooks/useRerender";
|
||||
import { BlockCodeEditor } from "@/routes/workflows/components/BlockCodeEditor";
|
||||
import { CodeEditor } from "@/routes/workflows/components/CodeEditor";
|
||||
import { useBlockScriptStore } from "@/store/BlockScriptStore";
|
||||
@@ -58,6 +59,7 @@ function NavigationNode({ id, data, type }: NodeProps<NavigationNode>) {
|
||||
const thisBlockIsPlaying =
|
||||
workflowRunIsRunningOrQueued && thisBlockIsTargetted;
|
||||
const elideFromDebugging = debugStore.isDebugMode && !debuggable;
|
||||
const rerender = useRerender({ prefix: "accordian" });
|
||||
const [inputs, setInputs] = useState({
|
||||
allowDownloads: data.allowDownloads,
|
||||
cacheActions: data.cacheActions,
|
||||
@@ -194,13 +196,14 @@ function NavigationNode({ id, data, type }: NodeProps<NavigationNode>) {
|
||||
})}
|
||||
type="single"
|
||||
collapsible
|
||||
onValueChange={() => rerender.bump()}
|
||||
>
|
||||
<AccordionItem value="advanced" className="border-b-0">
|
||||
<AccordionTrigger className="py-0">
|
||||
Advanced Settings
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pl-6 pr-1 pt-1">
|
||||
<div className="space-y-4">
|
||||
<div key={rerender.key} className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<ParametersMultiSelect
|
||||
availableOutputParameters={outputParameterKeys}
|
||||
|
||||
@@ -42,6 +42,7 @@ import { NodeHeader } from "../components/NodeHeader";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
||||
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
||||
import { useRerender } from "@/hooks/useRerender";
|
||||
|
||||
function TaskNode({ id, data, type }: NodeProps<TaskNode>) {
|
||||
const { updateNodeData } = useReactFlow();
|
||||
@@ -59,6 +60,8 @@ function TaskNode({ id, data, type }: NodeProps<TaskNode>) {
|
||||
urlBlockLabel !== undefined && urlBlockLabel === label;
|
||||
const thisBlockIsPlaying =
|
||||
workflowRunIsRunningOrQueued && thisBlockIsTargetted;
|
||||
|
||||
const rerender = useRerender({ prefix: "accordian" });
|
||||
const nodes = useNodes<AppNode>();
|
||||
const edges = useEdges();
|
||||
const outputParameterKeys = getAvailableOutputParameterKeys(nodes, edges, id);
|
||||
@@ -130,10 +133,14 @@ function TaskNode({ id, data, type }: NodeProps<TaskNode>) {
|
||||
totpUrl={inputs.totpVerificationUrl}
|
||||
type={type}
|
||||
/>
|
||||
<Accordion type="multiple" defaultValue={["content", "extraction"]}>
|
||||
<Accordion
|
||||
type="multiple"
|
||||
defaultValue={["content", "extraction"]}
|
||||
onValueChange={() => rerender.bump()}
|
||||
>
|
||||
<AccordionItem value="content">
|
||||
<AccordionTrigger>Content</AccordionTrigger>
|
||||
<AccordionContent className="pl-[1.5rem] pr-1">
|
||||
<AccordionContent key={rerender.key} className="pl-[1.5rem] pr-1">
|
||||
<div className="space-y-4">
|
||||
<div className="space-y-2">
|
||||
<div className="flex justify-between">
|
||||
|
||||
@@ -21,6 +21,7 @@ import { NodeHeader } from "../components/NodeHeader";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
||||
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
||||
import { useRerender } from "@/hooks/useRerender";
|
||||
|
||||
function Taskv2Node({ id, data, type }: NodeProps<Taskv2Node>) {
|
||||
const { debuggable, editable, label } = data;
|
||||
@@ -36,6 +37,7 @@ function Taskv2Node({ id, data, type }: NodeProps<Taskv2Node>) {
|
||||
workflowRunIsRunningOrQueued && thisBlockIsTargetted;
|
||||
const { updateNodeData } = useReactFlow();
|
||||
const isFirstWorkflowBlock = useIsFirstBlockInWorkflow({ id });
|
||||
const rerender = useRerender({ prefix: "accordian" });
|
||||
|
||||
const [inputs, setInputs] = useState({
|
||||
prompt: data.prompt,
|
||||
@@ -122,12 +124,16 @@ function Taskv2Node({ id, data, type }: NodeProps<Taskv2Node>) {
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
<Accordion type="single" collapsible>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
onValueChange={() => rerender.bump()}
|
||||
>
|
||||
<AccordionItem value="advanced" className="border-b-0">
|
||||
<AccordionTrigger className="py-0">
|
||||
Advanced Settings
|
||||
</AccordionTrigger>
|
||||
<AccordionContent className="pl-6 pr-1 pt-4">
|
||||
<AccordionContent key={rerender.key} className="pl-6 pr-1 pt-4">
|
||||
<div className="space-y-4">
|
||||
<ModelSelector
|
||||
className="nopan w-52 text-xs"
|
||||
|
||||
@@ -38,6 +38,7 @@ import { NodeHeader } from "../components/NodeHeader";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { statusIsRunningOrQueued } from "@/routes/tasks/types";
|
||||
import { useWorkflowRunQuery } from "@/routes/workflows/hooks/useWorkflowRunQuery";
|
||||
import { useRerender } from "@/hooks/useRerender";
|
||||
|
||||
function ValidationNode({ id, data, type }: NodeProps<ValidationNode>) {
|
||||
const { updateNodeData } = useReactFlow();
|
||||
@@ -61,6 +62,8 @@ function ValidationNode({ id, data, type }: NodeProps<ValidationNode>) {
|
||||
errorCodeMapping: data.errorCodeMapping,
|
||||
model: data.model,
|
||||
});
|
||||
|
||||
const rerender = useRerender({ prefix: "accordian" });
|
||||
const nodes = useNodes<AppNode>();
|
||||
const edges = useEdges();
|
||||
const outputParameterKeys = getAvailableOutputParameterKeys(nodes, edges, id);
|
||||
@@ -143,13 +146,17 @@ function ValidationNode({ id, data, type }: NodeProps<ValidationNode>) {
|
||||
/>
|
||||
</div>
|
||||
<Separator />
|
||||
<Accordion type="single" collapsible>
|
||||
<Accordion
|
||||
type="single"
|
||||
collapsible
|
||||
onValueChange={() => rerender.bump()}
|
||||
>
|
||||
<AccordionItem value="advanced" className="border-b-0">
|
||||
<AccordionTrigger className="py-0">
|
||||
Advanced Settings
|
||||
</AccordionTrigger>
|
||||
<AccordionContent>
|
||||
<div className="ml-6 mt-4 space-y-4">
|
||||
<div key={rerender.key} className="ml-6 mt-4 space-y-4">
|
||||
<div className="space-y-2">
|
||||
<ModelSelector
|
||||
className="nopan mr-[1px] w-52 text-xs"
|
||||
|
||||
Reference in New Issue
Block a user