- add a generic AJAX submitter for forms inside dialogs
- keep modal values and show field errors on server validation failure
- soft-refresh the page content on success, preserving scroll, search and filters
- share toast and re-init hooks for tables, markdown, sections and group page
- require passwords and add minlength/match validation on auth forms
- Lab page is now read-only with a settings screen for levels/variants;
variant issuance moved to a large modal on the group page (assign-fragment).
- Header: bordeaux logo and 2px accent underline, bordeaux login/logout/theme
buttons; smaller radii across the UI; filled secondary/danger buttons.
- Includes prior agent work (login backoff, no-cache pages, API timeouts,
content tweaks) and fixes (variant usage Map.values, import order).
- Bump static asset version to v=9.
- tablekit builds a filter row under the headers for every th with data-filter;
distinct cell values become a select (label from data-filter-label), or a
text substring filter with data-filter="text"
- filters combine with the global table search; placeholder rows (colspan) are
not filtered away; filter row follows the lab-focus column hiding
- enabled on: matrix lab columns (by variant), defense table (ЛР, status with
readable values), students (Основа, Пароль), lab assignment lists (Уровень,
Источник, Сдача), labs list (Статус)
- identity group detail (and thus every student list) is ordered by full name;
defense rows on the group page sorted by name + lab number
- tablekit.js: click a header to sort (numeric-aware, ru locale), second click
flips direction (▲/▼ indicator); search input with data-target filters rows
by substring live
- tables wired: group matrix (with data-sort on variant cells), defense table
(data-sort on status/date), students table, lab assignment lists per group,
groups list and labs list; name/number columns pre-marked ascending
- non-sortable columns marked data-nosort (checkbox/actions)