Skip to content

[Data Object Editor] Create a new object from the object relation toolbar - #4040

Open
idaiv wants to merge 5 commits into
2026.xfrom
new-object-relation-fields
Open

[Data Object Editor] Create a new object from the object relation toolbar#4040
idaiv wants to merge 5 commits into
2026.xfrom
new-object-relation-fields

Conversation

@idaiv

@idaiv idaiv commented Aug 27, 2026

Copy link
Copy Markdown
Contributor

Changes in this pull request

Refs #1052

The (advanced) many-to-many object relation already exposes an allowToCreateNewObject flag in the class definition — several demo classes have it switched on — but the relation grid offered no way to act on it. Objects had to exist before they could be related.

Adds a New object action as the first item in the relation toolbar, rendered only when the class definition enables it and the relation accepts objects. It opens a modal asking for the name and the target parent, creates the object, and drops it straight into the relation grid.

Both variants are covered, since ManyToManyObjectRelation and AdvancedManyToManyObjectRelation both render the shared ManyToManyRelation toolbar.

Additional info

Behaviour

  • Parent is display-only and can only be filled through the element selector, so the value always references a real element (single selection, objects area, folders and objects).
  • Class picker appears only when the relation accepts more than one class; with a single class it is hidden and preselected.
  • Offered classes are the relation’s allowed classes intersected with the classes the current user may create, so a class that would fail on save is never offered.
  • allowedClasses is matched on id and name — the plain relation derives it from the class-definition classes entries (names), while the advanced variant passes allowedClassId straight through.

The flag is not in the generated API types

No class-definition key is enumerated in studio-backend-bundle — not allowToClearRelation, maxItems, displayMode or pathFormatterClass either — field definitions are serialised as generic passthrough. Since its sibling allowToClearRelation already drives runtime behaviour the same way, allowToCreateNewObject is declared on ManyToManyRelationClassDefinitionProps alongside it.

Known limitation: the new row’s path is composed, not fetched

The add endpoint returns only the new id, and there is no lazy get-by-id hook in this codebase, so the grid row is built from the parent path plus the entered key. If the backend sanitises that key, the row shows the pre-sanitised path until the editor is reloaded. Fetching the created object instead would be exact at the cost of an extra request — happy to switch if reviewers prefer that trade.

New objects are shown as unpublished, matching what the add endpoint creates.

Notes

  • Field spacing in the modal uses token.marginXS (8px), tightening the theme-wide Form.itemMarginBottom for this modal only.
  • Adding the modal import broke the loading of the existing toolbar.test.tsx — the shared Form pulls the app store and untranspiled ESM through Jest. Mocked there, matching the mocks that file already uses for the same reason.
  • 6 new translation keys across all 7 locales.

Verification

eslint ✅ · tsc --noEmit ✅ · jest relation suite 6 suites / 32 tests

Manually exercised in the demo, where the flag is already enabled on Car.categories, Event.cars, AccessoryPart.compatibleTo (plain) and Customer.manualSegments (advanced).

Not covered by tests: the modal’s submit flow end to end — only the grid-row construction is unit tested.

…lbar

The (advanced) many-to-many object relation exposes an allowToCreateNewObject
flag in the class definition, but the relation grid offered no way to act on
it — objects had to exist before they could be related.

Adds a "New object" action as the first item in the relation toolbar, shown
only when the class definition enables it and the relation accepts objects.
It opens a modal asking for the name and the target parent, creates the
object and drops it straight into the relation grid.

The parent is display-only and can be filled solely through the element
selector, so the value always references a real element. A class picker
appears only when the relation accepts more than one class; with a single
class it is hidden and preselected. The offered classes are the relation's
allowed classes intersected with the ones the current user may create, so a
class that would fail on save is never offered. Allowed classes are matched
on id and name, since the plain relation passes class names while the
advanced variant passes allowedClassId.

The add endpoint returns only the new id, so the grid row is composed from
the parent path and the entered key; if the backend sanitises that key the
row shows the pre-sanitised path until the editor is reloaded.

Refs #1052

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings August 27, 2026 17:28
@idaiv idaiv added this to the 2026.3.0 milestone Aug 27, 2026
@pimcore-deployments

Copy link
Copy Markdown
Collaborator

🌐 Translations synced automatically

The key changes below were generated for all target languages, passed the
mechanical validation gate (key parity, order, placeholders, types, plurals),
and are being committed to this branch by the workflow (check the run status
if the commit is not visible).
Please review the generated translations.

Added (6):

  • relations.create-object.title
  • relations.create-object.submit
  • relations.create-object.name
  • relations.create-object.parent
  • relations.create-object.parent.placeholder
  • relations.create-object.class

🧹 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.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Verdict: Needs changes. The PR correctly adds object creation at the shared relation-toolbar boundary, but item-limit and empty-class cases remain broken.

Changes:

  • Adds the creation modal, parent selector, class filtering, and API integration.
  • Adds the toolbar action for object relations.
  • Adds translations and row-construction tests.

Assessment:

  • Root cause addressed in the owning shared toolbar (toolbar.tsx:65-76).
  • Plain, advanced, and reverse relation call paths inherit the behavior.
  • No breaking API change; the new prop is optional.
  • Submission and toolbar behavior lack tests (create-object-modal.tsx:56-74, toolbar.test.tsx:43-46).
  • Remaining risks include exceeding maxItems, zero creatable classes, and the documented composed-path limitation.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
translations/studio.sv.yaml Adds Swedish labels.
translations/studio.no.yaml Adds Norwegian labels.
translations/studio.it.yaml Adds Italian labels.
translations/studio.fr.yaml Adds French labels.
translations/studio.es.yaml Adds Spanish labels.
translations/studio.en.yaml Adds English labels.
translations/studio.de.yaml Adds German labels.
many-to-many-relation.tsx Declares the creation flag.
toolbar/toolbar.tsx Adds the toolbar action and modal.
toolbar/toolbar.test.tsx Mocks the new modal dependency.
create-object/utils.ts Builds newly created relation rows.
create-object/utils.test.ts Tests row construction.
create-object/use-creatable-relation-classes.ts Filters creatable classes.
create-object/parent-selector.tsx Selects the target parent.
create-object/create-object-modal.tsx Handles creation workflow.
create-object/create-object-form.tsx Defines modal fields and validation.
create-object/create-object-form.styles.ts Adds modal form spacing.

💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

pimcore-deployments and others added 3 commits August 27, 2026 17:38
…tion

Sonar and the Copilot review found real holes in the first revision.

The action ignored maxItems. Creation hits the backend before addItems runs,
and addItems enforces no limit, so a full relation would have persisted an
object and then gone over its cap. The limit is now checked before the modal
opens, warning through the same items-limit-reached alert the upload button
uses rather than inventing a second pattern.

dataObjectsAllowed was read as "allowed unless explicitly false", while
allowed-types.ts treats an omitted value as not allowed. On a shared toolbar
that exposed creation on relations that never opted in; it now requires true.

An empty allowed-class/user-permission intersection hid the class picker just
as a single class does, so the form validated but submission had no classId
and failed with an internal error. The class lookup moved to the toolbar,
which hides the action when nothing is creatable — matching the tree action —
and passes the result to the modal. The lookup is skipped entirely for
relations that cannot create objects, so asset and document relations no
longer fetch the class collection.

Sonar flagged a nested template literal in the path builder and a swallowed
exception; the path is built from a named variable and the caught error is
now included in the reported message.

Test and story coverage the review asked for: the submit flow moved into
useCreateObject so its payload, success and both failure paths are covered
without mounting the form, the toolbar suite now proves the action is first,
appears only for an enabled object relation, opens the modal, warns at the
limit and skips the lookup when disabled, and the modal has a story covering
loading and the single, multiple and no-class cases.

Refs #1052

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

@idaiv
idaiv requested a review from ValeriaMaltseva August 28, 2026 07:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants