feat: Add MicroDAO Dashboard with activity feed and statistics
- Add microdao_activity table for news/updates/events - Add statistics columns to microdaos table - Implement dashboard API endpoints - Create UI components (HeaderCard, ActivitySection, TeamSection) - Add seed data for DAARION DAO - Update backend models and repositories - Add frontend types and API client
This commit is contained in:
@@ -4248,8 +4248,13 @@ async def get_microdao_dashboard(slug: str) -> dict:
|
||||
# Конвертувати citizens в PublicCitizenSummary
|
||||
citizen_summaries = []
|
||||
for citizen in citizens:
|
||||
# Переконатися що slug не None
|
||||
slug = citizen.get("slug")
|
||||
if not slug:
|
||||
continue # Пропустити громадян без slug
|
||||
|
||||
citizen_summaries.append({
|
||||
"slug": citizen.get("slug"),
|
||||
"slug": slug,
|
||||
"display_name": citizen["display_name"],
|
||||
"public_title": citizen.get("public_title"),
|
||||
"public_tagline": citizen.get("public_tagline"),
|
||||
@@ -4257,7 +4262,7 @@ async def get_microdao_dashboard(slug: str) -> dict:
|
||||
"kind": citizen.get("kind"),
|
||||
"district": citizen.get("district"),
|
||||
"primary_room_slug": citizen.get("primary_room_slug"),
|
||||
"public_skills": citizen.get("public_skills", []),
|
||||
"public_skills": list(citizen.get("public_skills", [])) if citizen.get("public_skills") else [],
|
||||
"online_status": citizen.get("status", "unknown"),
|
||||
"status": citizen.get("status"),
|
||||
"node_id": citizen.get("node_id"),
|
||||
@@ -4268,15 +4273,20 @@ async def get_microdao_dashboard(slug: str) -> dict:
|
||||
# Конвертувати activity в MicrodaoActivity
|
||||
activity_list = []
|
||||
for act in activity:
|
||||
# Конвертувати UUID в string, якщо потрібно
|
||||
author_id = act.get("author_agent_id")
|
||||
if author_id:
|
||||
author_id = str(author_id) if not isinstance(author_id, str) else author_id
|
||||
|
||||
activity_list.append({
|
||||
"id": str(act["id"]),
|
||||
"microdao_slug": act["microdao_slug"],
|
||||
"kind": act["kind"],
|
||||
"title": act.get("title"),
|
||||
"body": act["body"],
|
||||
"author_agent_id": str(act["author_agent_id"]) if act.get("author_agent_id") else None,
|
||||
"author_agent_id": author_id,
|
||||
"author_name": act.get("author_name"),
|
||||
"created_at": act["created_at"]
|
||||
"created_at": act["created_at"].isoformat() if hasattr(act["created_at"], "isoformat") else str(act["created_at"])
|
||||
})
|
||||
|
||||
# Створити MicrodaoSummary
|
||||
@@ -4305,11 +4315,17 @@ async def get_microdao_dashboard(slug: str) -> dict:
|
||||
}
|
||||
|
||||
# Створити stats
|
||||
last_update = microdao.get("updated_at")
|
||||
if last_update and hasattr(last_update, "isoformat"):
|
||||
last_update = last_update.isoformat()
|
||||
elif last_update:
|
||||
last_update = str(last_update)
|
||||
|
||||
stats = {
|
||||
"rooms_count": rooms_count,
|
||||
"citizens_count": citizens_count,
|
||||
"agents_count": agents_count,
|
||||
"last_update_at": microdao.get("updated_at")
|
||||
"last_update_at": last_update
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -4792,12 +4792,47 @@ async def trigger_node_self_healing(node_id: str):
|
||||
async def api_get_microdao_dashboard(slug: str):
|
||||
"""Отримати повний дашборд для MicroDAO"""
|
||||
try:
|
||||
dashboard = await repo_city.get_microdao_dashboard(slug)
|
||||
dashboard_dict = await repo_city.get_microdao_dashboard(slug)
|
||||
|
||||
# Конвертувати dict в Pydantic моделі
|
||||
# MicrodaoSummary вже правильно сформований
|
||||
# Stats потрібно конвертувати
|
||||
stats = dashboard_dict["stats"]
|
||||
if stats.get("last_update_at"):
|
||||
try:
|
||||
if isinstance(stats["last_update_at"], str):
|
||||
stats["last_update_at"] = datetime.fromisoformat(stats["last_update_at"].replace("Z", "+00:00"))
|
||||
elif hasattr(stats["last_update_at"], "isoformat"):
|
||||
pass # Вже datetime
|
||||
except Exception:
|
||||
stats["last_update_at"] = None
|
||||
|
||||
# Activity потрібно конвертувати
|
||||
activity_list = []
|
||||
for act in dashboard_dict["recent_activity"]:
|
||||
act_dict = dict(act)
|
||||
if act_dict.get("created_at"):
|
||||
try:
|
||||
if isinstance(act_dict["created_at"], str):
|
||||
act_dict["created_at"] = datetime.fromisoformat(act_dict["created_at"].replace("Z", "+00:00"))
|
||||
except Exception:
|
||||
pass
|
||||
activity_list.append(MicrodaoActivity(**act_dict))
|
||||
|
||||
# Створити повний об'єкт
|
||||
dashboard = MicrodaoDashboard(
|
||||
microdao=MicrodaoSummary(**dashboard_dict["microdao"]),
|
||||
stats=MicrodaoStats(**stats),
|
||||
recent_activity=activity_list,
|
||||
rooms=[CityRoomSummary(**r) for r in dashboard_dict["rooms"]],
|
||||
citizens=[PublicCitizenSummary(**c) for c in dashboard_dict["citizens"]]
|
||||
)
|
||||
|
||||
return dashboard
|
||||
except ValueError as e:
|
||||
raise HTTPException(status_code=404, detail=str(e))
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to get microdao dashboard for {slug}: {e}")
|
||||
logger.error(f"Failed to get microdao dashboard for {slug}: {e}", exc_info=True)
|
||||
raise HTTPException(status_code=500, detail="Failed to load dashboard")
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user