fix: complete admin UX review findings

This commit is contained in:
2026-08-28 16:01:00 +03:00
parent 5d3fb68c2f
commit 78493b9248
10 changed files with 55 additions and 16 deletions

View File

@@ -1,6 +1,6 @@
# Changelog # Changelog
## 0.7.9 ## 0.8.0
- Улучшены доступность, фильтры, состояния и адаптивность административного каталога. - Улучшены доступность, фильтры, состояния и адаптивность административного каталога.

View File

@@ -711,10 +711,26 @@
border-radius: 6px; border-radius: 6px;
} }
.columns-modal__checkbox { .columns-modal__checkbox {
width: 16px; width: 16px;
height: 16px; height: 16px;
} }
.columns-modal__presets {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 8px;
margin-top: 18px;
padding: 0;
border: 0;
}
.columns-modal__preset-label {
color: #4b5563;
font-size: 13px;
font-weight: 700;
}
@media (max-width: 920px) { @media (max-width: 920px) {
.directory__filters { .directory__filters {

View File

@@ -11,6 +11,11 @@
"profile", "profile",
]; ];
const storageKey = "miem.directory.columns"; const storageKey = "miem.directory.columns";
const columnPresets = {
review: ["full_name", "status", "academic_degree", "last_seen_at", "profile"],
contacts: ["full_name", "status", "email", "phone", "address", "profile"],
full: ["full_name", "status", "positions", "hse_start_year", "email", "phone", "address", "academic_degree", "publications_count", "courses_count", "news_count", "first_seen_at", "last_seen_at", "dismissed_at", "profile"],
};
function readColumns() { function readColumns() {
try { try {
@@ -53,6 +58,13 @@
modal.close(); modal.close();
}); });
}); });
document.querySelectorAll("[data-columns-preset]").forEach((button) => {
button.addEventListener("click", () => {
columns = columnPresets[button.dataset.columnsPreset];
writeColumns(columns);
applyColumns(columns);
});
});
modal.addEventListener("click", (event) => { modal.addEventListener("click", (event) => {
if (event.target === modal) modal.close(); if (event.target === modal) modal.close();
}); });
@@ -109,10 +121,12 @@
} catch (_error) { } catch (_error) {
const error = document.querySelector("[data-progress-error]"); const error = document.querySelector("[data-progress-error]");
if (error) error.hidden = false; if (error) error.hidden = false;
return false; return true;
} }
}; };
document.querySelectorAll("[data-progress-retry]").forEach((button) => button.addEventListener("click", poll));
const interval = window.setInterval(async () => { const interval = window.setInterval(async () => {
const keepGoing = await poll(); const keepGoing = await poll();
if (!keepGoing) window.clearInterval(interval); if (!keepGoing) window.clearInterval(interval);

View File

@@ -50,7 +50,7 @@
<div class="progress-bar__fill" data-progress-fill style="width: {{ run.progress_percent if run else 0 }}%"></div> <div class="progress-bar__fill" data-progress-fill style="width: {{ run.progress_percent if run else 0 }}%"></div>
</div> </div>
<div class="progress-panel__percent"><span data-progress-percent>{{ run.progress_percent if run else 0 }}</span>%</div> <div class="progress-panel__percent"><span data-progress-percent>{{ run.progress_percent if run else 0 }}</span>%</div>
<p class="progress-panel__error" data-progress-error role="status" hidden>Не удалось обновить прогресс. Повторите позже.</p> <p class="progress-panel__error" data-progress-error role="status" hidden>Не удалось обновить прогресс. <button class="button button--ghost button--compact" type="button" data-progress-retry>Повторить</button></p>
</div> </div>
</section> </section>
<section class="panel"> <section class="panel">

View File

@@ -133,8 +133,8 @@
</div> </div>
</section> </section>
<dialog class="columns-modal" id="columns-dialog" data-columns-modal> <dialog class="columns-modal" id="columns-dialog" data-columns-modal aria-labelledby="columns-dialog-title">
<section class="columns-modal__panel" aria-labelledby="columns-dialog-title"> <section class="columns-modal__panel">
<div class="columns-modal__header"> <div class="columns-modal__header">
<h3 class="columns-modal__title" id="columns-dialog-title">Отображаемые колонки</h3> <h3 class="columns-modal__title" id="columns-dialog-title">Отображаемые колонки</h3>
<button class="button button--ghost" type="button" data-columns-close>Закрыть</button> <button class="button button--ghost" type="button" data-columns-close>Закрыть</button>
@@ -144,6 +144,12 @@
<label class="columns-modal__option"><input class="columns-modal__checkbox" type="checkbox" value="{{ key }}" data-column-toggle> {{ label }}</label> <label class="columns-modal__option"><input class="columns-modal__checkbox" type="checkbox" value="{{ key }}" data-column-toggle> {{ label }}</label>
{% endfor %} {% endfor %}
</div> </div>
<fieldset class="columns-modal__presets">
<legend class="columns-modal__preset-label">Быстрый набор</legend>
<button class="button button--ghost button--compact" type="button" data-columns-preset="review">Проверка</button>
<button class="button button--ghost button--compact" type="button" data-columns-preset="contacts">Контакты</button>
<button class="button button--ghost button--compact" type="button" data-columns-preset="full">Все поля</button>
</fieldset>
</section> </section>
</dialog> </dialog>
{% endblock %} {% endblock %}

View File

@@ -21,7 +21,7 @@
<div class="progress-bar__fill" data-progress-fill style="width: {{ percent }}%"></div> <div class="progress-bar__fill" data-progress-fill style="width: {{ percent }}%"></div>
</div> </div>
<div class="progress-panel__percent"><span data-progress-percent>{{ percent }}</span>%</div> <div class="progress-panel__percent"><span data-progress-percent>{{ percent }}</span>%</div>
<p class="progress-panel__error" data-progress-error role="status" hidden>Не удалось обновить прогресс. Повторите позже.</p> <p class="progress-panel__error" data-progress-error role="status" hidden>Не удалось обновить прогресс. <button class="button button--ghost button--compact" type="button" data-progress-retry>Повторить</button></p>
</div> </div>
{% else %} {% else %}
<div class="progress-panel" data-progress-panel> <div class="progress-panel" data-progress-panel>
@@ -35,7 +35,7 @@
<div class="progress-bar__fill" data-progress-fill style="width: 0%"></div> <div class="progress-bar__fill" data-progress-fill style="width: 0%"></div>
</div> </div>
<div class="progress-panel__percent"><span data-progress-percent>0</span>%</div> <div class="progress-panel__percent"><span data-progress-percent>0</span>%</div>
<p class="progress-panel__error" data-progress-error role="status" hidden>Не удалось обновить прогресс. Повторите позже.</p> <p class="progress-panel__error" data-progress-error role="status" hidden>Не удалось обновить прогресс. <button class="button button--ghost button--compact" type="button" data-progress-retry>Повторить</button></p>
</div> </div>
{% endif %} {% endif %}
<table class="table"> <table class="table">

View File

@@ -1,3 +1,3 @@
APP_VERSION = "0.7.9" APP_VERSION = "0.8.0"
FRONTEND_VERSION = "0.7.9" FRONTEND_VERSION = "0.8.0"
BACKEND_VERSION = "0.7.9" BACKEND_VERSION = "0.8.0"

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "miem-workers" name = "miem-workers"
version = "0.7.9" version = "0.8.0"
description = "MIEM employees parser, admin API, and web admin" description = "MIEM employees parser, admin API, and web admin"
requires-python = ">=3.11" requires-python = ">=3.11"
dependencies = [ dependencies = [

View File

@@ -33,7 +33,9 @@ def test_directory_template_is_russian_and_uses_display_dates():
assert '<label class="directory__field">Статус' in template assert '<label class="directory__field">Статус' in template
assert 'id="columns-dialog"' in template assert 'id="columns-dialog"' in template
assert 'aria-controls="columns-dialog"' in template assert 'aria-controls="columns-dialog"' in template
assert 'aria-labelledby="columns-dialog-title"' in template
assert "Сбросить фильтры" in template assert "Сбросить фильтры" in template
assert 'data-columns-preset="review"' in template
assert '<dialog class="columns-modal"' in template assert '<dialog class="columns-modal"' in template
assert 'id="columns-dialog"' in template assert 'id="columns-dialog"' in template
assert 'aria-controls="columns-dialog"' in template assert 'aria-controls="columns-dialog"' in template
@@ -116,6 +118,7 @@ def test_admin_js_uses_native_dialog_for_column_settings():
assert "showModal()" in source assert "showModal()" in source
assert "modal.close()" in source assert "modal.close()" in source
assert 'setAttribute("aria-expanded", "true")' in source assert 'setAttribute("aria-expanded", "true")' in source
assert "data-progress-retry" in source
def test_base_template_has_skip_link_and_current_navigation_state(): def test_base_template_has_skip_link_and_current_navigation_state():

View File

@@ -17,7 +17,7 @@ def test_health_returns_versions():
response = TestClient(app).get("/api/health") response = TestClient(app).get("/api/health")
assert response.status_code == 200 assert response.status_code == 200
assert response.json()["backend_version"] == "0.7.9" assert response.json()["backend_version"] == "0.8.0"
def test_mcp_endpoint_is_removed(): def test_mcp_endpoint_is_removed():