fix: convert from use-query-params to nuqs

This commit is contained in:
bracesproul
2025-03-17 13:13:28 -07:00
parent a4d8e512ff
commit 706cc7cc1a
9 changed files with 2073 additions and 4165 deletions

View File

@@ -42,6 +42,7 @@
"lodash": "^4.17.21", "lodash": "^4.17.21",
"lucide-react": "^0.476.0", "lucide-react": "^0.476.0",
"next-themes": "^0.4.4", "next-themes": "^0.4.4",
"nuqs": "^2.4.1",
"prettier": "^3.5.2", "prettier": "^3.5.2",
"react": "^19.0.0", "react": "^19.0.0",
"react-dom": "^19.0.0", "react-dom": "^19.0.0",
@@ -55,7 +56,6 @@
"sonner": "^2.0.1", "sonner": "^2.0.1",
"tailwind-merge": "^3.0.2", "tailwind-merge": "^3.0.2",
"tailwindcss-animate": "^1.0.7", "tailwindcss-animate": "^1.0.7",
"use-query-params": "^2.2.1",
"use-stick-to-bottom": "^1.0.46", "use-stick-to-bottom": "^1.0.46",
"uuid": "^11.0.5", "uuid": "^11.0.5",
"zod": "^3.24.2" "zod": "^3.24.2"

6174
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@ import { InboxItemInput } from "./inbox-item-input";
import useInterruptedActions from "../hooks/use-interrupted-actions"; import useInterruptedActions from "../hooks/use-interrupted-actions";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { toast } from "sonner"; import { toast } from "sonner";
import { StringParam, useQueryParam } from "use-query-params"; import { useQueryState } from 'nuqs'
import { constructOpenInStudioURL } from "../utils"; import { constructOpenInStudioURL } from "../utils";
import { HumanInterrupt } from "@langchain/langgraph/prebuilt"; import { HumanInterrupt } from "@langchain/langgraph/prebuilt";
@@ -60,7 +60,7 @@ export function ThreadActionsView({
showDescription, showDescription,
showState, showState,
}: ThreadActionsViewProps) { }: ThreadActionsViewProps) {
const [threadId] = useQueryParam("threadId", StringParam); const [threadId] = useQueryState("threadId");
const { const {
acceptAllowed, acceptAllowed,
hasEdited, hasEdited,
@@ -81,7 +81,7 @@ export function ThreadActionsView({
} = useInterruptedActions({ } = useInterruptedActions({
interrupt, interrupt,
}); });
const [apiUrl] = useQueryParam("apiUrl", StringParam); const [apiUrl] = useQueryState("apiUrl");
const handleOpenInStudio = () => { const handleOpenInStudio = () => {
if (!apiUrl) { if (!apiUrl) {

View File

@@ -4,7 +4,7 @@ import { Thread } from "@langchain/langgraph-sdk";
import { useEffect } from "react"; import { useEffect } from "react";
import { getContentString } from "../utils"; import { getContentString } from "../utils";
import { useQueryParam, StringParam, BooleanParam } from "use-query-params"; import { useQueryState, parseAsBoolean } from 'nuqs'
import { import {
Sheet, Sheet,
SheetContent, SheetContent,
@@ -22,7 +22,7 @@ function ThreadList({
threads: Thread[]; threads: Thread[];
onThreadClick?: (threadId: string) => void; onThreadClick?: (threadId: string) => void;
}) { }) {
const [threadId, setThreadId] = useQueryParam("threadId", StringParam); const [threadId, setThreadId] = useQueryState("threadId");
return ( return (
<div className="h-full flex flex-col w-full gap-2 items-start justify-start overflow-y-scroll [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-gray-300 [&::-webkit-scrollbar-track]:bg-transparent"> <div className="h-full flex flex-col w-full gap-2 items-start justify-start overflow-y-scroll [&::-webkit-scrollbar]:w-1.5 [&::-webkit-scrollbar-thumb]:rounded-full [&::-webkit-scrollbar-thumb]:bg-gray-300 [&::-webkit-scrollbar-track]:bg-transparent">
@@ -71,9 +71,9 @@ function ThreadHistoryLoading() {
export default function ThreadHistory() { export default function ThreadHistory() {
const isLargeScreen = useMediaQuery("(min-width: 1024px)"); const isLargeScreen = useMediaQuery("(min-width: 1024px)");
const [chatHistoryOpen, setChatHistoryOpen] = useQueryParam( const [chatHistoryOpen, setChatHistoryOpen] = useQueryState(
"chatHistoryOpen", "chatHistoryOpen",
BooleanParam, parseAsBoolean.withDefault(false),
); );
const { getThreads, threads, setThreads, threadsLoading, setThreadsLoading } = const { getThreads, threads, setThreads, threadsLoading, setThreadsLoading } =

View File

@@ -21,7 +21,7 @@ import {
PanelRightClose, PanelRightClose,
SquarePen, SquarePen,
} from "lucide-react"; } from "lucide-react";
import { BooleanParam, StringParam, useQueryParam } from "use-query-params"; import { useQueryState, parseAsBoolean } from 'nuqs'
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom"; import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
import ThreadHistory from "./history"; import ThreadHistory from "./history";
import { toast } from "sonner"; import { toast } from "sonner";
@@ -68,14 +68,14 @@ function ScrollToBottom(props: { className?: string }) {
} }
export function Thread() { export function Thread() {
const [threadId, setThreadId] = useQueryParam("threadId", StringParam); const [threadId, setThreadId] = useQueryState("threadId");
const [chatHistoryOpen, setChatHistoryOpen] = useQueryParam( const [chatHistoryOpen, setChatHistoryOpen] = useQueryState(
"chatHistoryOpen", "chatHistoryOpen",
BooleanParam, parseAsBoolean.withDefault(false),
); );
const [hideToolCalls, setHideToolCalls] = useQueryParam( const [hideToolCalls, setHideToolCalls] = useQueryState(
"hideToolCalls", "hideToolCalls",
BooleanParam, parseAsBoolean.withDefault(false),
); );
const [input, setInput] = useState(""); const [input, setInput] = useState("");
const [firstTokenReceived, setFirstTokenReceived] = useState(false); const [firstTokenReceived, setFirstTokenReceived] = useState(false);

View File

@@ -11,7 +11,7 @@ import { MessageContentComplex } from "@langchain/core/messages";
import { Fragment } from "react/jsx-runtime"; import { Fragment } from "react/jsx-runtime";
import { isAgentInboxInterruptSchema } from "@/lib/agent-inbox-interrupt"; import { isAgentInboxInterruptSchema } from "@/lib/agent-inbox-interrupt";
import { ThreadView } from "../agent-inbox"; import { ThreadView } from "../agent-inbox";
import { BooleanParam, useQueryParam } from "use-query-params"; import { useQueryState, parseAsBoolean } from 'nuqs'
function CustomComponent({ function CustomComponent({
message, message,
@@ -74,7 +74,9 @@ export function AssistantMessage({
handleRegenerate: (parentCheckpoint: Checkpoint | null | undefined) => void; handleRegenerate: (parentCheckpoint: Checkpoint | null | undefined) => void;
}) { }) {
const contentString = getContentString(message.content); const contentString = getContentString(message.content);
const [hideToolCalls] = useQueryParam("hideToolCalls", BooleanParam); const [hideToolCalls] = useQueryState("hideToolCalls",
parseAsBoolean.withDefault(false),
);
const thread = useStreamContext(); const thread = useStreamContext();
const isLastMessage = const isLastMessage =

View File

@@ -1,22 +1,21 @@
import { createRoot } from "react-dom/client";
import "./index.css"; import "./index.css";
import App from "./App.tsx"; import App from "./App.tsx";
import { createRoot } from "react-dom/client";
import { StreamProvider } from "./providers/Stream.tsx"; import { StreamProvider } from "./providers/Stream.tsx";
import { ThreadProvider } from "./providers/Thread.tsx"; import { ThreadProvider } from "./providers/Thread.tsx";
import { QueryParamProvider } from "use-query-params";
import { ReactRouter6Adapter } from "use-query-params/adapters/react-router-6";
import { BrowserRouter } from "react-router-dom";
import { Toaster } from "@/components/ui/sonner"; import { Toaster } from "@/components/ui/sonner";
import { NuqsAdapter } from "nuqs/adapters/react-router/v6";
import { BrowserRouter } from "react-router-dom";
createRoot(document.getElementById("root")!).render( createRoot(document.getElementById("root")!).render(
<BrowserRouter> <BrowserRouter>
<QueryParamProvider adapter={ReactRouter6Adapter}> <NuqsAdapter>
<ThreadProvider> <ThreadProvider>
<StreamProvider> <StreamProvider>
<App /> <App />
</StreamProvider> </StreamProvider>
</ThreadProvider> </ThreadProvider>
</QueryParamProvider>
<Toaster /> <Toaster />
</NuqsAdapter>
</BrowserRouter>, </BrowserRouter>,
); );

View File

@@ -12,7 +12,7 @@ import {
type UIMessage, type UIMessage,
type RemoveUIMessage, type RemoveUIMessage,
} from "@langchain/langgraph-sdk/react-ui"; } from "@langchain/langgraph-sdk/react-ui";
import { useQueryParam, StringParam } from "use-query-params"; import { useQueryState } from 'nuqs'
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { LangGraphLogoSVG } from "@/components/icons/langgraph"; import { LangGraphLogoSVG } from "@/components/icons/langgraph";
@@ -74,7 +74,7 @@ const StreamSession = ({
apiUrl: string; apiUrl: string;
assistantId: string; assistantId: string;
}) => { }) => {
const [threadId, setThreadId] = useQueryParam("threadId", StringParam); const [threadId, setThreadId] = useQueryState("threadId");
const { getThreads, setThreads } = useThreads(); const { getThreads, setThreads } = useThreads();
const streamValue = useTypedStream({ const streamValue = useTypedStream({
apiUrl, apiUrl,
@@ -123,7 +123,7 @@ const StreamSession = ({
export const StreamProvider: React.FC<{ children: ReactNode }> = ({ export const StreamProvider: React.FC<{ children: ReactNode }> = ({
children, children,
}) => { }) => {
const [apiUrl, setApiUrl] = useQueryParam("apiUrl", StringParam); const [apiUrl, setApiUrl] = useQueryState("apiUrl");
const [apiKey, _setApiKey] = useState(() => { const [apiKey, _setApiKey] = useState(() => {
return getApiKey(); return getApiKey();
}); });
@@ -133,9 +133,8 @@ export const StreamProvider: React.FC<{ children: ReactNode }> = ({
_setApiKey(key); _setApiKey(key);
}; };
const [assistantId, setAssistantId] = useQueryParam( const [assistantId, setAssistantId] = useQueryState(
"assistantId", "assistantId",
StringParam,
); );
if (!apiUrl || !assistantId) { if (!apiUrl || !assistantId) {

View File

@@ -1,7 +1,7 @@
import { validate } from "uuid"; import { validate } from "uuid";
import { getApiKey } from "@/lib/api-key"; import { getApiKey } from "@/lib/api-key";
import { Thread } from "@langchain/langgraph-sdk"; import { Thread } from "@langchain/langgraph-sdk";
import { useQueryParam, StringParam } from "use-query-params"; import { useQueryState } from 'nuqs'
import { import {
createContext, createContext,
useContext, useContext,
@@ -34,8 +34,8 @@ function getThreadSearchMetadata(
} }
export function ThreadProvider({ children }: { children: ReactNode }) { export function ThreadProvider({ children }: { children: ReactNode }) {
const [apiUrl] = useQueryParam("apiUrl", StringParam); const [apiUrl] = useQueryState("apiUrl");
const [assistantId] = useQueryParam("assistantId", StringParam); const [assistantId] = useQueryState("assistantId");
const [threads, setThreads] = useState<Thread[]>([]); const [threads, setThreads] = useState<Thread[]>([]);
const [threadsLoading, setThreadsLoading] = useState(false); const [threadsLoading, setThreadsLoading] = useState(false);