40 Commits

Author SHA1 Message Date
alonso.torres
9e8be56eb3 🐛 Revert whole user actions in a rollback
A rollback reverts whole undo groups, across files and saves, so that
no user action is left half done. Some actions still split:

- An action that commits several times inside one undo transaction
  (e.g. applying a token to several shapes) gave each commit its own
  group, so a rejection could revert part of it: shapes ended up linked
  to a token whose value was never applied. An undo transaction now
  opens with a commit group that every commit made inside it takes.
- The commit that undoes saved commits of a rejected action joined an
  open transaction's group, so a later rejection there reverted the
  undo too. It gets a group of its own.
- Emptying the open transaction during a rollback dropped its group, so
  its later commits were no longer one unit. It keeps its group.
- Waiting for a save ended as soon as the queue emptied, while later
  commits could still wait in the buffer. Waiters now also wait for an
  empty buffer.

A test covers a token action of three commits in one save whose third
commit is rejected.
2026-11-03 11:17:19 +01:00
alonso.torres
909ba438a9 ✨ Keep the valid commits of a save that fails validation
A save whose changes failed validation was rejected as a whole: autosave
stopped, the edits made after it piled up unsent, and a reload lost
them all, the valid ones included.

The frontend now sends each commit of a save as its own group with its
commit id (:changes-with-metadata). When applying and validating all of
them at once fails, the backend searches by bisection for the first
commit that fails, keeps the commits before it and answers with
:rejected (that commit and every later one). Only the kept changes are
stored, snapshotted and broadcast, so other users never see the rejected
ones. Flat :changes and groups without ids stay all-or-nothing; database
and network errors still fail the whole request. A rejection without an
error type is reported as an internal error.

The frontend rolls the file back to what the server holds: it undoes
every pending commit of that file, applies again the remote changes that
arrived meanwhile, and redoes the kept commits. Undoing only the
rejected commits would write stale values over a peer's later change to
the same attribute. The rejected and later commits leave the queue, the
buffer and the undo history, and a warning that hides after ten seconds
tells the user. The pure bookkeeping lives in
app.main.data.persistence.commits.

The pending notice of a commit the rollback dropped no longer leaves the
save status at pending, which made "Pin this version" hang and fail.

Debug tools drive these cases by hand: debug.commitInvalidChange() makes a
save fail validation, holdSaves() delays the answers, failNextSave() and
failNextRollback() fail them on purpose (backend flag debug-save-faults),
and persistenceState() shows the queue.
2026-11-03 11:17:14 +01:00
alonso.torres
8bacc7b58b 🐛 Apply remote changes under buffered local edits too
A remote commit undoes the pending local commits, applies the remote
changes and replays the local ones, so the local file ends like the
server will: remote first, local last. Only queued commits took part;
the ones still waiting in the persistence buffer (up to ~3s of edits)
stayed under the remote change. When both touched the same attribute,
the remote value won locally but lost on the server.

The buffer now lives in the store ([:persistence :buffer]) instead of
an rx buffer, so the rebase can reach it. A flush merges it per file
into queue entries that keep the list of commits they carry, and the
leave-page guard reads buffer and queue from the store. A buffer left
by a previous session is queued when persistence starts.
2026-11-03 11:17:11 +01:00
Pablo Alba
0532f15cee
🐛 Fix tab on variant name doesn't validate formula (#12655)
* 🐛 Fix tab on variant name doesn't validate formula

* ✨ Move helpers to common

* ✨ Mr proposed changes
2026-10-28 11:44:38 +01:00
Andrey Antukh
34b24a9d9d ✨ Retry transient saves with backoff and reconnect notice
Classify save failures as transient or terminal (`transient-error?`
over the repo retryable types plus `:invalid-save-response`).
Transient failures keep the head commit queued under a new `:retrying`
status and resend it with backoff (2s/8s/20s, then terminal):
stamp rotation reuses the same `:commit-id`, the in-flight guard
prevents double-sends, and episode tokens silence stale timers.
One tagged reconnect notice per episode (hidden on save and on
terminal failure, silent recovery) plus a `:retrying` save-indicator
state; the browser `online` event and new edits resume the episode.
Terminal failures keep the exact `:error` path. Covers tasks 4, 6
and 7 with 31 persistence tests; updates the persistence memory.

Relates to #11724

AI-assisted-by: muse-spark-1.3-contributor
2026-09-23 12:05:24 +02:00
Alonso Torres
ff88a055fd
🐛 Fix stalled saving states (#11699) 2026-09-15 16:04:00 +02:00
Alejandro Alonso
fb22c1547c
🐛 Skip component sync for derived WASM text layout commits (#11490)
Post-font-load selrect fixes and position-data regeneration write
sync-attrs on texts inside mains. That made watch-component-changes
treat them as edits and run touch/sync per component, freezing large
files. Mark those commits with skip-component-sync? (same idea as
translation?) so only real user edits propagate.
2026-09-03 13:43:36 +02:00
Andrey Antukh
81c3b3cd56
📎 Update copyright name on file header (#11346) 2026-08-25 11:55:10 +02:00
Alejandro Alonso
4cd34b22e2
🐛 Fix wasm context restore guards (#10824)
* 🐛 Prevent WASM panics during WebGL context restore

Delay context-restored until reload finishes and no-op app
mutations while reloading so resize/modifiers cannot panic
mid-teardown.

* 🐛 Fall back to CLJS bool content when WASM is not ready

Returning nil from calculate-bool would persist empty path content
during context loss/reload; use path/calc-bool-content instead.
2026-07-29 10:06:52 +02:00
Alonso Torres
ccd34a2705
🐛 Fix problems with async font loading (#10081) 2026-06-10 14:51:46 +02:00
Andrey Antukh
c5de4c27b0 Merge remote-tracking branch 'origin/main' into staging 2026-06-01 12:57:39 +02:00
Yamila Moreno
ddba2ffa75
📎 Update Kaleidos Copyright (#9929) 2026-05-29 11:24:58 +02:00
Belén Albeza
4a73a97a32 🐛 Fix shapes not being rendered after render switch 2026-05-21 16:31:56 +02:00
Alejandro Alonso
164f0cba7a Merge remote-tracking branch 'origin/staging' into develop 2026-05-04 11:56:07 +02:00
Elena Torro
27d854ed5b ⚡ Skip component-sync on pure-translation drag commits 2026-04-30 13:45:45 +02:00
Andrés Moya
a3ea9fbecb
🔧 Add more validations for components, to avoid some crashes (#7820)
* 🔧 Validate only after propagation in tests

* 💄 Enhance some component sync traces

* 🔧 Add fake uuid generator for debugging

* 🐛 Remove old feature of advancing references when reset changes

Since long time ago, we only allow to reset changes in the top copy
shape. In this case the near and the remote shapes are the same, so
the advance-ref has no effect.

* 🐛 Fix some bugs and add validations, repair and migrations

Also added several utilities to debug and to create scripts that
processes files

* 🐛 Fix misplaced parenthesis passing propagate-fn to wrong function

The :propagate-fn keyword argument was incorrectly placed inside the
ths/get-shape call instead of being passed to tho/reset-overrides.
This caused reset-overrides to never propagate component changes,
making the test not validate what it intended.

* 🐛 Accept and forward :include-deleted? in find-near-match

Callers were passing :include-deleted? true but the parameter was not
in the destructuring, so it was silently ignored and the function
always hardcoded true. This made the API misleading and would cause
incorrect behavior if called with :include-deleted? false.

* 💄 Use set/union alias instead of fully-qualified clojure.set/union

The namespace already requires [clojure.set :as set], so use the alias
for consistency.

* 🐛 Add tests for reset-overrides with and without propagate-fn

Add two focused tests to comp_reset_test to cover the propagate-fn
path in reset-overrides:

- test-reset-with-propagation-updates-copies: verifies that resetting
  an override on a nested copy inside a main and supplying propagate-fn
  causes the canonical color to appear in all downstream copies.

- test-reset-without-propagation-does-not-update-copies: regression
  guard for the misplaced-parenthesis bug; confirms that omitting
  propagate-fn leaves copies with the overridden value because the
  component sync never runs.

---------

Co-authored-by: Andrey Antukh <niwi@niwi.nz>
2026-04-15 08:42:42 +02:00
Dream
0c08dfb13d
✨ Add the ability for save and restore selection state in undo/redo (#8652)
* ✨ Capture selection state before changes are applied

Save current selection IDs in commit-changes so undo entries
can track what was selected before each action.

* ✨ Save and restore selection state in undo/redo

Extend undo entry with selected-before and selected-after fields.
On undo, restore selection to what it was before the action.
On redo, restore selection to what it was after the action.
Handles single entries, stacked entries, accumulated transactions,
and undo groups.

Fixes #6007

* ♻️ Wire selected-before through workspace undo stream

Pass the captured selection state from commit data into
the undo entry so it is stored alongside changes.

* 🐛 Fix unmatched delimiter in changes.cljs

* 🐛 Pass selected-before through commit event to undo entry

selected-before was captured in commit-changes but dropped by the
commit function since it was missing from the destructuring and the
commit map. This caused restore-selection to receive nil on undo.

---------

Signed-off-by: eureka928 <meobius123@gmail.com>
Co-authored-by: Mihai <noreply@github.com>
2026-04-07 16:30:47 +02:00
alonso.torres
1b29e9a50f 🐛 Fix race condition with fix fonts patch 2025-12-03 10:39:05 +01:00
alonso.torres
ed4df73e42 ✨ Changes to modifiers 2025-10-31 11:56:28 +01:00
alonso.torres
17fefcf0bc ✨ Changes WASM serialization mechanism 2025-10-31 11:56:28 +01:00
Alonso Torres
40e9a78f67
✨ Add telemetry for events performance measures (#7457) 2025-10-08 14:03:09 +02:00
Andrey Antukh
b9030fcc73 ✨ Add better workspace file indexing strategy
Improve file indexes initialization on workspace.

Instead of initialize indexes for all pages only initialize
indexes for the loaded page.
2025-09-29 12:07:49 +02:00
Andrey Antukh
575342b3bb ♻️ Use direct schemas instead of references
Only a very common use, basic types schemas should be used as
reference (with namespaced keywords)
2025-08-20 12:33:07 +02:00
Andrey Antukh
283eb0419c ♻️ Refactor time related namespaces
Mainly removes the custom app.util.time namespace
from frontend and backend and normalize all to use
the app.common.time namespace
2025-08-01 11:20:01 +02:00
Miguel de Benito Delgado
968ea56197
♻️ Reorganize index management on worker code (#6477)
* ♻️ Factor index management out of app.worker.impl

* 💄 Fix silly spacing

* 💄 Lint
2025-05-15 09:46:49 +02:00
Andrey Antukh
f8ffae75c4 ⚡ Make feature resolved on team load
That simplifies features retrieval to simple get
2025-04-01 20:01:21 +02:00
Andrey Antukh
85746e7cb2 ♻️ Refactor state locality
The main purpose of this refactor is reduce
a custom state from different pages and unify
them under common access patterns
2025-01-16 15:31:18 +01:00
Andrey Antukh
e5894ceea1 ♻️ Rename workspace-libraries to libraries on state and refs 2024-12-10 14:45:56 +01:00
alonso.torres
838c1324b9 🎉 Add new gradients UI 2024-11-19 16:41:01 +01:00
alonso.torres
ecb7f0a2f6 ✨ File history versions management 2024-10-29 14:23:35 +01:00
Andrey Antukh
d6da8afdce ✨ Add improved abstraction for team permissions
Relevant changes:
- replace user-viewer? with can-edit removing many double
  negations on the code
- always use team permissions making the permissions access uniform
  around all the code
- expose team permissions to ui tree through ctx/team-permissions
  context
2024-10-21 12:36:01 +02:00
Pablo Alba
bd08e99080 ♻️ Clean up and refactors of viewer role 2024-10-18 10:12:59 +02:00
Pablo Alba
226ab7233b ✨ Add viewer role to workspace 2024-10-15 13:38:46 +02:00
Andrey Antukh
b82c6326cf ✨ Add better error reporting on changes validation 2024-09-18 12:15:12 +02:00
Andrey Antukh
4f84e77b10 ✨ Add generative tests for set-guide change 2024-09-18 12:15:12 +02:00
Andrey Antukh
bde1cd3f5f 🐛 Fix unexpected exception on frontend test
caused by unexpected return nil on a merge-map
2024-08-07 16:07:59 +02:00
Andrey Antukh
a2cc7764fb ✨ Improve how indexes are updated on concurrent sessions 2024-06-19 11:48:08 +02:00
Andrey Antukh
d35569dc55 ✨ Simplify transducer definition for proces redo changes 2024-06-10 18:59:39 +02:00
Andrey Antukh
3c1086dfcc 🐛 Fix race condition between shape modifiation and persistence 2024-06-10 18:51:48 +02:00
Andrey Antukh
6436ef334b ♻️ Refactor persistence layer 2024-06-04 10:15:32 +02:00