Phase 1 fixes: broken dialogs, score width, status badge, MSK date round-trip

- group/lab/labs: move dialogs/scripts INSIDE the #content fragment (they were
  outside — the layout fragment dropped them, which is why 'add student' did nothing)
- group.html toast had swallowed the dialog (th:if createdStudent) — split properly
- .input-score width no longer overridden by .inline-form .input-sm (10rem min)
- lab page: remove separate 'change status' button — status badge is now a toggle
  button itself (confirm dialog kept)
- DateUtils.localInput/toUtcIso: dates entered in datetime-local are Moscow-local,
  stored as UTC instant, shown back MSK — correct round-trip both ways
- academic parseInstant: naive local datetimes treated as Europe/Moscow
- README/module docs left as-is
This commit is contained in:
2026-09-11 23:11:40 +03:00
parent eec804a0ac
commit 7818f459bd
7 changed files with 215 additions and 190 deletions

View File

@@ -34,43 +34,44 @@
</tbody>
</table>
</div>
</div>
<dialog id="modal-create-lab" class="modal">
<div class="modal-header">
<h2 class="modal-title">Новая лабораторная</h2>
<button class="modal-close" type="button" onclick="closeModal('modal-create-lab')">✕</button>
</div>
<div class="modal-body">
<form class="form-stack" th:action="@{/admin/labs/create}" method="post">
<div class="grid grid-2">
<div><label class="label" for="labNumber">Номер</label>
<input class="input" id="labNumber" name="number" type="number" min="1" required></div>
<div><label class="label" for="labPoints">Максимум баллов</label>
<input class="input" id="labPoints" name="pointsMax" type="number" step="0.1" min="0" value="5" required></div>
</div>
<div><label class="label" for="labTitle">Название</label>
<input class="input" id="labTitle" name="title" required></div>
<div class="grid grid-2">
<div><label class="label" for="labDeadline">Срок сдачи</label>
<input class="input" id="labDeadline" name="deadlineAt" type="datetime-local"></div>
<div><label class="label" for="labDefense">Дата защиты</label>
<input class="input" id="labDefense" name="defenseAt" type="datetime-local"></div>
</div>
<div><label class="label" for="labStatus">Статус</label>
<select class="input" id="labStatus" name="status">
<option value="draft">draft</option>
<option value="published">published</option>
</select></div>
<div><label class="label" for="labLevels">Уровни (по одному на строку: код; название)</label>
<textarea class="input" id="labLevels" name="levels" rows="4" placeholder="basic; Основная группа&#10;advanced; Повышенная сложность"></textarea>
<p class="hint">Если оставить пустым, будет создан уровень «Основная группа». Варианты добавите на странице лабы.</p></div>
<div><label class="label" for="labDesc">Условие (markdown, можно позже)</label>
<textarea class="input" id="labDesc" name="descriptionMd" rows="6"></textarea></div>
<button class="btn btn-primary" type="submit">Создать</button>
<input type="hidden" name="_csrf" th:value="${csrfToken}">
</form>
</div>
</dialog>
<dialog id="modal-create-lab" class="modal">
<div class="modal-header">
<h2 class="modal-title">Новая лабораторная</h2>
<button class="modal-close" type="button" onclick="closeModal('modal-create-lab')">✕</button>
</div>
<div class="modal-body">
<form class="form-stack" th:action="@{/admin/labs/create}" method="post">
<div class="grid grid-2">
<div><label class="label" for="labNumber">Номер</label>
<input class="input" id="labNumber" name="number" type="number" min="1" required></div>
<div><label class="label" for="labPoints">Максимум баллов</label>
<input class="input" id="labPoints" name="pointsMax" type="number" step="0.1" min="0" value="5" required></div>
</div>
<div><label class="label" for="labTitle">Название</label>
<input class="input" id="labTitle" name="title" required></div>
<div class="grid grid-2">
<div><label class="label" for="labDeadline">Срок сдачи</label>
<input class="input" id="labDeadline" name="deadlineAt" type="datetime-local"></div>
<div><label class="label" for="labDefense">Дата защиты</label>
<input class="input" id="labDefense" name="defenseAt" type="datetime-local"></div>
</div>
<div><label class="label" for="labStatus">Статус</label>
<select class="input" id="labStatus" name="status">
<option value="draft">draft</option>
<option value="published">published</option>
</select></div>
<div><label class="label" for="labLevels">Уровни (по одному на строку: код; название)</label>
<textarea class="input" id="labLevels" name="levels" rows="4" placeholder="basic; Основная группа&#10;advanced; Повышенная сложность"></textarea>
<p class="hint">Если оставить пустым, будет создан уровень «Основная группа». Варианты добавите на странице лабы.</p></div>
<div><label class="label" for="labDesc">Условие (markdown, можно позже)</label>
<textarea class="input" id="labDesc" name="descriptionMd" rows="6"></textarea></div>
<button class="btn btn-primary" type="submit">Создать</button>
<input type="hidden" name="_csrf" th:value="${csrfToken}">
</form>
</div>
</dialog>
</div>
</body>
</html>