mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-08-04 14:57:42 +00:00
fix: Ignore programmatic agent form resets
This commit is contained in:
parent
66614bbebc
commit
897cc50187
2 changed files with 48 additions and 6 deletions
|
|
@ -11,7 +11,7 @@ import {
|
|||
PermissionBits,
|
||||
isAssistantsEndpoint,
|
||||
} from 'librechat-data-provider';
|
||||
import type { FieldNamesMarkedBoolean } from 'react-hook-form';
|
||||
import type { FieldNamesMarkedBoolean, FieldPath } from 'react-hook-form';
|
||||
import type { Agent } from 'librechat-data-provider';
|
||||
import type { TranslationKeys } from '~/hooks/useLocalize';
|
||||
import type { AgentForm, StringOption } from '~/common';
|
||||
|
|
@ -280,6 +280,7 @@ export default function AgentPanel() {
|
|||
reset,
|
||||
watch,
|
||||
getValues,
|
||||
getFieldState,
|
||||
setValue,
|
||||
formState: { dirtyFields },
|
||||
} = methods;
|
||||
|
|
@ -316,6 +317,17 @@ export default function AgentPanel() {
|
|||
|
||||
const shouldPersistDraft = hasPersistableDirtyFields(dirtyFields);
|
||||
|
||||
const isDirtyPersistableDraftField = useCallback(
|
||||
(name?: string): boolean => {
|
||||
if (!isPersistableDraftField(name)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return getFieldState(name as FieldPath<AgentForm>).isDirty;
|
||||
},
|
||||
[getFieldState],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (currentAgentIdRef.current === current_agent_id) {
|
||||
return;
|
||||
|
|
@ -348,7 +360,7 @@ export default function AgentPanel() {
|
|||
|
||||
useEffect(() => {
|
||||
const subscription = watch((_, { name }) => {
|
||||
if (!shouldPersistDraftRef.current && !isPersistableDraftField(name)) {
|
||||
if (!shouldPersistDraftRef.current && !isDirtyPersistableDraftField(name)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -362,7 +374,7 @@ export default function AgentPanel() {
|
|||
}
|
||||
subscription.unsubscribe();
|
||||
};
|
||||
}, [getValues, persistAgentDraft, watch]);
|
||||
}, [getValues, isDirtyPersistableDraftField, persistAgentDraft, watch]);
|
||||
|
||||
const uploadAvatarMutation = useUploadAgentAvatarMutation({
|
||||
onSuccess: (updatedAgent) => {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
* @jest-environment jsdom
|
||||
*/
|
||||
import * as React from 'react';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { describe, it, expect, beforeEach, jest } from '@jest/globals';
|
||||
import type { AgentForm, NavLink } from '~/common';
|
||||
import { ActivePanelProvider, useActivePanel } from '~/Providers/ActivePanelContext';
|
||||
|
|
@ -21,6 +21,7 @@ const SAVE_AGENT_LABEL = 'Save Agent';
|
|||
const AGENTS_BUTTON_LABEL = 'Agents';
|
||||
const FILES_BUTTON_LABEL = 'Files';
|
||||
const FILES_PANEL_LABEL = 'Files panel';
|
||||
const PROGRAMMATIC_UPDATE_LABEL = 'Programmatic agent update';
|
||||
|
||||
type MockButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
|
||||
size?: string;
|
||||
|
|
@ -136,9 +137,24 @@ jest.mock('~/common', () => {
|
|||
|
||||
jest.mock('../AgentSelect', () => ({
|
||||
__esModule: true,
|
||||
default: ({ hasDraft }: MockAgentSelectProps) => {
|
||||
default: function MockAgentSelect({ hasDraft }: MockAgentSelectProps) {
|
||||
const { useFormContext } = jest.requireActual(
|
||||
'react-hook-form',
|
||||
) as typeof import('react-hook-form');
|
||||
const { setValue } = useFormContext<AgentForm>();
|
||||
|
||||
mockLastAgentSelectHasDraft = hasDraft;
|
||||
return <div>{AGENT_SELECT_LABEL}</div>;
|
||||
return (
|
||||
<>
|
||||
<div>{AGENT_SELECT_LABEL}</div>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setValue('name', 'Saved from API', { shouldDirty: false })}
|
||||
>
|
||||
{PROGRAMMATIC_UPDATE_LABEL}
|
||||
</button>
|
||||
</>
|
||||
);
|
||||
},
|
||||
}));
|
||||
|
||||
|
|
@ -283,4 +299,18 @@ describe('AgentPanel draft preservation', () => {
|
|||
expect(getAgentDraft(undefined)).toBeUndefined();
|
||||
expect(mockLastAgentSelectHasDraft).toBe(false);
|
||||
});
|
||||
|
||||
it('does not save a draft for programmatic form updates', async () => {
|
||||
mockCurrentAgentId = 'agent-123';
|
||||
|
||||
render(<Harness />);
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: PROGRAMMATIC_UPDATE_LABEL }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByLabelText('Draft name')).toHaveValue('Saved from API');
|
||||
});
|
||||
expect(getAgentDraft('agent-123')).toBeUndefined();
|
||||
expect(mockLastAgentSelectHasDraft).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue