21823 Commits

Author SHA1 Message Date
Dexterity
f4317d00e5
🐛 Fix swapped analytics event names on MCP tab-switch dialog (#9322) 2026-05-06 17:40:39 +02:00
Milos Milic
aa8f2ab80d
🐛 Fix missing labels.open i18n key surfacing raw key as aria-label (#9320) 2026-05-06 17:39:26 +02:00
Andrey Antukh
e07ad9cb53 Merge remote-tracking branch 'origin/staging' into develop 2026-05-06 15:07:45 +02:00
Andrey Antukh
14a0660352 Merge remote-tracking branch 'origin/main' into staging 2026-05-06 15:06:59 +02:00
FairyPiggyDev
4892799cf6
♻️ Migrate fontfaces and viewer thumbnails components to modern syntax (#9293)
Step toward issue #9260 (incremental migration of legacy UI
components to the modern `*`-suffixed syntax, removing the per-render
JS-to-Clojure props conversion overhead).

Two unrelated namespaces, both clean Case-A migrations grouped in a
single PR for review efficiency.

frontend/src/app/main/ui/shapes/text/fontfaces.cljs
---------------------------------------------------

Three components, all previously using `::mf/wrap-props false` with a
custom memoizer (`#(mf/memo' % (mf/check-props ["fonts"]))`) and
reading `fonts` via `(obj/get props "fonts")`. The custom memoizer
existed because the legacy components received raw JS-object props,
where the default `mf/memo` Clojure-equality comparison would always
fail.

- `fontfaces-style-html`   → `fontfaces-style-html*`
- `fontfaces-style-render` → `fontfaces-style-render*`
- `fontfaces-style`        → `fontfaces-style*`

Migration:

- Standard destructuring `[{:keys [fonts]}]` replaces the
  `[props]` + `(obj/get props "fonts")` pattern.
- `::mf/wrap-props false` removed.
- Custom memoizer collapses to `::mf/wrap [mf/memo]`. With modern
  destructuring the props are Clojure data, so default `=`-based memo
  is structurally correct (and a stronger guarantee than the previous
  shallow JS-prop check).
- `app.util.object` require dropped from the namespace — it was only
  used for the `obj/get props "fonts"` reads that are now gone.
- Internal call site of `fontfaces-style-render*` (within
  `fontfaces-style*`) keeps its `[:>` form, just with the new name.

External call sites updated:

- `frontend/src/app/main/render.cljs` — three sites
  (`[:& ff/fontfaces-style {:fonts fonts}]` × 3) →
  `[:> ff/fontfaces-style* {:fonts fonts}]`.
- `frontend/src/app/main/ui/workspace/shapes.cljs` — one site,
  call signature unchanged. (Note: this caller passes `:shapes`
  rather than `:fonts`; the legacy component already ignored
  `:shapes` because it only read `(obj/get props "fonts")`, so the
  modern destructuring `{:keys [fonts]}` preserves the same
  behavior. Pre-existing bug, intentionally left out of scope.)

frontend/src/app/main/ui/viewer/thumbnails.cljs
-----------------------------------------------

Four components, all using standard destructuring already (no
`::mf/wrap-props false`, no `unchecked-get`). Migration is the
straight `*` rename plus `?`-prop renames per the prompt's mapping:

- `thumbnails-content`  → `thumbnails-content*`   (`expanded?` →
  `is-expanded`)
- `thumbnails-summary`  → `thumbnails-summary*`   (no `?`-props)
- `thumbnail-item`      → `thumbnail-item*`       (`selected?` →
  `is-selected`; `::mf/wrap [mf/memo #(mf/deferred …)]` preserved)
- `thumbnails-panel`    → `thumbnails-panel*`     (`show?` →
  `show` — no `is-` prefix needed, reads naturally as a verb)

Internal callsites of all three sub-components in `thumbnails-panel*`
updated to `[:> …*` with renamed kwargs (`:expanded?` →
`:is-expanded`, `:selected?` → `:is-selected`).

The `expanded?` symbol still appears in `thumbnails-panel*`'s body —
it's a local `let`-binding deref'd from the `expanded-state` atom,
not a component param, so the `?` suffix is preserved per the
prompt's "local bindings stay" rule.

External call sites updated:

- `frontend/src/app/main/ui/viewer.cljs` — one site, plus the
  `:refer [thumbnails-panel]` → `:refer [thumbnails-panel*]` require
  update.

Github #9260

Signed-off-by: FairyPigDev <luislee3108@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-05-06 14:55:55 +02:00
Andrey Antukh
54928e9ffb Merge branch 'backport-2.14' 2026-05-06 14:38:17 +02:00
Andrey Antukh
df01f76056 🐛 Fix incorrect invitation token handling on register process (#9380)
* 🐛 Fix incorrect invitation token handling on register process

- Reject prepare-register-profile when an active profile already
  exists for the requested email.
- Stop embedding an existing profile's :profile-id into the
  prepared-register JWE. Profile resolution in register-profile is
  now done exclusively by email lookup, never by a JWE claim.
- Add created? guard to the invitation-success branch in
  register-profile, so existing profiles (active or not) cannot
  reach session creation via anonymous registration.

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

* ♻️ Restructure invitation handling inside register-profile

Move the invitation-success branch into the created? sub-cond so it
sits alongside the other post-creation branches, making the control
flow consistent.

- Active new profile + matching invitation: mint session and return
  :invitation-token (frontend redirects to :auth-verify-token).
- Not-yet-active new profile + matching invitation: embed the
  invitation token inside the verify-email JWE and send the
  verification email. When the user clicks the link, they get
  logged in and the frontend completes the team-invitation flow.
- Extend send-email-verification! with an optional invitation-token
  parameter propagated into the verify-email JWE claims.
- Update the frontend verify-email handler to navigate to
  :auth-verify-token when the response carries :invitation-token.

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

* 🐛 Handle email-already-exists error on registration form

Add a specific handler for the [:validation :email-already-exists] error
code in the registration form's on-error callback. The backend raises
this error when an active profile already exists for the requested email,
but the frontend was falling through to the generic error message.

Now it shows the existing "Email already used" i18n message instead of
the generic "Something wrong has happened" toast.

* 🐛 Reset submitted state on registration form error

The on-error handler in the registration form was not resetting the
submitted? state, causing the submit button to remain disabled after
any error. The completion callback in rx/subs! only fires on success,
not on error.

Add (reset! submitted? false) at the beginning of the on-error handler
so the form becomes submittable again after any error, allowing the user
to fix their input and retry.

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2.14.5
2026-05-06 14:32:31 +02:00
Aitor Moreno
4cd44efa93
Merge pull request #9371 from penpot/superalex-fix-drag-and-drop-cache-eligibility-rules
🐛 Fix drag and drop cache eligibility rules
2026-05-06 14:28:22 +02:00
Andrey Antukh
1e1ca82ba5 📚 Add missing changelog entry and document changelog locations
Add changelog entry for the fix-incorrect-invitation-token-handling
change (PR #9380) under `## 2.15.0 (Unreleased)` > `🐛 Bugs fixed`.
Add a `## Changelogs` section to AGENTS.md documenting both changelog
locations (main project: `CHANGES.md`, plugins: `plugins/CHANGELOG.md`).

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2.15.0-RC4
2026-05-06 12:24:55 +00:00
Andrey Antukh
9e681260cc
🐛 Fix incorrect invitation token handling on register process (#9380)
* 🐛 Fix incorrect invitation token handling on register process

- Reject prepare-register-profile when an active profile already
  exists for the requested email.
- Stop embedding an existing profile's :profile-id into the
  prepared-register JWE. Profile resolution in register-profile is
  now done exclusively by email lookup, never by a JWE claim.
- Add created? guard to the invitation-success branch in
  register-profile, so existing profiles (active or not) cannot
  reach session creation via anonymous registration.

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

* ♻️ Restructure invitation handling inside register-profile

Move the invitation-success branch into the created? sub-cond so it
sits alongside the other post-creation branches, making the control
flow consistent.

- Active new profile + matching invitation: mint session and return
  :invitation-token (frontend redirects to :auth-verify-token).
- Not-yet-active new profile + matching invitation: embed the
  invitation token inside the verify-email JWE and send the
  verification email. When the user clicks the link, they get
  logged in and the frontend completes the team-invitation flow.
- Extend send-email-verification! with an optional invitation-token
  parameter propagated into the verify-email JWE claims.
- Update the frontend verify-email handler to navigate to
  :auth-verify-token when the response carries :invitation-token.

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

* 🐛 Handle email-already-exists error on registration form

Add a specific handler for the [:validation :email-already-exists] error
code in the registration form's on-error callback. The backend raises
this error when an active profile already exists for the requested email,
but the frontend was falling through to the generic error message.

Now it shows the existing "Email already used" i18n message instead of
the generic "Something wrong has happened" toast.

* 🐛 Reset submitted state on registration form error

The on-error handler in the registration form was not resetting the
submitted? state, causing the submit button to remain disabled after
any error. The completion callback in rx/subs! only fires on success,
not on error.

Add (reset! submitted? false) at the beginning of the on-error handler
so the form becomes submittable again after any error, allowing the user
to fix their input and retry.

---------

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-06 14:20:55 +02:00
Pablo Alba
e8ac5f26db 💄 Fix nitrate change org combo style 2026-05-06 13:37:37 +02:00
Alejandro Alonso
708c4065b3 🐛 Fix drag and drop cache eligibility rules 2026-05-06 13:20:57 +02:00
Alejandro Alonso
9dd7835815 Merge remote-tracking branch 'origin/staging' into develop 2026-05-06 12:43:13 +02:00
María Valderrama
7efeed1348 🐛 Fix nitrate activation modal not opening 2026-05-06 12:41:19 +02:00
Xaviju
0ea3ea332f
🎉 Display autocomplete combobox on token creation (#9109)
Co-authored-by: Eva Marco <evamarcod@gmail.com>
2026-05-06 12:40:23 +02:00
Alonso Torres
2fbff4f88e
Buffer update shapes changes on token application 2026-05-06 12:16:35 +02:00
Alejandro Alonso
528d006b8d
Events enhancements
*  Compute moved-subtree data once in find-valid-parent-and-frame-ids
*  Smooth WASM drag preview stream
*  Limit WASM outline modifier application
2026-05-06 12:16:09 +02:00
María Valderrama
e65ce8bdeb 🐛 Fix date issue in nitrate activation success modal 2026-05-06 11:58:00 +02:00
Dominik Jain
ed935e533f Expose variants retrieval via isVariant() type guard on LibraryComponent
Change isVariant() return type from boolean to 'this is LibraryVariantComponent',
enabling TypeScript users to directly access variants, variantProps, and
variantError after a type-narrowing check. Update MCP instructions with
improved variant navigation guidance.

Closes #9185

Co-authored-by: Claude (Anthropic) <noreply@anthropic.com>
2026-05-06 11:28:15 +02:00
Andrey Antukh
34cc0e9d56 🔥 Materialize the canary feature flag across the codebase
Remove the :canary flag from the flags definition and make all
features gated behind it always available:

- Enable "download font" option in dashboard fonts context menu
- Enable Tab/Shift+Tab keyboard navigation for renaming shapes
  in layer items
- Enable "duplicate color" option in asset panel when applicable
- Enable "duplicate typography" option in asset panel when applicable
- Enable "copy as image" context menu option for frame shapes

Also remove unused [app.config :as cf] requires from files that
no longer reference it after the materialization.

Signed-off-by: Andrey Antukh <niwi@niwi.nz>
2026-05-06 11:19:04 +02:00
Marina López
6ad83d24c9 Add nitrate manual cancel subscription 2026-05-06 11:04:35 +02:00
Eva Marco
5f40673fde
🐛 Remove drag to change when there is a token applied on numeric-inputs (#9314) 2026-05-06 10:31:39 +02:00
María Valderrama
4ddabaebff
Add Nitrate's advanced permissions
*  Add Nitrate's advanced permissions

* 📎 Code review
2026-05-06 10:13:17 +02:00
Andrey Antukh
1744d17385 Merge remote-tracking branch 'origin/develop' into staging 2.16.0-RC2 2026-05-06 09:34:46 +02:00
Hosted Weblate
94f8370d98
🌐 Merge branch 'origin/develop' into Weblate. 2026-05-06 08:58:11 +02:00
Eva Marco
ce24fed32b
🐛 Fix incorrect text-edition warning when applying tokens (#9355) 2026-05-06 08:47:30 +02:00
Alejandro Alonso
dc5f02a11c 📎 Fix linting issues 2026-05-05 18:50:25 +02:00
Alejandro Alonso
67bb109331 📎 Fix linting issues 2026-05-05 18:32:25 +02:00
Alejandro Alonso
00c27287bd Merge remote-tracking branch 'origin/staging' into develop 2026-05-05 18:27:09 +02:00
Alejandro Alonso
b34054940f
Merge pull request #9361 from penpot/elenatorro-14100-wasm-fast-paths
 Improve drag rendering on text and paths
2026-05-05 18:21:36 +02:00
Aitor Moreno
61f5df8461
Merge pull request #9354 from penpot/superalex-fix-allow-selection-while-bounding-box-cloaking-is-active
🐛 Fix allow selection while bounding-box cloaking is active
2026-05-05 18:20:45 +02:00
Elena Torro
e950ec56eb Reduce per-render text layout work 2026-05-05 17:47:50 +02:00
Pablo Alba
2fbab08bde 🐛 Fix nitrate penpot-version schema 2026-05-05 17:47:47 +02:00
Elena Torro
4a0cd0b7ce Translation-only fast paths for Shape and Path transforms 2026-05-05 17:35:42 +02:00
Alejandro Alonso
2e8d188d87 🐛 Fix allow selection while bounding-box cloaking is active 2026-05-05 16:55:28 +02:00
Alejandro Alonso
ce1045c265
Merge pull request #9335 from penpot/alotor-fix-flex-auto-height
🐛 Fix problem with flex layout and text auto-height
2026-05-05 15:50:22 +02:00
Marina López
41996ed9a5 Add nitrate subscription text 2026-05-05 13:52:01 +02:00
Pablo Alba
3431aee177 🐛 Fix move org dialog must be select 2026-05-05 12:34:40 +02:00
alonso.torres
843b2aebd4 🐛 Fix problem with flex layout and text auto-height 2026-05-05 10:40:25 +02:00
Alejandro Alonso
7d923f8e1d Merge remote-tracking branch 'origin/staging' into develop 2026-05-05 06:52:38 +02:00
Alejandro Alonso
c794e0ed73
🎉 Events enhancements (#9310)
* 🎉 Coalesce viewport pointermove into one PointerEvent

* 🎉 Skip worker hover selection query during transform

* 🎉 Coalesce snap X/Y into one worker query-snap-xy
2026-05-04 17:57:00 +02:00
Dominik Jain
07ad152ae5 🐛 Fix .component() returning outermost component for nested instances
The shape API method .component() used locate-component which walks
to the outermost instance root via get-instance-root. For nested
component instances (e.g. a button inside a card), this incorrectly
returned the outer component (the card) instead of the nearest one
(the button).

Added locate-head-component in utils.cljs which uses get-head-shape
to find the nearest component head, and updated the :component
property in shape.cljs to use it.

Fixes #9183
2026-05-04 16:13:25 +02:00
Clayton
4ce56e96fe
🐛 Fix MCP media uploads and SVG data URI image parsing (#9201)
* 🐛 Fix MCP media uploads and SVG data URI image parsing

Signed-off-by: Clayton <claytonlin1110@gmail.com>

* 🐛 Fix lint

Signed-off-by: Clayton <claytonlin1110@gmail.com>

* 🐛 Fix test

Signed-off-by: Clayton <claytonlin1110@gmail.com>

---------

Signed-off-by: Clayton <claytonlin1110@gmail.com>
2026-05-04 13:33:58 +02:00
Eva Marco
a2bcbe81dd
🎉 Add token numeric inputs for inputs on right sidebar (#9143)
Co-authored-by: Xavier Julian <xavier.julian@kaleidos.net>
2026-05-04 13:02:19 +02:00
Alejandro Alonso
164f0cba7a Merge remote-tracking branch 'origin/staging' into develop 2026-05-04 11:56:07 +02:00
María Valderrama
152967bea6 🐛 Fix sidebar overflow 2026-05-04 11:02:54 +02:00
Alonso Torres
e948020886
🐛 Fix problem with rounding in flex elements 2026-05-04 10:35:16 +02:00
andrés gonzález
66337f2ab9
📚 Add WebGL Troubleshooting Guide 2026-05-04 09:34:19 +02:00
María Valderrama
f24ad6bee4
Show current plan in Nitrate
*  Show current plan in Nitrate

* 📎 Code Review
2026-05-04 09:29:14 +02:00
alonso.torres
f6bd991968 🐛 Improved e2e tests stability 2026-05-04 09:04:30 +02:00