Add projects table controls and sync status tab with app version
This commit is contained in:
108
cmd/qfs/main.go
108
cmd/qfs/main.go
@@ -7,12 +7,14 @@ import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"math"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -42,6 +44,8 @@ import (
|
||||
// Version is set via ldflags during build
|
||||
var Version = "dev"
|
||||
|
||||
const backgroundSyncInterval = 5 * time.Minute
|
||||
|
||||
func main() {
|
||||
configPath := flag.String("config", "", "path to config file (default: user state dir or QFS_CONFIG_PATH)")
|
||||
localDBPath := flag.String("localdb", "", "path to local SQLite database (default: user state dir or QFS_DB_PATH)")
|
||||
@@ -207,7 +211,7 @@ func main() {
|
||||
workerCtx, workerCancel := context.WithCancel(context.Background())
|
||||
defer workerCancel()
|
||||
|
||||
syncWorker := sync.NewWorker(syncService, connMgr, 5*time.Minute)
|
||||
syncWorker := sync.NewWorker(syncService, connMgr, backgroundSyncInterval)
|
||||
go syncWorker.Start(workerCtx)
|
||||
|
||||
srv := &http.Server{
|
||||
@@ -580,7 +584,7 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
exportHandler := handlers.NewExportHandler(exportService, configService, componentService)
|
||||
pricingHandler := handlers.NewPricingHandler(mariaDB, pricingService, alertService, componentRepo, priceRepo, statsRepo)
|
||||
pricelistHandler := handlers.NewPricelistHandler(pricelistService, local)
|
||||
syncHandler, err := handlers.NewSyncHandler(local, syncService, connMgr, templatesPath)
|
||||
syncHandler, err := handlers.NewSyncHandler(local, syncService, connMgr, templatesPath, backgroundSyncInterval)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("creating sync handler: %w", err)
|
||||
}
|
||||
@@ -1041,10 +1045,32 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
|
||||
status := c.DefaultQuery("status", "active")
|
||||
search := strings.ToLower(strings.TrimSpace(c.Query("search")))
|
||||
author := strings.ToLower(strings.TrimSpace(c.Query("author")))
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
perPage, _ := strconv.Atoi(c.DefaultQuery("per_page", "10"))
|
||||
sortField := strings.ToLower(strings.TrimSpace(c.DefaultQuery("sort", "created_at")))
|
||||
sortDir := strings.ToLower(strings.TrimSpace(c.DefaultQuery("dir", "desc")))
|
||||
if status != "active" && status != "archived" && status != "all" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid status"})
|
||||
return
|
||||
}
|
||||
if page < 1 {
|
||||
page = 1
|
||||
}
|
||||
if perPage < 1 {
|
||||
perPage = 10
|
||||
}
|
||||
if perPage > 100 {
|
||||
perPage = 100
|
||||
}
|
||||
if sortField != "name" && sortField != "created_at" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid sort field"})
|
||||
return
|
||||
}
|
||||
if sortDir != "asc" && sortDir != "desc" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid sort direction"})
|
||||
return
|
||||
}
|
||||
|
||||
allProjects, err := projectService.ListByUser(dbUsername, true)
|
||||
if err != nil {
|
||||
@@ -1064,12 +1090,69 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
if search != "" && !strings.Contains(strings.ToLower(p.Name), search) {
|
||||
continue
|
||||
}
|
||||
if author != "" && !strings.Contains(strings.ToLower(strings.TrimSpace(p.OwnerUsername)), author) {
|
||||
continue
|
||||
}
|
||||
filtered = append(filtered, p)
|
||||
}
|
||||
|
||||
projectRows := make([]gin.H, 0, len(filtered))
|
||||
for i := range filtered {
|
||||
p := filtered[i]
|
||||
sort.Slice(filtered, func(i, j int) bool {
|
||||
left := filtered[i]
|
||||
right := filtered[j]
|
||||
if sortField == "name" {
|
||||
leftName := strings.ToLower(strings.TrimSpace(left.Name))
|
||||
rightName := strings.ToLower(strings.TrimSpace(right.Name))
|
||||
if leftName == rightName {
|
||||
if sortDir == "asc" {
|
||||
return left.CreatedAt.Before(right.CreatedAt)
|
||||
}
|
||||
return left.CreatedAt.After(right.CreatedAt)
|
||||
}
|
||||
if sortDir == "asc" {
|
||||
return leftName < rightName
|
||||
}
|
||||
return leftName > rightName
|
||||
}
|
||||
if left.CreatedAt.Equal(right.CreatedAt) {
|
||||
leftName := strings.ToLower(strings.TrimSpace(left.Name))
|
||||
rightName := strings.ToLower(strings.TrimSpace(right.Name))
|
||||
if sortDir == "asc" {
|
||||
return leftName < rightName
|
||||
}
|
||||
return leftName > rightName
|
||||
}
|
||||
if sortDir == "asc" {
|
||||
return left.CreatedAt.Before(right.CreatedAt)
|
||||
}
|
||||
return left.CreatedAt.After(right.CreatedAt)
|
||||
})
|
||||
|
||||
total := len(filtered)
|
||||
totalPages := 0
|
||||
if total > 0 {
|
||||
totalPages = int(math.Ceil(float64(total) / float64(perPage)))
|
||||
}
|
||||
if totalPages > 0 && page > totalPages {
|
||||
page = totalPages
|
||||
}
|
||||
|
||||
start := (page - 1) * perPage
|
||||
if start < 0 {
|
||||
start = 0
|
||||
}
|
||||
end := start + perPage
|
||||
if end > total {
|
||||
end = total
|
||||
}
|
||||
|
||||
paged := []models.Project{}
|
||||
if start < total {
|
||||
paged = filtered[start:end]
|
||||
}
|
||||
|
||||
projectRows := make([]gin.H, 0, len(paged))
|
||||
for i := range paged {
|
||||
p := paged[i]
|
||||
configs, err := projectService.ListConfigurations(p.UUID, dbUsername, "active")
|
||||
if err != nil {
|
||||
configs = &services.ProjectConfigurationsResult{
|
||||
@@ -1093,10 +1176,16 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"projects": projectRows,
|
||||
"status": status,
|
||||
"search": search,
|
||||
"total": len(projectRows),
|
||||
"projects": projectRows,
|
||||
"status": status,
|
||||
"search": search,
|
||||
"author": author,
|
||||
"sort": sortField,
|
||||
"dir": sortDir,
|
||||
"page": page,
|
||||
"per_page": perPage,
|
||||
"total": total,
|
||||
"total_pages": totalPages,
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1271,6 +1360,7 @@ func setupRouter(cfg *config.Config, local *localdb.LocalDB, connMgr *db.Connect
|
||||
{
|
||||
syncAPI.GET("/status", syncHandler.GetStatus)
|
||||
syncAPI.GET("/info", syncHandler.GetInfo)
|
||||
syncAPI.GET("/users-status", syncHandler.GetUsersStatus)
|
||||
syncAPI.POST("/components", syncHandler.SyncComponents)
|
||||
syncAPI.POST("/pricelists", syncHandler.SyncPricelists)
|
||||
syncAPI.POST("/all", syncHandler.SyncAll)
|
||||
|
||||
Reference in New Issue
Block a user