FairyPiggyDev 9c2a80bfa1
🐛 Fix crash pasting component with variants from shared library (#9136)
Copying a component with variants from a shared library file ("Lib")
and pasting it into a file that uses that library ("Using Lib") would
crash the destination file with the referential-integrity validator
error:

    {:code :component-main-external
     :hint "Main instance should refer to a component in the same file"}

Root cause
----------

Paste goes through `generate-duplicate-shape-change` in
`common/src/app/common/logic/libraries.cljc`. When the shape is a
main instance of a known component and the copy set includes its
variant container, dispatch lands in `duplicate-variant`, then
`generate-duplicate-component`, and finally `duplicate-component`,
which clones the main-instance shape tree. Its `update-new-shape`
helper already re-links the new outer main's `:component-id` to the
freshly created local component (`new-component-id`), but it never
touches `:component-file`. The cloned shape therefore inherits
`:component-file` from the source library while the new component is
registered in the destination's local library
(`:apply-changes-local-library? true`), leaving the main-instance
dangling.

Fix
---

Extend `update-new-shape` with a second clause, sibling to the
existing `:component-id` rewrite: when a destination file id is
provided and differs from the new main's current `:component-file`,
re-root the shape. The same `(= (:component-id new-shape) (:id
component))` guard already used for the id rewrite ensures only the
outer main-instance is touched; nested shapes are unaffected.

The destination file id is threaded from the paste entry point
through the two orchestration functions that already knew the
source/destination distinction:

- `generate-duplicate-shape-change` — supplies the destination
  `file-id` it already has in scope when dispatching to
  `generate-duplicate-component-change`.
- `generate-duplicate-component-change` — accepts `:new-component-file`
  as a kwarg; renames its internal `file-id` binding to
  `source-file-id` for clarity (it was always the component's
  originating library file); forwards `new-component-file` to
  `duplicate-variant`.
- `duplicate-variant` — takes and forwards the `new-component-file`
  positional arg.
- `generate-duplicate-component` — accepts `:new-component-file` kwarg
  and passes it to `duplicate-component`.
- `duplicate-component` — applies the rewrite inside
  `update-new-shape`. The `new-component-file` parameter is placed
  right after `new-component-id` since component-id and component-file
  are typically managed together.

Same-file duplication is not affected: without `:new-component-file`
the new clause is skipped, and when source and destination match the
`(not= new-component-file (:component-file new-shape))` guard fails.

Tests
-----

Added in `common/test/common_tests/logic/comp_creation_test.cljc`:

- `test-duplicate-component-rewrites-component-file-to-destination`
  asserts that passing `:new-component-file` to
  `generate-duplicate-component` produces a main-instance with
  `:component-file` equal to the destination id.
- `test-duplicate-component-keeps-component-file-without-dest`
  baseline: without `:new-component-file`, `:component-file` is left
  untouched, matching pre-existing same-file behavior.

Github #8144

Signed-off-by: FairyPigDev <luislee3108@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-30 15:54:24 +02:00
..
2024-09-03 23:35:53 +02:00
2026-01-22 13:55:41 +01:00
2026-03-11 15:24:40 +01:00