fix(knowledge): populate hit id in search results
Search hits and entity-knowledge hits never selected an id column, so
every KnowledgeHit.Id defaulted to the zero UUID. The frontend's keyed
{#each results as hit (hit.id)} then had all-duplicate keys, which
silently broke Svelte 5's if-block branch swap for the results panel —
search would set searched=true (Clear button appeared) but the view
never switched away from "Recently learned". Select e.id in both
queries and key the each block on hit.slug (guaranteed unique) instead.
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/dtoro/oikos/internal/httpapi/gen"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// serveRecentKnowledge backs the Knowledge page's "what the system knows / has
|
||||
@@ -111,7 +112,7 @@ func (s *Server) SearchKnowledge(ctx context.Context, request gen.SearchKnowledg
|
||||
limit := clampLimit(request.Params.Limit)
|
||||
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT e.slug, COALESCE(et.name,''), ke.title, ke.source, ke.tags,
|
||||
SELECT e.id, e.slug, COALESCE(et.name,''), ke.title, ke.source, ke.tags,
|
||||
ts_rank(ke.search, plainto_tsquery('english', $1)) AS rank,
|
||||
ts_headline('english', ke.content, plainto_tsquery('english', $1),
|
||||
'MaxWords=40, MinWords=15, ShortWord=3, MaxFragments=3,
|
||||
@@ -131,12 +132,13 @@ func (s *Server) SearchKnowledge(ctx context.Context, request gen.SearchKnowledg
|
||||
items := []gen.KnowledgeHit{}
|
||||
|
||||
for rows.Next() {
|
||||
var id uuid.UUID
|
||||
var slug, eType, title, source string
|
||||
var tags []string
|
||||
var rank float32
|
||||
var snippet *string
|
||||
|
||||
if err := rows.Scan(&slug, &eType, &title, &source, &tags, &rank, &snippet); err != nil {
|
||||
if err := rows.Scan(&id, &slug, &eType, &title, &source, &tags, &rank, &snippet); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -149,6 +151,7 @@ func (s *Server) SearchKnowledge(ctx context.Context, request gen.SearchKnowledg
|
||||
}
|
||||
|
||||
items = append(items, gen.KnowledgeHit{
|
||||
Id: id,
|
||||
Slug: slug,
|
||||
Title: title,
|
||||
Type: hitType,
|
||||
@@ -172,7 +175,7 @@ func (s *Server) GetEntityKnowledge(ctx context.Context, request gen.GetEntityKn
|
||||
entitySlug := request.EntityId
|
||||
|
||||
rows, err := s.pool.Query(ctx, `
|
||||
SELECT e.slug, COALESCE(et.name,''), ke.title, ke.source, ke.tags
|
||||
SELECT e.id, e.slug, COALESCE(et.name,''), ke.title, ke.source, ke.tags
|
||||
FROM knowledge_entities ke
|
||||
JOIN entities e ON e.id = ke.entity_id
|
||||
JOIN entity_types et ON et.name = e.type
|
||||
@@ -182,7 +185,7 @@ func (s *Server) GetEntityKnowledge(ctx context.Context, request gen.GetEntityKn
|
||||
AND r.valid_to IS NULL
|
||||
AND r.type IN ('documents', 'about')
|
||||
UNION
|
||||
SELECT e.slug, COALESCE(et.name,''), ke.title, ke.source, ke.tags
|
||||
SELECT e.id, e.slug, COALESCE(et.name,''), ke.title, ke.source, ke.tags
|
||||
FROM knowledge_entities ke
|
||||
JOIN entities e ON e.id = ke.entity_id
|
||||
JOIN entity_types et ON et.name = e.type
|
||||
@@ -191,7 +194,7 @@ func (s *Server) GetEntityKnowledge(ctx context.Context, request gen.GetEntityKn
|
||||
JOIN entities ent ON ent.type = target_type.name AND ent.slug = $1
|
||||
WHERE r.valid_to IS NULL
|
||||
AND r.type = 'procedure-for'
|
||||
ORDER BY 1`,
|
||||
ORDER BY 2`,
|
||||
entitySlug)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -200,10 +203,11 @@ func (s *Server) GetEntityKnowledge(ctx context.Context, request gen.GetEntityKn
|
||||
|
||||
items := []gen.KnowledgeHit{}
|
||||
for rows.Next() {
|
||||
var id uuid.UUID
|
||||
var slug, eType, title, source string
|
||||
var tags []string
|
||||
|
||||
if err := rows.Scan(&slug, &eType, &title, &source, &tags); err != nil {
|
||||
if err := rows.Scan(&id, &slug, &eType, &title, &source, &tags); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -216,6 +220,7 @@ func (s *Server) GetEntityKnowledge(ctx context.Context, request gen.GetEntityKn
|
||||
}
|
||||
|
||||
items = append(items, gen.KnowledgeHit{
|
||||
Id: id,
|
||||
Slug: slug,
|
||||
Title: title,
|
||||
Type: hitType,
|
||||
|
||||
@@ -115,7 +115,7 @@
|
||||
<p class="text-sm text-muted-foreground">{results.length} result{results.length === 1 ? '' : 's'} for "{query}"</p>
|
||||
<ScrollArea class="flex-1">
|
||||
<div class="flex flex-col gap-3 pr-4">
|
||||
{#each results as hit (hit.id)}
|
||||
{#each results as hit (hit.slug)}
|
||||
<Card.Root class="transition-colors hover:bg-muted/50">
|
||||
<Card.Header>
|
||||
<div class="flex items-center gap-2">
|
||||
|
||||
Reference in New Issue
Block a user