From 0616aa4bf25ccbee01b536648b2ce043cd185d8a Mon Sep 17 00:00:00 2001 From: Marco Beretta <81851188+berry-13@users.noreply.github.com> Date: Sun, 26 Jul 2026 14:34:19 +0200 Subject: [PATCH] refactor: keep only staged context in the tray --- client/src/components/Chat/Input/ChatForm.tsx | 5 - .../components/Chat/Input/Composer/Tray.tsx | 237 +----------------- .../Input/Composer/__tests__/Tray.spec.tsx | 112 +-------- 3 files changed, 11 insertions(+), 343 deletions(-) diff --git a/client/src/components/Chat/Input/ChatForm.tsx b/client/src/components/Chat/Input/ChatForm.tsx index a12e816689..b30e74e42d 100644 --- a/client/src/components/Chat/Input/ChatForm.tsx +++ b/client/src/components/Chat/Input/ChatForm.tsx @@ -587,16 +587,11 @@ const ChatForm = memo(function ChatForm({ {endpoint && (
diff --git a/client/src/components/Chat/Input/Composer/Tray.tsx b/client/src/components/Chat/Input/Composer/Tray.tsx index 11c87fdc57..c2c04b9c7e 100644 --- a/client/src/components/Chat/Input/Composer/Tray.tsx +++ b/client/src/components/Chat/Input/Composer/Tray.tsx @@ -1,19 +1,11 @@ import { memo } from 'react'; -import { useRecoilValue } from 'recoil'; -import { Zap, Clock, Pencil, Trash2, RotateCcw, TextQuote, WandSparkles } from 'lucide-react'; -import type { TMessage, TConversation } from 'librechat-data-provider'; -import type { SteeringControls, QueuedMessageContext } from '~/hooks/Chat/useSteering'; +import { TextQuote, WandSparkles } from 'lucide-react'; +import type { TConversation } from 'librechat-data-provider'; import type { ComposerItem, ComposerItemKind } from '~/hooks/Input/useComposerItems'; -import type { PendingSteer, QueuedMessage } from '~/store/families'; -import type { RestoreToComposer } from '../InFlightSteers'; import type { ExtendedFile, FileSetter } from '~/common'; -import type { MenuEntry } from '../SteerMenu'; -import { RowMenu, useDefaultToggleEntry, ICON_BTN_CLASS, PRIMARY_BTN_CLASS } from '../SteerMenu'; -import { useFileHandlingNoChatContext } from '~/hooks'; +import { useFileHandlingNoChatContext, useLocalize } from '~/hooks'; import Chip, { type ChipTone } from './Chip'; import FileRow from '../Files/FileRow'; -import { useLocalize } from '~/hooks'; -import store from '~/store'; const KIND_ICON: Record = { quote:
)} - {failedSteers.map((steer) => ( - - ))} - {queuedMessages.map((message) => ( - - ))} ); } diff --git a/client/src/components/Chat/Input/Composer/__tests__/Tray.spec.tsx b/client/src/components/Chat/Input/Composer/__tests__/Tray.spec.tsx index 7ef823a1d9..fe02c2ef7c 100644 --- a/client/src/components/Chat/Input/Composer/__tests__/Tray.spec.tsx +++ b/client/src/components/Chat/Input/Composer/__tests__/Tray.spec.tsx @@ -1,11 +1,8 @@ import React from 'react'; import { RecoilRoot } from 'recoil'; import { render, screen, fireEvent } from '@testing-library/react'; -import type { PendingSteer, QueuedMessage } from '~/store/families'; import type { ComposerItem } from '~/hooks/Input/useComposerItems'; -import type { SteeringControls } from '~/hooks/Chat/useSteering'; import type { ExtendedFile } from '~/common'; -import store from '~/store'; import Tray from '../Tray'; jest.mock('~/hooks', () => ({ @@ -21,31 +18,6 @@ jest.mock('../../Files/FileRow', () => ({ files.size > 0 ?
{files.size}
: null, })); -const mockRemoveSteer = jest.fn(); -const mockRemoveQueued = jest.fn(); -const mockRetrySteer = jest.fn(); - -jest.mock('../../SteerMenu', () => ({ - RowMenu: () =>
, - useDefaultToggleEntry: () => ({ key: 'toggle', label: 'toggle', onClick: jest.fn() }), - ICON_BTN_CLASS: '', - PRIMARY_BTN_CLASS: '', -})); - -const CONVO_ID = 'convo-1'; - -const steering = { - enabled: true, - queueKey: CONVO_ID, - duringRunActive: false, - canSteer: false, - removeSteer: mockRemoveSteer, - removeQueued: mockRemoveQueued, - retrySteer: mockRetrySteer, - sendQueuedNow: jest.fn(), - convertSteerToQueue: jest.fn(), -} as unknown as SteeringControls; - const item = (overrides: Partial = {}): ComposerItem => ({ id: 'quote:0', kind: 'quote', @@ -55,32 +27,21 @@ const item = (overrides: Partial = {}): ComposerItem => ({ ...overrides, }); -function renderTray( - items: ComposerItem[], - seed?: (snapshot: MutableSnapshotLike) => void, - files: Map = new Map(), -) { +function renderTray(items: ComposerItem[], files: Map = new Map()) { return render( - + , ); } -type MutableSnapshotLike = { set: (atom: never, value: never) => void }; - describe('Tray', () => { beforeEach(() => jest.clearAllMocks()); @@ -95,7 +56,6 @@ describe('Tray', () => { item({ id: 'quote:0', kind: 'quote', label: 'the second paragraph' }), item({ id: 'skill:a', kind: 'skill', label: 'code-review' }), ], - undefined, new Map([['f1', {} as ExtendedFile]]), ); @@ -123,74 +83,8 @@ describe('Tray', () => { }); it('opens for staged files even with nothing else in it', () => { - renderTray([], undefined, new Map([['f1', {} as ExtendedFile]])); + renderTray([], new Map([['f1', {} as ExtendedFile]])); expect(screen.getByTestId('composer-tray')).toBeInTheDocument(); expect(screen.getByTestId('file-row')).toBeInTheDocument(); }); - - it('keeps queued messages as full-width rows with their own actions', () => { - const queued: QueuedMessage[] = [ - { id: 'q1', text: 'follow up on this', files: [], quotes: [], manualSkills: [] }, - ] as unknown as QueuedMessage[]; - - renderTray([], ({ set }: MutableSnapshotLike) => - set(store.queuedMessagesByConvoId(CONVO_ID) as never, queued as never), - ); - - expect(screen.getByTestId('queued-message-row')).toBeInTheDocument(); - fireEvent.click(screen.getByLabelText('com_ui_remove_queued')); - expect(mockRemoveQueued).toHaveBeenCalledWith('q1'); - }); - - it('surfaces failed steers with a retry affordance', () => { - const steers: PendingSteer[] = [ - { - steerId: 's1', - text: 'actually use zod', - status: 'failed', - files: [], - quotes: [], - manualSkills: [], - }, - ] as unknown as PendingSteer[]; - - renderTray([], ({ set }: MutableSnapshotLike) => - set(store.pendingSteersByConvoId(CONVO_ID) as never, steers as never), - ); - - expect(screen.getByTestId('steer-message-row')).toBeInTheDocument(); - expect(screen.getByText('com_ui_steer_failed')).toBeInTheDocument(); - fireEvent.click(screen.getByText('com_ui_steer_retry')); - expect(mockRetrySteer).toHaveBeenCalled(); - }); - - it('ignores steer state when steering is disabled for the endpoint', () => { - const queued = [ - { id: 'q1', text: 'follow up', files: [], quotes: [], manualSkills: [] }, - ] as unknown as QueuedMessage[]; - - const { container } = render( - - set(store.queuedMessagesByConvoId(CONVO_ID) as never, queued as never) - } - > - - , - ); - - expect(container).toBeEmptyDOMElement(); - }); });