refactor: Remove log generator functionality and update UI components

- Eliminated the log generator feature from the admin logs template and related handlers.
- Updated icons in the log viewer for consistency and improved visual clarity.
- Adjusted mobile dropdown functionality in the layout template for better user experience.
- Cleaned up debug logging statements in the WebSocket handler for recent logs.
This commit is contained in:
StarFleetCPTN
2025-04-10 20:57:07 -07:00
parent 2221e6a29c
commit ca54b450de
5 changed files with 35 additions and 71 deletions
+1 -32
View File
@@ -28,7 +28,7 @@ templ AdminLogs(ctx context.Context, data LogViewerData) {
<!-- Page Header --> <!-- Page Header -->
<div class="mb-6 flex flex-col md:flex-row md:items-center md:justify-between gap-4"> <div class="mb-6 flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<h1 class="text-2xl font-bold text-gray-900 dark:text-white flex items-center"> <h1 class="text-2xl font-bold text-gray-900 dark:text-white flex items-center">
<i class="fas fa-file-alt w-6 h-6 mr-2 text-blue-500 dark:text-blue-400"></i> Log Viewer <i class="fas fa-stream w-6 h-6 mr-2 text-blue-500 dark:text-blue-400"></i> Log Viewer
</h1> </h1>
<div class="flex gap-2"> <div class="flex gap-2">
<button id="pause-logs" class="flex items-center justify-center text-white bg-yellow-500 hover:bg-yellow-600 focus:ring-4 focus:ring-yellow-300 font-medium rounded-lg px-4 py-2 dark:bg-yellow-600 dark:hover:bg-yellow-700 focus:outline-none dark:focus:ring-yellow-800"> <button id="pause-logs" class="flex items-center justify-center text-white bg-yellow-500 hover:bg-yellow-600 focus:ring-4 focus:ring-yellow-300 font-medium rounded-lg px-4 py-2 dark:bg-yellow-600 dark:hover:bg-yellow-700 focus:outline-none dark:focus:ring-yellow-800">
@@ -43,9 +43,6 @@ templ AdminLogs(ctx context.Context, data LogViewerData) {
<button id="download-logs" class="flex items-center justify-center text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg px-4 py-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800"> <button id="download-logs" class="flex items-center justify-center text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg px-4 py-2 dark:bg-blue-600 dark:hover:bg-blue-700 focus:outline-none dark:focus:ring-blue-800">
<i class="fas fa-download w-4 h-4 mr-2"></i> Download <i class="fas fa-download w-4 h-4 mr-2"></i> Download
</button> </button>
<button id="start-generator" class="flex items-center justify-center text-white bg-purple-700 hover:bg-purple-800 focus:ring-4 focus:ring-purple-300 font-medium rounded-lg px-4 py-2 dark:bg-purple-600 dark:hover:bg-purple-700 focus:outline-none dark:focus:ring-purple-800">
<i class="fas fa-cogs w-4 h-4 mr-2"></i> Start Log Generator
</button>
</div> </div>
</div> </div>
@@ -150,7 +147,6 @@ templ AdminLogs(ctx context.Context, data LogViewerData) {
const resumeButton = document.getElementById('resume-logs'); const resumeButton = document.getElementById('resume-logs');
const clearButton = document.getElementById('clear-logs'); const clearButton = document.getElementById('clear-logs');
const downloadButton = document.getElementById('download-logs'); const downloadButton = document.getElementById('download-logs');
const generatorButton = document.getElementById('start-generator');
const connectionStatus = document.getElementById('connection-status'); const connectionStatus = document.getElementById('connection-status');
const filterLevel = document.getElementById('filter-level'); const filterLevel = document.getElementById('filter-level');
const filterSource = document.getElementById('filter-source'); const filterSource = document.getElementById('filter-source');
@@ -512,33 +508,6 @@ templ AdminLogs(ctx context.Context, data LogViewerData) {
searchTimeout = setTimeout(applyFilters, 300); searchTimeout = setTimeout(applyFilters, 300);
}); });
// Start Log Generator button click
generatorButton.addEventListener('click', function() {
fetch('/admin/logs/start-generator', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
})
.then(response => response.json())
.then(data => {
console.log(data.message);
// Show toast or notification
const toast = document.createElement('div');
toast.className = 'fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg z-50';
toast.innerHTML = 'Log generator started';
document.body.appendChild(toast);
// Remove toast after 3 seconds
setTimeout(() => {
toast.remove();
}, 3000);
})
.catch(error => {
console.error('Error starting log generator:', error);
});
});
// Initial connection // Initial connection
connectWebSocket(); connectWebSocket();
}); });
+27 -3
View File
@@ -194,7 +194,7 @@ templ LayoutWithContext(title string, ctx context.Context) {
Audit Logs Audit Logs
</a> </a>
<a href="/admin/logs" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"> <a href="/admin/logs" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700">
<i class="fas fa-file-alt w-4 h-4 mr-2 text-gray-500 dark:text-gray-400"></i> <i class="fas fa-stream w-4 h-4 mr-2 text-gray-500 dark:text-gray-400"></i>
Log Viewer Log Viewer
</a> </a>
<a href="/admin/database" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"> <a href="/admin/database" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700">
@@ -297,19 +297,23 @@ templ LayoutWithContext(title string, ctx context.Context) {
<i class="fas fa-clipboard-list w-4 h-4 mr-2 text-gray-500 dark:text-gray-400"></i> <i class="fas fa-clipboard-list w-4 h-4 mr-2 text-gray-500 dark:text-gray-400"></i>
Audit Logs Audit Logs
</a> </a>
<a href="/admin/logs" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700">
<i class="fas fa-stream w-4 h-4 mr-2 text-gray-500 dark:text-gray-400"></i>
Log Viewer
</a>
<a href="/admin/database" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700"> <a href="/admin/database" class="group flex items-center px-2 py-2 text-sm font-medium rounded-md text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-700">
<i class="fas fa-database w-4 h-4 mr-2 text-gray-500 dark:text-gray-400"></i> <i class="fas fa-database w-4 h-4 mr-2 text-gray-500 dark:text-gray-400"></i>
Database Tools Database Tools
</a> </a>
// Settings Dropdown // Settings Dropdown
<button type="button" class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700" aria-controls="dropdown-settings" data-collapse-toggle="dropdown-settings"> <button type="button" class="flex items-center w-full p-2 text-base text-gray-900 transition duration-75 rounded-lg group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700" aria-controls="dropdown-settings-mobile" data-collapse-toggle="dropdown-settings-mobile">
<i class="fas fa-cog w-4 h-4 mr-2 text-gray-500 dark:text-gray-400"></i> <i class="fas fa-cog w-4 h-4 mr-2 text-gray-500 dark:text-gray-400"></i>
<span class="flex-1 ms-3 text-left rtl:text-right whitespace-nowrap">Settings</span> <span class="flex-1 ms-3 text-left rtl:text-right whitespace-nowrap">Settings</span>
<svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6"> <svg class="w-3 h-3" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 10 6">
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/> <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 1 4 4 4-4"/>
</svg> </svg>
</button> </button>
<ul id="dropdown-settings" class="hidden py-2 space-y-2"> <ul id="dropdown-settings-mobile" class="hidden py-2 space-y-2">
// <li> // <li>
// <a href="#" class="flex items-center w-full p-2 text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700">General (Coming Soon)</a> // <a href="#" class="flex items-center w-full p-2 text-gray-900 transition duration-75 rounded-lg pl-11 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700">General (Coming Soon)</a>
// </li> // </li>
@@ -510,6 +514,26 @@ templ LayoutWithContext(title string, ctx context.Context) {
<!-- Application scripts --> <!-- Application scripts -->
<script defer src="/static/dist/app.js"></script> <script defer src="/static/dist/app.js"></script>
<script defer src="/static/dist/init.js"></script> <script defer src="/static/dist/init.js"></script>
<!-- Dropdown fix for mobile -->
<script>
document.addEventListener("DOMContentLoaded", function() {
// Initialize the mobile dropdown separately
const mobileDropdownButton = document.querySelector('[data-collapse-toggle="dropdown-settings-mobile"]');
const mobileDropdown = document.getElementById("dropdown-settings-mobile");
if (mobileDropdownButton && mobileDropdown) {
// Show dropdown if on admin pages
if (window.location.pathname.startsWith("/admin")) {
// Keep it hidden by default, will be toggled by button
mobileDropdown.classList.add("hidden");
}
mobileDropdownButton.addEventListener("click", function() {
mobileDropdown.classList.toggle("hidden");
});
}
});
</script>
</body> </body>
</html> </html>
} }
+4 -31
View File
@@ -1473,7 +1473,7 @@ func (h *Handlers) sendRecentLogs(ws *websocket.Conn) {
fmt.Fprintf(os.Stderr, "[DEBUG-WS] Read %d lines from %s for client %v.\n", len(lines), logFilePath, ws.RemoteAddr()) fmt.Fprintf(os.Stderr, "[DEBUG-WS] Read %d lines from %s for client %v.\n", len(lines), logFilePath, ws.RemoteAddr())
// Parse and send each line as a log entry, protected by the client's mutex // Parse and send each line as a log entry, protected by the client's mutex
for i, line := range lines { for _, line := range lines {
level, source, message := parseLogLine(line) level, source, message := parseLogLine(line)
timestamp := extractTimestamp(line) timestamp := extractTimestamp(line)
@@ -1485,18 +1485,18 @@ func (h *Handlers) sendRecentLogs(ws *websocket.Conn) {
} }
// Use the specific client's mutex // Use the specific client's mutex
fmt.Fprintf(os.Stderr, "[DEBUG-WS] Sending recent log %d/%d to client %v\n", i+1, len(lines), ws.RemoteAddr()) // fmt.Fprintf(os.Stderr, "[DEBUG-WS] Sending recent log %d/%d to client %v\n", i+1, len(lines), ws.RemoteAddr())
mutex.Lock() mutex.Lock()
err := ws.WriteJSON(logEntry) err := ws.WriteJSON(logEntry)
mutex.Unlock() mutex.Unlock()
if err != nil { if err != nil {
fmt.Fprintf(os.Stderr, "[DEBUG-WS] Error sending recent log %d to client %v: %v. Stopping recent logs send.\n", i+1, ws.RemoteAddr(), err) // fmt.Fprintf(os.Stderr, "[DEBUG-WS] Error sending recent log %d to client %v: %v. Stopping recent logs send.\n", i+1, ws.RemoteAddr(), err)
// Don't try to remove the client here, let the main read loop handle it // Don't try to remove the client here, let the main read loop handle it
break // Stop sending recent logs on first error break // Stop sending recent logs on first error
} }
} }
fmt.Fprintf(os.Stderr, "[DEBUG-WS] Finished sending %d recent logs to client %v.\n", len(lines), ws.RemoteAddr()) // fmt.Fprintf(os.Stderr, "[DEBUG-WS] Finished sending %d recent logs to client %v.\n", len(lines), ws.RemoteAddr())
} }
// readLastLines reads the last n lines from a file // readLastLines reads the last n lines from a file
@@ -1722,30 +1722,3 @@ func (h *Handlers) sendExampleLogs(ws *websocket.Conn) {
} }
fmt.Fprintf(os.Stderr, "[DEBUG-WS] Finished sending example logs to client %v.\n", ws.RemoteAddr()) fmt.Fprintf(os.Stderr, "[DEBUG-WS] Finished sending example logs to client %v.\n", ws.RemoteAddr())
} }
// HandleStartLogGenerator handles requests to start the log generator for testing
func (h *Handlers) HandleStartLogGenerator(c *gin.Context) {
// Directly send a log to verify the WebSocket is working
h.BroadcastLog("info", "Starting log generator...", "test")
// Start a goroutine to generate some test logs
go func() {
logLevels := []string{"debug", "info", "warn", "error"}
sources := []string{"test", "generator", "system", "scheduler"}
// First, send a direct log message to all clients
for i := 0; i < 20; i++ {
level := logLevels[i%len(logLevels)]
source := sources[i%len(sources)]
message := fmt.Sprintf("Test log entry #%d generated at %s", i+1, time.Now().Format(time.RFC3339))
// First directly broadcast without going through normal logging
h.BroadcastLog(level, message, source)
// Wait a short time between logs
time.Sleep(500 * time.Millisecond)
}
}()
c.JSON(http.StatusOK, gin.H{"success": true, "message": "Log generator started"})
}
+3 -2
View File
@@ -132,9 +132,11 @@ func (h *Handlers) RegisterRoutes(router *gin.Engine) {
{ {
adminRoles.GET("", h.HandleRoles) adminRoles.GET("", h.HandleRoles)
adminRoles.GET("/new", h.HandleNewRole) adminRoles.GET("/new", h.HandleNewRole)
adminRoles.GET("/:id", h.HandleEditRole)
adminRoles.GET("/:id/edit", h.HandleRoles) adminRoles.GET("/:id/edit", h.HandleRoles)
adminRoles.POST("", h.HandleCreateRole) adminRoles.POST("", h.HandleCreateRole)
adminRoles.PUT("/:id", h.HandleEditRole) adminRoles.POST("/:id", h.HandleUpdateRole)
adminRoles.PUT("/:id", h.HandleUpdateRole)
adminRoles.DELETE("/:id", h.HandleDeleteRole) adminRoles.DELETE("/:id", h.HandleDeleteRole)
} }
@@ -152,7 +154,6 @@ func (h *Handlers) RegisterRoutes(router *gin.Engine) {
{ {
logsGroup.GET("", h.HandleLogViewer) logsGroup.GET("", h.HandleLogViewer)
logsGroup.GET("/ws", h.HandleLogStream) logsGroup.GET("/ws", h.HandleLogStream)
logsGroup.POST("/start-generator", h.HandleStartLogGenerator)
} }
// System settings routes // System settings routes
-3
View File
@@ -66,9 +66,6 @@ func main() {
// Set Gin to release mode // Set Gin to release mode
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
// Initialize random for test log generator (Go 1.20+ compatible)
// No need to seed in newer Go versions as it's automatically initialized
// Initialize configuration // Initialize configuration
cfg, err := config.Load() cfg, err := config.Load()
if err != nil { if err != nil {