Loading...
;
+ if (!currentChat || !assistantConfig) return No data.
;
+
return (
{messages?.map((msg, i) => (
props.startStream()}
+ onClick={() =>
+ props.startStream(
+ null,
+ currentChat.thread_id,
+ currentChat.assistant_id,
+ )
+ }
>
Click to continue.
@@ -72,12 +89,19 @@ export function Chat(props: ChatProps) {
)}
+ props.startStream(
+ msg,
+ currentChat.thread_id,
+ currentChat.assistant_id,
+ )
+ }
onInterrupt={
props.stream?.status === "inflight" ? props.stopStream : undefined
}
inflight={props.stream?.status === "inflight"}
- isDocumentRetrievalActive={props.isDocumentRetrievalActive}
+ currentConfig={assistantConfig}
+ currentChat={currentChat}
/>
diff --git a/frontend/src/components/ChatList.tsx b/frontend/src/components/ChatList.tsx
index a8764296..16118c23 100644
--- a/frontend/src/components/ChatList.tsx
+++ b/frontend/src/components/ChatList.tsx
@@ -1,22 +1,22 @@
import { PlusIcon } from "@heroicons/react/24/outline";
import { ChatListProps } from "../hooks/useChatList";
-import { ConfigListProps } from "../hooks/useConfigList";
import { cn } from "../utils/cn";
+import { useThreadAndAssistant } from "../hooks/useThreadAndAssistant.ts";
export function ChatList(props: {
chats: ChatListProps["chats"];
- currentChat: ChatListProps["currentChat"];
- enterChat: ChatListProps["enterChat"];
- currentConfig: ConfigListProps["currentConfig"];
- enterConfig: ConfigListProps["enterConfig"];
+ enterChat: (id: string | null) => void;
+ enterConfig: (id: string | null) => void;
}) {
+ const { currentChat, assistantConfig } = useThreadAndAssistant();
+
return (
<>
props.enterChat(null)}
className={cn(
- props.currentChat === null && props.currentConfig !== null
+ !currentChat && assistantConfig
? "bg-gray-50 text-indigo-600"
: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50",
"group flex gap-x-3 rounded-md -mx-2 p-2 leading-6 font-semibold cursor-pointer",
@@ -24,7 +24,7 @@ export function ChatList(props: {
>
props.enterConfig(null)}
className={cn(
- props.currentConfig === null
+ !assistantConfig
? "bg-gray-50 text-indigo-600"
: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50",
"mt-1 group flex gap-x-3 rounded-md -mx-2 p-2 leading-6 font-semibold cursor-pointer",
@@ -46,7 +46,7 @@ export function ChatList(props: {
>
props.enterChat(chat.thread_id)}
className={cn(
- chat === props.currentChat
+ chat.thread_id === currentChat?.thread_id
? "bg-gray-50 text-indigo-600"
: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50",
"group flex gap-x-3 rounded-md p-2 leading-6 cursor-pointer",
@@ -74,7 +74,7 @@ export function ChatList(props: {
>
void;
}) {
const [values, setValues] = useState(
props.config?.config ?? props.configDefaults,
@@ -579,7 +583,8 @@ export function Config(props: {
vals.configurable["type==agent/tools"] = [...selectedTools];
setSelectedTools([]);
}
- await props.saveConfig(key, vals!, files, isPublic);
+ const assistantId = await props.saveConfig(key, vals!, files, isPublic);
+ props.enterConfig(assistantId);
setInflight(false);
}}
>
diff --git a/frontend/src/components/ConfigList.tsx b/frontend/src/components/ConfigList.tsx
index a2646590..e97d00a9 100644
--- a/frontend/src/components/ConfigList.tsx
+++ b/frontend/src/components/ConfigList.tsx
@@ -4,15 +4,15 @@ import { cn } from "../utils/cn";
function ConfigItem(props: {
config: Config;
- currentConfig: ConfigListProps["currentConfig"];
- enterConfig: ConfigListProps["enterConfig"];
+ currentConfig: Config | null;
+ enterConfig: (id: string | null) => void;
}) {
return (
props.enterConfig(props.config.assistant_id)}
className={cn(
- props.config === props.currentConfig
+ props.config.assistant_id === props.currentConfig?.assistant_id
? "bg-gray-50 text-indigo-600"
: "text-gray-700 hover:text-indigo-600 hover:bg-gray-50",
"group flex gap-x-3 rounded-md p-2 leading-6 cursor-pointer",
@@ -20,7 +20,7 @@ function ConfigItem(props: {
>
void;
}) {
return (
<>
diff --git a/frontend/src/components/NewChat.tsx b/frontend/src/components/NewChat.tsx
index ba967ad3..4d22e19a 100644
--- a/frontend/src/components/NewChat.tsx
+++ b/frontend/src/components/NewChat.tsx
@@ -2,50 +2,73 @@ import { ConfigList } from "./ConfigList";
import { Schemas } from "../hooks/useSchemas";
import TypingBox from "./TypingBox";
import { Config } from "./Config";
-import { ConfigListProps } from "../hooks/useConfigList";
+import {
+ ConfigListProps,
+ Config as ConfigInterface,
+} from "../hooks/useConfigList";
import { cn } from "../utils/cn";
import { MessageWithFiles } from "../utils/formTypes.ts";
+import { useNavigate, useParams } from "react-router-dom";
+import { useThreadAndAssistant } from "../hooks/useThreadAndAssistant.ts";
interface NewChatProps extends ConfigListProps {
configSchema: Schemas["configSchema"];
configDefaults: Schemas["configDefaults"];
- startChat: (message: MessageWithFiles) => Promise;
- isDocumentRetrievalActive: boolean;
+ enterConfig: (id: string | null) => void;
+ startChat: (
+ config: ConfigInterface,
+ message: MessageWithFiles,
+ ) => Promise;
}
export function NewChat(props: NewChatProps) {
+ const navigator = useNavigate();
+ const { assistantId } = useParams();
+
+ const { assistantConfig, isLoading } = useThreadAndAssistant();
+
+ if (isLoading) return Loading...
;
+ if (!assistantConfig)
+ return Could not find assistant with given id.
;
+
return (
navigator(`/assistant/${id}`)}
/>
{
+ if (assistantConfig) {
+ await props.startChat(assistantConfig, msg);
+ }
+ }}
+ currentConfig={assistantConfig}
+ currentChat={null}
/>
diff --git a/frontend/src/components/NotFound.tsx b/frontend/src/components/NotFound.tsx
new file mode 100644
index 00000000..6a4fe3b4
--- /dev/null
+++ b/frontend/src/components/NotFound.tsx
@@ -0,0 +1,3 @@
+export function NotFound() {
+ return Page not found.
;
+}
diff --git a/frontend/src/components/TypingBox.tsx b/frontend/src/components/TypingBox.tsx
index 6097c87e..c369c9d6 100644
--- a/frontend/src/components/TypingBox.tsx
+++ b/frontend/src/components/TypingBox.tsx
@@ -7,10 +7,12 @@ import {
DocumentIcon,
} from "@heroicons/react/20/solid";
import { cn } from "../utils/cn";
-import { Fragment, useCallback, useState } from "react";
+import { Fragment, useCallback, useEffect, useState } from "react";
import { useDropzone } from "react-dropzone";
import { MessageWithFiles } from "../utils/formTypes.ts";
-import { DROPZONE_CONFIG } from "../constants.ts";
+import { DROPZONE_CONFIG, TYPE_NAME } from "../constants.ts";
+import { Config } from "../hooks/useConfigList.ts";
+import { Chat } from "../hooks/useChatList.ts";
function getFileTypeIcon(fileType: string) {
switch (fileType) {
@@ -43,14 +45,38 @@ function convertBytesToReadableSize(bytes: number) {
}
export default function TypingBox(props: {
- onSubmit: (data: MessageWithFiles) => Promise;
+ onSubmit: (data: MessageWithFiles) => void;
onInterrupt?: () => void;
inflight?: boolean;
- isDocumentRetrievalActive: boolean;
+ currentConfig: Config;
+ currentChat: Chat | null;
}) {
const [inflight, setInflight] = useState(false);
const isInflight = props.inflight || inflight;
const [files, setFiles] = useState([]);
+ const [isDocumentRetrievalActive, setIsDocumentRetrievalActive] =
+ useState(false);
+
+ const { currentConfig, currentChat } = props;
+
+ useEffect(() => {
+ let configurable = null;
+ if (currentConfig) {
+ configurable = currentConfig.config?.configurable;
+ }
+ const agent_type = configurable?.["type"] as TYPE_NAME | null;
+ if (agent_type === null || agent_type === "chatbot") {
+ setIsDocumentRetrievalActive(false);
+ return;
+ }
+ if (agent_type === "chat_retrieval") {
+ setIsDocumentRetrievalActive(true);
+ return;
+ }
+ const tools =
+ (configurable?.["type==agent/tools"] as { name: string }[]) ?? [];
+ setIsDocumentRetrievalActive(tools.some((t) => t.name === "Retrieval"));
+ }, [currentConfig, currentChat]);
const onDrop = useCallback((acceptedFiles: File[]) => {
setFiles((prevFiles) => {
@@ -146,7 +172,7 @@ export default function TypingBox(props: {
placeholder="Send a message"
readOnly={isInflight}
/>
- {props.isDocumentRetrievalActive && (
+ {isDocumentRetrievalActive && (
Promise;
- enterChat: (id: string | null) => void;
}
function chatsReducer(
@@ -60,7 +58,6 @@ function chatsReducer(
export function useChatList(): ChatListProps {
const [chats, setChats] = useReducer(chatsReducer, null);
- const [current, setCurrent] = useState(null);
useEffect(() => {
async function fetchChats() {
@@ -81,29 +78,23 @@ export function useChatList(): ChatListProps {
assistant_id: string,
thread_id: string = uuidv4(),
) => {
- const saved = await fetch(`/threads/${thread_id}`, {
+ const response = await fetch(`/threads/${thread_id}`, {
method: "PUT",
body: JSON.stringify({ assistant_id, name }),
headers: {
"Content-Type": "application/json",
Accept: "application/json",
},
- }).then((r) => r.json());
+ });
+ const saved = await response.json();
setChats(saved);
- setCurrent(saved.thread_id);
return saved;
},
[],
);
- const enterChat = useCallback((id: string | null) => {
- setCurrent(id);
- }, []);
-
return {
chats,
- currentChat: chats?.find((c) => c.thread_id === current) || null,
createChat,
- enterChat,
};
}
diff --git a/frontend/src/hooks/useConfigList.ts b/frontend/src/hooks/useConfigList.ts
index 561da5ab..276056e8 100644
--- a/frontend/src/hooks/useConfigList.ts
+++ b/frontend/src/hooks/useConfigList.ts
@@ -1,4 +1,4 @@
-import { useCallback, useEffect, useReducer, useState } from "react";
+import { useCallback, useEffect, useReducer } from "react";
import orderBy from "lodash/orderBy";
import { v4 as uuidv4 } from "uuid";
@@ -18,14 +18,12 @@ export interface Config {
export interface ConfigListProps {
configs: Config[] | null;
- currentConfig: Config | null;
saveConfig: (
key: string,
config: Config["config"],
files: File[],
isPublic: boolean,
- ) => Promise;
- enterConfig: (id: string | null) => void;
+ ) => Promise;
}
function configsReducer(
@@ -45,43 +43,22 @@ function configsReducer(
export function useConfigList(): ConfigListProps {
const [configs, setConfigs] = useReducer(configsReducer, null);
- const [current, setCurrent] = useState(null);
useEffect(() => {
async function fetchConfigs() {
- const searchParams = new URLSearchParams(window.location.search);
- const shared_id = searchParams.get("shared_id");
- const [myConfigs, publicConfigs] = await Promise.all([
- fetch("/assistants/", {
- headers: {
- Accept: "application/json",
- },
- })
- .then((r) => r.json())
- .then((li) => li.map((c: Config) => ({ ...c, mine: true }))),
- fetch(
- "/assistants/public/" + (shared_id ? `?shared_id=${shared_id}` : ""),
- {
- headers: {
- Accept: "application/json",
- },
- },
- ).then((r) => r.json()),
- ]);
- setConfigs(myConfigs.concat(publicConfigs));
- if (publicConfigs.find((a: Config) => a.assistant_id === shared_id)) {
- setCurrent(shared_id);
- }
+ const myConfigs = await fetch("/assistants/", {
+ headers: {
+ Accept: "application/json",
+ },
+ })
+ .then((r) => r.json())
+ .then((li) => li.map((c: Config) => ({ ...c, mine: true })));
+ setConfigs(myConfigs);
}
fetchConfigs();
}, []);
- const enterConfig = useCallback((key: string | null) => {
- setCurrent(key);
- window.scrollTo({ top: 0 });
- }, []);
-
const saveConfig = useCallback(
async (
name: string,
@@ -89,7 +66,7 @@ export function useConfigList(): ConfigListProps {
files: File[],
isPublic: boolean,
assistant_id: string = uuidv4(),
- ) => {
+ ): Promise => {
const formData = files.reduce((formData, file) => {
formData.append("files", file);
return formData;
@@ -115,15 +92,13 @@ export function useConfigList(): ConfigListProps {
: Promise.resolve(),
]);
setConfigs({ ...saved, mine: true });
- enterConfig(saved.assistant_id);
+ return saved.assistant_id;
},
- [enterConfig],
+ [],
);
return {
configs,
- currentConfig: configs?.find((c) => c.assistant_id === current) || null,
saveConfig,
- enterConfig,
};
}
diff --git a/frontend/src/hooks/useThreadAndAssistant.ts b/frontend/src/hooks/useThreadAndAssistant.ts
new file mode 100644
index 00000000..4b48fd9e
--- /dev/null
+++ b/frontend/src/hooks/useThreadAndAssistant.ts
@@ -0,0 +1,37 @@
+import { useQuery } from "react-query";
+import { useParams } from "react-router-dom";
+import { getAssistant } from "../api/assistants";
+import { getThread } from "../api/threads";
+
+export function useThreadAndAssistant() {
+ // Extract route parameters
+ const { chatId, assistantId } = useParams();
+
+ // React Query to fetch chat details if chatId is present
+ const { data: currentChat, isLoading: isLoadingChat } = useQuery(
+ ["thread", chatId],
+ () => getThread(chatId as string),
+ {
+ enabled: !!chatId,
+ },
+ );
+
+ // Determine the assistantId to use: either from the chat or the route directly
+ const effectiveAssistantId = assistantId || currentChat?.assistant_id;
+
+ // React Query to fetch assistant configuration based on the effectiveAssistantId
+ const { data: assistantConfig, isLoading: isLoadingAssistant } = useQuery(
+ ["assistant", effectiveAssistantId],
+ () => getAssistant(effectiveAssistantId as string),
+ {
+ enabled: !!effectiveAssistantId,
+ },
+ );
+
+ // Return both loading states, the chat data, and the assistant configuration
+ return {
+ currentChat,
+ assistantConfig,
+ isLoading: isLoadingChat || isLoadingAssistant,
+ };
+}
diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx
index 6d36793d..af504278 100644
--- a/frontend/src/main.tsx
+++ b/frontend/src/main.tsx
@@ -2,9 +2,28 @@ import ReactDOM from "react-dom/client";
import { v4 as uuidv4 } from "uuid";
import App from "./App.tsx";
import "./index.css";
+import { BrowserRouter, Route, Routes } from "react-router-dom";
+import { StrictMode } from "react";
+import { QueryClient, QueryClientProvider } from "react-query";
+import { NotFound } from "./components/NotFound.tsx";
if (document.cookie.indexOf("user_id") === -1) {
- document.cookie = `opengpts_user_id=${uuidv4()}`;
+ document.cookie = `opengpts_user_id=${uuidv4()}; path=/; SameSite=Lax`;
}
-ReactDOM.createRoot(document.getElementById("root")!).render();
+const queryClient = new QueryClient();
+
+ReactDOM.createRoot(document.getElementById("root")!).render(
+
+
+
+
+ } />
+ } />
+ } />
+ } />
+
+
+
+ ,
+);
diff --git a/frontend/yarn.lock b/frontend/yarn.lock
index 3d29aae8..67836c5b 100644
--- a/frontend/yarn.lock
+++ b/frontend/yarn.lock
@@ -191,6 +191,13 @@
dependencies:
regenerator-runtime "^0.14.0"
+"@babel/runtime@^7.23.8", "@babel/runtime@^7.5.5", "@babel/runtime@^7.6.2", "@babel/runtime@^7.7.2":
+ version "7.24.1"
+ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.1.tgz#431f9a794d173b53720e69a6464abc6f0e2a5c57"
+ integrity sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==
+ dependencies:
+ regenerator-runtime "^0.14.0"
+
"@babel/template@^7.22.15":
version "7.22.15"
resolved "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz"
@@ -456,6 +463,11 @@
"@nodelib/fs.scandir" "2.1.5"
fastq "^1.6.0"
+"@remix-run/router@1.15.3":
+ version "1.15.3"
+ resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.15.3.tgz#d2509048d69dbb72d5389a14945339f1430b2d3c"
+ integrity sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==
+
"@tailwindcss/forms@^0.5.6":
version "0.5.6"
resolved "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.6.tgz"
@@ -754,6 +766,11 @@ balanced-match@^1.0.0:
resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
+big-integer@^1.6.16:
+ version "1.6.52"
+ resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85"
+ integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==
+
binary-extensions@^2.0.0:
version "2.2.0"
resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
@@ -774,6 +791,20 @@ braces@^3.0.2, braces@~3.0.2:
dependencies:
fill-range "^7.0.1"
+broadcast-channel@^3.4.1:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-3.7.0.tgz#2dfa5c7b4289547ac3f6705f9c00af8723889937"
+ integrity sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==
+ dependencies:
+ "@babel/runtime" "^7.7.2"
+ detect-node "^2.1.0"
+ js-sha3 "0.8.0"
+ microseconds "0.2.0"
+ nano-time "1.0.0"
+ oblivious-set "1.0.0"
+ rimraf "3.0.2"
+ unload "2.2.0"
+
browserslist@^4.21.10, browserslist@^4.21.9:
version "4.22.1"
resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.1.tgz"
@@ -911,6 +942,11 @@ deep-is@^0.1.3:
resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==
+detect-node@^2.0.4, detect-node@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1"
+ integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==
+
didyoumean@^1.2.2:
version "1.2.2"
resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz"
@@ -1355,6 +1391,11 @@ jiti@^1.19.1:
resolved "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz"
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
+js-sha3@0.8.0:
+ version "0.8.0"
+ resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840"
+ integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==
+
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
@@ -1470,6 +1511,14 @@ marked@^9.1.5:
resolved "https://registry.npmjs.org/marked/-/marked-9.1.5.tgz"
integrity sha512-14QG3shv8Kg/xc0Yh6TNkMj90wXH9mmldi5941I2OevfJ/FQAFLEwtwU2/FfgSAOMlWHrEukWSGQf8MiVYNG2A==
+match-sorter@^6.0.2:
+ version "6.3.4"
+ resolved "https://registry.yarnpkg.com/match-sorter/-/match-sorter-6.3.4.tgz#afa779d8e922c81971fbcb4781c7003ace781be7"
+ integrity sha512-jfZW7cWS5y/1xswZo8VBOdudUiSd9nifYRWphc9M5D/ee4w4AoXLgBEdRbgVaxbMuagBPeUC5y2Hi8DO6o9aDg==
+ dependencies:
+ "@babel/runtime" "^7.23.8"
+ remove-accents "0.5.0"
+
merge2@^1.3.0, merge2@^1.4.1:
version "1.4.1"
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
@@ -1483,6 +1532,11 @@ micromatch@^4.0.4, micromatch@^4.0.5:
braces "^3.0.2"
picomatch "^2.3.1"
+microseconds@0.2.0:
+ version "0.2.0"
+ resolved "https://registry.yarnpkg.com/microseconds/-/microseconds-0.2.0.tgz#233b25f50c62a65d861f978a4a4f8ec18797dc39"
+ integrity sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==
+
mini-svg-data-uri@^1.2.3:
version "1.4.4"
resolved "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz"
@@ -1509,6 +1563,13 @@ mz@^2.7.0:
object-assign "^4.0.1"
thenify-all "^1.0.0"
+nano-time@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/nano-time/-/nano-time-1.0.0.tgz#b0554f69ad89e22d0907f7a12b0993a5d96137ef"
+ integrity sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==
+ dependencies:
+ big-integer "^1.6.16"
+
nanoid@^3.3.6:
version "3.3.6"
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz"
@@ -1544,6 +1605,11 @@ object-hash@^3.0.0:
resolved "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz"
integrity sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==
+oblivious-set@1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/oblivious-set/-/oblivious-set-1.0.0.tgz#c8316f2c2fb6ff7b11b6158db3234c49f733c566"
+ integrity sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==
+
once@^1.3.0:
version "1.4.0"
resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
@@ -1741,11 +1807,35 @@ react-is@^16.13.1:
resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+react-query@^3.39.3:
+ version "3.39.3"
+ resolved "https://registry.yarnpkg.com/react-query/-/react-query-3.39.3.tgz#4cea7127c6c26bdea2de5fb63e51044330b03f35"
+ integrity sha512-nLfLz7GiohKTJDuT4us4X3h/8unOh+00MLb2yJoGTPjxKs2bc1iDhkNx2bd5MKklXnOD3NrVZ+J2UXujA5In4g==
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ broadcast-channel "^3.4.1"
+ match-sorter "^6.0.2"
+
react-refresh@^0.14.0:
version "0.14.0"
resolved "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz"
integrity sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==
+react-router-dom@^6.22.3:
+ version "6.22.3"
+ resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.22.3.tgz#9781415667fd1361a475146c5826d9f16752a691"
+ integrity sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==
+ dependencies:
+ "@remix-run/router" "1.15.3"
+ react-router "6.22.3"
+
+react-router@6.22.3:
+ version "6.22.3"
+ resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.22.3.tgz#9d9142f35e08be08c736a2082db5f0c9540a885e"
+ integrity sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==
+ dependencies:
+ "@remix-run/router" "1.15.3"
+
react@^18.2.0:
version "18.2.0"
resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz"
@@ -1772,6 +1862,11 @@ regenerator-runtime@^0.14.0:
resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz"
integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
+remove-accents@0.5.0:
+ version "0.5.0"
+ resolved "https://registry.yarnpkg.com/remove-accents/-/remove-accents-0.5.0.tgz#77991f37ba212afba162e375b627631315bed687"
+ integrity sha512-8g3/Otx1eJaVD12e31UbJj1YzdtVvzH85HV7t+9MJYk/u3XmkOUJ5Ys9wQrf9PCPK8+xn4ymzqYCiZl6QWKn+A==
+
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
@@ -1791,7 +1886,7 @@ reusify@^1.0.4:
resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
-rimraf@^3.0.2:
+rimraf@3.0.2, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
@@ -1995,6 +2090,14 @@ typescript@^5.0.2:
resolved "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz"
integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==
+unload@2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/unload/-/unload-2.2.0.tgz#ccc88fdcad345faa06a92039ec0f80b488880ef7"
+ integrity sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==
+ dependencies:
+ "@babel/runtime" "^7.6.2"
+ detect-node "^2.0.4"
+
update-browserslist-db@^1.0.13:
version "1.0.13"
resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz"