Update UI and migrations, fix dockerfile

This commit is contained in:
Your Name
2026-07-18 21:29:05 +05:00
parent 580c75cbf6
commit 26ef145ccf
95 changed files with 9541 additions and 111 deletions
+29 -8
View File
@@ -69,13 +69,22 @@
<span>{{ p.posted_at_fmt or p.created_at_fmt }}</span>
</div>
<div class="editor-title-row">
<span class="pill {% if p.editorial_status == 'accepted' %}ok{% elif p.editorial_status == 'rejected' %}bad{% elif p.editorial_status == 'regenerating' %}warn{% endif %}">
<span class="pill {% if p.editorial_status in ['accepted', 'published'] %}ok{% elif p.editorial_status in ['rejected', 'publish_failed'] %}bad{% elif p.editorial_status == 'regenerating' %}warn{% endif %}" title="{{ p.publication_error or p.tg_publication_url or '' }}">
{{ p.editorial_status_label }}
</span>
<span class="pill">{{ p.review_category or "без категории" }}</span>
<span class="muted">AI {{ p.qualification_score or "?" }}/10</span>
</div>
<div class="editor-text">{{ p.review_text }}</div>
<div class="publication-badges">
{% for pub in p.publication_platforms %}
{% if pub.url %}
<a class="pill {{ pub.class }}" href="{{ pub.url }}" target="_blank" title="{{ pub.error or pub.status_label }}">{{ pub.label }} · {{ pub.status_label }}</a>
{% else %}
<span class="pill {{ pub.class }}" title="{{ pub.error or pub.status_label }}">{{ pub.label }} · {{ pub.status_label }}</span>
{% endif %}
{% endfor %}
</div>
<div class="editor-text">{{ p.publication_preview_text }}</div>
<details class="source-compare">
<summary>Исходник и AI-заметки</summary>
<div class="compare-grid">
@@ -154,10 +163,11 @@
<label><span>Категория</span>
<select name="final_category">
{% for category in categories %}
<option value="{{ category }}" {% if p.review_category == category %}selected{% endif %}>{{ category }}</option>
<option value="{{ category.name }}" data-tag="{{ category.tag }}" {% if p.review_category == category.name %}selected{% endif %}>{{ category.name }}</option>
{% endfor %}
{% if p.review_category and p.review_category not in categories %}
<option value="{{ p.review_category }}" selected>{{ p.review_category }} · старая категория</option>
{% set category_names = categories | map(attribute="name") | list %}
{% if p.review_category and p.review_category not in category_names %}
<option value="{{ p.review_category }}" data-tag="{{ p.review_category_tag }}" selected>{{ p.review_category }} · старая категория</option>
{% endif %}
</select>
</label>
@@ -165,6 +175,9 @@
<input name="final_source_tag" value="{{ p.review_source_tag or p.source_tag or '' }}">
</label>
</div>
<label><span>Предпросмотр публикации</span>
<div class="publication-preview" data-publication-preview>{{ p.publication_preview_text }}</div>
</label>
<div class="hashtag-preview" data-hashtag-preview>#{{ p.review_category_tag or p.review_category or "category" }} #{{ p.review_source_tag or p.source_tag or "source" }}</div>
<label><span>Заметка редактора</span>
<textarea name="editor_notes" rows="3">{{ p.editor_notes or "" }}</textarea>
@@ -253,9 +266,11 @@
button.addEventListener("click", () => document.getElementById(button.dataset.closeDialog)?.close());
});
document.querySelectorAll(".edit-form").forEach((form) => {
const textArea = form.querySelector('[name="final_text"]');
const category = form.querySelector('[name="final_category"]');
const source = form.querySelector('[name="final_source_tag"]');
const preview = form.querySelector("[data-hashtag-preview]");
const hashtagPreview = form.querySelector("[data-hashtag-preview]");
const publicationPreview = form.querySelector("[data-publication-preview]");
const normalize = (value, fallback) => {
const tag = String(value || "").trim().replace(/^#+/, "").toLowerCase()
.replace(/\s+/g, "_")
@@ -265,9 +280,15 @@
return tag || fallback;
};
const update = () => {
if (!preview) return;
preview.textContent = `#${normalize(category?.value, "category")} #${normalize(source?.value, "source")}`;
const option = category?.selectedOptions?.[0];
const tags = `#${normalize(option?.dataset?.tag || category?.value, "category")} #${normalize(source?.value, "source")}`;
if (hashtagPreview) hashtagPreview.textContent = tags;
if (publicationPreview) {
const cleanText = String(textArea?.value || "").trim();
publicationPreview.textContent = cleanText ? `${cleanText}\n\n${tags}` : tags;
}
};
textArea?.addEventListener("input", update);
category?.addEventListener("change", update);
source?.addEventListener("input", update);
update();