feat(hutches): allow hutches to be renamed #12

Merged
cpressland merged 1 commit from feat/hutch-renames into main 2026-08-25 12:29:42 +01:00
Owner

Rename hutches

Hutches sometimes get physically moved around, at which point the lettering
system needs rebasing. There was no way to rename one short of editing the
database by hand.

letter is what groups a hutch's compartments together, so renaming has to
update every row of that hutch at once — otherwise the floors of a single hutch
would split across two names.

Changes

A Rename button beside Edit / Floors / Del opens a dialog prefilled with the
current name. Saving renames every compartment of the hutch in one transaction
and re-renders the row in place. Rabbits, cleaning dates, playtime and the floor
layout are all untouched — only the name moves. Each compartment gets its own
audit entry recording old → new, so the Activity Log shows what happened.

Rename is staff-level, consistent with Edit and Floors.

Validation

  • Empty names and names over 20 characters (the column limit) are rejected.
  • Collisions are rejected case-insensitively, so A and a cannot both exist,
    though a hutch may still change its own capitalisation.
  • Names are limited to letters, numbers, hyphens and underscores. The letter
    ends up in a URL path and in the id of the row's tbody, so it has to be
    safe in both.
  • Whitespace is trimmed, and renaming to the current name is a no-op.

The Rename button normally swaps the table row it belongs to, but a rejected
rename needs to go back to the dialog instead. Rather than out-of-band swaps,
the error response sets HX-Retarget: #clean-modal-host and
HX-Reswap: innerHTML, so htmx redirects that one response to the modal host
and the existing afterSwap handler reopens the dialog with the reason and the
typed value still in the field. The table is left alone.

Testing

Extended the hutches smoke suite to ~90 assertions, all passing, including the
existing compartment coverage. New checks: every compartment moving together
(ids, floors and occupants each verified), collision rejection with the
retarget headers asserted, invalid characters, over-length names, empty and
whitespace-only input, case-only renames, no-op renames, trimming,
per-compartment auditing, and 404s for a hutch that does not exist.

Also driven through the browser: renaming A to N showed the error in the
reopened dialog with the table untouched, then A to A1 applied in place with all
three floors, their rabbits and their cleaning dates intact.

Known limitations

Re-lettering a whole row of hutches in sequence (A→B, B→C) fails at the first
step, because B still exists. It needs a temporary name in between. Collisions
are a hard rejection on purpose: silently merging two hutches would leave one
letter holding duplicate floors. If bulk re-lettering turns out to be a regular
job, a dedicated reorder screen would suit it better than loosening this rule.

The New Hutch form does not share the character validation, so a hutch can still
be created with a space in its name. Such a hutch is already broken in the
existing UI — Edit, Floors and Del all build a #hutch-<letter> selector that
is not valid CSS with a space in it — so this predates the change rather than
being introduced by it.

## Rename hutches Hutches sometimes get physically moved around, at which point the lettering system needs rebasing. There was no way to rename one short of editing the database by hand. `letter` is what groups a hutch's compartments together, so renaming has to update every row of that hutch at once — otherwise the floors of a single hutch would split across two names. ### Changes A **Rename** button beside Edit / Floors / Del opens a dialog prefilled with the current name. Saving renames every compartment of the hutch in one transaction and re-renders the row in place. Rabbits, cleaning dates, playtime and the floor layout are all untouched — only the name moves. Each compartment gets its own audit entry recording old → new, so the Activity Log shows what happened. Rename is staff-level, consistent with Edit and Floors. ### Validation - Empty names and names over 20 characters (the column limit) are rejected. - Collisions are rejected case-insensitively, so `A` and `a` cannot both exist, though a hutch may still change its own capitalisation. - Names are limited to letters, numbers, hyphens and underscores. The letter ends up in a URL path *and* in the id of the row's `tbody`, so it has to be safe in both. - Whitespace is trimmed, and renaming to the current name is a no-op. The Rename button normally swaps the table row it belongs to, but a rejected rename needs to go back to the dialog instead. Rather than out-of-band swaps, the error response sets `HX-Retarget: #clean-modal-host` and `HX-Reswap: innerHTML`, so htmx redirects that one response to the modal host and the existing `afterSwap` handler reopens the dialog with the reason and the typed value still in the field. The table is left alone. ### Testing Extended the hutches smoke suite to ~90 assertions, all passing, including the existing compartment coverage. New checks: every compartment moving together (ids, floors and occupants each verified), collision rejection with the retarget headers asserted, invalid characters, over-length names, empty and whitespace-only input, case-only renames, no-op renames, trimming, per-compartment auditing, and 404s for a hutch that does not exist. Also driven through the browser: renaming A to N showed the error in the reopened dialog with the table untouched, then A to A1 applied in place with all three floors, their rabbits and their cleaning dates intact. ### Known limitations Re-lettering a whole row of hutches in sequence (A→B, B→C) fails at the first step, because B still exists. It needs a temporary name in between. Collisions are a hard rejection on purpose: silently merging two hutches would leave one letter holding duplicate floors. If bulk re-lettering turns out to be a regular job, a dedicated reorder screen would suit it better than loosening this rule. The New Hutch form does not share the character validation, so a hutch can still be created with a space in its name. Such a hutch is already broken in the existing UI — Edit, Floors and Del all build a `#hutch-<letter>` selector that is not valid CSS with a space in it — so this predates the change rather than being introduced by it.
feat(hutches): allow hutches to be renamed
All checks were successful
ci / buildah-build-push (push) Successful in 16s
ci / build (push) Successful in 0s
c9d21991ff
cpressland deleted branch feat/hutch-renames 2026-08-25 12:29:42 +01:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
cpressland/rabbitdb!12
No description provided.