From c9ff16549174ba1909abcbd59fa1c0e1296fd2b5 Mon Sep 17 00:00:00 2001 From: arc53-machine <232052973+arc53-machine@users.noreply.github.com> Date: Tue, 29 Sep 2026 00:54:07 +0100 Subject: [PATCH] Keep the file picker's account when the source type changes The reset ran in an effect after the new picker had reported its default account, so remote uploads could send no connection. It now happens with the type change. A connection tile that is not set up says Not connected. --- frontend/src/upload/Upload.test.tsx | 65 +++++++++++++++++++++++++++++ frontend/src/upload/Upload.tsx | 12 +++--- 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/frontend/src/upload/Upload.test.tsx b/frontend/src/upload/Upload.test.tsx index 37f866ce..50cd1b08 100644 --- a/frontend/src/upload/Upload.test.tsx +++ b/frontend/src/upload/Upload.test.tsx @@ -43,6 +43,25 @@ vi.mock('../connectors/useConnectorLauncher', () => ({ default: () => ({ launch, modals: null }), })); +// The file picker reports its default account and a pick as it mounts. +vi.mock('../components/FilePicker', async () => { + const { useEffect } = await import('react'); + return { + FilePicker: function Picker(props: { + onConnectionChange: (id: string | null) => void; + onSelectionChange: (files: string[], folders?: string[]) => void; + onFirstPickName: (name: string) => void; + }) { + useEffect(() => { + props.onConnectionChange('drive-1'); + props.onSelectionChange(['file-1'], []); + props.onFirstPickName('Handbook'); + }, []); + return null; + }, + }; +}); + import Upload from './Upload'; Object.assign(globalThis, { IS_REACT_ACT_ENVIRONMENT: true }); @@ -265,6 +284,52 @@ describe('Upload source-type tiles', () => { connectorsState.connections = []; }); + it("sends the picker's account, not one cleared by the type change", async () => { + connectorsState.catalog = [ + { + key: 'google_drive', + icon: 'drive', + sync_ingestor: 'google_drive', + auth_kind: 'oauth', + available: true, + missing_settings: [], + }, + ]; + const sent: FormData[] = []; + class FakeXhr { + upload = { addEventListener() {} }; + addEventListener() {} + open() {} + setRequestHeader() {} + send(body: FormData) { + sent.push(body); + } + } + vi.stubGlobal('XMLHttpRequest', FakeXhr); + await act(async () => + root.render( + , + ), + ); + const train = Array.from(document.body.querySelectorAll('button')).find( + (b) => b.textContent === 'modals.uploadDoc.train', + )!; + await act(async () => train.click()); + expect(sent).toHaveLength(1); + expect(JSON.parse(String(sent[0].get('data'))).connection_id).toBe( + 'drive-1', + ); + vi.unstubAllGlobals(); + connectorsState.catalog = []; + }); + it('leaves the disabled Train button on the default variant', async () => { await render(); const crawler = tiles().find((tile) => diff --git a/frontend/src/upload/Upload.tsx b/frontend/src/upload/Upload.tsx index aadb7a55..0b533402 100644 --- a/frontend/src/upload/Upload.tsx +++ b/frontend/src/upload/Upload.tsx @@ -556,10 +556,6 @@ function Upload({ // user made in the account picker. const accountPicked = useRef(false); const firstKeyAccount = keyAccounts[0]?.id; - useEffect(() => { - accountPicked.current = false; - setConnectionId(null); - }, [ingestor.type]); useEffect(() => { if (selectedConnector?.auth_kind !== 'api_key' || accountPicked.current) return; @@ -1159,6 +1155,11 @@ function Upload({ })); }; const handleIngestorTypeChange = (type: IngestorType | null) => { + // The account resets with the type, here rather than in an effect: the + // new type's picker reports its default account as it mounts, and an + // effect would run after that and clear it. + accountPicked.current = false; + setConnectionId(null); if (type === null) { setIngestor({ type: null, @@ -1204,7 +1205,8 @@ function Upload({ count: accounts.length, formatted: formatCount(accounts.length), }); - return t('settings.connectors.status.connect'); + // A status, not a button: the tile itself starts the connection. + return t('modals.uploadDoc.tileNotConnected'); }; // With the catalog loaded, members only see connections they can use: