Skip to content

feat(contexts): carry the menu through export and import - #3138

Draft
rubenvdlinde wants to merge 2 commits into
feat/noid/app-menu-nestingfrom
feat/noid/app-menu-export-import
Draft

rubenvdlinde wants to merge 2 commits into
feat/noid/app-menu-nestingfrom
feat/noid/app-menu-export-import

Conversation

@rubenvdlinde

@rubenvdlinde rubenvdlinde commented Oct 22, 2026 •

Copy link
Copy Markdown

Part of #3099, on top of #3137 (menu nesting). A menu now travels with its application when the application's scheme is exported and imported, and when a user's data is moved to another instance.

Size: 871 lines: 428 code, 418 tests and 25 generated OpenAPI.

What changes

  • Export writes each item with its target by a stable reference: tables and views by UUID, pages and parent items by technical name, automatic names like item_7 included, so nesting survives the round trip.
  • Import links each item to the matching table or view on the receiving side. A page item is linked to the page with the same technical name, and skipped if there's none, because a scheme import doesn't create pages yet. An item whose target didn't come along is skipped too.
  • Moving a user's data (TablesMigrator) carries the menu's links and the items for the moved table and pages. View items are skipped for now, because that import has no mapping from old view ids to new ones.
  • Every import keeps the menu one level deep, takes at most 200 items, skips items with broken ids, and logs every skipped item with the reason.
  • The scheme preview now also shows the menu: what it is now, what it would become, and which items would be skipped.
  • ViewMapper::findByUuid and TableMapper::findByUuid were already declared to return nothing when the UUID is unknown, but threw an exception instead. They now return null, which the import relies on.

How it was tested

On Nextcloud 34 with PostgreSQL:

  • FindByUuidTest: both mappers return null for an unknown UUID
  • database round trips of a menu through importContext() and through a scheme, including a child under an automatically named parent
  • a crafted file with three levels, and a broken menu in an export file
  • the full unit suite on PostgreSQL and SQLite: 665 tests
  • composer cs:check, psalm and rector, all clean

🖼️ Screenshots

Backend only, no UI changes.

🏁 Checklist

  • ⛑️ Tests (unit and/or integration) are included or not needed
  • 🔙 Backport requests are created or not needed: /backport to stableX.X
  • 📅 Milestone is set
  • 🌸 PR title is meaningful (if it should be in the changelog: is it meaningful to users?)

🤖 AI (if applicable)

  • The content of this PR was partly or fully generated using AI

Menus travel with the application's scheme and with a user's data,
with targets referenced by UUID or technical name. TableMapper and
ViewMapper findByUuid now return null when nothing matches, as their
signatures already said.

Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Ruben van der Linde <ruben@conduction.nl>
Assisted-by: ClaudeCode:claude-opus-5-5
Signed-off-by: Ruben van der Linde <ruben@conduction.nl>
@rubenvdlinde
rubenvdlinde force-pushed the feat/noid/app-menu-export-import branch from 04aafd2 to 455a391 Compare October 24, 2026 08:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants