From 32e371c5fcafdd12e7b0c5d0a7726beddda2ce25 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 8 Jan 2026 11:07:07 +0000 Subject: [PATCH] fix(webapp): use useFetcher for env var edits to preserve scroll/toggle state MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replaces `redirectDocument` with `useFetcher` for editing environment variables. This allows background form submission without full page reload, which preserves: - Scroll position in the env vars list - "Reveal values" toggle state - Search filter state Changes: - EditEnvironmentVariablePanel now uses `useFetcher` instead of `Form` - Action returns `json({ success: true })` instead of `redirectDocument` - Dialog auto-closes on successful submission via useEffect - Form ID is now unique per variable to prevent conflicts Fixes #2845 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Eric Allam --- .../route.tsx | 41 ++++++++----------- 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx index edef3d3060..80976d41fc 100644 --- a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx @@ -9,14 +9,13 @@ import { PlusIcon, TrashIcon, } from "@heroicons/react/20/solid"; -import { Form, type MetaFunction, Outlet, useActionData, useNavigation } from "@remix-run/react"; +import { Form, type MetaFunction, Outlet, useActionData, useFetcher, useNavigation } from "@remix-run/react"; import { type ActionFunctionArgs, type LoaderFunctionArgs, json, - redirectDocument, } from "@remix-run/server-runtime"; -import { useMemo, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import { typedjson, useTypedLoaderData } from "remix-typedjson"; import { z } from "zod"; import { EnvironmentCombo } from "~/components/environments/EnvironmentLabel"; @@ -159,19 +158,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => { return json(submission); } - //use redirectDocument because it reloads the page - return redirectDocument( - v3EnvironmentVariablesPath( - { slug: organizationSlug }, - { slug: projectParam }, - { slug: envParam } - ), - { - headers: { - refresh: "true", - }, - } - ); + return json({ ...submission, success: true }); } case "delete": { const repository = new EnvironmentVariablesRepository(prisma); @@ -417,16 +404,20 @@ function EditEnvironmentVariablePanel({ revealAll: boolean; }) { const [isOpen, setIsOpen] = useState(false); - const lastSubmission = useActionData(); - const navigation = useNavigation(); + const fetcher = useFetcher(); + const lastSubmission = fetcher.data as any; - const isLoading = - navigation.state !== "idle" && - navigation.formMethod === "post" && - navigation.formData?.get("action") === "edit"; + const isLoading = fetcher.state !== "idle"; + + // Close dialog on successful submission + useEffect(() => { + if (lastSubmission?.success && fetcher.state === "idle") { + setIsOpen(false); + } + }, [lastSubmission?.success, fetcher.state]); const [form, { id, environmentId, value }] = useForm({ - id: "edit-environment-variable", + id: `edit-environment-variable-${variable.id}-${variable.environment.id}`, // TODO: type this lastSubmission: lastSubmission as any, onValidate({ formData }) { @@ -444,7 +435,7 @@ function EditEnvironmentVariablePanel({ Edit environment variable -
+ - +
);