fix(12.2): close code-review blockers on uploads, JSON caps, and pivot fill

Keep form save behind in-flight uploads, make retries idempotent via X-Upload-Id, cap remaining JSON bodies, and surface pending pivot type errors instead of zeroing them.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-10-02 23:10:48 +02:00
parent 6bfc0faa8a
commit 516f9c9025
22 changed files with 533 additions and 96 deletions

View File

@@ -156,6 +156,7 @@ describe('fileupload on a new record (tracer)', () => {
expect(new URL(upload.url, 'http://local').pathname).toBe(`${BASE}/0/files/photos`)
expect(upload.url).not.toContain('?')
expect(upload.headers[SESSION_HEADER]).toBe(key)
expect(upload.headers['X-Upload-Id']).toMatch(/^[A-Za-z0-9_-]{8,}$/)
expect(upload.headers['X-Requested-With']).toBe('XMLHttpRequest')
expect((upload.body!.get('file_data') as File).name).toBe('box.png')
expect(wrapper.find('[data-state="uploading"]').exists()).toBe(true)
@@ -199,6 +200,23 @@ describe('fileupload on a new record (tracer)', () => {
expect(wrapper.find('[data-file-item]').text()).toContain('box.png')
})
it('does not save while an upload is still in flight', async () => {
const { wrapper, calls } = await mountApp('/acme/demo/gadgets/create', routes())
await choose(wrapper, [png('box.png')])
expect(FakeXHR.sent).toHaveLength(1)
await wrapper.find('#field-name').setValue('Box')
expect(wrapper.find('[data-action="save"]').attributes('disabled')).toBeDefined()
await wrapper.find('[data-action="save"]').trigger('click')
await flushPromises()
expect(requestsTo(calls, 'POST', BASE)).toHaveLength(0)
FakeXHR.sent[0]!.respond(201, { data: fileItem(41, 'box.png', true), meta: {} })
await flushPromises()
expect(wrapper.find('[data-action="save"]').attributes('disabled')).toBeUndefined()
await wrapper.find('[data-action="save"]').trigger('click')
await flushPromises()
expect(requestsTo(calls, 'POST', BASE)).toHaveLength(1)
})
it('refuses a wrong type and an oversized file before sending and drops files past maxFiles', async () => {
const { wrapper } = await mountApp('/acme/demo/gadgets/create', routes())