fix(sheets): auto-extend grid + friendlier error for rich writes that overflow column count (#5613)

This commit is contained in:
Aaron Perez 2026-04-22 21:44:18 -05:00 committed by GitHub
parent 4bd49d0afa
commit 051b96d661
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 260 additions and 1 deletions

View file

@ -7,6 +7,8 @@ import {
useNodes,
useReactFlow,
} from "@xyflow/react";
import { ReloadIcon } from "@radix-ui/react-icons";
import { useParams } from "react-router-dom";
import type { StartNode } from "./types";
import { AppNode } from "..";
import {
@ -15,6 +17,16 @@ import {
AccordionItem,
AccordionTrigger,
} from "@/components/ui/accordion";
import {
Dialog,
DialogClose,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import {
Select,
SelectContent,
@ -41,6 +53,7 @@ import { MAX_SCREENSHOT_SCROLLS_DEFAULT } from "../Taskv2Node/types";
import { KeyValueInput } from "@/components/KeyValueInput";
import { placeholders } from "@/routes/workflows/editor/helpContent";
import { useToggleScriptForNodeCallback } from "@/routes/workflows/hooks/useToggleScriptForNodeCallback";
import { useResetProfileMutation } from "@/routes/workflows/hooks/useResetProfileMutation";
import { useWorkflowSettingsStore } from "@/store/WorkflowSettingsStore";
import { Flippable } from "@/components/Flippable";
import { useRerender } from "@/hooks/useRerender";
@ -69,12 +82,19 @@ function StartNode({ id, data, parentId }: NodeProps<StartNode>) {
const nodes = useNodes<AppNode>();
const edges = useEdges();
const [facing, setFacing] = useState<"front" | "back">("front");
const [isResetProfileDialogOpen, setIsResetProfileDialogOpen] =
useState(false);
const { workflowPermanentId } = useParams();
const blockScriptStore = useBlockScriptStore();
const recordingStore = useRecordingStore();
const script = blockScriptStore.scripts.__start_block__;
const rerender = useRerender({ prefix: "accordion" });
const toggleScriptForNodeCallback = useToggleScriptForNodeCallback();
const isRecording = recordingStore.isRecording;
const resetProfileMutation = useResetProfileMutation({
workflowPermanentId,
onSuccess: () => setIsResetProfileDialogOpen(false),
});
// Local state for webhook URL to fix race condition where data.webhookCallbackUrl
// isn't updated yet when user clicks "Test Webhook" after typing
@ -394,6 +414,52 @@ function StartNode({ id, data, parentId }: NodeProps<StartNode>) {
}}
/>
</div>
{data.persistBrowserSession && workflowPermanentId && (
<Dialog
open={isResetProfileDialogOpen}
onOpenChange={setIsResetProfileDialogOpen}
>
<DialogTrigger asChild>
<Button
type="button"
variant="secondary"
size="sm"
className="nopan"
>
<ReloadIcon className="mr-2 h-3 w-3" />
Reset Profile
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Reset saved profile?</DialogTitle>
<DialogDescription>
Clears the saved browser profile for this
workflow. The next run will start from a fresh
browser state. Use this if the saved profile
is stuck or producing errors.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<DialogClose asChild>
<Button variant="secondary">Cancel</Button>
</DialogClose>
<Button
variant="destructive"
onClick={() => {
resetProfileMutation.mutate();
}}
disabled={resetProfileMutation.isPending}
>
{resetProfileMutation.isPending && (
<ReloadIcon className="mr-2 h-4 w-4 animate-spin" />
)}
Reset Profile
</Button>
</DialogFooter>
</DialogContent>
</Dialog>
)}
</div>
<div className="space-y-2">
<div className="flex items-center gap-2">

View file

@ -0,0 +1,49 @@
import { useMutation } from "@tanstack/react-query";
import { isAxiosError } from "axios";
import { getClient } from "@/api/AxiosClient";
import { toast } from "@/components/ui/use-toast";
import { useCredentialGetter } from "@/hooks/useCredentialGetter";
const useResetProfileMutation = ({
workflowPermanentId,
onSuccess,
}: {
workflowPermanentId?: string;
onSuccess?: () => void;
}) => {
const credentialGetter = useCredentialGetter();
return useMutation({
mutationFn: async () => {
if (!workflowPermanentId) {
throw new Error("workflowPermanentId is required");
}
const client = await getClient(credentialGetter, "sans-api-v1");
return client
.post(`/workflows/${workflowPermanentId}/browser_session/reset_profile`)
.then((response) => response.data);
},
onSuccess: () => {
toast({
variant: "success",
title: "Profile Reset",
description:
"The saved browser profile has been cleared. The next run will start with a fresh session.",
});
onSuccess?.();
},
onError: (error) => {
const description = isAxiosError(error)
? (error.response?.data?.detail ?? error.message)
: error.message;
toast({
variant: "destructive",
title: "Failed to Reset Profile",
description,
});
},
});
};
export { useResetProfileMutation };