From 8efa076de547e559412ea0894946dfe1cf0321c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joachim=20R=C3=BCtter?= Date: Thu, 29 Oct 2026 22:01:26 +0000 Subject: [PATCH] Replace the asset on upload in a link field Co-Authored-By: Claude Opus 5.5 --- .../fieldtypes/assets/AssetsFieldtype.vue | 7 +++- .../fieldtypes/AssetsFieldtype.test.js | 37 ++++++++++++++++++- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/resources/js/components/fieldtypes/assets/AssetsFieldtype.vue b/resources/js/components/fieldtypes/assets/AssetsFieldtype.vue index 3a63bba2cc1..c4abbc7617d 100644 --- a/resources/js/components/fieldtypes/assets/AssetsFieldtype.vue +++ b/resources/js/components/fieldtypes/assets/AssetsFieldtype.vue @@ -580,7 +580,12 @@ export default { * When the uploader component has finished uploading a file. */ uploadComplete(asset) { - this.assets.push(asset); + // A link field has no validation to flag extra assets, so replace instead of appending. + if (this.isInLinkField && this.maxFiles === 1) { + this.assets = [asset]; + } else { + this.assets.push(asset); + } this.lockDynamicFolder(); }, diff --git a/resources/js/tests/components/fieldtypes/AssetsFieldtype.test.js b/resources/js/tests/components/fieldtypes/AssetsFieldtype.test.js index 4cb805f3786..29074fe12b1 100644 --- a/resources/js/tests/components/fieldtypes/AssetsFieldtype.test.js +++ b/resources/js/tests/components/fieldtypes/AssetsFieldtype.test.js @@ -11,7 +11,7 @@ window.cp_url = (url) => url; window.__ = (key) => key; preferences.initialize({}, {}); -const makeField = ({ axiosPost = vi.fn(() => Promise.resolve({ data: [] })), props = {} } = {}) => { +const makeField = ({ axiosPost = vi.fn(() => Promise.resolve({ data: [] })), props = {}, provide = {} } = {}) => { return mount(AssetsFieldtype, { shallow: true, props: { @@ -25,6 +25,7 @@ const makeField = ({ axiosPost = vi.fn(() => Promise.resolve({ data: [] })), pro ...props, }, global: { + provide, mocks: { $axios: { post: axiosPost }, $progress: { loading: () => {} }, @@ -81,3 +82,37 @@ test('removing an asset emits an update', async () => { expect(field.emitted('update:value')).toEqual([[['main::b.jpg']]]); }); + +const singleAssetField = (provide = {}) => + makeField({ + provide, + props: { + value: ['main::a.jpg'], + config: { max_files: 1 }, + meta: { + container: { id: 'main', can_view: true, can_upload: true }, + data: [{ id: 'main::a.jpg' }], + }, + }, + }); + +test('an upload replaces the asset in a link field', async () => { + const field = singleAssetField({ isInLinkField: true }); + await flushPromises(); + + field.vm.uploadComplete({ id: 'main::b.jpg' }); + await flushPromises(); + field.vm.uploadComplete({ id: 'main::c.jpg' }); + await flushPromises(); + + expect(field.emitted('update:value')).toEqual([[['main::b.jpg']], [['main::c.jpg']]]); +}); + +test('an upload is appended in a single asset field so validation can flag it', async () => { + const field = singleAssetField(); + await flushPromises(); + + field.vm.uploadComplete({ id: 'main::b.jpg' }); + + expect(field.vm.assets).toEqual([{ id: 'main::a.jpg' }, { id: 'main::b.jpg' }]); +});