Key-rename permission checks the parent's allowAdd, not the node's (#374) - #387
Merged
Conversation
) A key-rename is a delete of the old key + an add of the new one to the PARENT collection, so gate it as exactly that: the node must be deletable AND its parent collection must accept adds. The add-half now reads the parent's allowAdd (via the `canAddHere` prop #386 already threads down) instead of the node's own, and allowEdit no longer takes part — a value-locked key can still be renamed. This fixes the footgun where restricting allowAdd to a few collections silently locked every key in the tree, and makes "can a key appear in collection X?" a single answer (allowAdd(X)) across the add button, rename, and drag relocate. - src/hooks/useCommon.ts: rewrite the canEditKey gate. - test/JsonEditor.test.tsx: 3 regression tests (red before, green after) + an array-index guard. - demo edit-restrictions example: redesigned as self-documenting matrix data (addable / sealed / editable boxes), mirroring drag-drop-rules; the `editable` box shows raw-JSON editing overriding per-leaf rules. - README_V2 NOTE, migration-guide §5 subsection, CHANGELOG beta.6. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Bundle size impact
|
| Format | Base raw | PR raw | Δ raw | Base gzip | PR gzip | Δ gzip |
|---|---|---|---|---|---|---|
| esm | 57.99 KB | 58.00 KB | 🔺 +10 B (+0.02%) | 20.70 KB | 20.70 KB | 🔺 +6 B (+0.03%) |
| cjs | 59.49 KB | 59.50 KB | 🔺 +10 B (+0.02%) | 20.74 KB | 20.74 KB | 🔺 +2 B (+0.01%) |
Measured from build/index.{cjs,esm}.js. Gzip at level 9.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes key-rename permission logic so renaming a property key is gated by deleting the node (allowDelete(node)) and adding to the parent collection (allowAdd(parent) via the threaded canAddHere), and no longer depends on allowEdit (since a rename is not a value edit). This aligns key-renaming with the permission model used elsewhere (notably drag-and-drop relocate rules).
Changes:
- Update
canEditKeyto requirecanDelete && canAddHere(parent add permission) and dropcanEdit/node-canAddfrom the rename gate. - Add regression tests covering parent-vs-node add permission, parent-sealed blocking,
allowEdit={false}allowing rename, and array index non-renamability. - Update docs/changelog and redesign the demo “edit-restrictions” example to reflect the corrected permission semantics.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
src/hooks/useCommon.ts |
Fixes canEditKey to use parent add permission (canAddHere) and remove allowEdit from rename gating. |
test/JsonEditor.test.tsx |
Adds regression tests validating the corrected rename permission rules. |
README_V2.md |
Updates documentation note to describe the new rename permission rule and its rationale. |
migration-guide.md |
Adds a migration note describing the behavior change for restrictive permission filters. |
demo/src/examples/static/edit-restrictions/Example.tsx |
Reworks the demo to clearly demonstrate edit/delete/add combinations and the parent-based rename rule. |
demo/src/examples/registry.ts |
Updates the example blurb to match the redesigned demo and new semantics. |
CHANGELOG.md |
Adds a 2.0.0-beta.6 entry documenting the rename permission change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Reads from the README "Controlling editing" / permissions context: lead with the three editing permissions (not including drag-n-drop), and introduce all three boxes up front (addable / sealed / editable) rather than "two boxes" + a later third. Same wording fix in the example's source comment. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #374.
What
A key-rename is a delete of the old key + an add of the new one to the parent collection, but the gate (
canEditKeyinuseCommon.ts) evaluatedallowEdit && allowAdd && allowDeleteall on the node itself. That was wrong on two counts:allowAdd, not the node's —allowAdd(node)is meaningless on a leaf, and restrictingallowAddto a few collections silently locked every key in the tree;allowEditshouldn't gate a rename at all — a rename isn't a value edit.Rule
A key is renamable when it isn't the root or an array index, the node is
allowDelete, and its parent collection isallowAdd.allowEditplays no part — a value-locked key can still be renamed.This makes "can a key appear in collection X?" a single answer —
allowAdd(X)— across the add button, rename, and drag relocate (the relocate rule landed in #386):allowAdd(collection)allowDelete(source)+allowAdd(destination)allowEdit(collection)allowDelete(node)+allowAdd(parent)How
One-liner, no new threading: #386 already threads the parent's
allowAddto every child as thecanAddHereprop (CollectionNodepassescanAddHere={canAdd}; root passesfalse). It's onBaseNodeProps, souseCommonalready receives it — the gate just reads it:canEdit/canAddstay (still used for the value editor, add button, and child threading).Compatibility (semver-significant)
Defaults are
true, so most consumers see no change. Only those with restrictiveallowEdit/allowAddfilters shift — toward the more correct behaviour:allowEdit:falseno longer blocks a key-rename (useallowDelete:false/ a restrictiveallowAddon the parent to lock keys);allowAdd, not the node's own.Tests
test/JsonEditor.test.tsx: 3 new regression tests (confirmed red before the fix, green after) — add-half checks the parent not the node; parent forbidding adds blocks the rename even when the node allows them;allowEdit:falseno longer blocks a rename — plus an array-index guard. Full suite 682 pass, lint +tscclean, demotsc+ eslint clean.Demo
Redesigned the
edit-restrictionsexample as self-documenting matrix data (mirroring thedrag-drop-rulespage): three boxes — addable (allowAdd✓), sealed (allowAdd✗), editable (the whole box edits as raw JSON) — each holding the same four emoji-labelled leaves (🟢 edit+delete, 🟡 delete-only, 🟠 edit-only, 🔴 neither). It demonstrates every non-DnD permission combo, that the same 🟢 renames in addable but not sealed (the parent-side check), that 🟡 renames despite a frozen value (noallowEdit), and that editing the editable box as JSON overrides every per-leaf rule inside it. Registry blurb rewritten to match.Docs
README_V2 key-rename NOTE rewritten; migration-guide §5 gets a short subsection; CHANGELOG entry under a new
2.0.0-beta.6(beta.5is already the publishedbetatag).Not done in this PR
package.jsonleft atbeta.5— the version bump is yours at publish time.🤖 Generated with Claude Code