Show related drafts in author cluster cards
Each cluster card now shows draft count badge and up to 5 linked draft titles with clickable links to draft detail pages. Data collected from member nodes' draft lists during cluster detection. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -572,15 +572,22 @@ def get_author_network_full(db: Database) -> dict:
|
||||
|
||||
if len(component) >= 2:
|
||||
org_mix: dict[str, int] = Counter()
|
||||
cluster_drafts: dict[str, str] = {} # name -> title
|
||||
for m in component:
|
||||
org = author_info.get(m, {}).get("org", "")
|
||||
if org:
|
||||
org_mix[org] += 1
|
||||
for dn in author_info.get(m, {}).get("drafts", []):
|
||||
if dn not in cluster_drafts:
|
||||
d = db.get_draft(dn)
|
||||
cluster_drafts[dn] = d.title[:80] if d else dn
|
||||
clusters.append({
|
||||
"id": len(clusters),
|
||||
"members": component,
|
||||
"org_mix": dict(org_mix.most_common()),
|
||||
"size": len(component),
|
||||
"drafts": [{"name": n, "title": t} for n, t in list(cluster_drafts.items())[:15]],
|
||||
"draft_count": len(cluster_drafts),
|
||||
})
|
||||
|
||||
clusters.sort(key=lambda c: c["size"], reverse=True)
|
||||
|
||||
@@ -118,16 +118,31 @@
|
||||
<div class="cluster-card bg-slate-800/50 rounded-lg border border-slate-700/50 p-4 cursor-pointer" data-cluster-id="{{ c.id }}" onclick="highlightCluster({{ c.id }})">
|
||||
<div class="flex items-center justify-between mb-2">
|
||||
<span class="text-sm font-semibold text-white">Cluster #{{ c.id + 1 }}</span>
|
||||
<div class="flex gap-1.5">
|
||||
<span class="text-xs px-2 py-0.5 rounded-full bg-blue-500/20 text-blue-400">{{ c.size }} authors</span>
|
||||
<span class="text-xs px-2 py-0.5 rounded-full bg-emerald-500/20 text-emerald-400">{{ c.draft_count }} drafts</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-1 mb-2">
|
||||
{% for org, count in c.org_mix.items() %}
|
||||
<span class="text-xs px-2 py-0.5 rounded-full bg-slate-700 text-slate-300">{{ org }} ({{ count }})</span>
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="text-xs text-slate-500 truncate" title="{{ c.members | join(', ') }}">
|
||||
<div class="text-xs text-slate-500 mb-2 truncate" title="{{ c.members | join(', ') }}">
|
||||
{{ c.members[:5] | join(', ') }}{% if c.members | length > 5 %} +{{ c.members | length - 5 }} more{% endif %}
|
||||
</div>
|
||||
{% if c.drafts %}
|
||||
<div class="border-t border-slate-700/50 pt-2 mt-2">
|
||||
{% for d in c.drafts[:5] %}
|
||||
<div class="text-xs truncate mb-0.5" title="{{ d.name }}: {{ d.title }}">
|
||||
<a href="/drafts/{{ d.name }}" class="text-blue-400/70 hover:text-blue-300 transition" onclick="event.stopPropagation()">{{ d.title }}</a>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% if c.draft_count > 5 %}
|
||||
<div class="text-xs text-slate-600 mt-1">+{{ c.draft_count - 5 }} more drafts</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user