Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
78e01e3
feat(react-client): migrate from recoil to zustand
jbeckerdm May 9, 2025
724807f
fix(react-client): add store exports
jbeckerdm May 9, 2025
b91e776
fix(react-client): fix tsup build
jbeckerdm May 9, 2025
c777d6c
feat(react-client): add mcp zustand store
jbeckerdm May 9, 2025
da6f961
fix(react-client): move chatInputs to chat store
jbeckerdm May 12, 2025
0d850d3
chore(frontend, copilot): replace recoil with new zustand stores
jbeckerdm May 12, 2025
611f0c4
fix(frontend): fix wrong setThreadHistory call after zustand update
jbeckerdm May 23, 2025
c5b5e1b
Merge branch 'main' into migrate-recoil-zustand
jbeckerdm Jun 17, 2025
cbc21ee
fix(react-client): define chatSettingsValue type. add default value s…
jbeckerdm Jun 18, 2025
08b3cb6
fix(react-client): allow partial chatsettings update
jbeckerdm Jun 18, 2025
855bcf1
fix(react-client): chat settings value not merging correctly
jbeckerdm Jun 27, 2025
cba5a55
fix(react-client): revert auth edits
jbeckerdm Jun 30, 2025
3238b88
Merge branch 'main' into migrate-recoil-zustand
jbeckerdm Jul 1, 2025
9435426
Merge branch 'main' into migrate-recoil-zustand
jbeckerdm Jul 3, 2025
793258e
Merge branch 'main' into migrate-recoil-zustand
asvishnyakov Jul 15, 2025
0e02abb
Merge branch 'main' into migrate-recoil-zustand
asvishnyakov Jul 18, 2025
6f3fe87
Merge branch 'main' into migrate-recoil-zustand
jbeckerdm Jul 23, 2025
9597404
Merge branch 'main' into migrate-recoil-zustand
hayescode Jul 28, 2025
185f56e
refactor: get rid of abbreviations
asvishnyakov Aug 3, 2025
1dd5479
Merge branch 'main' into react-19
asvishnyakov Aug 3, 2025
68ab544
fix: fix remaining merge issues
asvishnyakov Aug 3, 2025
c996fdd
fix: merge & refactoring issues
asvishnyakov Aug 3, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions frontend/src/components/AutoResumeThread.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import { toast } from 'sonner';

import {
resumeThreadErrorState,
useChatInteract,
useChatSession,
useConfig
useConfig,
useThreadStore
} from '@chainlit/react-client';

interface Props {
Expand All @@ -19,8 +18,9 @@ export default function AutoResumeThread({ id }: Props) {
const { config } = useConfig();
const { clear, setIdToResume } = useChatInteract();
const { session, idToResume } = useChatSession();
const [resumeThreadError, setResumeThreadError] = useRecoilState(
resumeThreadErrorState
const resumeThreadError = useThreadStore((state) => state.resumeThreadError);
const setResumeThreadError = useThreadStore(
(state) => state.setResumeThreadError
);

useEffect(() => {
Expand Down
10 changes: 6 additions & 4 deletions frontend/src/components/ChatSettings/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import mapValues from 'lodash/mapValues';
import { useEffect } from 'react';
import { useForm } from 'react-hook-form';
import { useRecoilState, useSetRecoilState } from 'recoil';
import { useRecoilState } from 'recoil';

import {
chatSettingsValueState,
useChatData,
useChatInteract
useChatInteract,
useChatStore
} from '@chainlit/react-client';

import { Button } from '@/components/ui/button';
Expand Down Expand Up @@ -36,7 +36,9 @@ export default function ChatSettingsModal() {
const { handleSubmit, setValue, reset, watch } = useForm({
defaultValues: chatSettingsValue
});
const setChatSettingsValue = useSetRecoilState(chatSettingsValueState);
const setChatSettingsValue = useChatStore(
(state) => state.setChatSettingsValue
);

// Reset form when default values change
useEffect(() => {
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/components/ElementSideView.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { cn } from '@/lib/utils';
import { ArrowLeft } from 'lucide-react';
import { useEffect, useState } from 'react';
import { useRecoilState } from 'recoil';

import { sideViewState } from '@chainlit/react-client';
import { useChatStore } from '@chainlit/react-client';

import { Card, CardContent } from '@/components/ui/card';
import { ResizableHandle, ResizablePanel } from '@/components/ui/resizable';
Expand All @@ -20,7 +19,9 @@ import { Element } from './Elements';
import { Button } from './ui/button';

export default function ElementSideView() {
const [sideView, setSideView] = useRecoilState(sideViewState);
const sideView = useChatStore((state) => state.sideView);
const setSideView = useChatStore((state) => state.setSideView);

const isMobile = useIsMobile();
const [isVisible, setIsVisible] = useState(false);

Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/Elements/CustomElement/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,16 @@ import {
useState
} from 'react';
import { Runner } from 'react-runner';
import { useRecoilValue } from 'recoil';
import { v4 as uuidv4 } from 'uuid';

import {
ChainlitContext,
IAction,
ICustomElement,
IElement,
sessionIdState,
useAuth,
useChatInteract
useChatInteract,
useSessionState
} from '@chainlit/react-client';

import Alert from '@/components/Alert';
Expand All @@ -28,7 +27,8 @@ import * as Renderer from './Renderer';

const CustomElement = memo(function ({ element }: { element: ICustomElement }) {
const apiClient = useContext(ChainlitContext);
const sessionId = useRecoilValue(sessionIdState);
const sessionId = useSessionState((state) => state.sessionId);

const { sendMessage } = useChatInteract();
const { user } = useAuth();
const { askUser } = useContext(MessageContext);
Expand Down
12 changes: 6 additions & 6 deletions frontend/src/components/LeftSidebar/ThreadHistory.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { uniqBy } from 'lodash';
import { useContext, useEffect, useRef, useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { useRecoilState } from 'recoil';

import {
ChainlitContext,
threadHistoryState,
useAuthStore,
useChatMessages
} from '@chainlit/react-client';

Expand All @@ -25,7 +24,9 @@ export function ThreadHistory() {
const scrollRef = useRef<HTMLDivElement>(null);
const apiClient = useContext(ChainlitContext);
const { firstInteraction, messages, threadId } = useChatMessages();
const [threadHistory, setThreadHistory] = useRecoilState(threadHistoryState);
const threadHistory = useAuthStore((state) => state.threadHistory);
const setThreadHistory = useAuthStore((state) => state.setThreadHistory);

const [error, setError] = useState<string>();
const [isLoadingMore, setIsLoadingMore] = useState(false);
const [isFetching, setIsFetching] = useState(false);
Expand Down Expand Up @@ -91,11 +92,10 @@ export function ThreadHistory() {
);

if (allThreads) {
setThreadHistory((prev) => ({
...prev,
setThreadHistory({
pageInfo,
threads: allThreads
}));
});
}
} catch (err) {
setError(err instanceof Error ? err.message : 'Unknown error occurred');
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/LeftSidebar/ThreadList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import { size } from 'lodash';
import { useContext, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Link, useNavigate } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';
import { toast } from 'sonner';

import {
ChainlitContext,
ClientError,
ThreadHistory,
threadHistoryState,
useAuthStore,
useChatInteract,
useChatMessages,
useChatSession
Expand Down Expand Up @@ -78,7 +77,7 @@ export function ThreadList({
const [threadIdToDelete, setThreadIdToDelete] = useState<string>();
const [threadIdToRename, setThreadIdToRename] = useState<string>();
const [threadNewName, setThreadNewName] = useState<string>();
const setThreadHistory = useSetRecoilState(threadHistoryState);
const setThreadHistory = useAuthStore((state) => state.setThreadHistory);
const apiClient = useContext(ChainlitContext);

const sortedTimeGroupKeys = useMemo(() => {
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/ReadOnlyThread.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { MessageContext } from '@/contexts/MessageContext';
import { useCallback, useContext, useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useNavigate } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';
import { toast } from 'sonner';

import {
Expand All @@ -13,8 +12,8 @@ import {
IStep,
IThread,
nestMessages,
sideViewState,
useApi,
useChatStore,
useConfig
} from '@chainlit/react-client';

Expand All @@ -38,7 +37,8 @@ const ReadOnlyThread = ({ id }: Props) => {
revalidateOnFocus: false
});
const navigate = useNavigate();
const setSideView = useSetRecoilState(sideViewState);
const setSideView = useChatStore((state) => state.setSideView);

const [steps, setSteps] = useState<IStep[]>([]);
const apiClient = useContext(ChainlitContext);
const { t } = useTranslation();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { cn } from '@/lib/utils';
import { useRecoilValue } from 'recoil';

import { ICommand, commandsState } from '@chainlit/react-client';
import { ICommand, useChatStore } from '@chainlit/react-client';

import Icon from '@/components/Icon';
import { Button } from '@/components/ui/button';
Expand All @@ -23,8 +22,8 @@ export const CommandButtons = ({
selectedCommandId,
onCommandSelect
}: Props) => {
const commands = useRecoilValue(commandsState);
const commandButtons = commands.filter((c) => !!c.button);
const commands = useChatStore((state) => state.commands);
const commandButtons = commands.filter((command) => !!command.button);

if (!commandButtons.length) return null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ import {
PopoverTrigger
} from '@radix-ui/react-popover';
import { every } from 'lodash';
import { useRecoilValue } from 'recoil';

import { ICommand, commandsState } from '@chainlit/react-client';
import { ICommand, useChatStore } from '@chainlit/react-client';

import Icon from '@/components/Icon';
import { ToolBox } from '@/components/icons/ToolBox';
Expand All @@ -33,8 +32,8 @@ export const CommandPopoverButton = ({
disabled = false,
onCommandSelect
}: Props) => {
const commands = useRecoilValue(commandsState);
const allButtons = every(commands.map((c) => !!c.button));
const commands = useChatStore((state) => state.commands);
const allButtons = every(commands.map((command) => !!command.button));

if (!commands.length || allButtons) return null;

Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/chat/MessageComposer/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import React, {
useRef,
useState
} from 'react';
import { useRecoilValue } from 'recoil';

import { ICommand, commandsState } from '@chainlit/react-client';
import { ICommand, useChatStore } from '@chainlit/react-client';

import Icon from '@/components/Icon';
import {
Expand Down Expand Up @@ -49,7 +48,7 @@ const Input = forwardRef<InputMethods, Props>(
},
ref
) => {
const commands = useRecoilValue(commandsState);
const commands = useChatStore((state) => state.commands);
const [isComposing, setIsComposing] = useState(false);
const [showCommands, setShowCommands] = useState(false);
const [selectedIndex, setSelectedIndex] = useState(0);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useContext, useState } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { toast } from 'sonner';

import {
ChainlitContext,
mcpState,
sessionIdState
useMcpStore,
useSessionState
} from '@chainlit/react-client';

import { Button } from '@/components/ui/button';
Expand Down Expand Up @@ -36,8 +35,8 @@ export const McpAddForm = ({
allowHttp
}: McpAddFormProps) => {
const apiClient = useContext(ChainlitContext);
const sessionId = useRecoilValue(sessionIdState);
const setMcps = useSetRecoilState(mcpState);
const sessionId = useSessionState((state) => state.sessionId);
const setMcps = useMcpStore((state) => state.setMcps);

const [serverName, setServerName] = useState('');
// Pick the first protocol enabled by the parent component.
Expand Down
16 changes: 9 additions & 7 deletions frontend/src/components/chat/MessageComposer/Mcp/List.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import { cn } from '@/lib/utils';
import { Link, RefreshCw, SquareTerminal, Trash2, Wrench } from 'lucide-react';
import { useContext, useState } from 'react';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { toast } from 'sonner';

import {
ChainlitContext,
IMcp,
mcpState,
sessionIdState
useMcpStore,
useSessionState
} from '@chainlit/react-client';

import CopyButton from '@/components/CopyButton';
Expand All @@ -33,8 +32,10 @@ interface McpListProps {

export const McpList = ({ onAddNewClick }: McpListProps) => {
const apiClient = useContext(ChainlitContext);
const sessionId = useRecoilValue(sessionIdState);
const [mcps, setMcps] = useRecoilState(mcpState);
const sessionId = useSessionState((state) => state.sessionId);
const mcps = useMcpStore((state) => state.mcps);
const setMcps = useMcpStore((state) => state.setMcps);

const [isLoading, setIsLoading] = useState(false);

const deleteMcp = (mcp: IMcp) => {
Expand Down Expand Up @@ -194,8 +195,9 @@ const DeleteMcpButton = ({ mcp, onDelete, disabled }: DeleteMcpButtonProps) => {

const ReconnectMcpButton = ({ mcp }: { mcp: IMcp }) => {
const apiClient = useContext(ChainlitContext);
const setMcps = useSetRecoilState(mcpState);
const sessionId = useRecoilValue(sessionIdState);
const setMcps = useMcpStore((state) => state.setMcps);
const sessionId = useSessionState((state) => state.sessionId);

const [isLoading, setIsLoading] = useState(false);

const reconnectMcp = () => {
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/components/chat/MessageComposer/Mcp/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Plug } from 'lucide-react';
import { useState } from 'react';
import { useRecoilState } from 'recoil';

import { mcpState, useConfig } from '@chainlit/react-client';
import { useConfig, useMcpStore } from '@chainlit/react-client';

import { Button } from '@/components/ui/button';
import {
Expand Down Expand Up @@ -30,7 +29,7 @@ interface Props {

const McpButton = ({ disabled }: Props) => {
const { config } = useConfig();
const [mcps] = useRecoilState(mcpState);
const mcps = useMcpStore((state) => state.mcps);

const [open, setOpen] = useState(false);
const [activeTab, setActiveTab] = useState('add');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { MessageContext } from 'contexts/MessageContext';
import { useCallback, useContext, useMemo, useState } from 'react';
import { useRecoilValue } from 'recoil';
import { toast } from 'sonner';

import {
ChainlitContext,
type IAction,
sessionIdState
useSessionState
} from '@chainlit/react-client';

import Icon from '@/components/Icon';
Expand All @@ -26,7 +25,7 @@ interface ActionProps {
const ActionButton = ({ action }: ActionProps) => {
const { loading, askUser } = useContext(MessageContext);
const apiClient = useContext(ChainlitContext);
const sessionId = useRecoilValue(sessionIdState);
const sessionId = useSessionState((state) => state.sessionId);
const [isRunning, setIsRunning] = useState(false);

const content = useMemo(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import { MessageContext } from '@/contexts/MessageContext';
import { MessageCircle, ThumbsDown, ThumbsUp } from 'lucide-react';
import { useCallback, useContext, useState } from 'react';
import { useRecoilValue } from 'recoil';

import {
IStep,
firstUserInteraction,
useChatSession
} from '@chainlit/react-client';
import { IStep, useChatSession, useUserState } from '@chainlit/react-client';

import Translator from '@/components/i18n/Translator';
import { Button } from '@/components/ui/button';
Expand Down Expand Up @@ -42,7 +37,8 @@ export function FeedbackButtons({ message }: FeedbackButtonsProps) {
);
const [showDialog, setShowDialog] = useState<number>();
const [commentInput, setCommentInput] = useState<string>();
const firstInteraction = useRecoilValue(firstUserInteraction);
const firstInteraction = useUserState((state) => state.firstUserInteraction);

const { idToResume } = useChatSession();

if (!showFeedbackButtons) {
Expand Down
Loading
Loading