Skip to content

Group and custom-field reordering, and a working reparent drag - #278

Merged
SiteRelEnby merged 3 commits into
mainfrom
feat/ordering-groups-fields
Sep 8, 2026
Merged

Group and custom-field reordering, and a working reparent drag#278
SiteRelEnby merged 3 commits into
mainfrom
feat/ordering-groups-fields

Conversation

@SiteRelEnby

Copy link
Copy Markdown
Contributor

Adds manual ordering for groups and custom fields, and fixes drag-to-reparent on the Groups page, which turned out to be broken in both browser engines.

Group reordering did not exist: groups had no order column and the list endpoint hardcoded alphabetical. They now carry order, sorted (order, name) so untouched systems keep today's A-Z view, applied everywhere the app lists groups and now also on public profiles and share links (owner's arrangement, name tiebreak - the same order visitors would infer from the app anyway once the owner curates it). The column rides the export, the native importer, and the OpenPlural sheaf extension, with both parity suites classifying it. Custom fields had the column all along but no web surface; both now share the same affordance: up/down arrows (drag on groups is taken by reparenting), backed by symmetric atomic bulk endpoints PUT /v1/groups/reorder and PUT /v1/fields/reorder (ordered ids -> order = index, tenant-scoped, duplicates and foreign ids rejected, declared ahead of the /{id} routes).

The reparent drag failed differently per engine: Chromium cancels a drag whose source DOM mutates during dragstart, and setting the dragging state there re-rendered the row and mounted the drop zone in the same tick, aborting the drag instantly (the cursor moved, the row never lifted); the state update is now deferred one tick. Firefox additionally never starts a drag with an empty drag data store, which dragstart never populated; it now does. Both verified live on localdev.

Also hardens the custom-field importer's order coercion (a crafted non-integer order aborted the whole import) to match the new group path.

Migration adds the column with a fail-fast lock_timeout; metadata-only on modern Postgres. Full behavioural suite and the public_profiles config pass; ruff, tsc, eslint, and a production build are clean. New endpoint tests cover happy path, duplicates, foreign ids via a second account, and unnamed-rows-keep-position; import round-trip covers order preservation and junk coercion.

Groups gain an order column (migration backfills 0, so untouched systems
keep their alphabetical view via the (order, name) sort), carried through
the schemas, the list endpoints, the export, the native importer, and the
OpenPlural sheaf extension, with both parity suites classifying it. A new
PUT /v1/groups/reorder applies an ordered id list as order = index in one
transaction, tenant-scoped, with duplicate and foreign ids rejected;
PUT /v1/fields/reorder is its twin for custom-field definitions, whose
order column existed but had no web surface. Up/down arrows move a group
among its siblings on the Groups page and reorder fields in Settings;
drag stays reparenting. Public profiles and share links follow the
owner's order for both groups and member-card fields, name as tiebreak.

Drag-to-reparent itself was broken in both engines, each its own way:
Chromium cancels a drag whose source DOM mutates during dragstart, and
setting draggingId there re-rendered the row and mounted the drop zone
in that same tick, so the drag aborted instantly (cursor moved, row
never lifted); the state update is now deferred one tick. Firefox never
started the drag at all because nothing populated the drag data store,
which it requires; dragstart now sets it. Drop handlers preventDefault
for hygiene.

The custom-field importer's order coercion is also hardened to match the
new group path, so a crafted non-integer order can no longer abort an
import.
…e merge

Both files were newly created and never staged - the feature commit used
commit -a, which only stages modifications to tracked files. Local runs
passed because the files sat in the working tree; CI built from the
commit, had no migration, and every request touching groups.order failed
with UndefinedColumnError.
@SiteRelEnby
SiteRelEnby merged commit 7523e57 into main Sep 8, 2026
18 checks passed
@SiteRelEnby
SiteRelEnby deleted the feat/ordering-groups-fields branch September 8, 2026 03:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant