Files
ARTEX/server/commands.go
T
FileShare Developer c76d0f4c93 feat: delete traffic targets and LLM task conversations from UI
Add delete controls to the Traffic and LLM Records pages so users can
purge recorded data without hand-editing the data volume.

Traffic page:
- Host target picker (Popover with checkboxes + select-all toggle)
- Exact-match batch delete for multiple hosts (DELETE /api/traffic/hosts)
- Substring delete for the host-filter input (DELETE /api/traffic?host=)
- Orphaned content-addressed blob garbage collection after deletes
- Distinct-hosts endpoint (GET /api/traffic/hosts) for the picker

LLM Records page:
- Task picker dropdown (distinct task_id + record counts)
- Per-task delete (DELETE /api/llm/records?task=)

Other:
- Add /dist/ to .gitignore (build artifact)
- Extend traffic_test.go with DeleteHost, DeleteHostsExact, Hosts tests
- Fix Popover render bug (replace ScrollArea that broke height calc)
- Remove fade/zoom animation on the host picker Popover
2026-08-10 11:10:58 +08:00

89 lines
2.4 KiB
Go

package server
import (
"net/http"
"strconv"
"strings"
)
// pgListCommands returns tool executions (any tool) from the activity table.
func (s *Server) pgListCommands(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
page := atoiDefault(q.Get("page"), 0)
size := atoiDefault(q.Get("size"), 50)
keyword := q.Get("q")
var expID *int64
if tv := q.Get("task"); tv != "" {
if n, err := strconv.ParseInt(tv, 10, 64); err == nil {
expID = &n
}
}
records, total, err := s.m.PG().ListCommands(expID, keyword, page, size)
if err != nil {
writeErr(w, 500, err.Error())
return
}
writeJSON(w, 200, map[string]any{"commands": records, "total": total})
}
// pgListLLMRecords returns paginated LLM call records.
func (s *Server) pgListLLMRecords(w http.ResponseWriter, r *http.Request) {
q := r.URL.Query()
page := atoiDefault(q.Get("page"), 0)
size := atoiDefault(q.Get("size"), 50)
model := q.Get("model")
session := q.Get("session")
task := q.Get("task")
records, total, err := s.m.PG().ListLLMRecords(model, session, task, page, size)
if err != nil {
writeErr(w, 500, err.Error())
return
}
writeJSON(w, 200, map[string]any{"records": records, "total": total})
}
// pgLLMTasks returns distinct recorded tasks with counts, for the page's task
// picker (pick a task → filter the list, then delete its conversations).
func (s *Server) pgLLMTasks(w http.ResponseWriter, r *http.Request) {
tasks, err := s.m.PG().LLMTasks()
if err != nil {
writeErr(w, 500, err.Error())
return
}
writeJSON(w, 200, map[string]any{"tasks": tasks})
}
// pgDeleteLLMRecords removes all LLM records for one exact task_id (the same
// match the task picker uses). Empty task → 400. Returns rows deleted.
func (s *Server) pgDeleteLLMRecords(w http.ResponseWriter, r *http.Request) {
task := strings.TrimSpace(r.URL.Query().Get("task"))
if task == "" {
writeErr(w, 400, "missing task")
return
}
n, err := s.m.PG().DeleteLLMRecords(task)
if err != nil {
writeErr(w, 500, err.Error())
return
}
writeJSON(w, 200, map[string]any{"deleted": n})
}
// pgGetLLMRecord returns a single LLM record with full request/response bodies.
func (s *Server) pgGetLLMRecord(w http.ResponseWriter, r *http.Request) {
id, err := strconv.ParseInt(r.PathValue("id"), 10, 64)
if err != nil {
writeErr(w, 400, "invalid id")
return
}
rec, err := s.m.PG().GetLLMRecord(id)
if err != nil {
writeErr(w, 404, "not found")
return
}
writeJSON(w, 200, rec)
}