Skip to content

Commit 7d29f5a

Browse files
fix(webapp): use useFetcher for env var edits to preserve scroll/toggle state (#2847)
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 Fixes #2845 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Eric Allam <[email protected]>
1 parent 36b0762 commit 7d29f5a

File tree

1 file changed

+16
-25
lines changed
  • apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables

1 file changed

+16
-25
lines changed

apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.$projectParam.env.$envParam.environment-variables/route.tsx

Lines changed: 16 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,13 @@ import {
99
PlusIcon,
1010
TrashIcon,
1111
} from "@heroicons/react/20/solid";
12-
import { Form, type MetaFunction, Outlet, useActionData, useNavigation } from "@remix-run/react";
12+
import { Form, type MetaFunction, Outlet, useActionData, useFetcher, useNavigation } from "@remix-run/react";
1313
import {
1414
type ActionFunctionArgs,
1515
type LoaderFunctionArgs,
1616
json,
17-
redirectDocument,
1817
} from "@remix-run/server-runtime";
19-
import { useMemo, useState } from "react";
18+
import { useEffect, useMemo, useState } from "react";
2019
import { typedjson, useTypedLoaderData } from "remix-typedjson";
2120
import { z } from "zod";
2221
import { EnvironmentCombo } from "~/components/environments/EnvironmentLabel";
@@ -159,19 +158,7 @@ export const action = async ({ request, params }: ActionFunctionArgs) => {
159158
return json(submission);
160159
}
161160

162-
//use redirectDocument because it reloads the page
163-
return redirectDocument(
164-
v3EnvironmentVariablesPath(
165-
{ slug: organizationSlug },
166-
{ slug: projectParam },
167-
{ slug: envParam }
168-
),
169-
{
170-
headers: {
171-
refresh: "true",
172-
},
173-
}
174-
);
161+
return json({ ...submission, success: true });
175162
}
176163
case "delete": {
177164
const repository = new EnvironmentVariablesRepository(prisma);
@@ -417,16 +404,20 @@ function EditEnvironmentVariablePanel({
417404
revealAll: boolean;
418405
}) {
419406
const [isOpen, setIsOpen] = useState(false);
420-
const lastSubmission = useActionData();
421-
const navigation = useNavigation();
407+
const fetcher = useFetcher<typeof action>();
408+
const lastSubmission = fetcher.data as any;
422409

423-
const isLoading =
424-
navigation.state !== "idle" &&
425-
navigation.formMethod === "post" &&
426-
navigation.formData?.get("action") === "edit";
410+
const isLoading = fetcher.state !== "idle";
411+
412+
// Close dialog on successful submission
413+
useEffect(() => {
414+
if (lastSubmission?.success && fetcher.state === "idle") {
415+
setIsOpen(false);
416+
}
417+
}, [lastSubmission?.success, fetcher.state]);
427418

428419
const [form, { id, environmentId, value }] = useForm({
429-
id: "edit-environment-variable",
420+
id: `edit-environment-variable-${variable.id}-${variable.environment.id}`,
430421
// TODO: type this
431422
lastSubmission: lastSubmission as any,
432423
onValidate({ formData }) {
@@ -444,7 +435,7 @@ function EditEnvironmentVariablePanel({
444435
</DialogTrigger>
445436
<DialogContent>
446437
<DialogHeader>Edit environment variable</DialogHeader>
447-
<Form method="post" {...form.props}>
438+
<fetcher.Form method="post" {...form.props}>
448439
<input type="hidden" name="action" value="edit" />
449440
<input {...conform.input(id, { type: "hidden" })} value={variable.id} />
450441
<input
@@ -490,7 +481,7 @@ function EditEnvironmentVariablePanel({
490481
}
491482
/>
492483
</Fieldset>
493-
</Form>
484+
</fetcher.Form>
494485
</DialogContent>
495486
</Dialog>
496487
);

0 commit comments

Comments
 (0)