mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-25 09:41:04 +01:00
fix(ui): redirect agent detail page to new URL key after rename
Agent detail URLs use a name-derived key, so renaming an agent (or rolling back a config revision that restores an old name) invalidated the reference in the URL. The save handler then refetched the detail query for the stale reference, which 404s and rendered "Agent not found". On save/rollback success, compare the previous and updated route refs; when the key changed, drop the stale cached detail queries and replace the URL with the new canonical reference instead of refetching the old one. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
a4993a72a6
commit
cba11ea168
1 file changed
+37
-6
@@ -1,6 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo, useState, useRef } from "react";
|
||||
import { useParams, useNavigate, Link, Navigate, useBeforeUnload } from "@/lib/router";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { useParams, useNavigate, Link, Navigate, useBeforeUnload, type NavigateFunction } from "@/lib/router";
|
||||
import { useQuery, useMutation, useQueryClient, type QueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
agentsApi,
|
||||
type AgentKey,
|
||||
@@ -1638,6 +1638,29 @@ function CostsSection({
|
||||
|
||||
/* ---- Agent Configure Page ---- */
|
||||
|
||||
/**
|
||||
* Agent detail URLs use a name-derived key, so updates that change the agent's
|
||||
* name (a rename or a config-revision rollback) can invalidate the reference
|
||||
* currently in the URL. When that happens, refetching the old reference would
|
||||
* 404 with "Agent not found". Instead, drop the stale cached queries and
|
||||
* replace the URL with the new canonical reference. Returns true when a
|
||||
* redirect happened.
|
||||
*/
|
||||
function syncAgentRouteAfterRename(
|
||||
queryClient: QueryClient,
|
||||
navigate: NavigateFunction,
|
||||
previous: { id: string; urlKey?: string | null; name?: string | null },
|
||||
updated: { id: string; urlKey?: string | null; name?: string | null },
|
||||
tab: string,
|
||||
): boolean {
|
||||
const previousRef = agentRouteRef(previous);
|
||||
const nextRef = agentRouteRef(updated);
|
||||
if (nextRef === previousRef) return false;
|
||||
queryClient.removeQueries({ queryKey: queryKeys.agents.detail(previousRef) });
|
||||
navigate(`/agents/${nextRef}/${tab}`, { replace: true });
|
||||
return true;
|
||||
}
|
||||
|
||||
function AgentConfigurePage({
|
||||
agent,
|
||||
agentId,
|
||||
@@ -1658,6 +1681,8 @@ function AgentConfigurePage({
|
||||
updatePermissions: { mutate: (permissions: AgentPermissionUpdate) => void; isPending: boolean };
|
||||
}) {
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
const { tab: urlTab } = useParams<{ tab?: string }>();
|
||||
const [revisionsOpen, setRevisionsOpen] = useState(false);
|
||||
|
||||
const { data: configRevisions } = useQuery({
|
||||
@@ -1667,10 +1692,12 @@ function AgentConfigurePage({
|
||||
|
||||
const rollbackConfig = useMutation({
|
||||
mutationFn: (revisionId: string) => agentsApi.rollbackConfigRevision(agent.id, revisionId, companyId),
|
||||
onSuccess: () => {
|
||||
onSuccess: (updated) => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.id) });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.urlKey) });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.agents.configRevisions(agent.id) });
|
||||
if (!syncAgentRouteAfterRename(queryClient, navigate, agent, updated, urlTab ?? "configuration")) {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.urlKey) });
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
@@ -1770,6 +1797,8 @@ function ConfigurationTab({
|
||||
hideInstructionsFile?: boolean;
|
||||
}) {
|
||||
const queryClient = useQueryClient();
|
||||
const navigate = useNavigate();
|
||||
const { tab: urlTab } = useParams<{ tab?: string }>();
|
||||
const { pushToast } = useToastActions();
|
||||
const [awaitingRefreshAfterSave, setAwaitingRefreshAfterSave] = useState(false);
|
||||
const lastAgentRef = useRef(agent);
|
||||
@@ -1804,11 +1833,13 @@ function ConfigurationTab({
|
||||
onMutate: () => {
|
||||
setAwaitingRefreshAfterSave(true);
|
||||
},
|
||||
onSuccess: () => {
|
||||
onSuccess: (updated) => {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.id) });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.urlKey) });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.agents.configRevisions(agent.id) });
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.agents.list(agent.companyId) });
|
||||
if (!syncAgentRouteAfterRename(queryClient, navigate, agent, updated, urlTab ?? "configuration")) {
|
||||
queryClient.invalidateQueries({ queryKey: queryKeys.agents.detail(agent.urlKey) });
|
||||
}
|
||||
pushToast({ title: "Agent saved", tone: "success" });
|
||||
},
|
||||
onError: (err) => {
|
||||
|
||||
Reference in new issue
Block a user