fix(glossary-list): show real embedding progress in glossary list view
- Add current_version_embedding_status/embedded_count/term_count to GlossaryResponse
- Batch-fetch current versions in list endpoint (single extra query, not N queries)
- Add get_versions_by_ids() helper to glossary_service
- Fix GlossaryList.tsx: embeddingBadge('') → embeddingBadge(g) with real status + pct
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e70a67718e
commit
4645e67611
5 changed files with 33 additions and 7 deletions
|
|
@ -47,7 +47,8 @@ async def list_glossaries(
|
|||
"""List all active glossaries for a client."""
|
||||
assert_user_in_org(ctx, client_id, OrgRole.VIEWER)
|
||||
glossaries = await svc.get_glossaries_for_client(client_id)
|
||||
return [_to_response(g) for g in glossaries]
|
||||
version_map = await svc.get_versions_by_ids([g.current_version_id for g in glossaries if g.current_version_id])
|
||||
return [_to_response(g, version_map.get(g.current_version_id)) for g in glossaries]
|
||||
|
||||
|
||||
# ── Upload new glossary ───────────────────────────────────────────────────────
|
||||
|
|
@ -286,7 +287,7 @@ def _validate_xlsx(file: UploadFile) -> None:
|
|||
)
|
||||
|
||||
|
||||
def _to_response(g) -> GlossaryResponse:
|
||||
def _to_response(g, current_version=None) -> GlossaryResponse:
|
||||
return GlossaryResponse(
|
||||
id=str(g.id),
|
||||
client_id=g.client_id,
|
||||
|
|
@ -296,6 +297,9 @@ def _to_response(g) -> GlossaryResponse:
|
|||
source=g.source,
|
||||
status=g.status,
|
||||
current_version_id=g.current_version_id,
|
||||
current_version_embedding_status=current_version.embedding_status if current_version else None,
|
||||
current_version_embedded_count=current_version.embedded_count if current_version else None,
|
||||
current_version_term_count=current_version.term_count if current_version else None,
|
||||
created_at=g.created_at,
|
||||
created_by=g.created_by,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ class GlossaryResponse(BaseModel):
|
|||
source: GlossarySource
|
||||
status: GlossaryStatus
|
||||
current_version_id: str | None = None
|
||||
current_version_embedding_status: EmbeddingStatus | None = None
|
||||
current_version_embedded_count: int | None = None
|
||||
current_version_term_count: int | None = None
|
||||
created_at: datetime
|
||||
created_by: str
|
||||
|
||||
|
|
|
|||
|
|
@ -728,6 +728,17 @@ async def get_glossary(glossary_id: str) -> Glossary | None:
|
|||
return glossary_from_doc(doc) if doc else None
|
||||
|
||||
|
||||
async def get_versions_by_ids(version_ids: list[str]) -> dict[str, GlossaryVersion]:
|
||||
"""Batch-fetch versions by ID, returns {version_id: GlossaryVersion}."""
|
||||
if not version_ids:
|
||||
return {}
|
||||
db = await get_database()
|
||||
docs = await db[_COLL_VERSIONS].find(
|
||||
{"_id": {"$in": [ObjectId(vid) for vid in version_ids]}}
|
||||
).to_list(length=len(version_ids))
|
||||
return {str(d["_id"]): glossary_version_from_doc(d) for d in docs}
|
||||
|
||||
|
||||
async def get_versions(glossary_id: str) -> list[GlossaryVersion]:
|
||||
db = await get_database()
|
||||
cursor = db[_COLL_VERSIONS].find(
|
||||
|
|
|
|||
|
|
@ -11,12 +11,17 @@ function statusBadge(status: string) {
|
|||
: 'bg-gray-100 text-gray-500';
|
||||
}
|
||||
|
||||
function embeddingBadge(status: string) {
|
||||
function embeddingBadge(g: import('../../../types/api').Glossary) {
|
||||
const status = g.current_version_embedding_status;
|
||||
const pct = g.current_version_term_count && g.current_version_term_count > 0
|
||||
? Math.round(((g.current_version_embedded_count ?? 0) / g.current_version_term_count) * 100)
|
||||
: 0;
|
||||
switch (status) {
|
||||
case 'done': return <span className="text-xs text-green-600">Embedded ✓</span>;
|
||||
case 'in_progress': return <span className="text-xs text-blue-600 animate-pulse">Embedding…</span>;
|
||||
case 'done': return <span className="text-xs text-green-600">Embedded ✓ ({g.current_version_term_count?.toLocaleString()})</span>;
|
||||
case 'in_progress': return <span className="text-xs text-blue-600 animate-pulse">Embedding… {pct}%</span>;
|
||||
case 'failed': return <span className="text-xs text-red-500">Embed failed</span>;
|
||||
default: return <span className="text-xs text-gray-400">Pending embed</span>;
|
||||
case 'pending': return <span className="text-xs text-gray-400">Pending embed</span>;
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -107,7 +112,7 @@ export function GlossaryList() {
|
|||
</div>
|
||||
<div className="flex items-center gap-4 shrink-0">
|
||||
<div className="text-right text-xs text-gray-400">
|
||||
{g.current_version_id ? embeddingBadge('') : null}
|
||||
{g.current_version_id ? embeddingBadge(g) : null}
|
||||
</div>
|
||||
{isAdmin && g.status === 'active' && (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -822,6 +822,9 @@ export interface Glossary {
|
|||
source: string;
|
||||
status: GlossaryStatus;
|
||||
current_version_id?: string;
|
||||
current_version_embedding_status?: EmbeddingStatus;
|
||||
current_version_embedded_count?: number;
|
||||
current_version_term_count?: number;
|
||||
created_at: string;
|
||||
created_by: string;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue