10466 Commits

Author SHA1 Message Date
Andrey Antukh
109539dbcd Auto-link libraries during import based on slugified name
When a Penpot file is exported without bundled libraries and then
imported into a different environment, external library links are
broken because library UUIDs differ across environments.

This feature adds a heuristic to auto-relink libraries by matching
slugified library names against shared files in the target team:

- Export: embed external library metadata (id, name, slug, used-by)
  in the manifest when libraries are not included in the export.
- Import: resolve external libraries by slugifying shared file names
  in the destination team and matching against manifest slugs.
- Single match: auto-link silently (creates file-library-rel row).
- Multiple matches: emit SSE event so the frontend shows a selection
  dialog for the user to pick the correct library.
- No match: import continues without linking (current behavior).

Backend changes:
- Extended manifest schema with optional :external-libraries field
- Added slugify-name, get-files-names, get-shared-files-for-team,
  find-shared-files-by-slug helpers in app.binfile.common
- Threaded team-id into import cfg from RPC layer
- Added resolve-external-libraries and auto-link-libraries in v3
- Emit :library-candidates SSE event for multi-match cases

Frontend changes:
- Worker captures library-candidates SSE events and forwards them
- Import dialog shows auto-link notification and multi-match
  selection UI with select dropdowns
- Added link-files-to-library! RPC helper for user selections
- Added en/es translations for new UI strings

Closes #9263

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-06-15 13:35:06 +02:00
Andrey Antukh
d44c6250ea Merge remote-tracking branch 'origin/staging' into develop 2026-06-15 13:04:19 +02:00
Marina López
98e04bc5f0 Improve nitrate manual renew banner 2026-06-15 12:30:59 +02:00
Andrey Antukh
79227c4de8
Batch multiple thumbnail deletions into a single RPC call (#9943)
*  Batch multiple thumbnail deletions into a single RPC call

Replace the old per-object immediate thumbnail deletion with a
debounced batched approach. The frontend queues object-ids in state
and waits 200ms before sending a single RPC request with up to 200
object-ids. The backend deletes all matching thumbnails in one SQL
statement with a single RETURNING clause, then touches the affected
media objects.

This reduces RPC overhead when rapidly clearing thumbnails (e.g.
navigating pages) and makes deletions more efficient.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

* 📎 Fix missing issues

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-06-15 12:01:32 +02:00
Juan de la Cruz
ddeaf3ce2a
Add MCP status button to workspace toolbar with single-tab connection control (#9930)
*  Add MCP connection badge to the workspace toolbar

*  Add MCP status button with single-tab connection control

* ♻️ Extract component for MCP indicator in the toolbar

* ♻️ Some improvements

---------

Co-authored-by: Luis de Dios <luis.dedios@kaleidos.net>
2026-06-15 11:29:25 +02:00
Alonso Torres
92cf0cda7b
🐛 Fix openPage plugin problem (#10085)
* 🐛 Fix openPage plugin problem

* 🐛 Make history safer for tests
2026-06-15 11:27:35 +02:00
Eva Marco
c66ee1803f
🎉 Toggle color library visibility from the colorpicker shortcut button (#10129)
* ♻️ Transform a show button to a toggle button on colorpicker

* 🎉 Add test

* 🎉 Add aria-pressed to toggle palette button
2026-06-12 13:30:57 +02:00
María Valderrama
68d4238277 🐛 Fix license not loading in theme change 2026-06-12 12:13:50 +02:00
Andrey Antukh
a8d0c18c1b
🐛 Fix race condition between MCP initialization and plugin runtime (#10137)
* 🐛 Fix race condition between MCP init and plugin runtime

Add promise-based synchronization to ensure MCP initialization waits
for plugin runtime to be ready before calling global.ɵloadPlugin.

- Add runtime-ready-promise in app.plugins that resolves when
  init-plugins-runtime completes
- Add wait-for-runtime function for other modules to await readiness
- MCP init now waits for runtime via rx/from before starting plugin
- Add defensive guards in start-plugin!, load-plugin!, close-plugin!
  to check if plugin APIs exist before calling
- Rename init-plugins-runtime! to init-plugins-runtime

Fixes: global.ɵloadPlugin is not a function error when MCP plugin
starts before async plugin runtime initialization completes.

* 📎 Add 'create-pr' opencode skill
2026-06-12 11:40:02 +02:00
Andrey Antukh
f5874e159e
🔧 Replace UAParser.js with @penpot/ua-parser (#10007) 2026-06-12 10:46:09 +02:00
Alejandro Alonso
87eb91f805
♻️ Migrate viewer WASM viewport to modern syntax (#10106) 2026-06-12 10:29:58 +02:00
Alonso Torres
b2439694af
🐛 Fix float precision in typography line-height/letter-spacing string conversion (#9973) 2026-06-12 09:10:36 +02:00
Andrey Antukh
2e1839f898 🐛 Fix NotReadableError in rasterizer during thumbnail generation
The rasterizer's create-image function was clearing image.src in its
Rx teardown cleanup. This caused the decoded pixel data to be discarded
before downstream operators (drawImage / createImageBitmap) could read
it, resulting in a browser NotReadableError.

Changes:
- Remove image.src = "" from cleanup; the image element will be
  garbage collected naturally. Event handler nulling is kept to break
  circular references.
- Add dimension validation in svg-get-adjusted-size to return nil for
  zero/NaN dimensions instead of producing invalid sizes.
- Add fallback in svg-set-intrinsic-size! to use [max max] when SVG
  dimensions can't be determined.

Error occurred in production (2.16.0-RC10) during thumbnail generation
in the workspace.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-06-11 17:04:24 +02:00
Andrey Antukh
5f21ebd08d
🐛 Filter ignorable React removeChild errors at error boundary and fix HTML anti-pattern (#10145)
* 🐛 Filter ignorable exceptions in error-boundary onError callback

The global uncaught-error-handler already skips NotFoundError/removeChild
and other harmless errors, but react-error-boundary's onError callback fires
independently of the window.onerror pipeline. This means the error boundary
was still logging these errors and setting last-exception, causing them to
continue appearing in error reports despite being non-actionable.

Add the is-ignorable-exception? check to the error-boundary* onError so
harmless errors are silently ignored, matching the behavior of the global
handler.

* 🐛 Fix dangerouslySetInnerHTML anti-pattern in context-notification

The previous code used dangerouslySetInnerHTML on the same element that
could also contain React children. This is a React anti-pattern that can
cause reconciliation mismatches and lead to removeChild DOMExceptions.

Refactor to use two separate element branches: one for raw HTML injection
and one for normal React children with links.
2026-06-11 16:59:00 +02:00
Luis de Dios
9670140448
🐛 Fix first element on shared libraries list does not have border (#10062) 2026-06-11 13:35:10 +02:00
Alonso Torres
5b6041624a
🐛 Fix export presets not preserved in view mode inspect (#9972)
* 🐛 Fix export presets not preserved in view mode inspect

* 🐛 Changes after review
2026-06-11 13:33:48 +02:00
Andrey Antukh
70cbb65f9c Merge remote-tracking branch 'origin/staging' into develop 2026-06-11 13:27:43 +02:00
Andrey Antukh
86d508eaf1 Merge remote-tracking branch 'origin/main' into staging 2026-06-11 13:24:57 +02:00
Luis de Dios
331e66c1c6
Update company size options in in-app onboarding (#10110) 2026-06-11 13:23:41 +02:00
Alejandro Alonso
38d12b3363
Add hard reload path for renderer menu A/B test (#10133) 2026-06-11 13:16:09 +02:00
Andrey Antukh
12e7ea038f Merge remote-tracking branch 'origin/staging' into develop 2026-06-11 10:58:19 +02:00
Elena Torró
6ebefa2c16
Add single-file export to PDF using the WebGL render (#9860) 2026-06-11 10:41:21 +02:00
Andrey Antukh
3377473f05 Merge remote-tracking branch 'origin/main' into staging 2026-06-11 10:12:12 +02:00
Andrey Antukh
ba9b03268a
⬆️ Update backend and common dependencies (#10108)
* 🐛 Fix incorrect valkey uri on backend tests

* ⬆️ Update backend dependencies

* ⬆️ Update pnpm dependencies

* 📎 Fix minor linter issues
2026-06-11 10:11:23 +02:00
Aitor Moreno
17b38e3e6b
Merge pull request #10123 from penpot/superalex-fix-wasm-selected-text-hover-double-click
🐛 Keep hover on selected text layers in WASM renderer
2026-06-11 09:47:50 +02:00
María Valderrama
577ddfa03e 🐛 Fix number of days for deletion for nitrate 2026-06-11 09:41:45 +02:00
Belén Albeza
8eedd951a8
🐛 Fix mistmatch in mapping custom font variants (wasm) (#10122) 2026-06-11 09:36:29 +02:00
Alejandro Alonso
435cdcb1d4 🐛 Keep hover on selected text layers in WASM renderer 2026-06-11 09:23:03 +02:00
Dexterity
920a05de74
♻️ Migrate typography sidebar option components to modern syntax (#9443) 2026-06-10 18:16:13 +02:00
Alonso Torres
ccd34a2705
🐛 Fix problems with async font loading (#10081) 2026-06-10 14:51:46 +02:00
Dexterity
3ffc76a552
♻️ Migrate token theme-selector components to modern syntax (#9447)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-06-10 13:48:11 +02:00
Dexterity
0b60e4e16e
♻️ Migrate flex-controls padding/margin/gap to modern syntax (#9458)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-06-10 13:47:48 +02:00
Dexterity
5d2e0cb7cb
♻️ Migrate viewer/interactions viewport components to modern syntax (#9442)
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-06-10 13:46:25 +02:00
Dexterity
a178de2c69
♻️ Migrate v3 text-editor to modern component syntax (#9444)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-06-10 10:57:19 +02:00
Dexterity
890ce378a7
♻️ Migrate template-item to modern component syntax (#9441)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-06-10 10:54:46 +02:00
sxxtony
ebb5738c7b
♻️ Migrate dashboard assets to modern syntax (#9404)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-06-10 10:52:54 +02:00
sxxtony
bfad78d39c
♻️ Migrate account settings to modern syntax (#9401)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-06-10 10:52:14 +02:00
Dexterity
32d974aa3e
♻️ Migrate onboarding team-choice to modern component syntax (#9463)
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-06-10 10:51:35 +02:00
Aitor Moreno
facea16444
Merge pull request #10038 from penpot/superalex-viewer-wasm
🎉 Basic viewer with wasm
2026-06-09 11:00:19 +02:00
alonso.torres
70e8dbb38a 🐛 Fix cropped outer stroke of rotated board in view mode 2026-06-09 09:40:26 +02:00
Andrey Antukh
7aa720f150 Merge remote-tracking branch 'origin/staging' into develop 2026-06-08 14:36:44 +02:00
Andrey Antukh
eff533374d 🐛 Ignore Safari browser extension errors in error handler
Add detection for Safari's webkit-masked-url:// extension URLs and filter
the "Attempting to change value of a readonly property" TypeError to prevent
Safari browser extension errors from being surfaced to users.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-06-08 14:32:01 +02:00
Andrey Antukh
82cfbedc26 Merge remote-tracking branch 'origin/main' into staging 2026-06-08 14:28:30 +02:00
Alonso Torres
6808390827
🐛 Fix problem with color picker error (#10056) 2026-06-08 13:25:45 +02:00
Andrey Antukh
4d0a3efc5c
🐛 Fix plugin API crash when setting text fills (#10051)
The `update-text-range` event's `watch` method was returning a bare
potok event object (`dwwt/resize-wasm-text-debounce id`) directly
inside `rx/concat`, instead of wrapping it in `rx/of`. This caused
RxJS to throw "You provided an invalid object where a stream was
expected" when a plugin set text fills via the Plugin API.

The fix wraps the event in `rx/of` so it becomes a valid Observable,
matching the pattern used elsewhere in the codebase (e.g.,
`clipboard.cljs` lines 1050/1082 and `texts.cljs` line 1232).

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-06-08 11:33:36 +02:00
Pablo Alba
2a48747cf6 Review nitrate add team members permission 2026-06-08 10:56:18 +02:00
Alexis Morin
3da7e7eb77
🐛 Fix French Canada locale not loading correct translations (#10027)
* 🐛 Fix French Canada locale not loading correct translations

Signed-off-by: Alexis Morin <alexis.morin@autodesk.com>

* Update CHANGES.md

Signed-off-by: Andrey Antukh <niwi@niwi.nz>

---------

Signed-off-by: Alexis Morin <alexis.morin@autodesk.com>
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-06-08 09:36:45 +02:00
Alejandro Alonso
9f5e89d5f8 🎉 Basic viewer with wasm 2026-06-05 16:41:30 +02:00
Alejandro Alonso
f9f4d7e2cd
🐛 Fix offscreen canvas resizing 2026-06-05 14:55:17 +02:00
Elena Torró
60d3c81450
Add wasm rulers (#9858)
*  Add wasm rulers

* 🔧 Fix dpr on page zoom

Co-authored-by: Alejandro Alonso <alejandroalonsofernandez@gmail.com>
Co-authored-by: Elena Torro <elenatorro@gmail.com>

* 🔧 Change page-switch behavior to refresh rulers and keep blurred snapshot

* 🐛 Restore WASM rulers after WebGL context recovery

Co-Authored-By: Elena Torro <elenatorro@gmail.com>
Co-Authored-By: Alejandro Alonso <alejandroalonsofernandez@gmail.com>

---------

Co-authored-by: Alejandro Alonso <alejandroalonsofernandez@gmail.com>
2026-06-05 07:51:35 +02:00