docs: update documentation to OKF v0.1 format
This commit is contained in:
@@ -3,7 +3,7 @@ type: guide
|
||||
title: Admin — Categories
|
||||
description: How an admin lists, creates, edits, and deletes challenge categories from the /admin/categories page, including system-row protection and challenge-attached protection.
|
||||
tags: [guide, admin, categories, tester]
|
||||
timestamp: 2026-07-22T18:37:00Z
|
||||
timestamp: 2026-07-22T19:18:00Z
|
||||
---
|
||||
|
||||
# When this view is available
|
||||
@@ -45,6 +45,7 @@ side-nav (categories are also embedded inside the General settings page).
|
||||
| Form modal | `[data-testid="cat-form-modal"]` | Create/edit dialog (`cat-form-backdrop` is the click-outside dismiss layer). |
|
||||
| Delete modal | `[data-testid="cat-delete-modal"]` | Confirmation dialog (`cat-delete-backdrop` is the dismiss layer). |
|
||||
| Delete error | `[data-testid="cat-delete-error"]` | Inline error message after a failed delete. |
|
||||
| Form error | `[data-testid="cf-error"]` | Inline error rendered inside the form modal after a failed create/update/upload. |
|
||||
|
||||
# Form modal fields
|
||||
|
||||
@@ -54,7 +55,7 @@ side-nav (categories are also embedded inside the General settings page).
|
||||
| Abbreviation (uppercase) | `cf-abbr` | Required, 2–6 chars; server upper-cases on save. `readonly` when editing a system row. |
|
||||
| Description | `cf-desc` | Optional, max 2000 chars. |
|
||||
| Icon (file picker) | `cf-icon` | Optional image; uploaded to `POST /api/v1/uploads/category-icon` and resized/normalized server-side. |
|
||||
| Cancel / OK | `cf-cancel`, `cf-ok` | OK disabled while form invalid or already submitting. |
|
||||
| Cancel / OK | `cf-cancel`, `cf-ok` | OK disabled while form invalid, already submitting, or while the parent is performing the async save (bound `saving` input). |
|
||||
|
||||
# Expected behavior
|
||||
|
||||
@@ -84,10 +85,23 @@ side-nav (categories are also embedded inside the General settings page).
|
||||
|
||||
1. Click `cat-edit-{ABBR}` → modal opens in edit mode, pre-filled with
|
||||
the row's values.
|
||||
2. For system rows, the abbreviation field is `readonly`.
|
||||
3. On save the component issues `updateCategory(id, {...})`. If an icon
|
||||
file is selected, the new icon is uploaded first and the returned
|
||||
`publicUrl` replaces `iconPath` in the same update.
|
||||
2. For system rows, the abbreviation field is `readonly`. For user
|
||||
(non-system) rows the abbreviation is editable and is uppercased
|
||||
server-side on save (the existing category row is re-sorted
|
||||
alphabetically by the defensive client sort after a successful
|
||||
update).
|
||||
3. On save the component issues `updateCategory(id, {...})` with
|
||||
`name`, `abbreviation`, `description`, and (if an icon file was
|
||||
chosen) `iconPath`. When an icon file is selected, the new icon is
|
||||
uploaded first via `POST /api/v1/uploads/category-icon` and the
|
||||
returned `publicUrl` replaces `iconPath` in the same update.
|
||||
4. On either an upload rejection (HTTP 400) or an update rejection
|
||||
(HTTP 400/404/409), the modal stays open, the OK button is disabled
|
||||
while the request is in flight via the bound `saving` flag, and the
|
||||
server message is rendered inside the modal at
|
||||
`data-testid="cf-error"`. The list is not refreshed and any
|
||||
previously-valid icon on disk is preserved (the upload endpoint
|
||||
does not overwrite when Sharp decode fails).
|
||||
|
||||
### Edit prefill mechanics
|
||||
|
||||
@@ -112,6 +126,29 @@ input. `syncCategoryForm` is exported from the modal file so it can be
|
||||
exercised in isolation by
|
||||
`tests/frontend/admin-categories-form-modal.spec.ts`.
|
||||
|
||||
### Save error and loading state
|
||||
|
||||
`CategoryFormModalComponent` is purely presentational and does not own
|
||||
HTTP state. It exposes two additional signal inputs:
|
||||
|
||||
* `errorMessage: string | null` — when truthy, an inline error paragraph
|
||||
is rendered at `data-testid="cf-error"` showing the supplied message.
|
||||
* `saving: boolean` — when `true`, the OK button is disabled in addition
|
||||
to the existing `form.invalid` and `submitting` guards.
|
||||
|
||||
The parent `AdminCategoriesComponent` owns both signals:
|
||||
|
||||
* `formError` — set from the server's `error.message` (or a generic
|
||||
fallback) when create/update/upload fails, and cleared every time the
|
||||
modal is opened or a submission begins.
|
||||
* `saving` — set to `true` at the start of `onFormSubmit` and reset to
|
||||
`false` in `finally`, so the modal can never get stuck in a
|
||||
"submitting" state if the request rejects.
|
||||
|
||||
This separation matters because `deleteError` (rendered by the delete
|
||||
modal at `data-testid="cat-delete-error"`) is a different state machine
|
||||
and must not be reused for create/update failures.
|
||||
|
||||
## Delete behavior
|
||||
|
||||
* **System rows:** the delete modal renders
|
||||
|
||||
Reference in New Issue
Block a user