Spaces:
Running
Running
Commit History
-
make Studio Meshes migration factory-aware and extension-compatible
k0880kUnverified signature* feat(migrate): define target-owned factory table policies * feat(migrate): profile extension runtime compatibility * fix(migrate): retain mail override ownership metadata * feat(migrate): rehydrate factory ids and extension compatibility * test(migrate): cover factory maps and Joomla 6 break scanning * fix(migrate): match real Joomla namespace separators * test(migrate): run corruption-prevention checks on PRs731faf4
-
migrator: look extensions up by its real key, not `id`
Two lookups asked `#__extensions` for a column it does not have, and both failures were swallowed: `name_lookup` selected `id`. Joomla keys extensions on `extension_id` and content_types on `type_id`, so the query raised, the bare except returned an empty map, and every component_id strict-missed to 0 — "Component 'com_content' does not exist" on every migrated menu item, core links included. The strict fallback added with the element fix turned a partial break into a total one. The lookup now carries its key column, and it raises instead of returning nothing: an empty map here zeroes a whole column. `widgetkit_extension_rows` picked its columns by truthiness, not membership, and asked for `version` — which lives in manifest_cache on Joomla 4+, not in a column. It raised, the except returned [], every run concluded the source had no Widgetkit, and the tables were skipped as incompatible. That is why the target's widgetkit table stayed empty. Neither was catchable: the fake cursor an…060529b -
migrator: isolate failed row rollbacks
7486163 -
migrator: gate widgetkit tables on version parity
c1a78bc -
migrator: resolve component ids on the target, and leave its admin alone
component_id was being resolved against the WRONG COLUMN. The source was keyed by `element`, the target by `name`. Core stores name == element, so com_content matched and the bug hid; a third-party component's `name` is its language key ("COM_DOCMAN" against element "com_docman") and never matched. The lookup missed, `remap` fell back to the source's number, and the menu item opened whatever extension happened to hold that id on the new site — which is the one thing an install-time id can never be copied for. Now `element` at both ends, restricted to type='component'. A miss no longer falls back. An install-time id that does not resolve is not installed here, so the row gets 0 — what Joomla stores for "no component", an inert item — and every unresolved reference is named in the report. And `template_styles` no longer hands over client_id 1. That is the target's own administrator chrome; copying the source's landed a second admin `home` style and Joomla resolved to the one whose temp…ea7ad17 -
migrator: carry primary keys across, port the ACL, show the run
Identity was being thrown away. copy_table built its insert without the id column, so every row landed on a fresh auto-increment: asset names, asset_id, fields_values.item_id and every id written by hand inside a link pointed at a row that no longer had that number. The source pk is now written verbatim, and a number is only contested when a genuinely different row holds it — resolved by an explicit on_conflict (reassign, and say which; or overwrite) and never silently. PRESERVE_ID is gone: the same rule applies to every table. Assets are ported, not backfilled. sync_assets carries `rules` — the per-item ACL, which '{}' destroys rather than falls back from — resolves parent_id by name through the id maps, binds the row's asset_id, and derives lft/rgt from parent_id instead of copying another tree's numbers. articles get their #__workflow_associations row: Joomla 4+ joins that table in the admin list, so without it the articles exist, the category counts show them and the Articles tab…7a02fd1
-
feat(editor): fold the live-site editor into the Studio as a mounted app
The editor ships as a package mounted at /api/editor rather than merged in: one implementation runs standalone on a single-site box and here as a Studio tab, and the prefix settles the /healthz and /api/media collisions for free. core/dbmesh.py now reads and writes the editor's sites.json on the mounted volume. That registry was in-memory only, so a Space restart silently dropped every mesh; it now survives a redeploy, and a database registered in either face is both editable and migratable. healthz no longer 500s on a Space with nothing registered yet — liveness must not depend on configuration. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011mudH38FU1L34mEeNJNgbBc05106c