feat: implement task queue statistics and add UI templates for job management and visualization.
This commit is contained in:
+63
-10
@@ -1,9 +1,9 @@
|
||||
package ui
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/hireme/hireme/internal/config"
|
||||
"github.com/hireme/hireme/internal/db"
|
||||
@@ -33,12 +33,15 @@ func (s *Server) RegisterRoutes(mux *http.ServeMux) {
|
||||
mux.HandleFunc("GET /jobs", s.handleGetJobs)
|
||||
mux.HandleFunc("GET /jobs/{id}", s.handleGetJobDetail)
|
||||
mux.HandleFunc("POST /jobs/{id}/analyze", s.handleAnalyzeJob)
|
||||
mux.HandleFunc("POST /jobs/{id}/opt-out", s.handleOptOut)
|
||||
mux.HandleFunc("GET /applications", s.handleGetApplications)
|
||||
mux.HandleFunc("POST /applications", s.handleCreateApplication)
|
||||
mux.HandleFunc("PATCH /applications/{id}/status", s.handleUpdateAppStatus)
|
||||
mux.HandleFunc("POST /api/tasks/discover", s.handleDiscoverTasks)
|
||||
mux.HandleFunc("POST /api/tasks/clean", s.handleCleanTasks)
|
||||
mux.HandleFunc("POST /api/tasks/reprocess", s.handleReprocessJobs)
|
||||
mux.HandleFunc("POST /api/tasks/toggle", s.handleToggleTasks)
|
||||
mux.HandleFunc("GET /api/status", s.handleGetStatus)
|
||||
}
|
||||
|
||||
func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -189,6 +192,39 @@ func (s *Server) handleAnalyzeJob(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(`<span class="text-xs px-2 py-1 bg-yellow-100 text-yellow-800 rounded">Analysis Queued</span>`))
|
||||
}
|
||||
|
||||
func (s *Server) handleOptOut(w http.ResponseWriter, r *http.Request) {
|
||||
idStr := r.PathValue("id")
|
||||
id, err := strconv.ParseInt(idStr, 10, 64)
|
||||
if err != nil {
|
||||
http.Error(w, "invalid job id", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
_, err = s.db.CreateOrUpdateApplication(id, "OPTED_OUT", "")
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
jobs, err := s.db.GetJobsWithAnalysis()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_ = RenderJobList(w, jobs)
|
||||
}
|
||||
|
||||
func (s *Server) handleGetApplications(w http.ResponseWriter, r *http.Request) {
|
||||
apps, err := s.db.GetApplications()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_ = RenderApplyTable(w, apps)
|
||||
}
|
||||
|
||||
func (s *Server) handleCreateApplication(w http.ResponseWriter, r *http.Request) {
|
||||
if err := r.ParseForm(); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
@@ -213,13 +249,7 @@ func (s *Server) handleCreateApplication(w http.ResponseWriter, r *http.Request)
|
||||
return
|
||||
}
|
||||
|
||||
if strings.Contains(r.Header.Get("HX-Target"), "kanban") {
|
||||
apps, _ := s.db.GetApplications()
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_ = RenderKanbanBoard(w, apps)
|
||||
return
|
||||
}
|
||||
|
||||
// Always return the updated job list so the action column refreshes
|
||||
s.handleGetJobs(w, r)
|
||||
}
|
||||
|
||||
@@ -270,7 +300,7 @@ func (s *Server) handleUpdateAppStatus(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
updatedApps, _ := s.db.GetApplications()
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
_ = RenderKanbanBoard(w, updatedApps)
|
||||
_ = RenderApplyTable(w, updatedApps)
|
||||
}
|
||||
|
||||
func (s *Server) handleDiscoverTasks(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -295,7 +325,7 @@ func (s *Server) handleDiscoverTasks(w http.ResponseWriter, r *http.Request) {
|
||||
count++
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"status": "success", "message": "Queued ` + strconv.Itoa(count) + ` discovery tasks"}`))
|
||||
}
|
||||
@@ -332,3 +362,26 @@ func (s *Server) handleToggleTasks(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, _ = w.Write([]byte(`{"status": "` + status + `"}`))
|
||||
}
|
||||
|
||||
// handleGetStatus returns a JSON snapshot of worker pool state and task queue counts.
|
||||
// Used by the bottom bar to auto-refresh every few seconds without a full page reload.
|
||||
func (s *Server) handleGetStatus(w http.ResponseWriter, r *http.Request) {
|
||||
workerStatus := "paused"
|
||||
if s.pool.IsRunning() {
|
||||
workerStatus = "running"
|
||||
}
|
||||
|
||||
stats, err := s.db.GetQueueStats()
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
resp := map[string]interface{}{
|
||||
"worker_status": workerStatus,
|
||||
"queue": stats,
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_ = json.NewEncoder(w).Encode(resp)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user