feat(collab): selection soft-locks — remote-selected items can't be dragged locally (collab-presence 0007)
While a peer has an item selected, local users can still select it for
inspection but move/drag/rotate/delete skip it with an infobar naming the
holder (native locked-item UX; enforced via the fork's PCBJAM_REMOTE_LOCK
query — kicad 81f9cd80fd, the epic's first fork-touching phase). Overlapping
holds (both grabbed inside the awareness propagation window) tie-break
deterministically: lowest (user.id, clientID) keeps the item, every losing
client auto-releases it.
- lock-tiebreak.ts: pure policy — beats(), remoteLocks() (union of ALL other
clients' selections incl. own user's other tabs, minus own-held-and-winning
uuids so the winner isn't blocked mid-release), contestedReleases()
- presence.ts: clients() (per-client view, no user dedupe) + self(); FIX for
a pre-existing flaky stack overflow — resolveCollision re-entered itself
synchronously via its own patch's awareness 'change' and could ping-pong on
stale same-user states (~1-in-3 unit runs); re-entrancy guard defers
re-resolution to the next genuine delivery
- presence-kicad.ts: locks ride the kicadCollabSetRemote snapshot
(`locks:[{uuid,name}]`); losing overlaps call kicadCollabReleaseSelection
- wasm bindings (both TUs + merged dispatch): g_locks map + fork query
install; kicadCollabReleaseSelection (cancelInteractive only when a tool
stack is live — bare ESC would clear the whole selection — then selective
RemoveItemFromSel + infobar + forced re-emit); kicadCollabTestGetLocked
- tests: lock-tiebreak unit suite; presence-locks e2e for both editors (real
move veto — pcbnew click+M hotkey since its default left-drag is
rubber-band select, eeschema real drag — each with an unlocked control);
two-tab tests/web/locks.spec.ts (lock propagation + deterministic tiebreak
release + unlock on clear, passing vs real partykit)
Spec: docs/features/collab-presence/0007 (closed repo).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Lg5jwWuhFH5dL8hEcBDuP2
This commit is contained in:
parent
3186986a0a
commit
c30bcd4531
14 changed files with 1221 additions and 7 deletions
|
|
@ -59,6 +59,9 @@ std::string pcbCollabGetSelection();
|
|||
std::string pcbCollabGetSelectionFull();
|
||||
std::string pcbCollabTestGetCrossMapped();
|
||||
std::string pcbCollabTestSelectComponent();
|
||||
// Selection soft-locks (collab-presence 0007).
|
||||
void pcbCollabReleaseSelection( std::string aUuidsJson, std::string aHolder );
|
||||
std::string pcbCollabTestGetLocked();
|
||||
std::string pcbCollabTestSelectFirst();
|
||||
bool pcbCollabTestClearSelection();
|
||||
|
||||
|
|
@ -85,6 +88,9 @@ std::string schCollabGetSelection();
|
|||
std::string schCollabGetSelectionFull();
|
||||
std::string schCollabTestGetCrossMapped();
|
||||
std::string schCollabTestSelectComponent();
|
||||
// Selection soft-locks (collab-presence 0007).
|
||||
void schCollabReleaseSelection( std::string aUuidsJson, std::string aHolder );
|
||||
std::string schCollabTestGetLocked();
|
||||
std::string schCollabTestSelectFirst();
|
||||
bool schCollabTestClearSelection();
|
||||
|
||||
|
|
@ -227,6 +233,17 @@ static std::string collabTestSelectComponent()
|
|||
return pcbEditorActive() ? pcbCollabTestSelectComponent() : schCollabTestSelectComponent();
|
||||
}
|
||||
|
||||
static void collabReleaseSelection( std::string aUuidsJson, std::string aHolder )
|
||||
{
|
||||
pcbEditorActive() ? pcbCollabReleaseSelection( aUuidsJson, aHolder )
|
||||
: schCollabReleaseSelection( aUuidsJson, aHolder );
|
||||
}
|
||||
|
||||
static std::string collabTestGetLocked()
|
||||
{
|
||||
return pcbEditorActive() ? pcbCollabTestGetLocked() : schCollabTestGetLocked();
|
||||
}
|
||||
|
||||
static std::string collabTestSelectFirst()
|
||||
{
|
||||
return pcbEditorActive() ? pcbCollabTestSelectFirst() : schCollabTestSelectFirst();
|
||||
|
|
@ -268,6 +285,9 @@ EMSCRIPTEN_BINDINGS(kicad_editor) {
|
|||
function("kicadCollabGetSelectionFull", &collabGetSelectionFull);
|
||||
function("kicadCollabTestGetCrossMapped", &collabTestGetCrossMapped);
|
||||
function("kicadCollabTestSelectComponent", &collabTestSelectComponent);
|
||||
// Selection soft-locks (collab-presence 0007).
|
||||
function("kicadCollabReleaseSelection", &collabReleaseSelection);
|
||||
function("kicadCollabTestGetLocked", &collabTestGetLocked);
|
||||
function("kicadCollabTestSelectFirst", &collabTestSelectFirst);
|
||||
function("kicadCollabTestClearSelection", &collabTestClearSelection);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue