* ✨ Remove the need to navigate to page for deletion operation
* 🐛 Fix multiple selection with applied-tokens on stroke-color
* 🐛 Fix button position on page header
---------
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* ✨ Add read-only preview mode for saved versions (#7622)
* 🔧 Address review feedback on version preview (#7622)
* 🐛 Fix version preview for WASM renderer (#7622)
* 🐛 Fix stylelint color-named and color-function-notation in preview banner (#7622)
* 🐛 Fix invalid-arity call to initialize-workspace in exit-preview (#7622)
* 🐛 Fix unclosed defn paren in exit-preview (#7622)
* ♻️ Refactor version preview/restore flow
Separate enter-preview and enter-restore flows with dedicated dialogs
instead of a persistent banner. Removes preview-banner component in favor
of inline actions dialog. Uses backup/restore pattern for exit-preview
instead of full workspace reinitialization. Adds analytics events for
preview/restore actions.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
* ⚡ Extract on-name-input-focus as namespace-level private function
The callback had no dependencies on component-local state or props,
making it a pure function that can be hoisted to a defn-. This avoids
recreating the same callback identity on every render of version-entry*.
* ⚡ Extract extract-id-from-event helper to deduplicate snapshot callbacks
Three callbacks in snapshot-entry* shared the same DOM extraction logic
(get current target, read data-id, parse UUID). Extracted into a private
defn- to remove the duplication and simplify each callback.
* ⚡ Extract pure state-update callbacks from versions-toolbox* to namespace level
Eight callbacks that only emit fixed Potok events with no meaningful
deps were hoisted out of the component as defn- functions:
- on-create-version
- on-edit-version
- on-cancel-version-edition
- on-rename-version
- on-delete-version
- on-pin-version
- on-lock-version
- on-unlock-version
These no longer need mf/use-fn wrappers since namespace-level functions
have stable identity across renders, avoiding unnecessary callback
recreation on each render cycle.
* ✨ Rename filter parameter to filter-value in on-change-filter to avoid core shadowing
The parameter name 'filter' shadowed clojure.core/filter within the
function scope. Renamed to 'filter-value' for clarity and to prevent
potential bugs if core/filter were needed in future changes.
* 🔧 Fix linter warnings and errors across version-related namespaces
frontend/src/app/main/ui/workspace.cljs:
- Remove unused requires: app.common.data, app.main.data.notifications,
app.main.data.workspace.versions
frontend/src/app/main/data/workspace/versions.cljs:
- Remove unused require: app.common.uuid
- Fix duplicate reify type: enter-restore used ::restore-version
(same as the private restore-version fn), renamed to ::enter-restore
- Remove unused bindings: state in enter-restore, team-id in
exit-preview and restore-version-from-plugin
---------
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Signed-off-by: wdeveloper16 <wdeveloer16@protonmail.com>
Co-authored-by: wdeveloper16 <wdeveloer16@protonmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
* 🐛 Ensure typography-ref attrs are always present and fix nil encoding
Add :typography-ref-file and :typography-ref-id (both defaulting to nil)
to default-text-attrs so these keys are always present in text node maps,
whether or not a typography is attached.
Skip nil values in attrs-to-styles (Draft.js style encoder) and in
attrs->styles (v2 CSS custom-property mapper) so nil typography-ref
entries are never serialised to CSS.
Replace when with if/acc in get-styles-from-style-declaration to prevent
the accumulator from being clobbered to nil when a mixed-value entry is
skipped during style decoding.
* 🎉 Add test
---------
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
If the mcp key has expired, the switch that indicates the status in the dashboard will appear as disabled, and will show a modal for regenerate the key. It will also appear as disabled in the workspace, not allowing the plugin to connect
* ✨ Add loader feedback while importing and exporting files
Show a loader icon with a status label ("Importing files…" /
"Exporting files…") in the import and export dialog footers while the
operation is running, so users get clear in-progress feedback and
cannot retrigger the action by mistake.
Closes#9020
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
* ✨ Address import/export loader feedback PR review
- Show the loader beside file names in the import dialog while files
are being imported (previously queued entries kept showing the
Penpot logo until each one moved into :import-progress).
- Drop the loader from the "Importing files…" / "Exporting files…"
footer status, leaving just the text styled with the modal title
color, per the design proposal.
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
* ✨ Match design proposal for import/export progress feedback
- Move the in-progress label from the modal footer into the modal
body, under the file rows, styled italic with the modal title
color.
- Rename the labels to match the design wording: "Uploading file…"
for import and "Downloading file…" for export.
- Restore the disabled "Accept" button in the import footer during
the import-progress phase, mirroring the disabled "Close" button
used by export.
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
* 🐛 Rename deprecated bodySmallTypography mixin to body-small-typography
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
---------
Signed-off-by: moorsecopers99 <patellscott18@gmail.com>
Co-authored-by: Andrey Antukh <niwi@niwi.nz>
The inline (fn [] (ts/schedule ...)) passed as :on-blur to text-options
was an exact copy of the on-text-blur callback already defined via
mf/use-fn earlier in the same let block. Pass on-text-blur directly
to avoid allocating a new function object on every render.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
toggle-main-menu and toggle-more-options close over a state atom and
need no external deps. The declared deps (main-menu-open? /
more-options-open?) were unused inside the function bodies, causing
each callback to be reallocated on every toggle — self-reinforcing
churn. Drop the mf/deps calls to make both callbacks stable.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
(contains? cf/flags :token-typography-row) is a pure constant:
cf/flags is immutable after startup. Define it once as a private
namespace-level var token-typography-row? instead of re-evaluating
the check on every render in text-decoration-options* and text-menu*.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Wrap the (case type (tr ...) ...) expression in mf/with-memo [type]
so the translation is resolved only when the type prop changes
instead of on every render.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Wrap the two radio-button option maps in mf/with-memo [token-applied]
so the vector and its (tr ...) calls are evaluated only when the
token-applied prop changes, not on every render.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Wrap the three radio-button option maps in mf/with-memo [] so the
vector and its (tr ...) calls are evaluated once per mount instead
of on every render.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Wrap the two radio-button option maps in mf/with-memo [] so the
vector and its (tr ...) calls are evaluated once per mount instead
of on every render.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Wrap the four radio-button option maps in mf/with-memo [] so the
vector and its (tr ...) calls are evaluated once per mount instead
of on every render.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Wrap the radio-button options vector in `mf/with-memo []` so the
vector allocation and `(tr ...)` calls happen once per component
mount instead of on every render.
Also document the translation memoization rule in frontend/AGENTS.md:
`(tr ...)` must never be called at namespace level (locale is
runtime-only), and static option lists should always be wrapped in
`mf/with-memo []`.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
- Add session ID tracking to RPC layer (backend and frontend)
- Send session ID header with RPC requests for request correlation
- Rename file-restore to file-restored for consistency
- Extract initialize-file function from initialize-workspace flow
- Improve file restoration initialization with wait-for-persistence
- Extract initialize-version event handler for version restoration
- Fix viewport key generation with file version numbers for proper re-renders
- Update layout item schema and constraints to use internal sizing state
- Add v-sizing state retrieval in layout-size-constraints component
- Refactor file-change notifications stream handling with rx/map
- Fix team-id lookup in restore-version-from-plugins
Improves request traceability across frontend/backend sessions and streamlines
the workspace initialization flow for file restoration scenarios.
Signed-off-by: Andrey Antukh <niwi@niwi.nz>
Rename text-align-options, text-direction-options, vertical-align,
grow-options, text-decoration-options and text-menu to their * variants.
Update all call sites in shapes/text.cljs, shapes/group.cljs and
shapes/multiple.cljs.
Rename components to blur-menu*, constraints-menu* and stroke-menu*.
Update :refer imports and all [:& ...] call sites to [:> ...*] for
blur-menu*, constraints-menu* and stroke-menu* across all nine
shapes-specific options panels.