...
This commit is contained in:
		| @@ -4,7 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/system/stats" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/system/stats" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|  | ||||
| @@ -77,7 +77,7 @@ func (h *AdminHandler) getProcessStatsJSON(c *fiber.Ctx) error { | ||||
| 	if err != nil { | ||||
| 		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ | ||||
| 			"success": false, | ||||
| 			"error": "Failed to get process stats: " + err.Error(), | ||||
| 			"error":   "Failed to get process stats: " + err.Error(), | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -3,7 +3,7 @@ package api | ||||
| import ( | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/sal/executor" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/sal/executor" | ||||
|  | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|   | ||||
| @@ -7,9 +7,9 @@ import ( | ||||
| 	"strconv" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/processmanager" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/processmanager" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|  | ||||
| @@ -102,26 +102,26 @@ func (h *ServiceHandler) getProcessList() ([]ProcessDisplayInfo, error) { | ||||
| 	if !ok { | ||||
| 		// Try to handle the result as a map or other structure | ||||
| 		h.logger.Printf("Warning: unexpected result type from ListProcesses, trying alternative parsing") | ||||
| 		 | ||||
|  | ||||
| 		// Try to convert the result to JSON and then parse it | ||||
| 		resultJSON, err := json.Marshal(result) | ||||
| 		if err != nil { | ||||
| 			h.logger.Printf("Error marshaling result to JSON: %v", err) | ||||
| 			return nil, fmt.Errorf("failed to marshal result: %w", err) | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		var processStatuses []interfaces.ProcessStatus | ||||
| 		if err := json.Unmarshal(resultJSON, &processStatuses); err != nil { | ||||
| 			h.logger.Printf("Error unmarshaling result to ProcessStatus: %v", err) | ||||
| 			return nil, fmt.Errorf("failed to unmarshal process list result: %w", err) | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		// Convert to display info format | ||||
| 		displayInfoList := make([]ProcessDisplayInfo, 0, len(processStatuses)) | ||||
| 		for _, proc := range processStatuses { | ||||
| 			// Calculate uptime based on start time | ||||
| 			uptime := formatUptime(time.Since(proc.StartTime)) | ||||
| 			 | ||||
|  | ||||
| 			displayInfo := ProcessDisplayInfo{ | ||||
| 				ID:        fmt.Sprintf("%d", proc.PID), | ||||
| 				Name:      proc.Name, | ||||
| @@ -133,7 +133,7 @@ func (h *ServiceHandler) getProcessList() ([]ProcessDisplayInfo, error) { | ||||
| 			} | ||||
| 			displayInfoList = append(displayInfoList, displayInfo) | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		// Debug: Log the number of processes | ||||
| 		h.logger.Printf("Found %d processes", len(displayInfoList)) | ||||
| 		return displayInfoList, nil | ||||
| @@ -144,7 +144,7 @@ func (h *ServiceHandler) getProcessList() ([]ProcessDisplayInfo, error) { | ||||
| 	for _, proc := range processStatuses { | ||||
| 		// Calculate uptime based on start time | ||||
| 		uptime := formatUptime(time.Since(proc.StartTime)) | ||||
| 		 | ||||
|  | ||||
| 		displayInfo := ProcessDisplayInfo{ | ||||
| 			ID:        fmt.Sprintf("%d", proc.PID), | ||||
| 			Name:      proc.Name, | ||||
| @@ -276,7 +276,7 @@ func (h *ServiceHandler) stopService(c *fiber.Ctx) error { | ||||
| 			"error":   fmt.Sprintf("Failed to stop service: %v", err), | ||||
| 		}) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Check if the result indicates success | ||||
| 	if !result.Success { | ||||
| 		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ | ||||
| @@ -331,7 +331,7 @@ func (h *ServiceHandler) restartService(c *fiber.Ctx) error { | ||||
| 			"error":   fmt.Sprintf("Failed to restart service: %v", err), | ||||
| 		}) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Check if the result indicates success | ||||
| 	if !result.Success { | ||||
| 		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ | ||||
| @@ -382,7 +382,7 @@ func (h *ServiceHandler) deleteService(c *fiber.Ctx) error { | ||||
| 			"error":   fmt.Sprintf("Failed to delete service: %v", err), | ||||
| 		}) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Check if the result indicates success | ||||
| 	if !result.Success { | ||||
| 		return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ | ||||
|   | ||||
| @@ -12,16 +12,16 @@ import ( | ||||
| 	"syscall" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/heroagent/api" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/heroagent/handlers" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/heroagent/pages" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/processmanager" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/sal/executor" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/servers/redisserver" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/system/stats" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/heroagent/api" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/heroagent/handlers" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/heroagent/pages" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/processmanager" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/sal/executor" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/servers/redisserver" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/system/stats" | ||||
|  | ||||
| 	// "github.com/freeflowuniverse/heroagent/pkg/vfs/interfaces" | ||||
| 	// "github.com/freeflowuniverse/heroagent/pkg/vfs/interfaces/mock" | ||||
| 	// "git.ourworld.tf/herocode/heroagent/pkg/vfs/interfaces" | ||||
| 	// "git.ourworld.tf/herocode/heroagent/pkg/vfs/interfaces/mock" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| 	"github.com/gofiber/fiber/v2/middleware/cors" | ||||
| 	"github.com/gofiber/fiber/v2/middleware/logger" | ||||
| @@ -239,7 +239,7 @@ func (hl *HeroLauncher) GetUptime() string { | ||||
| func (hl *HeroLauncher) startProcessManager() error { | ||||
| 	_, filename, _, _ := runtime.Caller(0) | ||||
| 	projectRoot := filepath.Join(filepath.Dir(filename), "../..") | ||||
| 	processManagerPath := filepath.Join(projectRoot, "cmd/processmanager/main.go") | ||||
| 	processManagerPath := filepath.Join(projectRoot, "pkg/processmanager/examples/openrpc/main.go") | ||||
|  | ||||
| 	log.Printf("Starting process manager from: %s", processManagerPath) | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import ( | ||||
| 	"log" | ||||
| 	"strconv" // Added strconv for JobID parsing | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/herojobs" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/herojobs" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -10,7 +10,7 @@ import ( | ||||
| 	"net/http/httptest" | ||||
| 	"testing" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/herojobs" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/herojobs" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/mock" | ||||
|   | ||||
| @@ -7,7 +7,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/logger" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/logger" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|  | ||||
| @@ -65,40 +65,40 @@ func NewLogHandler(logPath string) (*LogHandler, error) { | ||||
| type LogType string | ||||
|  | ||||
| const ( | ||||
| 	LogTypeSystem   LogType = "system" | ||||
| 	LogTypeService  LogType = "service" | ||||
| 	LogTypeJob      LogType = "job" | ||||
| 	LogTypeProcess  LogType = "process" | ||||
| 	LogTypeAll      LogType = "all"     // Special type to retrieve logs from all sources | ||||
| 	LogTypeSystem  LogType = "system" | ||||
| 	LogTypeService LogType = "service" | ||||
| 	LogTypeJob     LogType = "job" | ||||
| 	LogTypeProcess LogType = "process" | ||||
| 	LogTypeAll     LogType = "all" // Special type to retrieve logs from all sources | ||||
| ) | ||||
|  | ||||
| // GetLogs renders the logs page with logs content | ||||
| func (h *LogHandler) GetLogs(c *fiber.Ctx) error { | ||||
| 	// Check which logger to use based on the log type parameter | ||||
| 	logTypeParam := c.Query("log_type", string(LogTypeSystem)) | ||||
| 	 | ||||
|  | ||||
| 	// Parse query parameters | ||||
| 	category := c.Query("category", "") | ||||
| 	logItemType := parseLogType(c.Query("type", "")) | ||||
| 	maxItems := c.QueryInt("max_items", 100) | ||||
| 	page := c.QueryInt("page", 1) | ||||
| 	itemsPerPage := 20 // Default items per page | ||||
| 	 | ||||
|  | ||||
| 	// Parse time range | ||||
| 	fromTime := parseTimeParam(c.Query("from", "")) | ||||
| 	toTime := parseTimeParam(c.Query("to", "")) | ||||
| 	 | ||||
|  | ||||
| 	// Create search arguments | ||||
| 	searchArgs := logger.SearchArgs{ | ||||
| 		Category:      category, | ||||
| 		LogType:       logItemType, | ||||
| 		MaxItems:      maxItems, | ||||
| 		Category: category, | ||||
| 		LogType:  logItemType, | ||||
| 		MaxItems: maxItems, | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	if !fromTime.IsZero() { | ||||
| 		searchArgs.TimestampFrom = &fromTime | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	if !toTime.IsZero() { | ||||
| 		searchArgs.TimestampTo = &toTime | ||||
| 	} | ||||
| @@ -107,7 +107,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error { | ||||
| 	var logs []logger.LogItem | ||||
| 	var err error | ||||
| 	var logTypeTitle string | ||||
| 	 | ||||
|  | ||||
| 	// Check if we want to merge logs from all sources | ||||
| 	if LogType(logTypeParam) == LogTypeAll { | ||||
| 		// Get merged logs from all loggers | ||||
| @@ -116,7 +116,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error { | ||||
| 	} else { | ||||
| 		// Select the appropriate logger based on the log type | ||||
| 		var selectedLogger *logger.Logger | ||||
| 		 | ||||
|  | ||||
| 		switch LogType(logTypeParam) { | ||||
| 		case LogTypeService: | ||||
| 			selectedLogger = h.serviceLogger | ||||
| @@ -131,13 +131,13 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error { | ||||
| 			selectedLogger = h.systemLogger | ||||
| 			logTypeTitle = "System Logs" | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		// Check if the selected logger is properly initialized | ||||
| 		if selectedLogger == nil { | ||||
| 			return c.Render("admin/system/logs", fiber.Map{ | ||||
| 				"title": logTypeTitle, | ||||
| 				"error": "Logger not initialized", | ||||
| 				"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 				"title":           logTypeTitle, | ||||
| 				"error":           "Logger not initialized", | ||||
| 				"logTypes":        []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 				"selectedLogType": logTypeParam, | ||||
| 			}) | ||||
| 		} | ||||
| @@ -149,25 +149,24 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error { | ||||
| 	// Handle search error | ||||
| 	if err != nil { | ||||
| 		return c.Render("admin/system/logs", fiber.Map{ | ||||
| 			"title": logTypeTitle, | ||||
| 			"error": err.Error(), | ||||
| 			"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 			"title":           logTypeTitle, | ||||
| 			"error":           err.Error(), | ||||
| 			"logTypes":        []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 			"selectedLogType": logTypeParam, | ||||
| 		}) | ||||
| 	} | ||||
| 	 | ||||
| 	 | ||||
|  | ||||
| 	// Calculate total pages | ||||
| 	totalLogs := len(logs) | ||||
| 	totalPages := (totalLogs + itemsPerPage - 1) / itemsPerPage | ||||
| 	 | ||||
|  | ||||
| 	// Apply pagination | ||||
| 	startIndex := (page - 1) * itemsPerPage | ||||
| 	endIndex := startIndex + itemsPerPage | ||||
| 	if endIndex > totalLogs { | ||||
| 		endIndex = totalLogs | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Slice logs for current page | ||||
| 	pagedLogs := logs | ||||
| 	if startIndex < totalLogs { | ||||
| @@ -175,7 +174,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error { | ||||
| 	} else { | ||||
| 		pagedLogs = []logger.LogItem{} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Convert logs to a format suitable for the UI | ||||
| 	formattedLogs := make([]fiber.Map, 0, len(pagedLogs)) | ||||
| 	for _, log := range pagedLogs { | ||||
| @@ -185,7 +184,7 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error { | ||||
| 			logTypeStr = "ERROR" | ||||
| 			logTypeClass = "log-error" | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		formattedLogs = append(formattedLogs, fiber.Map{ | ||||
| 			"timestamp": log.Timestamp.Format("2006-01-02T15:04:05"), | ||||
| 			"category":  log.Category, | ||||
| @@ -194,20 +193,20 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error { | ||||
| 			"typeClass": logTypeClass, | ||||
| 		}) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	return c.Render("admin/system/logs", fiber.Map{ | ||||
| 		"title": logTypeTitle, | ||||
| 		"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 		"title":           logTypeTitle, | ||||
| 		"logTypes":        []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 		"selectedLogType": logTypeParam, | ||||
| 		"logs": formattedLogs, | ||||
| 		"total": totalLogs, | ||||
| 		"showing": len(formattedLogs), | ||||
| 		"page": page, | ||||
| 		"totalPages": totalPages, | ||||
| 		"categoryParam": category, | ||||
| 		"typeParam": c.Query("type", ""), | ||||
| 		"fromParam": c.Query("from", ""), | ||||
| 		"toParam": c.Query("to", ""), | ||||
| 		"logs":            formattedLogs, | ||||
| 		"total":           totalLogs, | ||||
| 		"showing":         len(formattedLogs), | ||||
| 		"page":            page, | ||||
| 		"totalPages":      totalPages, | ||||
| 		"categoryParam":   category, | ||||
| 		"typeParam":       c.Query("type", ""), | ||||
| 		"fromParam":       c.Query("from", ""), | ||||
| 		"toParam":         c.Query("to", ""), | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| @@ -215,27 +214,27 @@ func (h *LogHandler) GetLogs(c *fiber.Ctx) error { | ||||
| func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error { | ||||
| 	// Check which logger to use based on the log type parameter | ||||
| 	logTypeParam := c.Query("log_type", string(LogTypeSystem)) | ||||
| 	 | ||||
|  | ||||
| 	// Parse query parameters | ||||
| 	category := c.Query("category", "") | ||||
| 	logItemType := parseLogType(c.Query("type", "")) | ||||
| 	maxItems := c.QueryInt("max_items", 100) | ||||
| 	 | ||||
|  | ||||
| 	// Parse time range | ||||
| 	fromTime := parseTimeParam(c.Query("from", "")) | ||||
| 	toTime := parseTimeParam(c.Query("to", "")) | ||||
| 	 | ||||
|  | ||||
| 	// Create search arguments | ||||
| 	searchArgs := logger.SearchArgs{ | ||||
| 		Category:      category, | ||||
| 		LogType:       logItemType, | ||||
| 		MaxItems:      maxItems, | ||||
| 		Category: category, | ||||
| 		LogType:  logItemType, | ||||
| 		MaxItems: maxItems, | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	if !fromTime.IsZero() { | ||||
| 		searchArgs.TimestampFrom = &fromTime | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	if !toTime.IsZero() { | ||||
| 		searchArgs.TimestampTo = &toTime | ||||
| 	} | ||||
| @@ -243,7 +242,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error { | ||||
| 	// Variables for logs and error | ||||
| 	var logs []logger.LogItem | ||||
| 	var err error | ||||
| 	 | ||||
|  | ||||
| 	// Check if we want to merge logs from all sources | ||||
| 	if LogType(logTypeParam) == LogTypeAll { | ||||
| 		// Get merged logs from all loggers | ||||
| @@ -251,7 +250,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error { | ||||
| 	} else { | ||||
| 		// Select the appropriate logger based on the log type | ||||
| 		var selectedLogger *logger.Logger | ||||
| 		 | ||||
|  | ||||
| 		switch LogType(logTypeParam) { | ||||
| 		case LogTypeService: | ||||
| 			selectedLogger = h.serviceLogger | ||||
| @@ -262,7 +261,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error { | ||||
| 		default: | ||||
| 			selectedLogger = h.systemLogger | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		// Check if the selected logger is properly initialized | ||||
| 		if selectedLogger == nil { | ||||
| 			return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ | ||||
| @@ -280,7 +279,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error { | ||||
| 			"error": err.Error(), | ||||
| 		}) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Convert logs to a format suitable for the UI | ||||
| 	response := make([]fiber.Map, 0, len(logs)) | ||||
| 	for _, log := range logs { | ||||
| @@ -288,7 +287,7 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error { | ||||
| 		if log.LogType == logger.LogTypeError { | ||||
| 			logTypeStr = "ERROR" | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		response = append(response, fiber.Map{ | ||||
| 			"timestamp": log.Timestamp.Format(time.RFC3339), | ||||
| 			"category":  log.Category, | ||||
| @@ -296,9 +295,9 @@ func (h *LogHandler) GetLogsAPI(c *fiber.Ctx) error { | ||||
| 			"type":      logTypeStr, | ||||
| 		}) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	return c.JSON(fiber.Map{ | ||||
| 		"logs": response, | ||||
| 		"logs":  response, | ||||
| 		"total": len(logs), | ||||
| 	}) | ||||
| } | ||||
| @@ -309,29 +308,29 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error { | ||||
|  | ||||
| 	// Check which logger to use based on the log type parameter | ||||
| 	logTypeParam := c.Query("log_type", string(LogTypeSystem)) | ||||
| 	 | ||||
|  | ||||
| 	// Parse query parameters | ||||
| 	category := c.Query("category", "") | ||||
| 	logItemType := parseLogType(c.Query("type", "")) | ||||
| 	maxItems := c.QueryInt("max_items", 100) | ||||
| 	page := c.QueryInt("page", 1) | ||||
| 	itemsPerPage := 20 // Default items per page | ||||
| 	 | ||||
|  | ||||
| 	// Parse time range | ||||
| 	fromTime := parseTimeParam(c.Query("from", "")) | ||||
| 	toTime := parseTimeParam(c.Query("to", "")) | ||||
| 	 | ||||
|  | ||||
| 	// Create search arguments | ||||
| 	searchArgs := logger.SearchArgs{ | ||||
| 		Category:      category, | ||||
| 		LogType:       logItemType, | ||||
| 		MaxItems:      maxItems, | ||||
| 		Category: category, | ||||
| 		LogType:  logItemType, | ||||
| 		MaxItems: maxItems, | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	if !fromTime.IsZero() { | ||||
| 		searchArgs.TimestampFrom = &fromTime | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	if !toTime.IsZero() { | ||||
| 		searchArgs.TimestampTo = &toTime | ||||
| 	} | ||||
| @@ -340,7 +339,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error { | ||||
| 	var logs []logger.LogItem | ||||
| 	var err error | ||||
| 	var logTypeTitle string | ||||
| 	 | ||||
|  | ||||
| 	// Check if we want to merge logs from all sources | ||||
| 	if LogType(logTypeParam) == LogTypeAll { | ||||
| 		// Get merged logs from all loggers | ||||
| @@ -349,7 +348,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error { | ||||
| 	} else { | ||||
| 		// Select the appropriate logger based on the log type | ||||
| 		var selectedLogger *logger.Logger | ||||
| 		 | ||||
|  | ||||
| 		switch LogType(logTypeParam) { | ||||
| 		case LogTypeService: | ||||
| 			selectedLogger = h.serviceLogger | ||||
| @@ -364,13 +363,13 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error { | ||||
| 			selectedLogger = h.systemLogger | ||||
| 			logTypeTitle = "System Logs" | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		// Check if the selected logger is properly initialized | ||||
| 		if selectedLogger == nil { | ||||
| 			return c.Render("admin/system/logs_fragment", fiber.Map{ | ||||
| 				"title": logTypeTitle, | ||||
| 				"error": "Logger not initialized", | ||||
| 				"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 				"title":           logTypeTitle, | ||||
| 				"error":           "Logger not initialized", | ||||
| 				"logTypes":        []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 				"selectedLogType": logTypeParam, | ||||
| 			}) | ||||
| 		} | ||||
| @@ -382,24 +381,24 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error { | ||||
| 	// Handle search error | ||||
| 	if err != nil { | ||||
| 		return c.Render("admin/system/logs_fragment", fiber.Map{ | ||||
| 			"title": logTypeTitle, | ||||
| 			"error": err.Error(), | ||||
| 			"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 			"title":           logTypeTitle, | ||||
| 			"error":           err.Error(), | ||||
| 			"logTypes":        []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 			"selectedLogType": logTypeParam, | ||||
| 		}) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Calculate total pages | ||||
| 	totalLogs := len(logs) | ||||
| 	totalPages := (totalLogs + itemsPerPage - 1) / itemsPerPage | ||||
| 	 | ||||
|  | ||||
| 	// Apply pagination | ||||
| 	startIndex := (page - 1) * itemsPerPage | ||||
| 	endIndex := startIndex + itemsPerPage | ||||
| 	if endIndex > totalLogs { | ||||
| 		endIndex = totalLogs | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Slice logs for current page | ||||
| 	pagedLogs := logs | ||||
| 	if startIndex < totalLogs { | ||||
| @@ -407,7 +406,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error { | ||||
| 	} else { | ||||
| 		pagedLogs = []logger.LogItem{} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Convert logs to a format suitable for the UI | ||||
| 	formattedLogs := make([]fiber.Map, 0, len(pagedLogs)) | ||||
| 	for _, log := range pagedLogs { | ||||
| @@ -417,7 +416,7 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error { | ||||
| 			logTypeStr = "ERROR" | ||||
| 			logTypeClass = "log-error" | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		formattedLogs = append(formattedLogs, fiber.Map{ | ||||
| 			"timestamp": log.Timestamp.Format("2006-01-02T15:04:05"), | ||||
| 			"category":  log.Category, | ||||
| @@ -426,18 +425,18 @@ func (h *LogHandler) GetLogsFragment(c *fiber.Ctx) error { | ||||
| 			"typeClass": logTypeClass, | ||||
| 		}) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Set layout to empty to disable the layout for fragment responses | ||||
| 	return c.Render("admin/system/logs_fragment", fiber.Map{ | ||||
| 		"title": logTypeTitle, | ||||
| 		"logTypes": []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 		"title":           logTypeTitle, | ||||
| 		"logTypes":        []LogType{LogTypeAll, LogTypeSystem, LogTypeService, LogTypeJob, LogTypeProcess}, | ||||
| 		"selectedLogType": logTypeParam, | ||||
| 		"logs": formattedLogs, | ||||
| 		"total": totalLogs, | ||||
| 		"showing": len(formattedLogs), | ||||
| 		"page": page, | ||||
| 		"totalPages": totalPages, | ||||
| 		"layout": "", // Disable layout for partial template | ||||
| 		"logs":            formattedLogs, | ||||
| 		"total":           totalLogs, | ||||
| 		"showing":         len(formattedLogs), | ||||
| 		"page":            page, | ||||
| 		"totalPages":      totalPages, | ||||
| 		"layout":          "", // Disable layout for partial template | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| @@ -458,12 +457,12 @@ func parseTimeParam(timeStr string) time.Time { | ||||
| 	if timeStr == "" { | ||||
| 		return time.Time{} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	t, err := time.Parse(time.RFC3339, timeStr) | ||||
| 	if err != nil { | ||||
| 		return time.Time{} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| @@ -471,10 +470,10 @@ func parseTimeParam(timeStr string) time.Time { | ||||
| func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, error) { | ||||
| 	// Create a slice to hold all logs | ||||
| 	allLogs := make([]logger.LogItem, 0) | ||||
| 	 | ||||
|  | ||||
| 	// Create a map to track errors | ||||
| 	errors := make(map[string]error) | ||||
| 	 | ||||
|  | ||||
| 	// Get logs from system logger if available | ||||
| 	if h.systemLogger != nil { | ||||
| 		systemLogs, err := h.systemLogger.Search(args) | ||||
| @@ -488,7 +487,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er | ||||
| 			allLogs = append(allLogs, systemLogs...) | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Get logs from service logger if available | ||||
| 	if h.serviceLogger != nil { | ||||
| 		serviceLogs, err := h.serviceLogger.Search(args) | ||||
| @@ -502,7 +501,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er | ||||
| 			allLogs = append(allLogs, serviceLogs...) | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Get logs from job logger if available | ||||
| 	if h.jobLogger != nil { | ||||
| 		jobLogs, err := h.jobLogger.Search(args) | ||||
| @@ -516,7 +515,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er | ||||
| 			allLogs = append(allLogs, jobLogs...) | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Get logs from process logger if available | ||||
| 	if h.processLogger != nil { | ||||
| 		processLogs, err := h.processLogger.Search(args) | ||||
| @@ -530,7 +529,7 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er | ||||
| 			allLogs = append(allLogs, processLogs...) | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Check if we have any logs | ||||
| 	if len(allLogs) == 0 && len(errors) > 0 { | ||||
| 		// Combine error messages | ||||
| @@ -540,16 +539,16 @@ func (h *LogHandler) getMergedLogs(args logger.SearchArgs) ([]logger.LogItem, er | ||||
| 		} | ||||
| 		return nil, fmt.Errorf("failed to retrieve logs: %s", strings.Join(errorMsgs, "; ")) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Sort logs by timestamp (newest first) | ||||
| 	sort.Slice(allLogs, func(i, j int) bool { | ||||
| 		return allLogs[i].Timestamp.After(allLogs[j].Timestamp) | ||||
| 	}) | ||||
| 	 | ||||
|  | ||||
| 	// Apply max items limit if specified | ||||
| 	if args.MaxItems > 0 && len(allLogs) > args.MaxItems { | ||||
| 		allLogs = allLogs[:args.MaxItems] | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	return allLogs, nil | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/system/stats" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/system/stats" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|  | ||||
| @@ -43,8 +43,8 @@ func (h *ProcessHandler) GetProcessStatsJSON(c *fiber.Ctx) error { | ||||
|  | ||||
| 	// Convert to fiber.Map for JSON response | ||||
| 	response := fiber.Map{ | ||||
| 		"total": processData.Total, | ||||
| 		"filtered": processData.Filtered, | ||||
| 		"total":     processData.Total, | ||||
| 		"filtered":  processData.Filtered, | ||||
| 		"timestamp": time.Now().Unix(), | ||||
| 	} | ||||
|  | ||||
| @@ -61,7 +61,7 @@ func (h *ProcessHandler) GetProcessStatsJSON(c *fiber.Ctx) error { | ||||
| 			"is_current":      proc.IsCurrent, | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	response["processes"] = processes | ||||
|  | ||||
| 	// Return JSON response | ||||
| @@ -127,8 +127,8 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error { | ||||
| 	// Check if StatsManager is properly initialized | ||||
| 	if h.statsManager == nil { | ||||
| 		return c.Render("admin/system/processes_data", fiber.Map{ | ||||
| 			"error":   "System error: Stats manager not initialized", | ||||
| 			"layout":  "", | ||||
| 			"error":  "System error: Stats manager not initialized", | ||||
| 			"layout": "", | ||||
| 		}) | ||||
| 	} | ||||
|  | ||||
| @@ -156,7 +156,7 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error { | ||||
| 		} else { | ||||
| 			processData, err = h.statsManager.GetProcessStatsFresh(0) | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		if err != nil { | ||||
| 			// Handle AJAX requests differently from regular requests | ||||
| 			isAjax := c.Get("X-Requested-With") == "XMLHttpRequest" | ||||
| @@ -165,8 +165,8 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error { | ||||
| 			} | ||||
| 			// For regular requests, render the error within the fragment | ||||
| 			return c.Render("admin/system/processes_data", fiber.Map{ | ||||
| 				"error":   "Failed to get process data: " + err.Error(), | ||||
| 				"layout":  "", | ||||
| 				"error":  "Failed to get process data: " + err.Error(), | ||||
| 				"layout": "", | ||||
| 			}) | ||||
| 		} | ||||
| 	} | ||||
| @@ -197,9 +197,7 @@ func (h *ProcessHandler) GetProcessesData(c *fiber.Ctx) error { | ||||
| 		"processStats": processStats, | ||||
| 		"layout":       "", // Disable layout for partial template | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	// Return only the table HTML content directly to be injected into the processes-table-content div | ||||
| 	return c.Render("admin/system/processes_data", templateData) | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -4,8 +4,8 @@ import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,7 @@ import ( | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/system/stats" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/system/stats" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| 	"github.com/shirou/gopsutil/v3/host" | ||||
| ) | ||||
| @@ -335,7 +335,7 @@ func (h *SystemHandler) GetProcessStatsAPI(c *fiber.Ctx) error { | ||||
| 			"is_current":      proc.IsCurrent, | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	response["processes"] = processes | ||||
|  | ||||
| 	// Return JSON response | ||||
|   | ||||
| @@ -7,8 +7,8 @@ import ( | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/heroagent/handlers" | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/system/stats" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/heroagent/handlers" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/system/stats" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| 	"github.com/shirou/gopsutil/v3/host" | ||||
| ) | ||||
| @@ -68,12 +68,12 @@ func (h *AdminHandler) RegisterRoutes(app *fiber.App) { | ||||
| 	// System routes | ||||
| 	admin.Get("/system/info", h.getSystemInfo) | ||||
| 	admin.Get("/system/hardware-stats", h.getHardwareStats) | ||||
| 	 | ||||
|  | ||||
| 	// Create process handler | ||||
| 	processHandler := handlers.NewProcessHandler(h.statsManager) | ||||
| 	admin.Get("/system/processes", processHandler.GetProcesses) | ||||
| 	admin.Get("/system/processes-data", processHandler.GetProcessesData) | ||||
| 	 | ||||
|  | ||||
| 	// Create log handler | ||||
| 	// Ensure log directory exists | ||||
| 	// Using the same shared logs path as process manager | ||||
| @@ -81,7 +81,7 @@ func (h *AdminHandler) RegisterRoutes(app *fiber.App) { | ||||
| 	if err := os.MkdirAll(logDir, 0755); err != nil { | ||||
| 		fmt.Printf("Error creating log directory: %v\n", err) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	logHandler, err := handlers.NewLogHandler(logDir) | ||||
| 	if err != nil { | ||||
| 		fmt.Printf("Error creating log handler: %v\n", err) | ||||
| @@ -96,11 +96,11 @@ func (h *AdminHandler) RegisterRoutes(app *fiber.App) { | ||||
| 		// but it now just redirects to the main logs endpoint | ||||
| 		admin.Get("/system/logs-fragment", logHandler.GetLogsFragment) | ||||
| 		admin.Get("/system/logs-test", h.getSystemLogsTest) // Keep the test logs route | ||||
| 		 | ||||
|  | ||||
| 		// Log API endpoints | ||||
| 		app.Get("/api/logs", logHandler.GetLogsAPI) | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	admin.Get("/system/settings", h.getSystemSettings) | ||||
|  | ||||
| 	// OpenRPC routes | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/herojobs" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/herojobs" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|  | ||||
|   | ||||
| @@ -4,14 +4,14 @@ import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/processmanager/interfaces/openrpc" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/processmanager/interfaces/openrpc" | ||||
| 	"github.com/gofiber/fiber/v2" | ||||
| ) | ||||
|  | ||||
| // ServiceHandler handles service-related page routes | ||||
| type ServiceHandler struct { | ||||
| 	client  *openrpc.Client | ||||
| 	logger  *log.Logger | ||||
| 	client *openrpc.Client | ||||
| 	logger *log.Logger | ||||
| } | ||||
|  | ||||
| // NewServiceHandler creates a new service handler with the provided socket path and secret | ||||
| @@ -90,7 +90,7 @@ func (h *ServiceHandler) getProcessList() ([]ProcessDisplayInfo, error) { | ||||
| 		if !ok { | ||||
| 			continue | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| 		// Create a ProcessDisplayInfo from the map | ||||
| 		displayInfo := ProcessDisplayInfo{ | ||||
| 			ID:        fmt.Sprintf("%v", procMap["pid"]), | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/freeflowuniverse/heroagent/pkg/processmanager" | ||||
| 	"git.ourworld.tf/herocode/heroagent/pkg/processmanager" | ||||
| ) | ||||
|  | ||||
| // ProcessDisplayInfo represents information about a process for display purposes | ||||
| @@ -22,7 +22,7 @@ type ProcessDisplayInfo struct { | ||||
| func ConvertToDisplayInfo(info *processmanager.ProcessInfo) ProcessDisplayInfo { | ||||
| 	// Calculate uptime from start time | ||||
| 	uptime := formatUptime(time.Since(info.StartTime)) | ||||
| 	 | ||||
|  | ||||
| 	return ProcessDisplayInfo{ | ||||
| 		ID:        fmt.Sprintf("%d", info.PID), | ||||
| 		Name:      info.Name, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user