Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions dashboard/osa/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,24 @@
color: #991b1b;
}

.section-heading {
color: #1e293b;
margin: 1rem 0 0.5rem;
font-size: 0.95rem;
font-weight: 600;
}
.tool-badge {
display: inline-block;
padding: 0.3rem 0.7rem;
background: #f1f5f9;
border: 1px solid #e2e8f0;
border-radius: 6px;
font-size: 0.82rem;
font-family: monospace;
color: #475569;
margin: 0.2rem;
}

/* Period toggle */
.period-toggle { display: flex; gap: 0.35rem; margin-bottom: 1rem; }
.period-btn {
Expand Down Expand Up @@ -493,6 +511,10 @@
.error-msg { color: #f87171; background: #3b1219; border-color: #5c1d2a; }
.site-footer { color: #6b7b92; border-color: #30363d; }
.site-footer a { color: #7ba3d4; }
.section-heading { color: #c8d6e8; }
.tool-badge { background: #1c2128; border-color: #30363d; color: #8a9bb5; }
.config-banner-warning { background: #2d1f04; border-color: #78350f; color: #fbbf24; }
.config-banner-error { background: #3b1219; border-color: #5c1d2a; color: #f87171; }
}
</style>
</head>
Expand Down Expand Up @@ -864,6 +886,8 @@ <h2>${safeName.toUpperCase()}</h2>
</div>
</div>
${renderSyncInfo(sync)}
${renderKnowledgeStats(sync)}
${renderAvailableTools(summary.available_tools_list)}
</div>
<div class="card">
<h2>Activity</h2>
Expand Down Expand Up @@ -909,6 +933,7 @@ <h3 style="color:#1e293b;margin-bottom:0.5rem;font-size:0.9rem;font-weight:600;"
mailman: 'Mailing List Sync',
beps: 'BEPs Sync',
faq: 'FAQ Sync',
discourse: 'Discourse Sync',
};

function renderSyncValue(item) {
Expand All @@ -922,6 +947,39 @@ <h3 style="color:#1e293b;margin-bottom:0.5rem;font-size:0.9rem;font-weight:600;"
return 'N/A';
}

const KNOWLEDGE_FIELDS = [
['github_items', 'GitHub Items'],
['papers', 'Papers'],
['docstrings', 'Docstrings'],
['discourse_topics', 'Discourse Topics'],
['faq_entries', 'FAQ Entries'],
['mailing_list_messages', 'Mailing List'],
];

function renderKnowledgeStats(sync) {
if (!sync || !sync.knowledge) return '';
const k = sync.knowledge;
const items = KNOWLEDGE_FIELDS
.filter(([key]) => k[key] > 0)
.map(([key, label]) => ({label, value: k[key]}));
if (items.length === 0) return '';
const metrics = items.map(i =>
`<div class="metric">
<div class="metric-value">${i.value.toLocaleString()}</div>
<div class="metric-label">${escapeHtml(i.label)}</div>
</div>`
).join('');
return `<h3 class="section-heading">Knowledge Base</h3><div class="overview-grid">${metrics}</div>`;
}

function renderAvailableTools(tools) {
if (!tools || tools.length === 0) return '';
const badges = tools.map(t =>
`<span class="tool-badge">${escapeHtml(t)}</span>`
).join('');
return `<h3 class="section-heading">Available Tools</h3><div style="margin:0.5rem 0;">${badges}</div>`;
}

function renderSyncInfo(sync) {
if (!sync) return '';

Expand Down
30 changes: 30 additions & 0 deletions src/api/routers/community.py
Original file line number Diff line number Diff line change
Expand Up @@ -1375,6 +1375,36 @@ async def community_metrics_public() -> dict[str, Any]:
else:
result["config_health"] = fallback_health

# Derive available tools from community config
if info.community_config:
try:
config = info.community_config
tools = []
if config.documentation:
tools.append(f"retrieve_{config.id}_docs")
if config.github and config.github.repos:
tools.append(f"search_{config.id}_discussions")
tools.append(f"list_{config.id}_recent")
if config.citations and (config.citations.queries or config.citations.dois):
tools.append(f"search_{config.id}_papers")
if config.docstrings and config.docstrings.repos:
tools.append(f"search_{config.id}_code_docs")
if config.faq_generation and config.mailman:
tools.append(f"search_{config.id}_faq")
if config.discourse:
tools.append(f"search_{config.id}_forum")
result["available_tools_list"] = tools
except (AttributeError, TypeError) as e:
logger.error(
"Failed to derive tools for community %s: %s",
community_id,
e,
exc_info=True,
)
result["available_tools_list"] = []
else:
result["available_tools_list"] = []

return result

@router.get("/metrics/public/usage")
Expand Down
33 changes: 28 additions & 5 deletions src/api/routers/sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,17 @@ class SyncItemStatus(BaseModel):
"""ISO timestamp of the next scheduled run, or None if not scheduled."""


class KnowledgeStats(BaseModel):
"""Counts of items in each knowledge category."""

github_items: int = 0
papers: int = 0
docstrings: int = 0
discourse_topics: int = 0
faq_entries: int = 0
mailing_list_messages: int = 0


class SyncStatusResponse(BaseModel):
"""Complete sync status response."""

Expand All @@ -84,13 +95,17 @@ class SyncStatusResponse(BaseModel):
scheduler: SchedulerStatus
health: HealthStatus
syncs: dict[str, SyncItemStatus] = {}
"""Per-sync-type status: github, papers, docstrings, mailman, beps, faq."""
"""Per-sync-type status: github, papers, docstrings, mailman, beps, faq, discourse."""
knowledge: KnowledgeStats | None = None
"""Counts of items in each knowledge category."""


class TriggerRequest(BaseModel):
"""Request to trigger sync."""

sync_type: str = "all" # "github", "papers", "docstrings", "mailman", "faq", "beps", or "all"
sync_type: str = (
"all" # "github", "papers", "docstrings", "mailman", "faq", "beps", "discourse", or "all"
)


class TriggerResponse(BaseModel):
Expand Down Expand Up @@ -293,7 +308,7 @@ async def get_sync_status(
logger.error("Failed to get next run times: %s", e, exc_info=True)

# Build per-sync-type status for all known sync types
all_sync_types = ("github", "papers", "docstrings", "mailman", "beps", "faq")
all_sync_types = ("github", "papers", "docstrings", "mailman", "beps", "faq", "discourse")
syncs: dict[str, SyncItemStatus] = {}
for sync_type in all_sync_types:
last_sync = _get_most_recent_sync(metadata, sync_type)
Expand Down Expand Up @@ -321,6 +336,14 @@ async def get_sync_status(
),
health=_calculate_health(metadata),
syncs=syncs,
knowledge=KnowledgeStats(
github_items=stats.get("github_total", 0),
papers=stats.get("papers_total", 0),
docstrings=stats.get("docstrings_total", 0),
discourse_topics=stats.get("discourse_total", 0),
faq_entries=stats.get("faq_total", 0),
mailing_list_messages=stats.get("mailing_list_total", 0),
),
)


Expand All @@ -334,12 +357,12 @@ async def trigger_sync(
Requires API key authentication.

Args:
request: Sync type to trigger (one of "github", "papers", "docstrings", "mailman", "faq", "beps", or "all")
request: Sync type to trigger (one of "github", "papers", "docstrings", "mailman", "faq", "beps", "discourse", or "all")

Returns:
Result of the sync operation
"""
valid_types = ("github", "papers", "docstrings", "mailman", "faq", "beps", "all")
valid_types = ("github", "papers", "docstrings", "mailman", "faq", "beps", "discourse", "all")
if request.sync_type not in valid_types:
raise HTTPException(
status_code=400,
Expand Down