diff --git a/src/components/admin/review-row.tsx b/src/components/admin/review-row.tsx index 6929ecd..db54ba4 100644 --- a/src/components/admin/review-row.tsx +++ b/src/components/admin/review-row.tsx @@ -18,6 +18,7 @@ import { Checkbox } from "@/components/ui/checkbox" import type { SchemaNode } from "@/app/ontology/page" import { DISPLAY_KEY_FALLBACKS, pickString } from "@/lib/node-display" import { useUserStore } from "@/stores/user-store" +import { useGraphStore } from "@/stores/graph-store" // ── Status badge ────────────────────────────────────────────────────────────── @@ -478,6 +479,7 @@ export function ReviewRow({ selectionLockedReason, }: ReviewRowProps) { const router = useRouter() + const setReturnTo = useGraphStore((s) => s.setReturnTo) const { isAdmin } = useUserStore() const [expanded, setExpanded] = useState(false) const [approving, setApproving] = useState(false) @@ -669,7 +671,7 @@ export function ReviewRow({ refId={id} resolved={subjectMap.get(id)} schemas={schemas} - onClick={() => router.push(`/?ref=${id}`)} + onClick={() => { setReturnTo('/admin/reviews'); router.push(`/?id=${id}`) }} /> ))} @@ -685,7 +687,7 @@ export function ReviewRow({ refId={direction.toId} resolved={subjectMap.get(direction.toId)} schemas={schemas} - onClick={() => router.push(`/?ref=${direction.toId}`)} + onClick={() => { setReturnTo('/admin/reviews'); router.push(`/?id=${direction.toId}`) }} /> @@ -824,7 +826,7 @@ export function ReviewRow({ refId={subject.ref_id} resolved={subject} schemas={schemas} - onClick={() => router.push(`/?ref=${subject.ref_id}`)} + onClick={() => { setReturnTo('/admin/reviews'); router.push(`/?id=${subject.ref_id}`) }} /> )} @@ -977,7 +979,7 @@ export function ReviewRow({ refId={sn.ref_id} resolved={sn} schemas={schemas} - onClick={() => router.push(`/?ref=${sn.ref_id}`)} + onClick={() => { setReturnTo('/admin/reviews'); router.push(`/?id=${sn.ref_id}`) }} /> ))} diff --git a/src/components/layout/left-pane.tsx b/src/components/layout/left-pane.tsx index 285ac0d..2d0f487 100644 --- a/src/components/layout/left-pane.tsx +++ b/src/components/layout/left-pane.tsx @@ -12,12 +12,16 @@ import { NodePreviewPanel } from "./node-preview-panel" import { cn } from "@/lib/utils" import { AgentPanel } from "@/components/agent/agent-panel" import { WorkflowsPanel } from "./workflows-panel" +import { useRouter } from "next/navigation" type Mode = "preview" | "sources" | "mycontent" | "clips" | "following" | "agent" | "workflows" | "feed" export function LeftPane() { + const router = useRouter() const selectedNode = useGraphStore((s) => s.selectedNode) const clearSelection = useGraphStore((s) => s.clearSelection) + const returnTo = useGraphStore((s) => s.returnTo) + const setReturnTo = useGraphStore((s) => s.setReturnTo) const sourcesOpen = useAppStore((s) => s.sourcesOpen) const myContentOpen = useAppStore((s) => s.myContentOpen) const clipsOpen = useAppStore((s) => s.clipsOpen) @@ -32,6 +36,13 @@ export function LeftPane() { const setWorkflowsOpen = useAppStore((s) => s.setWorkflowsOpen) const schemas = useSchemaStore((s) => s.schemas) + function handleBack() { + const dest = returnTo + setReturnTo(null) + clearSelection() + if (dest) router.push(dest) + } + function pickMode(): Mode { if (workflowsOpen) return "workflows" if (agentOpen) return "agent" @@ -51,7 +62,7 @@ export function LeftPane() {
{mode === "preview" && selectedNode && ( - + )} {mode === "sources" && setSourcesOpen(false)} />} {mode === "mycontent" && setMyContentOpen(false)} />} diff --git a/src/lib/__tests__/main-area.test.tsx b/src/lib/__tests__/main-area.test.tsx index be68b57..a0f6b30 100644 --- a/src/lib/__tests__/main-area.test.tsx +++ b/src/lib/__tests__/main-area.test.tsx @@ -14,8 +14,14 @@ const mockNode = { ref_id: "clip-1", node_type: "Clip", label: "Test Clip" } const graphState = { selectedNode: null as unknown, clearSelection: vi.fn(), + returnTo: null as string | null, + setReturnTo: vi.fn(), } +vi.mock("next/navigation", () => ({ + useRouter: () => ({ push: vi.fn() }), +})) + vi.mock("@/stores/graph-store", () => ({ useGraphStore: (sel?: (s: unknown) => unknown) => sel ? sel(graphState) : graphState, @@ -105,6 +111,10 @@ describe("LeftPane pickMode()", () => { render() expect(screen.getByTestId("clips-panel")).toBeTruthy() expect(screen.queryByTestId("node-preview-panel")).toBeNull() - expect(screen.queryByTestId("feed-view")).toBeNull() + // FeedView is always mounted but hidden via CSS when not in feed mode + const feedView = screen.queryByTestId("feed-view") + if (feedView) { + expect(feedView.closest(".hidden") ?? feedView.parentElement?.closest(".hidden")).toBeTruthy() + } }) }) diff --git a/src/lib/__tests__/node-preview-panel.test.tsx b/src/lib/__tests__/node-preview-panel.test.tsx index 9f616cc..dc42453 100644 --- a/src/lib/__tests__/node-preview-panel.test.tsx +++ b/src/lib/__tests__/node-preview-panel.test.tsx @@ -1503,7 +1503,7 @@ describe("NodePreviewPanel – pencil edit button", () => { ) }) - it("calls openEdit with fullNode when it is available", async () => { + it("calls openEdit with the current node when Edit node is clicked", async () => { const { fireEvent: fe } = await import("@testing-library/react") userStoreOverrides = { pubKey: "03admin", routeHint: "", isAdmin: true } mockApiGet.mockResolvedValue( @@ -1520,10 +1520,7 @@ describe("NodePreviewPanel – pencil edit button", () => { expect(mockOpenEdit).toHaveBeenCalledOnce() expect(mockOpenEdit).toHaveBeenCalledWith( - expect.objectContaining({ - ref_id: BASE_NODE.ref_id, - properties: expect.objectContaining({ description: "Full description" }), - }) + expect.objectContaining({ ref_id: BASE_NODE.ref_id }) ) }) }) diff --git a/src/stores/graph-store.ts b/src/stores/graph-store.ts index 996b6e2..cfbf4e9 100644 --- a/src/stores/graph-store.ts +++ b/src/stores/graph-store.ts @@ -26,6 +26,8 @@ interface GraphState { beginNeighborLoad: (refId: string) => void endNeighborLoad: (refId: string) => void clearSelection: () => void + returnTo: string | null + setReturnTo: (url: string | null) => void } function edgeKey(e: GraphEdge): string { @@ -75,4 +77,6 @@ export const useGraphStore = create((set) => ({ }), clearSelection: () => set({ selectedNode: null, sidebarSelectedNode: null, hoveredNode: null }), + returnTo: null, + setReturnTo: (returnTo) => set({ returnTo }), }))