feat: wiki homepage groups projects by stage
Projects now appear under three buckets based on their state entries: - Active Contracts - Leads & Prospects - Internal Tools & Infra Each card shows the stage as a tag on the project title, the client as an italic subtitle, and the project description. Empty buckets hide. Makes it obvious at a glance what's contracted vs lead vs internal. Paired with stage/type/client state entries added to all 6 projects so the grouping has data to work with. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -47,32 +47,74 @@ def render_homepage() -> str:
|
||||
for p in registered:
|
||||
entity_count = len(get_entities(project=p.project_id, limit=200))
|
||||
memory_count = len(get_memories(project=p.project_id, active_only=True, limit=200))
|
||||
state_count = len(get_state(p.project_id))
|
||||
state_entries = get_state(p.project_id)
|
||||
|
||||
# Pull stage/type/client from state entries
|
||||
stage = ""
|
||||
proj_type = ""
|
||||
client = ""
|
||||
for e in state_entries:
|
||||
if e.category == "status":
|
||||
if e.key == "stage":
|
||||
stage = e.value
|
||||
elif e.key == "type":
|
||||
proj_type = e.value
|
||||
elif e.key == "client":
|
||||
client = e.value
|
||||
|
||||
projects.append({
|
||||
"id": p.project_id,
|
||||
"description": p.description,
|
||||
"entities": entity_count,
|
||||
"memories": memory_count,
|
||||
"state": state_count,
|
||||
"state": len(state_entries),
|
||||
"stage": stage,
|
||||
"type": proj_type,
|
||||
"client": client,
|
||||
})
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Group by high-level bucket
|
||||
buckets: dict[str, list] = {
|
||||
"Active Contracts": [],
|
||||
"Leads & Prospects": [],
|
||||
"Internal Tools & Infra": [],
|
||||
"Other": [],
|
||||
}
|
||||
for p in projects:
|
||||
t = p["type"].lower()
|
||||
s = p["stage"].lower()
|
||||
if "lead" in t or "lead" in s or "prospect" in s:
|
||||
buckets["Leads & Prospects"].append(p)
|
||||
elif "contract" in t or ("active" in s and "contract" in s):
|
||||
buckets["Active Contracts"].append(p)
|
||||
elif "infra" in t or "tool" in t or "internal" in t:
|
||||
buckets["Internal Tools & Infra"].append(p)
|
||||
else:
|
||||
buckets["Other"].append(p)
|
||||
|
||||
lines = ['<h1>AtoCore Wiki</h1>']
|
||||
lines.append('<form class="search-box" action="/wiki/search" method="get">')
|
||||
lines.append('<input type="text" name="q" placeholder="Search entities, memories, projects..." autofocus>')
|
||||
lines.append('<button type="submit">Search</button>')
|
||||
lines.append('</form>')
|
||||
|
||||
lines.append('<h2>Projects</h2>')
|
||||
lines.append('<div class="card-grid">')
|
||||
for p in projects:
|
||||
lines.append(f'<a href="/wiki/projects/{p["id"]}" class="card">')
|
||||
lines.append(f'<h3>{p["id"]}</h3>')
|
||||
lines.append(f'<p>{p["description"][:120]}</p>')
|
||||
lines.append(f'<div class="stats">{p["entities"]} entities · {p["memories"]} memories · {p["state"]} state entries</div>')
|
||||
lines.append('</a>')
|
||||
lines.append('</div>')
|
||||
for bucket_name, items in buckets.items():
|
||||
if not items:
|
||||
continue
|
||||
lines.append(f'<h2>{bucket_name}</h2>')
|
||||
lines.append('<div class="card-grid">')
|
||||
for p in items:
|
||||
client_line = f'<div class="client">{p["client"]}</div>' if p["client"] else ''
|
||||
stage_tag = f'<span class="tag">{p["stage"].split(" — ")[0]}</span>' if p["stage"] else ''
|
||||
lines.append(f'<a href="/wiki/projects/{p["id"]}" class="card">')
|
||||
lines.append(f'<h3>{p["id"]} {stage_tag}</h3>')
|
||||
lines.append(client_line)
|
||||
lines.append(f'<p>{p["description"][:140]}</p>')
|
||||
lines.append(f'<div class="stats">{p["entities"]} entities · {p["memories"]} memories · {p["state"]} state</div>')
|
||||
lines.append('</a>')
|
||||
lines.append('</div>')
|
||||
|
||||
# Quick stats
|
||||
all_entities = get_entities(limit=500)
|
||||
@@ -245,6 +287,8 @@ _TEMPLATE = """<!DOCTYPE html>
|
||||
.card h3 { color: var(--accent); margin: 0 0 0.3rem 0; }
|
||||
.card p { font-size: 0.9em; margin: 0; opacity: 0.8; }
|
||||
.card .stats { font-size: 0.8em; margin-top: 0.5rem; opacity: 0.5; }
|
||||
.card .client { font-size: 0.85em; opacity: 0.65; margin-bottom: 0.3rem; font-style: italic; }
|
||||
.card h3 .tag { font-size: 0.65em; vertical-align: middle; margin-left: 0.4rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
Reference in New Issue
Block a user