fix(rnd): Fix jumping caret problem on builder input text field (#7917)

Issue 1:
Input text field cursor keeps moving to the end of the text.
Try to type "Hello World!" into the input text. Then try to type "some string" in the middle of the "Hello" and "World".

Issue 2:
History should only tracks on the input box onBlur/onLeave
Try to type a "longcharacters" and try to undo it, the undo is removing 1 character at a time, polluting the history, and make the undo pretty much unusable.

Issue 3:
KeyValue & ArrayInput is non-undoable.
Try to add key-value or add an entry to the list, it doesn't undo the value, but you need to click as many number of entries being added to make the undo work again
This commit is contained in:
Zamil Majdy
2024-08-29 08:12:10 -05:00
committed by GitHub
parent 7de12a2200
commit 5da58aa284
3 changed files with 41 additions and 25 deletions

View File

@@ -10,7 +10,7 @@ import {
BlockIONumberSubSchema,
BlockIOBooleanSubSchema,
} from "@/lib/autogpt-server-api/types";
import { FC, useState } from "react";
import { FC, useEffect, useState } from "react";
import { Button } from "./ui/button";
import { Switch } from "./ui/switch";
import {
@@ -296,23 +296,31 @@ const NodeKeyValueInput: FC<{
className,
displayName,
}) => {
let defaultEntries = new Map<string, any>();
connections
.filter((c) => c.targetHandle.startsWith(`${selfKey}_`))
.forEach((c) => {
const key = c.targetHandle.slice(`${selfKey}_#_`.length);
defaultEntries.set(key, "");
const getPairValues = () => {
let defaultEntries = new Map<string, any>();
connections
.filter((c) => c.targetHandle.startsWith(`${selfKey}_`))
.forEach((c) => {
const key = c.targetHandle.slice(`${selfKey}_#_`.length);
defaultEntries.set(key, "");
});
Object.entries(entries ?? schema.default ?? {}).forEach(([key, value]) => {
defaultEntries.set(key, value);
});
Object.entries(entries ?? schema.default ?? {}).forEach(([key, value]) => {
defaultEntries.set(key, value);
});
return Array.from(defaultEntries, ([key, value]) => ({ key, value }));
};
const [keyValuePairs, setKeyValuePairs] = useState<
{
key: string;
value: string | number | null;
}[]
>(Array.from(defaultEntries, ([key, value]) => ({ key, value })));
{ key: string; value: string | number | null }[]
>([]);
useEffect(
() => setKeyValuePairs(getPairValues()),
[connections, entries, schema.default],
);
function updateKeyValuePairs(newPairs: typeof keyValuePairs) {
setKeyValuePairs(newPairs);
@@ -373,7 +381,7 @@ const NodeKeyValueInput: FC<{
type="text"
placeholder="Value"
value={value ?? ""}
onChange={(e) =>
onBlur={(e) =>
updateKeyValuePairs(
keyValuePairs.toSpliced(index, 1, {
key: key,
@@ -560,7 +568,7 @@ const NodeStringInput: FC<{
placeholder={
schema?.placeholder || `Enter ${beautifyString(displayName)}`
}
onChange={(e) => handleInputChange(selfKey, e.target.value)}
onBlur={(e) => handleInputChange(selfKey, e.target.value)}
className="pr-8 read-only:cursor-pointer read-only:text-gray-500"
/>
<Button
@@ -605,9 +613,7 @@ const NodeNumberInput: FC<{
type="number"
id={selfKey}
value={value}
onChange={(e) =>
handleInputChange(selfKey, parseFloat(e.target.value))
}
onBlur={(e) => handleInputChange(selfKey, parseFloat(e.target.value))}
placeholder={
schema.placeholder || `Enter ${beautifyString(displayName)}`
}

View File

@@ -6,7 +6,16 @@ export interface InputProps
extends React.InputHTMLAttributes<HTMLInputElement> {}
const Input = React.forwardRef<HTMLInputElement, InputProps>(
({ className, type, ...props }, ref) => {
({ className, type, value, ...props }, ref) => {
// This ref allows the `Input` component to be both controlled and uncontrolled.
// The HTMLvalue will only be updated if the value prop changes, but the user can still type in the input.
ref = ref || React.createRef<HTMLInputElement>();
React.useEffect(() => {
if (ref?.current?.value !== value) {
console.log("Value changed from", ref?.current?.value, "to", value);
ref.current.value = value;
}
}, [value]);
return (
<input
type={type}
@@ -16,6 +25,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
className,
)}
ref={ref}
defaultValue={value}
{...props}
/>
);

View File

@@ -24,7 +24,7 @@ class ExecutionScheduler(AppService):
self.refresh_interval = refresh_interval
@property
def execution_manager_client(self):
def execution_manager_client(self) -> ExecutionManager:
return get_service_client(ExecutionManager)
def run_service(self):
@@ -49,15 +49,15 @@ class ExecutionScheduler(AppService):
self.__execute_graph,
CronTrigger.from_crontab(schedule.schedule),
id=schedule.id,
args=[schedule.graph_id, schedule.input_data],
args=[schedule.graph_id, schedule.input_data, schedule.user_id],
replace_existing=True,
)
def __execute_graph(self, graph_id: str, input_data: dict):
def __execute_graph(self, graph_id: str, input_data: dict, user_id: str):
try:
log(f"Executing recurring job for graph #{graph_id}")
execution_manager = self.execution_manager_client
execution_manager.add_execution(graph_id, input_data)
execution_manager.add_execution(graph_id, input_data, user_id)
except Exception as e:
logger.exception(f"Error executing graph {graph_id}: {e}")