feat: complete UI migration to Tailwind CSS + HTMX
This commit is contained in:
+102
-8
@@ -2020,8 +2020,9 @@ async def sources_list(request: Request, q: str = "", status_filter: str = "", p
|
||||
item["last_checked_at_fmt"] = format_dt(item.get("last_checked_at"))
|
||||
item["created_at_fmt"] = format_dt(item.get("created_at"))
|
||||
sources.append(item)
|
||||
template_name = "sources_content.html" if request.headers.get("hx-request") else "sources.html"
|
||||
return templates.TemplateResponse(
|
||||
"sources.html",
|
||||
template_name,
|
||||
base_context(
|
||||
request,
|
||||
user,
|
||||
@@ -2317,6 +2318,25 @@ async def source_toggle(request: Request, source_id: int, csrf_token: str = Form
|
||||
source_id,
|
||||
)
|
||||
await audit(user["id"], "source.toggle", "source", source_id, {"active": bool(row["active"]) if row else None})
|
||||
if request.headers.get("hx-request"):
|
||||
# Fetch the updated source
|
||||
source_row = await pool.fetchrow("SELECT * FROM sources WHERE id=$1", source_id)
|
||||
if source_row:
|
||||
s = dict(source_row)
|
||||
# Fetch stats just for this source to render correctly
|
||||
stats = await pool.fetchrow(
|
||||
"""
|
||||
SELECT COUNT(*) AS total_posts,
|
||||
COUNT(*) FILTER (WHERE created_at >= NOW() - INTERVAL '24 hours') AS recent_posts
|
||||
FROM raw_posts
|
||||
WHERE source_id=$1
|
||||
""",
|
||||
source_id
|
||||
)
|
||||
s["posts_count"] = stats["total_posts"]
|
||||
s["posts_24h"] = stats["recent_posts"]
|
||||
s["last_parsed_at_fmt"] = s["last_parsed_at"].strftime("%d.%m.%Y %H:%M") if s.get("last_parsed_at") else None
|
||||
return templates.TemplateResponse("source_row.html", base_context(request, user, s=s))
|
||||
return redirect("/sources")
|
||||
|
||||
|
||||
@@ -2329,11 +2349,12 @@ async def source_delete(request: Request, source_id: int, csrf_token: str = Form
|
||||
pool = await get_pool()
|
||||
await pool.execute("UPDATE sources SET archived_at=NOW(), active=FALSE, updated_at=NOW() WHERE id=$1", source_id)
|
||||
await audit(user["id"], "source.archive", "source", source_id)
|
||||
if request.headers.get("hx-request"):
|
||||
return HTMLResponse("")
|
||||
return redirect("/sources")
|
||||
|
||||
|
||||
@app.get("/raw", response_class=HTMLResponse)
|
||||
@app.get("/v2/raw", response_class=HTMLResponse)
|
||||
async def raw_posts(
|
||||
request: Request,
|
||||
status_filter: str = "",
|
||||
@@ -2482,11 +2503,7 @@ async def raw_posts(
|
||||
)
|
||||
posts = [prepare_raw_post(row) for row in rows]
|
||||
|
||||
is_v2 = request.url.path.startswith("/v2")
|
||||
if is_v2:
|
||||
template_name = "v2/raw_posts_content.html" if request.headers.get("hx-request") else "v2/raw_posts.html"
|
||||
else:
|
||||
template_name = "raw_posts.html"
|
||||
template_name = "raw_posts_content.html" if request.headers.get("hx-request") else "raw_posts.html"
|
||||
|
||||
return templates.TemplateResponse(
|
||||
template_name,
|
||||
@@ -2567,6 +2584,58 @@ async def raw_send_to_rewrite(
|
||||
return redirect(safe_next)
|
||||
|
||||
|
||||
async def fetch_single_editor_row(pool, post_id: int):
|
||||
return await pool.fetchrow(
|
||||
"""
|
||||
SELECT rp.*, s.name AS source_name, s.tag AS source_tag, s.platform AS source_platform, s.url AS source_url,
|
||||
u.login AS reviewed_by_login,
|
||||
COALESCE(c_id.tag, c_name.tag) AS resolved_category_tag,
|
||||
COUNT(rpm.id) AS media_count,
|
||||
COALESCE(
|
||||
jsonb_agg(
|
||||
jsonb_build_object(
|
||||
'id', rpm.id,
|
||||
'type', rpm.media_type,
|
||||
'url', rpm.original_url,
|
||||
'status', rpm.status,
|
||||
'error', rpm.error,
|
||||
'duration_sec', rpm.duration_sec
|
||||
)
|
||||
ORDER BY rpm.sort_order ASC, rpm.id ASC
|
||||
) FILTER (WHERE rpm.id IS NOT NULL),
|
||||
'[]'::jsonb
|
||||
) AS media_items,
|
||||
COALESCE(
|
||||
(
|
||||
SELECT jsonb_agg(
|
||||
jsonb_build_object(
|
||||
'platform', pp.platform,
|
||||
'status', pp.status,
|
||||
'target_id', pp.target_id,
|
||||
'external_id', pp.external_id,
|
||||
'url', pp.url,
|
||||
'error', pp.error,
|
||||
'published_at', pp.published_at
|
||||
)
|
||||
ORDER BY pp.platform
|
||||
)
|
||||
FROM post_publications pp
|
||||
WHERE pp.raw_post_id=rp.id
|
||||
),
|
||||
'[]'::jsonb
|
||||
) AS platform_publications
|
||||
FROM raw_posts rp
|
||||
JOIN sources s ON s.id=rp.source_id
|
||||
LEFT JOIN admin_users u ON u.id=rp.reviewed_by
|
||||
LEFT JOIN content_categories c_id ON c_id.sort_order=COALESCE(rp.final_category_id, rp.rewrite_category_id)
|
||||
LEFT JOIN content_categories c_name ON lower(c_name.name)=lower(COALESCE(rp.final_category, rp.rewrite_category, ''))
|
||||
LEFT JOIN raw_post_media rpm ON rpm.raw_post_id=rp.id AND COALESCE(rpm.editor_hidden, FALSE)=FALSE
|
||||
WHERE rp.id = $1
|
||||
GROUP BY rp.id, s.name, s.tag, s.platform, s.url, u.login, c_id.tag, c_name.tag
|
||||
""",
|
||||
post_id
|
||||
)
|
||||
|
||||
@app.get("/editor", response_class=HTMLResponse)
|
||||
async def editor_feed(
|
||||
request: Request,
|
||||
@@ -2709,8 +2778,9 @@ async def editor_feed(
|
||||
"""
|
||||
)
|
||||
counts = {str(row["status"]): int(row["count"]) for row in counts_rows}
|
||||
template_name = "editor_content.html" if request.headers.get("hx-request") else "editor.html"
|
||||
return templates.TemplateResponse(
|
||||
"editor.html",
|
||||
template_name,
|
||||
base_context(
|
||||
request,
|
||||
user,
|
||||
@@ -2782,6 +2852,14 @@ async def editor_accept(request: Request, post_id: int, csrf_token: str = Form(.
|
||||
user["id"],
|
||||
)
|
||||
await audit(user["id"], "editor.accept", "raw_post", post_id)
|
||||
if request.headers.get("hx-request"):
|
||||
row = await fetch_single_editor_row(pool, post_id)
|
||||
if row:
|
||||
categories = await writer_category_options()
|
||||
return templates.TemplateResponse(
|
||||
"editor_post.html",
|
||||
base_context(request, user, p=prepare_editor_post(row), categories=categories)
|
||||
)
|
||||
return redirect("/editor")
|
||||
|
||||
|
||||
@@ -2807,6 +2885,14 @@ async def editor_reject(request: Request, post_id: int, csrf_token: str = Form(.
|
||||
user["id"],
|
||||
)
|
||||
await audit(user["id"], "editor.reject", "raw_post", post_id)
|
||||
if request.headers.get("hx-request"):
|
||||
row = await fetch_single_editor_row(pool, post_id)
|
||||
if row:
|
||||
categories = await writer_category_options()
|
||||
return templates.TemplateResponse(
|
||||
"editor_post.html",
|
||||
base_context(request, user, p=prepare_editor_post(row), categories=categories)
|
||||
)
|
||||
return redirect("/editor")
|
||||
|
||||
|
||||
@@ -2934,6 +3020,14 @@ async def editor_save(
|
||||
user["id"],
|
||||
)
|
||||
await audit(user["id"], "editor.save" if status_value == "edited" else "editor.save_accept", "raw_post", post_id)
|
||||
if request.headers.get("hx-request"):
|
||||
row = await fetch_single_editor_row(pool, post_id)
|
||||
if row:
|
||||
categories = await writer_category_options()
|
||||
return templates.TemplateResponse(
|
||||
"editor_post.html",
|
||||
base_context(request, user, p=prepare_editor_post(row), categories=categories)
|
||||
)
|
||||
return redirect("/editor")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user