Skip to content

refactor(board): a board is edited in one place, not two - #969

Merged
ExtraToast merged 1 commit into
mainfrom
feat/board-editor-leaves-management
Sep 2, 2026
Merged

refactor(board): a board is edited in one place, not two#969
ExtraToast merged 1 commit into
mainfrom
feat/board-editor-leaves-management

Conversation

@ExtraToast

@ExtraToast ExtraToast commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

What this does

The board used to be edited in two places. /management/boards asked for an asset file nameboard9/Emma.jpg, a path into the frontend's own source tree — so adding a portrait was a pull request, a rebuild and a deploy. /board now does everything that screen did, from the page a visitor reads, with real uploads. This removes the second place, so there is exactly one.

Gone: the page, its route, its navigation entry, and the five adapter wrappers only it called.

Where each of the manager's guarantees lives now

The six /management/boards blocks in tests/e2e/boards.spec.ts tested capabilities that still exist. Each one, and where it is asserted today:

The manager block Where that capability is covered now
lists every board with its number and how many seats it holds boards.spec.ts — "carries every board on the timeline, named and dated" lists every board with its name and academic year, including one with no name of its own; board-edit.spec.ts — "every board is reachable, and every one of them can be corrected" is the editor's half. The seat count was a table column rather than a capability: the page shows the seats themselves (boards.spec.ts "reads the seats chair first…"), and the empty case is board-no-seats.
sends a board's number, cheer and colour when it is corrected board-edit.spec.ts — "corrects a board's number, name, cheer, colour, description and dates", which asserts the same request body and three more fields besides.
sends a seat's nickname beside its name board-seat-edit.spec.ts — "adds a seat to a board, in the board's own words for the role" (body.nickname), and "opens a seat on what it says, and corrects it" for the round trip.
shows a board's seats, and marks the ones nobody is linked to The seats: boards.spec.ts "reads the seats chair first…". The unlinked marking moved into the seat dialog, where it is asserted both ways: board-seat-edit.spec.ts "links a seat to an account…" asserts seat-dialog-attached is absent for the unlinked seat, and "detaches an account…" asserts it names the account for the linked one.
seats somebody who has no account board-seat-edit.spec.ts — "adds a seat to a board…". This one needed a new assertion: the page-side test checked the name, nickname, role and blurb but not that no account is sent, which was the whole point of the manager's block. expect(body.userId).toBeUndefined() is now on it.
detaches a member from a seat board-seat-edit.spec.ts — "detaches an account and leaves the seat standing under its own name", which also asserts the seat still reads under its own name afterwards.

The manager's own two guarantees are the ones that had to invert, so they are asserted rather than deleted, in a new what the management editor used to do, where it happens now block:

  • its address answers nothing at all — no route claims /management/boards any more, so the /:pathMatch(.*)* catch-all does and NotFound.vue renders. Asserted as a board member, who is the reader who used to get the page.
  • the navigation offers it to nobody, board member or visitor — checked for both. The management menu's activator gained a data-testid="nav-management" so the menu can actually be opened, and the emails entry beside it is asserted visible: the absence is that one entry's rather than a menu that never appeared.

App.navbar.test.ts also now asserts [to="/management/boards"] does not exist in the desktop management links, alongside the existing /management/jobs check.

The adapter, and why five rather than six

addSeat, saveSeat, linkSeatMember, dropSeat and saveBoard were thin wrappers kept by #933 so BoardManager needed no edit while it still existed. With it gone they had no callers and are removed; the page uses the *OrReason variants, which report the api's own words for a refusal.

dropBoard stays, and the asymmetry is deliberate. There is no dropBoardOrReason: #928 converted dropBoard in place to return {ok: true} | Refused rather than adding a second function beside it. BoardDialog.vue imports it directly and tests/unit/domains/boards/refusals.test.ts covers it, so it is live code, not a leftover.

Knock-on dead code

  • boardTitle, the digits-rather-than-numerals helper The board page reads as a timeline #930 moved into BoardManager precisely so it would die here, went with the file.
  • ManagerCard, UserPicker and TopBanner all still have other consumers. Nothing dangles.
  • No $require for board assets was left behind in src. src/assets/board* and the image / asset-file-name fields are untouched — those are The asset file names go #935, which this unblocks.

Removing the entry left no empty section: the management menu is one list and still carries addresses, account recovery, committees, users, jobs, emails and cohorts.

Out of scope

services/api/**, the committed OpenAPI spec and the generated SDK are untouched. This is a frontend removal.

Verification

From services/frontend, all by exit code:

  • yarn typecheck — 0
  • yarn lint --max-warnings=0 — 0
  • yarn test:unit — 0, 1017 tests in 138 files
  • yarn test:e2e --grep "board" — 0, 122 passed
  • yarn test:e2e (full) — 693 passed with two failures, both re-run to green in isolation and neither in touched code: a lone page.goto 5000ms timeout in email-manager.spec.ts (runner starvation, 8 workers on 4 vCPUs), and a 0.36px stacking assertion in the pre-existing boards.spec.ts "stacks the timeline… on a phone".

Closes #934


Diff breakdown added removed, scaled to the largest row.

frontend                                           +32   -804    7
  production         █░░░░░░░░░░░░░░░░░░░░░░░░░     +1   -691    4
  unit tests         █                              +2     -0    1
  e2e tests          █░░░░                         +29   -113    2

──────────────────────────────────────────────────────────────────
production                                          +1   -691
tests                                              +31   -113  31.00 test lines per prod line
total (hand-written)                               +32   -804  7 files

@ExtraToast ExtraToast added the ready-for-agent Sized and specified for an agent to pick up label Sep 2, 2026
@ExtraToast
ExtraToast merged commit 1f1159f into main Sep 2, 2026
25 checks passed
@github-actions github-actions Bot mentioned this pull request Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-agent Sized and specified for an agent to pick up

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The board editor leaves the management area

1 participant