feat: restore global search in app header

This commit is contained in:
2026-06-06 02:39:29 +08:00
parent cf770262e5
commit 0cd8a79049
15 changed files with 513 additions and 65 deletions
+7 -4
View File
@@ -209,10 +209,13 @@ type WorklogDTO struct {
}
type SearchResultDTO struct {
NodeID string `json:"nodeId"`
Title string `json:"title"`
Snippet string `json:"snippet"`
Type string `json:"type"`
NodeID string `json:"nodeId"`
TargetID string `json:"targetId,omitempty"`
Title string `json:"title"`
Snippet string `json:"snippet"`
Type string `json:"type"`
Path string `json:"path,omitempty"`
URL string `json:"url,omitempty"`
}
type EventDTO struct {
+119 -3
View File
@@ -5,6 +5,7 @@ import (
"os"
"os/exec"
"path/filepath"
"strings"
"verstak/internal/core/config"
"verstak/internal/core/nodes"
@@ -262,25 +263,140 @@ func (a *App) Search(query string) ([]SearchResultDTO, error) {
if err := a.requireVault(); err != nil {
return nil, err
}
query = strings.TrimSpace(query)
if query == "" {
return []SearchResultDTO{}, nil
}
out := []SearchResultDTO{}
seen := map[string]bool{}
add := func(r SearchResultDTO) {
if r.Title == "" {
return
}
key := r.Type + ":" + r.NodeID + ":" + r.TargetID + ":" + r.Title
if seen[key] {
return
}
seen[key] = true
out = append(out, r)
}
results, err := a.search.Search(query)
if err != nil {
return nil, err
}
out := make([]SearchResultDTO, len(results))
for i, r := range results {
out[i] = SearchResultDTO{
for _, r := range results {
path := r.Path
if path == "" && r.NodeID != "" {
path = a.nodes.Path(r.NodeID)
}
add(SearchResultDTO{
NodeID: r.NodeID,
Title: r.Title,
Snippet: r.Snippet,
Type: r.Type,
Path: path,
})
}
if len(out) < 20 {
nodes, err := a.nodes.Search(query, 20-len(out))
if err == nil {
for i := range nodes {
if nodes[i].IsDeleted() {
continue
}
add(SearchResultDTO{
NodeID: nodes[i].ID,
Title: nodes[i].Title,
Type: nodes[i].Type,
Path: a.nodes.Path(nodes[i].ID),
})
}
}
}
if len(out) < 20 {
rows, err := a.db.Query(
`SELECT l.id,l.node_id,l.title,l.url,l.hostname,COALESCE(l.note,''),n.deleted_at
FROM links l
LEFT JOIN nodes n ON n.id = l.node_id
WHERE n.deleted_at IS NULL
AND (LOWER(l.title) LIKE ? OR LOWER(l.url) LIKE ? OR LOWER(l.hostname) LIKE ? OR LOWER(COALESCE(l.note,'')) LIKE ?)
ORDER BY l.created_at DESC
LIMIT ?`,
likeQuery(query), likeQuery(query), likeQuery(query), likeQuery(query), 20-len(out))
if err == nil {
defer rows.Close()
for rows.Next() {
var id, nodeID, title, url, hostname, note string
var deletedAt interface{}
if err := rows.Scan(&id, &nodeID, &title, &url, &hostname, &note, &deletedAt); err != nil {
return nil, err
}
snippet := url
if note != "" {
snippet = note
}
add(SearchResultDTO{
NodeID: nodeID,
TargetID: id,
Title: title,
Snippet: snippet,
Type: "link",
Path: a.nodes.Path(nodeID),
URL: url,
})
}
if err := rows.Err(); err != nil {
return nil, err
}
}
}
if len(out) < 20 {
rows, err := a.db.Query(
`SELECT ac.id,ac.node_id,ac.title,ac.kind,COALESCE(ac.url,''),COALESCE(ac.command,''),n.deleted_at
FROM actions ac
LEFT JOIN nodes n ON n.id = ac.node_id
WHERE n.deleted_at IS NULL
AND (LOWER(ac.title) LIKE ? OR LOWER(ac.kind) LIKE ? OR LOWER(COALESCE(ac.url,'')) LIKE ? OR LOWER(COALESCE(ac.command,'')) LIKE ?)
ORDER BY ac.created_at DESC
LIMIT ?`,
likeQuery(query), likeQuery(query), likeQuery(query), likeQuery(query), 20-len(out))
if err == nil {
defer rows.Close()
for rows.Next() {
var id, nodeID, title, kind, url, command string
var deletedAt interface{}
if err := rows.Scan(&id, &nodeID, &title, &kind, &url, &command, &deletedAt); err != nil {
return nil, err
}
snippet := url
if snippet == "" {
snippet = command
}
add(SearchResultDTO{
NodeID: nodeID,
TargetID: id,
Title: title,
Snippet: snippet,
Type: "action",
Path: a.nodes.Path(nodeID),
})
}
if err := rows.Err(); err != nil {
return nil, err
}
}
}
return out, nil
}
func likeQuery(query string) string {
return "%" + strings.ToLower(strings.TrimSpace(query)) + "%"
}
func (a *App) VerstakVersion() string {
return "verstak-gui/v2"
}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -19,8 +19,8 @@
background: #13131f;
}
</style>
<script type="module" crossorigin src="/assets/main-Co5H5J-5.js"></script>
<link rel="stylesheet" crossorigin href="/assets/main-BW6W9uAx.css">
<script type="module" crossorigin src="/assets/main-2ehud8s_.js"></script>
<link rel="stylesheet" crossorigin href="/assets/main-N_NpVgn3.css">
</head>
<body>
<div id="app"></div>