[Document Editor] Inline upload for relation editable - #4000
Conversation
Adds an upload button to the many-to-one relation, so a document `relation`
editable can create a new asset and assign it without leaving the editor —
the capability the sibling `relations` editable already had.
The button is opt-in on the component (`assetInlineUploadAllowed`), because
ManyToOneRelation is also used as a plain element picker in ~25 places that
should not grow an upload button. The document editable enables it when the
editable allows assets, and honours the template config:
{{ pimcore_relation('myRelation', {
'uploadPath': '/content',
'disableInlineUpload': false
}) }}
Uploading reuses the shared upload modal, so conflict handling, size limits,
the upload queue and the iframe forwarding apply unchanged.
Also closes the same gap in the many-to-many toolbar: uploaded assets were
assigned without checking `allowedAssetTypes`, so a relation restricted to
images accepted an uploaded PDF — a value neither the element selector nor
drag and drop would have produced. Both components now validate the
server-assigned asset type before assigning it.
Refs #1620
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Verdict: Needs changes. Adds inline asset upload to document relation editables and subtype validation to both relation components.
Changes:
- Adds opt-in upload support, upload-path configuration, and assignment handling.
- Rejects uploaded assets with disallowed subtypes.
- Adds tests, Storybook coverage, and translations.
Assessment:
- Fixes the missing upload integration at the owning components.
- Optional props preserve backward compatibility and existing call sites.
- Regression tests cover upload gating, assignment, and subtype rejection.
- Blocker: asynchronous path resolution can upload files to the asset root before the configured path resolves.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
translations/studio.sv.yaml |
Adds Swedish rejection messages. |
translations/studio.no.yaml |
Adds Norwegian rejection messages. |
translations/studio.it.yaml |
Adds Italian rejection messages. |
translations/studio.fr.yaml |
Adds French rejection messages. |
translations/studio.es.yaml |
Adds Spanish rejection messages. |
translations/studio.en.yaml |
Adds English rejection messages. |
translations/studio.de.yaml |
Adds German rejection messages. |
dynamic-type-document-editable-relation.tsx |
Wires editable upload configuration. |
many-to-one-relation.tsx |
Implements inline upload and subtype validation. |
many-to-one-relation.test.tsx |
Tests upload behavior. |
many-to-one-relation.stories.tsx |
Documents the upload configuration. |
many-to-many-relation/components/toolbar/toolbar.tsx |
Validates uploaded asset subtypes. |
many-to-many-relation/components/toolbar/toolbar.test.tsx |
Tests partial and complete rejection. |
💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
🌐 Translations synced automaticallyThe key changes below were generated for all target languages, passed the Added (2):
🧹 Pre-existing translation errors (backlog partly cleared)18 validation error(s) predating this PR were present at the merge base. This run also fixed 6 of them; 12 still remain. The remainder is not blocking — later runs keep chipping at it. |
allowed), the assetUploadPath prop and the subtype guard on ManyToOneRelation. Keep that merged behavior and reduce this PR to its actual delta: a disableInlineUpload opt-out prop (mirroring ManyToManyRelation), the document relation editable wiring for the uploadPath and disableInlineUpload template options, and translations for the asset-upload-type-not-allowed key that #4039 added in English only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
There was a problem hiding this comment.
Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.
Note
This error may be related to your runner configuration. You can now configure runners for Copilot code review separately from Copilot cloud agent by creating a copilot-code-review.yml file with your setup steps. Read the docs for details.



Closes #1620
Adds inline upload to the document
relationeditable, mirroring what the siblingrelations(many-to-many) editable already offered.Note
This PR was reworked after #4039 was merged. #4039 already added the upload button to
ManyToOneRelation(shown whenever assets are allowed and the field is enabled), theassetUploadPathprop, the post-upload subtype guard and itsasset-upload-type-not-allowedmessage. This PR keeps that merged behavior unchanged and only adds what is still missing for #1620.What changed
ManyToOneRelationgained adisableInlineUploadopt-out prop that hides the upload button #4039 introduced. This mirrors the existingdisableInlineUploadprop on the siblingManyToManyRelationcomponent, so both relation components are now configured the same way.The document
relationeditable wires up the template config — same option names as therelationsandimageeditables, so all of them behave alike:{{ pimcore_relation('myRelation', { 'uploadPath': '/content', 'disableInlineUpload': false }) }}uploadPathwas already declared in the editable's config type but unused; it is passed to the component asassetUploadPathnow.disableInlineUploadalso covers the request in #1966 for the many-to-one case. The upload button itself appears on the editable via #4039's default (assets allowed + enabled) — no opt-in needed.No new upload machinery: it reuses the shared upload modal, so duplicate-name conflict handling, size limits, the upload queue and the iframe forwarding (
element.openUploadModal) all apply unchanged.Also fixed: subtype was not enforced on upload in many-to-many
#4039 fixed this for
ManyToOneRelation; the same gap existed in the many-to-many toolbar.allowedAssetTypeswas enforced for the element selector (createElementSelectorConfig) and for drag & drop (dndIsValidData→isAllowedSubType), but not for uploads. A relation restricted toimagetherefore accepted an uploaded PDF — a value neither of the other two paths could have produced.The toolbar now filters uploaded assets through
isAllowedSubTypebefore assigning, and warns when some were dropped. The check runs after upload rather than as anacceptfilter on the file dialog, because the server decides the asset type from the MIME type, whileacceptis only a dialog hint. The assets are already created at that point, so the message says so instead of pretending they were rejected.Translations
relations.upload.subtype-not-allowed(new) — phrased count-independently, since the many-to-many upload can partially fail; added to all seven locales at the English position.asset-upload-type-not-allowed(from Restore inline asset upload on the many-to-one relation field #4039, used byManyToOneRelation) — was English-only; the six missing locale translations are synced now (partly by the automated translation-sync workflow on this branch).Assetis left untranslated per the glossary.Verification
tsc --noEmit— cleaneslinton all touched files — cleanManyToOneRelationupload tests (unchanged and still green), a new test fordisableInlineUpload, and 3 tests for the many-to-many partial-rejection behaviourComponents/Data Entry/Relation/ManyToOneRelation→ Configurations → With Inline UploadNot verified in a browser. My workspace has a
2026.2backend against this2026.xfrontend, andPOST /assets/exists/{id}(the batched upload exists-check from #3986) only exists on backend2026.x— so every upload 405s locally, independent of this change. The iframe → parentopenUploadModalhop and the button's visual placement are therefore verified as code paths only, not empirically. CI plus a review on an aligned environment should cover the rest.Note for the reviewer
The many-to-many fix is a pre-existing bug in a sibling component, not part of #1620. It is here because it is the same defect #4039 fixed for many-to-one, and the same guard. Say the word if you would rather have it as its own PR.
🤖 Generated with Claude Code