Small entity editing: edit pages, switches in tables, relation removal with Undo #629

Open
opened 2026-10-28 12:46:46 +01:00 by simon · 0 comments
Owner

Motivation

Similar small configuration entities are edited in three different ways: data fields in place (the table is replaced by a form, no URL, Back leaves the page), fee types via a row click straight into a form with Delete as a row action, roles via the full index → detail → edit path. Toggling one yes/no setting of a data field costs three clicks plus a context switch, although the table already shows the value. Removing a member from a group uses a danger trash icon that looks like deleting the member. Row clicks lead to three kinds of targets. DESIGN_GUIDELINES §14 (small configuration entities), §8.7, §8.8 and §10.5 define the target. This issue absorbs #449 (route-based data field editing).

Visible improvement

One click per yes/no setting instead of three; every edit page has its own URL; removing a member from a group is clearly different from deleting a member, and can be undone.

Scope (ordered steps, just ci-dev green after each)

  1. Data fields (custom fields): own edit route (e.g. /admin/datafields/:slug/edit), row click opens it; sections and Danger zone on the edit page; remove the in-place form.
  2. Member fields: “Required” and “Show in overview” as switches in the table (immediate save, toast, explicit client rollback via the toggle hook on error (DESIGN_GUIDELINES §8.1), per-row authorization re-checked in the handler; the event carries the record id and the target value (one payload per event name) and the handler sets it, never toggles the stored value); no edit view.
  3. Data fields: “Required” and “Show in overview” as switches in the table, everything else on the edit page.
  4. Fee types: row click into the edit page (as today), Delete moves from the row into the Danger zone of the edit page.
  5. Roles: no detail page; row click opens the edit page; Danger zone on it.
  6. Relation removal: group member removal and join-form field removal become the ghost “×” button with row-specific aria-label and tooltip; success toast with “Undo” that restores the relation. The button renders only for users who may change the relation; the remove and the Undo handler both re-check the permission; Undo restores only the relation the server recorded for this removal, never ids sent by the client. Decide the toast duration and the focus target after the row disappears.
  7. Toasts (DESIGN_GUIDELINES §9.2): auto-dismiss per kind (info/success 5 s, warning 7 s, error 10 s; today only success dismisses), close button named “Close” (today “close”), toasts with an action pause while hovered or focused (WCAG 2.2.1).
  8. One row-click target per entity type; the name column is a real link to the same target.
  9. Showcase section: table with switches, relation-removal row, Undo toast, one toast per kind.
  10. Check #261 against the result: on main @ edfc8e98 the member overview rows have no delete or edit buttons, and data fields open on row click with Delete in the Danger zone, so most of #261 looks solved or outdated. Confirm each of its four acceptance points, then close #261 with a reference to this issue, or list what is still open.

Out of scope

  • Option lists for custom fields (comes with the feature; DESIGN_GUIDELINES §22.4).
  • Field permissions for roles (enhanced role feature).
  • Data field order (U10).

Acceptance criteria

  • DESIGN_GUIDELINES §8.7, §8.8, §9.2, §10.4, §10.5, §14 are met; no entity delete in any row; no in-place edit forms.
  • Tests: each switch saves, toasts and rolls back on error; a switch event sets the value it carries (sending the same target twice leaves it unchanged); unauthorized users see read-only values and the handler rejects forged events; Undo restores the relation; a remove or Undo event from a user without update permission is rejected; an Undo event with forged ids restores nothing else; edit routes load by URL.
  • Before/after screenshots: data fields index (switches), data field edit page, group members with “×” and Undo toast.
  • Accessibility: switches with role="switch" and row-specific names; Undo reachable by keyboard while the toast is visible; focus after removal handled as decided.
  • Showcase section added.
  • just ci-dev green after every step.

Dependencies

  • U4 (confirmation dialog for the Danger zones), U5 (<.section>, <.danger_zone>, switch input).
  • Replaces #449: close #449 with a reference to this issue.
  • Checks #261 (step 10): close it or name its remaining points.

Anchors (verified against main @ d9093a1f, re-check before filing)

  • Data fields in-place editing: lib/mv_web/live/datafields_live.ex, lib/mv_web/live/custom_field_live/index_component.ex, lib/mv_web/live/member_field_live/index_component.ex
  • Fee type row delete: lib/mv_web/live/membership_fee_settings_live.ex:248
  • Roles: lib/mv_web/router.ex:92-95, lib/mv_web/live/role_live/
  • Group member removal: lib/mv_web/live/group_live/show.ex:328

Caution

  • Inline switches need a permission check per row and in the handler; follow the load-budget rule (no extra reads per toggle beyond the update).
  • Route changes break bookmarks and tests that navigate in place; update tests per step.

#615 allowed two exceptions until a later issue (first meant for #540, which did not take them): "Create cycle" is still a form dialog (<.modal kind={:form}> in lib/mv_web/live/member_live/show/cycles_component.ex:20,305; DESIGN_GUIDELINES §10.3 exception), and the cycle status buttons still sit inside the table rows (§8.7 exception). Resolve both here: creating a cycle becomes its own small editing surface following this issue's pattern, and the status actions move out of the rows. Coordinate with followups/issue-error-paths.md (atomic "Delete all cycles" in the same component).

## Motivation Similar small configuration entities are edited in three different ways: data fields in place (the table is replaced by a form, no URL, Back leaves the page), fee types via a row click straight into a form with Delete as a row action, roles via the full index → detail → edit path. Toggling one yes/no setting of a data field costs three clicks plus a context switch, although the table already shows the value. Removing a member from a group uses a danger trash icon that looks like deleting the member. Row clicks lead to three kinds of targets. DESIGN_GUIDELINES §14 (small configuration entities), §8.7, §8.8 and §10.5 define the target. This issue absorbs #449 (route-based data field editing). ## Visible improvement One click per yes/no setting instead of three; every edit page has its own URL; removing a member from a group is clearly different from deleting a member, and can be undone. ## Scope (ordered steps, `just ci-dev` green after each) 1. Data fields (custom fields): own edit route (e.g. `/admin/datafields/:slug/edit`), row click opens it; sections and Danger zone on the edit page; remove the in-place form. 2. Member fields: “Required” and “Show in overview” as switches in the table (immediate save, toast, explicit client rollback via the toggle hook on error (DESIGN_GUIDELINES §8.1), per-row authorization re-checked in the handler; the event carries the record id and the target value (one payload per event name) and the handler sets it, never toggles the stored value); no edit view. 3. Data fields: “Required” and “Show in overview” as switches in the table, everything else on the edit page. 4. Fee types: row click into the edit page (as today), Delete moves from the row into the Danger zone of the edit page. 5. Roles: no detail page; row click opens the edit page; Danger zone on it. 6. Relation removal: group member removal and join-form field removal become the ghost “×” button with row-specific `aria-label` and tooltip; success toast with “Undo” that restores the relation. The button renders only for users who may change the relation; the remove and the Undo handler both re-check the permission; Undo restores only the relation the server recorded for this removal, never ids sent by the client. Decide the toast duration and the focus target after the row disappears. 7. Toasts (DESIGN_GUIDELINES §9.2): auto-dismiss per kind (info/success 5 s, warning 7 s, error 10 s; today only success dismisses), close button named “Close” (today “close”), toasts with an action pause while hovered or focused (WCAG 2.2.1). 8. One row-click target per entity type; the name column is a real link to the same target. 9. Showcase section: table with switches, relation-removal row, Undo toast, one toast per kind. 10. Check #261 against the result: on `main` @ `edfc8e98` the member overview rows have no delete or edit buttons, and data fields open on row click with Delete in the Danger zone, so most of #261 looks solved or outdated. Confirm each of its four acceptance points, then close #261 with a reference to this issue, or list what is still open. ## Out of scope - Option lists for custom fields (comes with the feature; DESIGN_GUIDELINES §22.4). - Field permissions for roles (enhanced role feature). - Data field order (U10). ## Acceptance criteria - DESIGN_GUIDELINES §8.7, §8.8, §9.2, §10.4, §10.5, §14 are met; no entity delete in any row; no in-place edit forms. - Tests: each switch saves, toasts and rolls back on error; a switch event sets the value it carries (sending the same target twice leaves it unchanged); unauthorized users see read-only values and the handler rejects forged events; Undo restores the relation; a remove or Undo event from a user without update permission is rejected; an Undo event with forged ids restores nothing else; edit routes load by URL. - Before/after screenshots: data fields index (switches), data field edit page, group members with “×” and Undo toast. - Accessibility: switches with `role="switch"` and row-specific names; Undo reachable by keyboard while the toast is visible; focus after removal handled as decided. - Showcase section added. - `just ci-dev` green after every step. ## Dependencies - U4 (confirmation dialog for the Danger zones), U5 (`<.section>`, `<.danger_zone>`, switch input). - Replaces #449: close #449 with a reference to this issue. - Checks #261 (step 10): close it or name its remaining points. ## Anchors (verified against `main` @ `d9093a1f`, re-check before filing) - Data fields in-place editing: `lib/mv_web/live/datafields_live.ex`, `lib/mv_web/live/custom_field_live/index_component.ex`, `lib/mv_web/live/member_field_live/index_component.ex` - Fee type row delete: `lib/mv_web/live/membership_fee_settings_live.ex:248` - Roles: `lib/mv_web/router.ex:92-95`, `lib/mv_web/live/role_live/` - Group member removal: `lib/mv_web/live/group_live/show.ex:328` ## Caution - Inline switches need a permission check per row and in the handler; follow the load-budget rule (no extra reads per toggle beyond the update). - Route changes break bookmarks and tests that navigate in place; update tests per step. ## Related: membership fee cycles (from #615, regrouped 2026-10-25) #615 allowed two exceptions until a later issue (first meant for #540, which did not take them): "Create cycle" is still a form dialog (`<.modal kind={:form}>` in `lib/mv_web/live/member_live/show/cycles_component.ex:20,305`; DESIGN_GUIDELINES §10.3 exception), and the cycle status buttons still sit inside the table rows (§8.7 exception). Resolve both here: creating a cycle becomes its own small editing surface following this issue's pattern, and the status actions move out of the rows. Coordinate with `followups/issue-error-paths.md` (atomic "Delete all cycles" in the same component).
Sign in to join this conversation.
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
local-it/mitgliederverwaltung#629
No description provided.