Browse Source

refactor(event): use WebSocket event bus instead of SSE #1197

Jacky 1 day ago
parent
commit
28cc1dad64

+ 22 - 0
.vscode/settings.json

@@ -12,5 +12,27 @@
     "batch": {
       "pageSize": 100
     }
+  },
+  "search.exclude": {
+    "**/node_modules": true,
+    "**/bower_components": true,
+    "**/*.code-search": true,
+    "**/vendor": true,
+    "**/dist": true,
+    "**/build": true,
+    "**/out": true,
+    "**/tmp": true,
+    "**/.git": true,
+    "**/.DS_Store": true,
+    "**/database.db": true,
+    "**/.pnpm-store": true,
+    "**/nginx-ui": true
+  },
+  "files.watcherExclude": {
+    "**/.git/objects/**": true,
+    "**/.git/subtree-cache/**": true,
+    "**/node_modules/*/**": true,
+    "**/tmp/**": true,
+    "**/.pnpm-store/**": true
   }
 }

+ 8 - 0
api/event/router.go

@@ -0,0 +1,8 @@
+package event
+
+import "github.com/gin-gonic/gin"
+
+// InitRouter registers the WebSocket event bus route
+func InitRouter(r *gin.RouterGroup) {
+	r.GET("events", EventBus)
+}

+ 296 - 0
api/event/websocket.go

@@ -0,0 +1,296 @@
+package event
+
+import (
+	"context"
+	"encoding/json"
+	"net/http"
+	"sync"
+	"time"
+
+	"github.com/0xJacky/Nginx-UI/internal/cache"
+	"github.com/0xJacky/Nginx-UI/internal/cert"
+	"github.com/0xJacky/Nginx-UI/internal/helper"
+	"github.com/0xJacky/Nginx-UI/internal/kernel"
+	"github.com/0xJacky/Nginx-UI/internal/notification"
+	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/gin-gonic/gin"
+	"github.com/gorilla/websocket"
+	"github.com/uozi-tech/cosy/logger"
+)
+
+// WebSocketMessage represents the structure of messages sent to the client
+type WebSocketMessage struct {
+	Event string      `json:"event"`
+	Data  interface{} `json:"data"`
+}
+
+// Client represents a WebSocket client connection
+type Client struct {
+	conn   *websocket.Conn
+	send   chan WebSocketMessage
+	ctx    context.Context
+	cancel context.CancelFunc
+	mutex  sync.RWMutex
+}
+
+// Hub maintains the set of active clients and broadcasts messages to them
+type Hub struct {
+	clients    map[*Client]bool
+	broadcast  chan WebSocketMessage
+	register   chan *Client
+	unregister chan *Client
+	mutex      sync.RWMutex
+}
+
+var (
+	hub     *Hub
+	hubOnce sync.Once
+)
+
+// GetHub returns the singleton hub instance
+func GetHub() *Hub {
+	hubOnce.Do(func() {
+		hub = &Hub{
+			clients:    make(map[*Client]bool),
+			broadcast:  make(chan WebSocketMessage, 256),
+			register:   make(chan *Client),
+			unregister: make(chan *Client),
+		}
+		go hub.run()
+	})
+	return hub
+}
+
+// run handles the main hub loop
+func (h *Hub) run() {
+	for {
+		select {
+		case client := <-h.register:
+			h.mutex.Lock()
+			h.clients[client] = true
+			h.mutex.Unlock()
+			logger.Debug("Client connected, total clients:", len(h.clients))
+
+		case client := <-h.unregister:
+			h.mutex.Lock()
+			if _, ok := h.clients[client]; ok {
+				delete(h.clients, client)
+				close(client.send)
+			}
+			h.mutex.Unlock()
+			logger.Debug("Client disconnected, total clients:", len(h.clients))
+
+		case message := <-h.broadcast:
+			h.mutex.RLock()
+			for client := range h.clients {
+				select {
+				case client.send <- message:
+				default:
+					close(client.send)
+					delete(h.clients, client)
+				}
+			}
+			h.mutex.RUnlock()
+		}
+	}
+}
+
+// BroadcastMessage sends a message to all connected clients
+func (h *Hub) BroadcastMessage(event string, data interface{}) {
+	message := WebSocketMessage{
+		Event: event,
+		Data:  data,
+	}
+	select {
+	case h.broadcast <- message:
+	default:
+		logger.Warn("Broadcast channel full, message dropped")
+	}
+}
+
+// WebSocket upgrader configuration
+var upgrader = websocket.Upgrader{
+	CheckOrigin: func(r *http.Request) bool {
+		return true
+	},
+	ReadBufferSize:  1024,
+	WriteBufferSize: 1024,
+}
+
+// EventBus handles the main WebSocket connection for the event bus
+func EventBus(c *gin.Context) {
+	ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
+	if err != nil {
+		logger.Error("Failed to upgrade connection:", err)
+		return
+	}
+	defer ws.Close()
+
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	client := &Client{
+		conn:   ws,
+		send:   make(chan WebSocketMessage, 256),
+		ctx:    ctx,
+		cancel: cancel,
+	}
+
+	hub := GetHub()
+	hub.register <- client
+
+	// Start goroutines for handling subscriptions
+	go client.handleNotifications()
+	go client.handleProcessingStatus()
+	go client.handleNginxLogStatus()
+
+	// Start write and read pumps
+	go client.writePump()
+	client.readPump()
+}
+
+// handleNotifications subscribes to notification events
+func (c *Client) handleNotifications() {
+	evtChan := make(chan *model.Notification, 10)
+	wsManager := notification.GetWebSocketManager()
+	wsManager.Subscribe(evtChan)
+
+	defer func() {
+		wsManager.Unsubscribe(evtChan)
+	}()
+
+	for {
+		select {
+		case n := <-evtChan:
+			hub.BroadcastMessage("notification", n)
+		case <-c.ctx.Done():
+			return
+		}
+	}
+}
+
+// handleProcessingStatus subscribes to processing status events
+func (c *Client) handleProcessingStatus() {
+	indexScanning := cache.SubscribeScanningStatus()
+	defer cache.UnsubscribeScanningStatus(indexScanning)
+
+	autoCert := cert.SubscribeProcessingStatus()
+	defer cert.UnsubscribeProcessingStatus(autoCert)
+
+	status := struct {
+		IndexScanning      bool `json:"index_scanning"`
+		AutoCertProcessing bool `json:"auto_cert_processing"`
+	}{
+		IndexScanning:      false,
+		AutoCertProcessing: false,
+	}
+
+	for {
+		select {
+		case indexStatus, ok := <-indexScanning:
+			if !ok {
+				return
+			}
+			status.IndexScanning = indexStatus
+			// Send processing status event
+			hub.BroadcastMessage("processing_status", status)
+			// Also send nginx log status event for backward compatibility
+			hub.BroadcastMessage("nginx_log_status", gin.H{
+				"scanning": indexStatus,
+			})
+
+		case certStatus, ok := <-autoCert:
+			if !ok {
+				return
+			}
+			status.AutoCertProcessing = certStatus
+			hub.BroadcastMessage("processing_status", status)
+
+		case <-c.ctx.Done():
+			return
+		}
+	}
+}
+
+// handleNginxLogStatus subscribes to nginx log scanning status events
+// Note: This uses the same cache.SubscribeScanningStatus as handleProcessingStatus
+// but sends different event types for different purposes
+func (c *Client) handleNginxLogStatus() {
+	// We don't need a separate subscription here since handleProcessingStatus
+	// already handles the index scanning status. This function is kept for
+	// potential future nginx-specific log status that might be different
+	// from the general index scanning status.
+
+	// For now, this is handled by handleProcessingStatus
+	<-c.ctx.Done()
+}
+
+// writePump pumps messages from the hub to the websocket connection
+func (c *Client) writePump() {
+	ticker := time.NewTicker(30 * time.Second)
+	defer func() {
+		ticker.Stop()
+		c.conn.Close()
+	}()
+
+	for {
+		select {
+		case message, ok := <-c.send:
+			c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
+			if !ok {
+				c.conn.WriteMessage(websocket.CloseMessage, []byte{})
+				return
+			}
+
+			if err := c.conn.WriteJSON(message); err != nil {
+				logger.Error("Failed to write message:", err)
+				if helper.IsUnexpectedWebsocketError(err) {
+					return
+				}
+			}
+
+		case <-ticker.C:
+			c.conn.SetWriteDeadline(time.Now().Add(10 * time.Second))
+			if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil {
+				logger.Error("Failed to write ping:", err)
+				return
+			}
+
+		case <-c.ctx.Done():
+			return
+
+		case <-kernel.Context.Done():
+			return
+		}
+	}
+}
+
+// readPump pumps messages from the websocket connection to the hub
+func (c *Client) readPump() {
+	defer func() {
+		hub := GetHub()
+		hub.unregister <- c
+		c.conn.Close()
+		c.cancel()
+	}()
+
+	c.conn.SetReadLimit(512)
+	c.conn.SetReadDeadline(time.Now().Add(60 * time.Second))
+	c.conn.SetPongHandler(func(string) error {
+		c.conn.SetReadDeadline(time.Now().Add(60 * time.Second))
+		return nil
+	})
+
+	for {
+		var msg json.RawMessage
+		err := c.conn.ReadJSON(&msg)
+		if err != nil {
+			if helper.IsUnexpectedWebsocketError(err) {
+				logger.Error("Unexpected WebSocket error:", err)
+			}
+			break
+		}
+		// Handle incoming messages if needed
+		// For now, this is a one-way communication (server to client)
+	}
+}

+ 0 - 50
api/nginx_log/sse.go

@@ -1,50 +0,0 @@
-package nginx_log
-
-import (
-	"io"
-	"time"
-
-	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/cache"
-	"github.com/gin-gonic/gin"
-)
-
-// GetNginxLogsLive is an SSE endpoint that sends real-time log scanning status updates
-func GetNginxLogsLive(c *gin.Context) {
-	api.SetSSEHeaders(c)
-	notify := c.Writer.CloseNotify()
-
-	// Subscribe to scanner status changes
-	statusChan := cache.SubscribeScanningStatus()
-
-	// Ensure we unsubscribe when the handler exits
-	defer cache.UnsubscribeScanningStatus(statusChan)
-
-	// Main event loop
-	for {
-		select {
-		case status, ok := <-statusChan:
-			// If channel closed, exit
-			if !ok {
-				return
-			}
-
-			// Send status update
-			c.Stream(func(w io.Writer) bool {
-				c.SSEvent("message", gin.H{
-					"scanning": status,
-				})
-				return false
-			})
-		case <-time.After(30 * time.Second):
-			// Send heartbeat to keep connection alive
-			c.Stream(func(w io.Writer) bool {
-				c.SSEvent("heartbeat", "")
-				return false
-			})
-		case <-notify:
-			// Client disconnected
-			return
-		}
-	}
-}

+ 0 - 47
api/notification/live.go

@@ -1,47 +0,0 @@
-package notification
-
-import (
-	"io"
-	"time"
-
-	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/kernel"
-	"github.com/0xJacky/Nginx-UI/internal/notification"
-	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/gin-gonic/gin"
-)
-
-func Live(c *gin.Context) {
-	api.SetSSEHeaders(c)
-
-	evtChan := make(chan *model.Notification)
-
-	notification.SetClient(c, evtChan)
-
-	notify := c.Writer.CloseNotify()
-
-	c.Stream(func(w io.Writer) bool {
-		c.SSEvent("heartbeat", "")
-		return false
-	})
-
-	for {
-		select {
-		case n := <-evtChan:
-			c.Stream(func(w io.Writer) bool {
-				c.SSEvent("message", n)
-				return false
-			})
-		case <-time.After(30 * time.Second):
-			c.Stream(func(w io.Writer) bool {
-				c.SSEvent("heartbeat", "")
-				return false
-			})
-		case <-notify:
-			notification.RemoveClient(c)
-			return
-		case <-kernel.Context.Done():
-			return
-		}
-	}
-}

+ 0 - 2
api/notification/router.go

@@ -7,6 +7,4 @@ func InitRouter(r *gin.RouterGroup) {
 	r.GET("notifications/:id", Get)
 	r.DELETE("notifications/:id", Destroy)
 	r.DELETE("notifications", DestroyAll)
-
-	r.GET("notifications/live", Live)
 }

+ 0 - 69
api/system/processing.go

@@ -1,69 +0,0 @@
-package system
-
-import (
-	"time"
-
-	"io"
-
-	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/cache"
-	"github.com/0xJacky/Nginx-UI/internal/cert"
-	"github.com/0xJacky/Nginx-UI/internal/kernel"
-	"github.com/gin-gonic/gin"
-)
-
-type ProcessingStatus struct {
-	IndexScanning      bool `json:"index_scanning"`
-	AutoCertProcessing bool `json:"auto_cert_processing"`
-}
-
-// GetProcessingStatus is an SSE endpoint that sends real-time processing status updates
-func GetProcessingStatus(c *gin.Context) {
-	api.SetSSEHeaders(c)
-	notify := c.Writer.CloseNotify()
-
-	indexScanning := cache.SubscribeScanningStatus()
-	defer cache.UnsubscribeScanningStatus(indexScanning)
-	autoCert := cert.SubscribeProcessingStatus()
-	defer cert.UnsubscribeProcessingStatus(autoCert)
-
-	// Track current status
-	status := ProcessingStatus{
-		IndexScanning:      false,
-		AutoCertProcessing: false,
-	}
-
-	sendStatus := func() {
-		c.Stream(func(w io.Writer) bool {
-			c.SSEvent("message", status)
-			return false
-		})
-	}
-
-	for {
-		select {
-		case indexStatus, ok := <-indexScanning:
-			if !ok {
-				return
-			}
-			status.IndexScanning = indexStatus
-			sendStatus()
-		case certStatus, ok := <-autoCert:
-			if !ok {
-				return
-			}
-			status.AutoCertProcessing = certStatus
-			sendStatus()
-		case <-time.After(30 * time.Second):
-			c.Stream(func(w io.Writer) bool {
-				c.SSEvent("heartbeat", "")
-				return false
-			})
-		case <-kernel.Context.Done():
-			return
-		case <-notify:
-			// Client disconnected
-			return
-		}
-	}
-}

+ 0 - 2
api/system/router.go

@@ -23,7 +23,6 @@ func InitPrivateRouter(r *gin.RouterGroup) {
 	r.GET("upgrade/release", GetRelease)
 	r.GET("upgrade/current", GetCurrentVersion)
 
-	r.GET("system/processing", GetProcessingStatus)
 	r.POST("system/port_scan", PortScan)
 }
 
@@ -31,7 +30,6 @@ func InitSelfCheckRouter(r *gin.RouterGroup) {
 	g := r.Group("self_check", authIfInstalled)
 	g.GET("", middleware.Proxy(), SelfCheck)
 	g.POST("/:name/fix", middleware.Proxy(), SelfCheckFix)
-	g.GET("sse", middleware.Proxy(), CheckSSE)
 	g.GET("websocket", middleware.ProxyWs(), CheckWebSocket)
 	g.GET("timeout", middleware.Proxy(), TimeoutCheck)
 }

+ 0 - 19
api/system/self_check.go

@@ -1,7 +1,6 @@
 package system
 
 import (
-	"io"
 	"net/http"
 
 	"github.com/gorilla/websocket"
@@ -9,7 +8,6 @@ import (
 
 	"time"
 
-	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/self_check"
 	"github.com/gin-gonic/gin"
 )
@@ -45,23 +43,6 @@ func CheckWebSocket(c *gin.Context) {
 	}
 }
 
-func CheckSSE(c *gin.Context) {
-	api.SetSSEHeaders(c)
-	notify := c.Writer.CloseNotify()
-	for i := 0; i < 10; i++ {
-		select {
-		case <-notify:
-			return
-		default:
-			c.Stream(func(w io.Writer) bool {
-				c.SSEvent("message", time.Now())
-				return false
-			})
-			time.Sleep(time.Second * 2)
-		}
-	}
-}
-
 func TimeoutCheck(c *gin.Context) {
 	time.Sleep(time.Minute)
 	c.JSON(http.StatusOK, gin.H{

+ 0 - 3
app/components.d.ts

@@ -21,7 +21,6 @@ declare module 'vue' {
     ACol: typeof import('ant-design-vue/es')['Col']
     ACollapse: typeof import('ant-design-vue/es')['Collapse']
     ACollapsePanel: typeof import('ant-design-vue/es')['CollapsePanel']
-    AComment: typeof import('ant-design-vue/es')['Comment']
     AConfigProvider: typeof import('ant-design-vue/es')['ConfigProvider']
     ADivider: typeof import('ant-design-vue/es')['Divider']
     ADrawer: typeof import('ant-design-vue/es')['Drawer']
@@ -47,7 +46,6 @@ declare module 'vue' {
     APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
     APopover: typeof import('ant-design-vue/es')['Popover']
     AProgress: typeof import('ant-design-vue/es')['Progress']
-    AQrcode: typeof import('ant-design-vue/es')['QRCode']
     AResult: typeof import('ant-design-vue/es')['Result']
     ARow: typeof import('ant-design-vue/es')['Row']
     ASelect: typeof import('ant-design-vue/es')['Select']
@@ -65,7 +63,6 @@ declare module 'vue' {
     ATag: typeof import('ant-design-vue/es')['Tag']
     ATextarea: typeof import('ant-design-vue/es')['Textarea']
     ATooltip: typeof import('ant-design-vue/es')['Tooltip']
-    AUploadDragger: typeof import('ant-design-vue/es')['UploadDragger']
     AutoCertFormAutoCertForm: typeof import('./src/components/AutoCertForm/AutoCertForm.vue')['default']
     AutoCertFormDNSChallenge: typeof import('./src/components/AutoCertForm/DNSChallenge.vue')['default']
     BaseEditorBaseEditor: typeof import('./src/components/BaseEditor/BaseEditor.vue')['default']

+ 14 - 17
app/src/components/Notification/Notification.vue

@@ -7,7 +7,7 @@ import dayjs from 'dayjs'
 import relativeTime from 'dayjs/plugin/relativeTime'
 import notificationApi from '@/api/notification'
 import { detailRender } from '@/components/Notification/detailRender'
-import { useSSE } from '@/composables/useSSE'
+import { useWebSocketEventBus } from '@/composables/useWebSocketEventBus'
 import { NotificationTypeT } from '@/constants'
 import { useUserStore } from '@/pinia'
 import notifications from './notifications'
@@ -24,24 +24,21 @@ const { unreadCount } = storeToRefs(useUserStore())
 
 const data = ref([]) as Ref<Notification[]>
 
-const { connect } = useSSE()
+const { subscribe } = useWebSocketEventBus()
 
 onMounted(() => {
-  connect({
-    url: '/api/notifications/live',
-    onMessage: (data: Notification) => {
-      const typeTrans = {
-        0: 'error',
-        1: 'warning',
-        2: 'info',
-        3: 'success',
-      }
-
-      notification[typeTrans[data.type]]({
-        message: $gettext(data.title),
-        description: detailRender({ text: data.details, record: data }),
-      })
-    },
+  subscribe('notification', (data: Notification) => {
+    const typeTrans = {
+      0: 'error',
+      1: 'warning',
+      2: 'info',
+      3: 'success',
+    }
+
+    notification[typeTrans[data.type]]({
+      message: $gettext(data.title),
+      description: detailRender({ text: data.details, record: data }),
+    })
   })
 })
 

+ 4 - 7
app/src/components/ProcessingStatus/ProcessingStatus.vue

@@ -1,19 +1,16 @@
 <script setup lang="tsx">
 import { SyncOutlined } from '@ant-design/icons-vue'
-import { useSSE } from '@/composables/useSSE'
+import { useWebSocketEventBus } from '@/composables/useWebSocketEventBus'
 import { useGlobalStore } from '@/pinia'
 
-const { connect } = useSSE()
+const { subscribe } = useWebSocketEventBus()
 
 const globalStore = useGlobalStore()
 const { processingStatus } = storeToRefs(globalStore)
 
 onMounted(() => {
-  connect({
-    url: '/api/system/processing',
-    onMessage: data => {
-      processingStatus.value = data
-    },
+  subscribe('processing_status', data => {
+    processingStatus.value = data
   })
 })
 

+ 0 - 2
app/src/components/SelfCheck/tasks/frontend/index.ts

@@ -1,12 +1,10 @@
 import type { FrontendTask } from '../types'
 import HttpsCheckTask from './https-check'
-import SSETask from './sse'
 import WebsocketTask from './websocket'
 
 // Collection of all frontend tasks
 const frontendTasks: Record<string, FrontendTask> = {
   'Frontend-Websocket': WebsocketTask,
-  'Frontend-SSE': SSETask,
   'Frontend-HttpsCheck': HttpsCheckTask,
   // Add more frontend tasks here
 }

+ 181 - 0
app/src/composables/useWebSocketEventBus.ts

@@ -0,0 +1,181 @@
+import { v4 as uuidv4 } from 'uuid'
+import ws from '@/lib/websocket'
+
+export interface WebSocketMessage {
+  event: string
+  // eslint-disable-next-line ts/no-explicit-any
+  data: any
+}
+
+// eslint-disable-next-line ts/no-explicit-any
+export type EventHandler<T = any> = (data: T) => void
+
+export interface EventSubscription {
+  id: string
+  event: string
+  handler: EventHandler
+}
+
+class WebSocketEventBus {
+  private static instance: WebSocketEventBus
+  private ws: WebSocket | null = null
+  private subscriptions: Map<string, EventSubscription> = new Map()
+  private isConnected = false
+
+  private constructor() {}
+
+  static getInstance(): WebSocketEventBus {
+    if (!WebSocketEventBus.instance) {
+      WebSocketEventBus.instance = new WebSocketEventBus()
+    }
+    return WebSocketEventBus.instance
+  }
+
+  // Connect to WebSocket
+  connect(): void {
+    if (this.ws && this.isConnected) {
+      return
+    }
+
+    // Close existing connection
+    if (this.ws) {
+      this.ws.close()
+    }
+
+    // Use the lib/websocket to create connection with auto-reconnect
+    this.ws = ws('/api/events', true) as WebSocket
+
+    this.ws.onopen = () => {
+      this.isConnected = true
+    }
+
+    this.ws.onmessage = (event: MessageEvent) => {
+      try {
+        const message: WebSocketMessage = JSON.parse(event.data)
+        this.handleMessage(message)
+      }
+      catch (error) {
+        console.error('Error parsing WebSocket message:', error)
+      }
+    }
+
+    this.ws.onclose = () => {
+      this.isConnected = false
+    }
+
+    this.ws.onerror = error => {
+      console.error('WebSocket error:', error)
+      this.isConnected = false
+    }
+  }
+
+  // Handle incoming WebSocket message
+  private handleMessage(message: WebSocketMessage): void {
+    // Find all subscriptions for this event
+    this.subscriptions.forEach(subscription => {
+      if (subscription.event === message.event) {
+        try {
+          subscription.handler(message.data)
+        }
+        catch (error) {
+          console.error(`Error handling event ${message.event}:`, error)
+        }
+      }
+    })
+  }
+
+  // Subscribe to an event
+  // eslint-disable-next-line ts/no-explicit-any
+  subscribe<T = any>(event: string, handler: EventHandler<T>): string {
+    const id = uuidv4()
+
+    this.subscriptions.set(id, {
+      id,
+      event,
+      handler,
+    })
+
+    // Ensure WebSocket is connected
+    if (!this.isConnected) {
+      this.connect()
+    }
+
+    return id
+  }
+
+  // Unsubscribe from an event
+  unsubscribe(subscriptionId: string): void {
+    this.subscriptions.delete(subscriptionId)
+  }
+
+  // Disconnect WebSocket
+  disconnect(): void {
+    this.isConnected = false
+    this.subscriptions.clear()
+
+    if (this.ws) {
+      this.ws.close()
+      this.ws = null
+    }
+  }
+
+  // Get connection status
+  getConnectionStatus(): boolean {
+    return this.isConnected
+  }
+}
+
+// WebSocket Event Bus Composable
+export function useWebSocketEventBus() {
+  const eventBus = WebSocketEventBus.getInstance()
+  const subscriptionIds = ref<string[]>([])
+
+  // Subscribe to an event
+  // eslint-disable-next-line ts/no-explicit-any
+  function subscribe<T = any>(event: string, handler: EventHandler<T>): string {
+    const id = eventBus.subscribe(event, handler)
+    subscriptionIds.value.push(id)
+    return id
+  }
+
+  // Unsubscribe from an event
+  function unsubscribe(subscriptionId: string): void {
+    eventBus.unsubscribe(subscriptionId)
+    const index = subscriptionIds.value.indexOf(subscriptionId)
+    if (index > -1) {
+      subscriptionIds.value.splice(index, 1)
+    }
+  }
+
+  // Connect to WebSocket
+  function connect(): void {
+    eventBus.connect()
+  }
+
+  // Disconnect from WebSocket
+  function disconnect(): void {
+    eventBus.disconnect()
+  }
+
+  // Get connection status
+  const isConnected = computed(() => eventBus.getConnectionStatus())
+
+  // Auto cleanup on unmount
+  if (getCurrentInstance()) {
+    onUnmounted(() => {
+      // Unsubscribe all subscriptions for this component
+      subscriptionIds.value.forEach(id => {
+        eventBus.unsubscribe(id)
+      })
+      subscriptionIds.value = []
+    })
+  }
+
+  return {
+    subscribe,
+    unsubscribe,
+    connect,
+    disconnect,
+    isConnected: readonly(isConnected),
+  }
+}

+ 167 - 179
app/src/language/ar/app.po

@@ -4,10 +4,10 @@ msgid ""
 msgstr ""
 "PO-Revision-Date: 2024-10-29 14:39+0000\n"
 "Last-Translator: mosaati <mohammed.saati@gmail.com>\n"
-"Language-Team: Arabic <https://weblate.nginxui.com/projects/nginx-ui/"
-"frontend/ar/>\n"
+"Language-Team: Arabic "
+"<https://weblate.nginxui.com/projects/nginx-ui/frontend/ar/>\n"
 "Language: ar\n"
-"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 "
 "&& n%100<=10 ? 3 : n%100>=11 ? 4 : 5;\n"
@@ -32,8 +32,7 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] تم إلغاء الشهادة بنجاح"
 
 #: src/language/generate.ts:37
-msgid ""
-"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr "[Nginx UI] تم استخدام الشهادة للخادم، إعادة تحميل شهادة TLS للخادم"
 
 #: src/language/generate.ts:38
@@ -112,7 +111,7 @@ msgstr "إعدادات المصادقة الثنائية"
 msgid "About"
 msgstr "عن"
 
-#: src/views/nginx_log/NginxLogList.vue:23
+#: src/views/nginx_log/NginxLogList.vue:38
 msgid "Access Log"
 msgstr "سجل الوصول"
 
@@ -141,7 +140,7 @@ msgstr "إجراء"
 #: src/views/config/configColumns.tsx:41
 #: src/views/environments/group/columns.ts:41
 #: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/nginx_log/NginxLogList.vue:67
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:76
 #: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:105
@@ -284,7 +283,7 @@ msgstr "هل أنت متأكد من إنشاء رموز استرداد جديد
 msgid "Are you sure to reset 2FA?"
 msgstr "هل أنت متأكد من إعادة تعيين المصادقة الثنائية؟"
 
-#: src/components/Notification/Notification.vue:113
+#: src/components/Notification/Notification.vue:110
 #: src/views/notification/Notification.vue:40
 msgid "Are you sure you want to clear all notifications?"
 msgstr "هل أنت متأكد أنك تريد مسح كافة التنبيهات؟"
@@ -415,7 +414,7 @@ msgstr "تم تمكين التجديد التلقائي لـ‏%{name}"
 msgid "AutoCert is running, please wait..."
 msgstr "AutoCert قيد التشغيل، يرجى الانتظار..."
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:41
+#: src/components/ProcessingStatus/ProcessingStatus.vue:38
 msgid "AutoCert is running..."
 msgstr "AutoCert قيد التشغيل..."
 
@@ -482,14 +481,13 @@ msgstr "جدول النسخ الاحتياطي"
 
 #: src/components/Notification/notifications.ts:38
 msgid "Backup task %{backup_name} completed successfully, file: %{file_path}"
-msgstr ""
-"تم إنجاز مهمة النسخ الاحتياطي %{backup_name} بنجاح، الملف: %{file_path}"
+msgstr "تم إنجاز مهمة النسخ الاحتياطي %{backup_name} بنجاح، الملف: %{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid ""
-"Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
-"فشلت مهمة النسخ الاحتياطي %{backup_name} أثناء تحميل التخزين، الخطأ: %{error}"
+"فشلت مهمة النسخ الاحتياطي %{backup_name} أثناء تحميل التخزين، الخطأ: "
+"%{error}"
 
 #: src/components/Notification/notifications.ts:30
 msgid "Backup task %{backup_name} failed to execute, error: %{error}"
@@ -568,8 +566,7 @@ msgstr "ذاكرة التخزين المؤقت"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:178
 msgid "Cache items not accessed within this time will be removed"
-msgstr ""
-"سيتم إزالة عناصر الذاكرة المؤقتة التي لم يتم الوصول إليها خلال هذا الوقت"
+msgstr "سيتم إزالة عناصر الذاكرة المؤقتة التي لم يتم الوصول إليها خلال هذا الوقت"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:350
 msgid "Cache loader processing time threshold"
@@ -802,23 +799,23 @@ msgstr "تحقق مرة أخرى"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v /"
-"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
-"run/docker.sock to communicate with the host Docker Engine via Docker Client "
-"API. This feature is used to control Nginx in another container and perform "
-"container replacement rather than binary replacement during OTA upgrades of "
-"Nginx UI to ensure container dependencies are also upgraded. If you don't "
-"need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v "
+"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
+"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
+"Client API. This feature is used to control Nginx in another container and "
+"perform container replacement rather than binary replacement during OTA "
+"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
+"you don't need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "تحقق مما إذا كان /var/run/docker.sock موجودًا. إذا كنت تستخدم صورة Docker "
-"الرسمية لـ Nginx UI، يرجى التأكد من توصيل مقبس Docker بهذه الطريقة: `-v /var/"
-"run/docker.sock:/var/run/docker.sock`. تستخدم صورة Nginx UI الرسمية /var/run/"
-"docker.sock للتواصل مع محرك Docker المضيف عبر واجهة برمجة تطبيقات Docker "
-"Client. تُستخدم هذه الميزة للتحكم في Nginx في حاوية أخرى وإجراء استبدال "
-"الحاوية بدلاً من استبدال الثنائي أثناء التحديثات OTA لـ Nginx UI لضمان تحديث "
-"تبعيات الحاوية أيضًا. إذا كنت لا تحتاج إلى هذه الميزة، يرجى إضافة متغير "
-"البيئة NGINX_UI_IGNORE_DOCKER_SOCKET=true إلى الحاوية."
+"الرسمية لـ Nginx UI، يرجى التأكد من توصيل مقبس Docker بهذه الطريقة: `-v "
+"/var/run/docker.sock:/var/run/docker.sock`. تستخدم صورة Nginx UI الرسمية "
+"/var/run/docker.sock للتواصل مع محرك Docker المضيف عبر واجهة برمجة تطبيقات "
+"Docker Client. تُستخدم هذه الميزة للتحكم في Nginx في حاوية أخرى وإجراء "
+"استبدال الحاوية بدلاً من استبدال الثنائي أثناء التحديثات OTA لـ Nginx UI "
+"لضمان تحديث تبعيات الحاوية أيضًا. إذا كنت لا تحتاج إلى هذه الميزة، يرجى "
+"إضافة متغير البيئة NGINX_UI_IGNORE_DOCKER_SOCKET=true إلى الحاوية."
 
 #: src/components/SelfCheck/tasks/frontend/https-check.ts:14
 msgid ""
@@ -830,19 +827,19 @@ msgstr ""
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is obtained "
-"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
-"point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the access log path."
-"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
-"nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is "
+"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
+"does not point to a valid, existing file, an error will be reported. In "
+"this case, you need to modify the configuration file to specify the access "
+"log path.Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 msgstr ""
-"تحقق مما إذا كان مسار سجل الوصول إلى nginx موجودًا. بشكل افتراضي، يتم الحصول "
-"على هذا المسار من 'nginx -V'. إذا لم يتم الحصول عليه أو إذا كان المسار الذي "
-"تم الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن خطأ. في هذه "
-"الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الوصول. راجع الوثائق "
-"لمزيد من التفاصيل: https://nginxui.com/zh_CN/guide/config-nginx."
-"html#accesslogpath"
+"تحقق مما إذا كان مسار سجل الوصول إلى nginx موجودًا. بشكل افتراضي، يتم "
+"الحصول على هذا المسار من 'nginx -V'. إذا لم يتم الحصول عليه أو إذا كان "
+"المسار الذي تم الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن "
+"خطأ. في هذه الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الوصول. "
+"راجع الوثائق لمزيد من التفاصيل: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -858,28 +855,29 @@ msgid ""
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
 "you need to modify the configuration file to specify the error log path. "
-"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
-"nginx.html#errorlogpath"
+"Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 msgstr ""
 "تحقق مما إذا كان مسار سجل أخطاء nginx موجودًا. بشكل افتراضي، يتم الحصول على "
 "هذا المسار من 'nginx -V'. إذا تعذر الحصول عليه أو إذا كان المسار الذي تم "
-"الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن خطأ. في هذه الحالة، "
-"تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الأخطاء. راجع الوثائق لمزيد من "
-"التفاصيل: https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"الحصول عليه لا يشير إلى ملف صالح موجود، فسيتم الإبلاغ عن خطأ. في هذه "
+"الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار سجل الأخطاء. راجع الوثائق "
+"لمزيد من التفاصيل: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
-"config-nginx.html#pidpath"
+"path.Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 msgstr ""
-"تحقق مما إذا كان مسار معرف عملية Nginx موجودًا. بشكل افتراضي، يتم الحصول على "
-"هذا المسار من الأمر 'nginx -V'. إذا تعذر الحصول عليه، سيتم الإبلاغ عن خطأ. "
-"في هذه الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار معرف عملية Nginx. "
-"راجع الوثائق لمزيد من التفاصيل: https://nginxui.com/zh_CN/guide/config-nginx."
-"html#pidpath"
+"تحقق مما إذا كان مسار معرف عملية Nginx موجودًا. بشكل افتراضي، يتم الحصول "
+"على هذا المسار من الأمر 'nginx -V'. إذا تعذر الحصول عليه، سيتم الإبلاغ عن "
+"خطأ. في هذه الحالة، تحتاج إلى تعديل ملف التكوين لتحديد مسار معرف عملية "
+"Nginx. راجع الوثائق لمزيد من التفاصيل: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx sbin path exists"
@@ -907,8 +905,8 @@ msgstr ""
 
 #: src/language/generate.ts:17
 msgid ""
-"Check if the streams-available and streams-enabled directories are under the "
-"nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under "
+"the nginx configuration directory"
 msgstr ""
 "تحقق مما إذا كانت الدلائل streams-available و streams-enabled موجودة ضمن "
 "دليل تكوين nginx"
@@ -922,12 +920,12 @@ msgid "Cleaning environment variables"
 msgstr "تنظيف متغيرات البيئة"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:23
-#: src/components/Notification/Notification.vue:118
+#: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
 msgstr "مسح"
 
-#: src/components/Notification/Notification.vue:71
+#: src/components/Notification/Notification.vue:68
 #: src/views/notification/Notification.vue:13
 msgid "Cleared successfully"
 msgstr "تم المسح بنجاح"
@@ -1121,7 +1119,7 @@ msgstr "نسخ الرموز"
 msgid "Core Upgrade"
 msgstr "ترقية نواة"
 
-#: src/views/dashboard/ServerAnalytic.vue:305
+#: src/views/dashboard/ServerAnalytic.vue:308
 msgid "CPU Status"
 msgstr "حالة CPU"
 
@@ -1507,7 +1505,7 @@ msgstr "معطل"
 msgid "Disabled successfully"
 msgstr "تم التعطيل بنجاح"
 
-#: src/views/dashboard/ServerAnalytic.vue:370
+#: src/views/dashboard/ServerAnalytic.vue:373
 msgid "Disk IO"
 msgstr "إدخال/إخراج القرص"
 
@@ -1598,8 +1596,8 @@ msgid ""
 "Due to the security policies of some browsers, you cannot use passkeys on "
 "non-HTTPS websites, except when running on localhost."
 msgstr ""
-"نظرًا لسياسات الأمان لبعض المتصفحات، لا يمكنك استخدام مفاتيح المرور على مواقع "
-"الويب غير HTTPS، إلا عند التشغيل على localhost."
+"نظرًا لسياسات الأمان لبعض المتصفحات، لا يمكنك استخدام مفاتيح المرور على "
+"مواقع الويب غير HTTPS، إلا عند التشغيل على localhost."
 
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:108
@@ -1805,7 +1803,7 @@ msgstr "خطأ"
 msgid "Error initializing diff viewer"
 msgstr "خطأ في تهيئة عارض الاختلافات"
 
-#: src/views/nginx_log/NginxLogList.vue:27
+#: src/views/nginx_log/NginxLogList.vue:42
 msgid "Error Log"
 msgstr "سجل الأخطاء"
 
@@ -2453,7 +2451,7 @@ msgstr ""
 "يشمل العملية الرئيسية وعمليات العامل وعمليات التخزين المؤقت وعمليات Nginx "
 "الأخرى"
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:34
+#: src/components/ProcessingStatus/ProcessingStatus.vue:31
 msgid "Indexing..."
 msgstr "جاري الفهرسة..."
 
@@ -2765,14 +2763,14 @@ msgstr "سجل"
 #: src/language/generate.ts:21
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
-"nginx-log.html for more information."
+"docker container, please refer to "
+"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
 msgstr ""
 "ملف السجل %{log_path} ليس ملفًا عاديًا. إذا كنت تستخدم nginx-ui في حاوية "
-"Docker، يرجى الرجوع إلى https://nginxui.com/zh_CN/guide/config-nginx-log."
-"html لمزيد من المعلومات."
+"Docker، يرجى الرجوع إلى "
+"https://nginxui.com/zh_CN/guide/config-nginx-log.html لمزيد من المعلومات."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:87
 msgid "Log List"
 msgstr "قائمة السجلات"
 
@@ -2794,19 +2792,19 @@ msgstr "تدوير السجلات"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions for "
-"users who install Nginx UI on the host machine, so you don't need to modify "
-"the parameters on this page. For users who install Nginx UI using Docker "
-"containers, you can manually enable this option. The crontab task scheduler "
-"of Nginx UI will execute the logrotate command at the interval you set in "
-"minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions "
+"for users who install Nginx UI on the host machine, so you don't need to "
+"modify the parameters on this page. For users who install Nginx UI using "
+"Docker containers, you can manually enable this option. The crontab task "
+"scheduler of Nginx UI will execute the logrotate command at the interval "
+"you set in minutes."
 msgstr ""
 "بشكل افتراضي، يتم تفعيل تدوير السجلات في معظم توزيعات لينكس الرئيسية "
 "للمستخدمين الذين يقومون بتثبيت واجهة Nginx UI على الجهاز المضيف، لذا لا "
-"تحتاج إلى تعديل معايير في هذه الصفحة. بالنسبة للمستخدمين الذين يقومون بتثبيت "
-"واجهة Nginx UI باستخدام حاويات Docker، يمكنك تمكين هذا الخيار يدويًا. سيقوم "
-"مجدول المهام crontab الخاص بواجهة Nginx UI بتنفيذ أمر تدوير السجلات في "
-"الفاصل الزمني الذي تحدده بالدقائق."
+"تحتاج إلى تعديل معايير في هذه الصفحة. بالنسبة للمستخدمين الذين يقومون "
+"بتثبيت واجهة Nginx UI باستخدام حاويات Docker، يمكنك تمكين هذا الخيار "
+"يدويًا. سيقوم مجدول المهام crontab الخاص بواجهة Nginx UI بتنفيذ أمر تدوير "
+"السجلات في الفاصل الزمني الذي تحدده بالدقائق."
 
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
@@ -2928,8 +2926,8 @@ msgstr "الحجم الإجمالي الأقصى للذاكرة المؤقتة"
 msgid "Maximum worker process number:"
 msgstr "الحد الأقصى لعدد عمليات العامل:"
 
-#: src/views/dashboard/ServerAnalytic.vue:226
 #: src/views/dashboard/ServerAnalytic.vue:227
+#: src/views/dashboard/ServerAnalytic.vue:228
 msgid "Memory"
 msgstr "ذاكرة"
 
@@ -3019,7 +3017,7 @@ msgstr "توجيه متعدد الأسطر"
 #: src/views/config/configColumns.tsx:5
 #: src/views/environments/group/columns.ts:7
 #: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:36
+#: src/views/nginx_log/NginxLogList.vue:51
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:75
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:35
 #: src/views/site/site_list/columns.tsx:16
@@ -3035,19 +3033,19 @@ msgstr "اسم"
 msgid "Need to enable the stub_status module"
 msgstr "يجب تمكين وحدة stub_status"
 
-#: src/views/dashboard/ServerAnalytic.vue:331
+#: src/views/dashboard/ServerAnalytic.vue:334
 msgid "Network"
 msgstr "شبكة"
 
-#: src/views/dashboard/ServerAnalytic.vue:273
+#: src/views/dashboard/ServerAnalytic.vue:276
 msgid "Network Statistics"
 msgstr "إحصائيات الشبكة"
 
-#: src/views/dashboard/ServerAnalytic.vue:280
+#: src/views/dashboard/ServerAnalytic.vue:283
 msgid "Network Total Receive"
 msgstr "إجمالي استقبال الشبكة"
 
-#: src/views/dashboard/ServerAnalytic.vue:286
+#: src/views/dashboard/ServerAnalytic.vue:289
 msgid "Network Total Send"
 msgstr "إجمالي إرسال الشبكة"
 
@@ -3278,8 +3276,8 @@ msgstr "تمت استعادة تكوين Nginx UI"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in a "
-"few seconds."
+"Nginx UI configuration has been restored and will restart automatically in "
+"a few seconds."
 msgstr "تمت استعادة تكوين Nginx UI وسيتم إعادة التشغيل تلقائيًا خلال بضع ثوانٍ."
 
 #: src/language/generate.ts:28
@@ -3299,7 +3297,7 @@ msgstr "يتضمن Nginx.conf دليل streams-enabled"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:143
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:99
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
-#: src/components/Notification/Notification.vue:111 src/language/curd.ts:38
+#: src/components/Notification/Notification.vue:108 src/language/curd.ts:38
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
@@ -3391,7 +3389,7 @@ msgstr ""
 msgid "Notification"
 msgstr "إشعار"
 
-#: src/components/Notification/Notification.vue:109
+#: src/components/Notification/Notification.vue:106
 #: src/routes/modules/notifications.ts:10
 msgid "Notifications"
 msgstr "الإشعارات"
@@ -3406,13 +3404,11 @@ msgstr "عدد عمليات العامل المتزامنة، يتم الضبط
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:315
 msgid "Number of files processed by cache loader at once"
-msgstr ""
-"عدد الملفات التي تتم معالجتها بواسطة محمل ذاكرة التخزين المؤقت في وقت واحد"
+msgstr "عدد الملفات التي تتم معالجتها بواسطة محمل ذاكرة التخزين المؤقت في وقت واحد"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:253
 msgid "Number of files processed by cache manager at once"
-msgstr ""
-"عدد الملفات التي تتم معالجتها بواسطة مدير ذاكرة التخزين المؤقت في وقت واحد"
+msgstr "عدد الملفات التي تتم معالجتها بواسطة مدير ذاكرة التخزين المؤقت في وقت واحد"
 
 #: src/composables/usePerformanceMetrics.ts:129
 #: src/composables/usePerformanceMetrics.ts:169
@@ -3462,7 +3458,7 @@ msgstr "غير متصل"
 #: src/components/ChatGPT/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:36
-#: src/components/Notification/Notification.vue:112 src/language/curd.ts:15
+#: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
 #: src/views/backup/components/BackupCreator.vue:149
 #: src/views/notification/Notification.vue:39
 #: src/views/site/components/SiteStatusSelect.vue:123
@@ -3606,7 +3602,7 @@ msgstr "كلمات المرور غير متطابقة"
 #: src/language/curd.ts:59
 #: src/views/config/components/ConfigRightPanel/Basic.vue:41
 #: src/views/config/components/Delete.vue:124
-#: src/views/nginx_log/NginxLogList.vue:44
+#: src/views/nginx_log/NginxLogList.vue:59
 msgid "Path"
 msgstr "مسار"
 
@@ -3675,8 +3671,7 @@ msgstr ""
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
 "button below."
-msgstr ""
-"يرجى إدخال اسم لمفتاح المرور الذي ترغب في إنشائه ثم انقر على زر موافق أدناه."
+msgstr "يرجى إدخال اسم لمفتاح المرور الذي ترغب في إنشائه ثم انقر على زر موافق أدناه."
 
 #: src/components/PortScanner/PortScannerCompact.vue:85
 msgid "Please enter a valid port range"
@@ -3724,8 +3719,8 @@ msgstr ""
 #: src/components/Notification/notifications.ts:190
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to prevent "
-"lockout."
+"Please generate new recovery codes in the preferences immediately to "
+"prevent lockout."
 msgstr "يرجى إنشاء رموز استرداد جديدة في التفضيلات على الفور لمنع الإغلاق."
 
 #: src/views/config/components/ConfigRightPanel/Basic.vue:27
@@ -3767,8 +3762,7 @@ msgid "Please log in."
 msgstr "الرجاء تسجيل الدخول."
 
 #: src/views/certificate/DNSCredential.vue:75
-msgid ""
-"Please note that the unit of time configurations below are all in seconds."
+msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr "يرجى ملاحظة أن تكوين وحدات الوقت أدناه كلها بالثواني."
 
 #: src/views/install/components/InstallView.vue:102
@@ -3904,11 +3898,11 @@ msgid "Read requests"
 msgstr "طلبات القراءة"
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:387
+#: src/views/dashboard/ServerAnalytic.vue:390
 msgid "Reads"
 msgstr "يقرأ"
 
-#: src/views/dashboard/ServerAnalytic.vue:338
+#: src/views/dashboard/ServerAnalytic.vue:341
 #: src/views/dashboard/ServerAnalytic.vue:35
 msgid "Receive"
 msgstr "يستقبل"
@@ -4038,7 +4032,7 @@ msgstr "إزالة"
 msgid "Remove successfully"
 msgstr "إزالة بنجاح"
 
-#: src/components/Notification/Notification.vue:80
+#: src/components/Notification/Notification.vue:77
 msgid "Removed successfully"
 msgstr "تمت الإزالة بنجاح"
 
@@ -4482,6 +4476,10 @@ msgstr "نتائج المسح"
 msgid "Scan the QR code with your mobile phone to add the account to the app."
 msgstr "امسح رمز الاستجابة السريعة بهاتفك المحمول لإضافة الحساب إلى التطبيق."
 
+#: src/views/nginx_log/NginxLogList.vue:100
+msgid "Scanning logs..."
+msgstr "جارٍ فحص السجلات..."
+
 #: src/views/backup/AutoBackup/AutoBackup.vue:113
 msgid "Schedule"
 msgstr "الجدول الزمني"
@@ -4544,8 +4542,8 @@ msgstr "الفحص الذاتي"
 msgid "Self check failed, Nginx UI may not work properly"
 msgstr "فشل الفحص الذاتي، قد لا يعمل واجهة NGINX بشكل صحيح"
 
-#: src/views/dashboard/ServerAnalytic.vue:348
 #: src/views/dashboard/ServerAnalytic.vue:35
+#: src/views/dashboard/ServerAnalytic.vue:351
 msgid "Send"
 msgstr "إرسال"
 
@@ -4615,19 +4613,19 @@ msgstr "تعيين موفر تحدي HTTP01"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
+"https://nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
-"إعدادات.Settings.NginxLogSettings.AccessLogPath فارغة، راجع https://nginxui."
-"com/guide/config-nginx.html لمزيد من المعلومات"
+"إعدادات.Settings.NginxLogSettings.AccessLogPath فارغة، راجع "
+"https://nginxui.com/guide/config-nginx.html لمزيد من المعلومات"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
+"https://nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
-"إعدادات.Settings.NginxLogSettings.ErrorLogPath فارغة، راجع https://nginxui."
-"com/guide/config-nginx.html لمزيد من المعلومات"
+"إعدادات.Settings.NginxLogSettings.ErrorLogPath فارغة، راجع "
+"https://nginxui.com/guide/config-nginx.html لمزيد من المعلومات"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4785,8 +4783,8 @@ msgstr "الحالة"
 msgid "Stopped"
 msgstr "متوقف"
 
-#: src/views/dashboard/ServerAnalytic.vue:254
-#: src/views/dashboard/ServerAnalytic.vue:255
+#: src/views/dashboard/ServerAnalytic.vue:257
+#: src/views/dashboard/ServerAnalytic.vue:258
 msgid "Storage"
 msgstr "تخزين"
 
@@ -4864,19 +4862,19 @@ msgstr "الأحد"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: https://"
-"nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "دعم الاتصال مع الخلفية من خلال بروتوكول Server-Sent Events. إذا كنت تستخدم "
-"واجهة Nginx UI عبر وكيل عكسي لـ Nginx، يرجى الرجوع إلى هذا الرابط لكتابة ملف "
-"التكوين المقابل: https://nginxui.com/guide/nginx-proxy-example.html"
+"واجهة Nginx UI عبر وكيل عكسي لـ Nginx، يرجى الرجوع إلى هذا الرابط لكتابة "
+"ملف التكوين المقابل: https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
-"link to write the corresponding configuration file: https://nginxui.com/"
-"guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
+"this link to write the corresponding configuration file: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "دعم الاتصال مع الخلفية من خلال بروتوكول WebSocket. إذا كنت تستخدم واجهة "
 "Nginx عبر وكيل عكسي لـ Nginx، يرجى الرجوع إلى هذا الرابط لكتابة ملف التكوين "
@@ -4895,8 +4893,8 @@ msgstr "دعم تحميل المجلدات بأكملها"
 msgid "Supported file type: .zip"
 msgstr "نوع الملف المدعوم: .zip"
 
-#: src/views/dashboard/ServerAnalytic.vue:240
-#: src/views/dashboard/ServerAnalytic.vue:241
+#: src/views/dashboard/ServerAnalytic.vue:242
+#: src/views/dashboard/ServerAnalytic.vue:243
 msgid "Swap"
 msgstr "تبديل"
 
@@ -5046,10 +5044,11 @@ msgstr "المدخل ليس مفتاح شهادة SSL"
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in "
+"settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"مسار السجل ليس ضمن المسارات الموجودة في settings.NginxSettings."
-"LogDirWhiteList"
+"مسار السجل ليس ضمن المسارات الموجودة في "
+"settings.NginxSettings.LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -5061,8 +5060,7 @@ msgstr ""
 "فقط."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid ""
-"The model used for code completion, if not set, the chat model will be used."
+msgid "The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "النموذج المستخدم لإكمال التعليمات البرمجية، إذا لم يتم تعيينه، سيتم استخدام "
 "نموذج الدردشة."
@@ -5175,14 +5173,13 @@ msgid "This field should not be empty"
 msgstr "يجب ألا يكون هذا الحقل فارغًا"
 
 #: src/constants/form_errors.ts:6
-msgid ""
-"This field should only contain letters, unicode characters, numbers, and -_."
+msgid "This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "يجب أن يحتوي هذا الحقل على حروف وأحرف يونيكود وأرقام و-_. فقط."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and -"
-"_./:"
+"This field should only contain letters, unicode characters, numbers, and "
+"-_./:"
 msgstr "يجب أن يحتوي هذا الحقل على أحرف وأحرف يونيكود وأرقام و -_./: فقط"
 
 #: src/views/dashboard/NginxDashBoard.vue:155
@@ -5190,8 +5187,8 @@ msgid ""
 "This module provides Nginx request statistics, connection count, etc. data. "
 "After enabling it, you can view performance statistics"
 msgstr ""
-"توفر هذه الوحدة إحصائيات طلبات Nginx وعدد الاتصالات وما إلى ذلك من البيانات. "
-"بعد تمكينها، يمكنك عرض إحصائيات الأداء"
+"توفر هذه الوحدة إحصائيات طلبات Nginx وعدد الاتصالات وما إلى ذلك من "
+"البيانات. بعد تمكينها، يمكنك عرض إحصائيات الأداء"
 
 #: src/views/certificate/components/RemoveCert.vue:106
 msgid ""
@@ -5232,12 +5229,11 @@ msgid ""
 "This will restore configuration files and database. Nginx UI will restart "
 "after the restoration is complete."
 msgstr ""
-"سيؤدي هذا إلى استعادة ملفات التكوين وقاعدة البيانات. سيعاد تشغيل واجهة Nginx "
-"بعد اكتمال الاستعادة."
+"سيؤدي هذا إلى استعادة ملفات التكوين وقاعدة البيانات. سيعاد تشغيل واجهة "
+"Nginx بعد اكتمال الاستعادة."
 
 #: src/views/environments/list/BatchUpgrader.vue:183
-msgid ""
-"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "سيتم ترقية أو إعادة تثبيت Nginx UI على %{nodeNames} إلى %{version}."
 
 #: src/views/preference/tabs/AuthSettings.vue:92
@@ -5291,8 +5287,8 @@ msgstr ""
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and we "
-"need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and "
+"we need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
 "لضمان عمل تجديد الشهادة التلقائي بشكل طبيعي، نحتاج إلى إضافة موقع يمكنه "
@@ -5305,9 +5301,9 @@ msgid ""
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
-"لاستخدام نموذج كبير محلي، قم بنشره باستخدام ollama أو vllm أو lmdeploy. توفر "
-"هذه الأدوات نقطة نهاية API متوافقة مع OpenAI، لذا ما عليك سوى تعيين baseUrl "
-"إلى API المحلي الخاص بك."
+"لاستخدام نموذج كبير محلي، قم بنشره باستخدام ollama أو vllm أو lmdeploy. "
+"توفر هذه الأدوات نقطة نهاية API متوافقة مع OpenAI، لذا ما عليك سوى تعيين "
+"baseUrl إلى API المحلي الخاص بك."
 
 #: src/views/dashboard/NginxDashBoard.vue:55
 msgid "Toggle failed"
@@ -5376,7 +5372,7 @@ msgstr "يتطلب المصادقة الثنائية"
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
-#: src/views/nginx_log/NginxLogList.vue:12
+#: src/views/nginx_log/NginxLogList.vue:27
 #: src/views/notification/notificationColumns.tsx:8
 #: src/views/preference/components/ExternalNotify/columns.tsx:18
 msgid "Type"
@@ -5533,12 +5529,12 @@ msgstr "تحقق من متطلبات النظام"
 msgid "Version"
 msgstr "إصدار"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:84
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:105
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
 msgid "View"
 msgstr "عرض"
 
-#: src/components/Notification/Notification.vue:181
+#: src/components/Notification/Notification.vue:178
 msgid "View all notifications"
 msgstr "عرض جميع التنبيهات"
 
@@ -5574,8 +5570,8 @@ msgid ""
 "you have a valid backup file and security token, and carefully select what "
 "to restore."
 msgstr ""
-"تحذير: ستقوم عملية الاستعادة بالكتابة فوق التكوينات الحالية. تأكد من أن لديك "
-"ملف نسخ احتياطي صالحًا ورمزًا أمنيًا، واختر بعناية ما تريد استعادته."
+"تحذير: ستقوم عملية الاستعادة بالكتابة فوق التكوينات الحالية. تأكد من أن "
+"لديك ملف نسخ احتياطي صالحًا ورمزًا أمنيًا، واختر بعناية ما تريد استعادته."
 
 #: src/views/certificate/DNSCredential.vue:69
 msgid ""
@@ -5585,8 +5581,8 @@ msgstr "سنضيف سجل أو أكثر من سجلات TXT إلى سجلات DN
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload the "
-"Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload "
+"the Nginx. Are you sure you want to continue?"
 msgstr ""
 "سنقوم بإزالة تكوين HTTPChallenge من هذا الملف وإعادة تحميل Nginx. هل أنت "
 "متأكد أنك تريد المتابعة؟"
@@ -5677,7 +5673,7 @@ msgid "Write private.key error: {0}"
 msgstr "خطأ في كتابة private.key: {0}"
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:377
+#: src/views/dashboard/ServerAnalytic.vue:380
 msgid "Writes"
 msgstr "يكتب"
 
@@ -5700,11 +5696,11 @@ msgstr "نعم"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a non-"
-"localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a "
+"non-localhost domain. This may expose sensitive information."
 msgstr ""
-"أنت تتصل بهذا الطرف عبر اتصال HTTP غير آمن في نطاق غير محلي. قد يؤدي هذا إلى "
-"كشف معلومات حساسة."
+"أنت تتصل بهذا الطرف عبر اتصال HTTP غير آمن في نطاق غير محلي. قد يؤدي هذا "
+"إلى كشف معلومات حساسة."
 
 #: src/constants/errors/config.ts:8
 msgid "You are not allowed to delete a file outside of the nginx config path"
@@ -5733,8 +5729,7 @@ msgid ""
 msgstr "لم تقم بتكوين إعدادات Webauthn، لذا لا يمكنك إضافة مفتاح مرور."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid ""
-"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
 "لم تقم بتمكين المصادقة الثنائية بعد. يرجى تمكين المصادقة الثنائية لإنشاء "
 "رموز الاسترداد."
@@ -5841,12 +5836,12 @@ msgstr "مفاتيح المرور الخاصة بك"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
-#~ "v /var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
+#~ "/var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
 #~ "تحقق مما إذا كان /var/run/docker.sock موجودًا. إذا كنت تستخدم صورة Docker "
-#~ "الرسمية لـ Nginx UI، يرجى التأكد من أن مقبس Docker مثبت بهذه الطريقة: `-"
-#~ "v /var/run/docker.sock:/var/run/docker.sock`."
+#~ "الرسمية لـ Nginx UI، يرجى التأكد من أن مقبس Docker مثبت بهذه الطريقة: `-v "
+#~ "/var/run/docker.sock:/var/run/docker.sock`."
 
 #~ msgid "Check if the nginx access log path exists"
 #~ msgstr "تحقق مما إذا كان مسار سجل الوصول لـ nginx موجودًا"
@@ -5885,8 +5880,8 @@ msgstr "مفاتيح المرور الخاصة بك"
 
 #, fuzzy
 #~ msgid ""
-#~ "When you enable/disable, delete, or save this stream, the nodes set in "
-#~ "the Node Group and the nodes selected below will be synchronized."
+#~ "When you enable/disable, delete, or save this stream, the nodes set in the "
+#~ "Node Group and the nodes selected below will be synchronized."
 #~ msgstr ""
 #~ "عند تفعيل/تعطيل، حذف، أو حفظ هذا الموقع، سيتم مزامنة العقد المحددة في فئة "
 #~ "الموقع والعقد المحددة أدناه."
@@ -5953,15 +5948,12 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgid "Please upgrade the remote Nginx UI to the latest version"
 #~ msgstr "يرجى ترقية واجهة Nginx البعيدة إلى أحدث إصدار"
 
-#~ msgid ""
-#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
-#~ "%{resp}"
+#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
 #~ msgstr ""
 #~ "فشل إعادة تسمية %{orig_path} إلى %{new_path} على %{env_name}، الاستجابة: "
 #~ "%{resp}"
 
-#~ msgid ""
-#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
 #~ msgstr ""
 #~ "خطأ في إعادة تسمية الموقع %{site} إلى %{new_site} على %{node}، الاستجابة: "
 #~ "%{resp}"
@@ -5976,17 +5968,15 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ "فشل مزامنة الشهادة %{cert_name} إلى %{env_name}، يرجى ترقية واجهة Nginx "
 #~ "البعيدة إلى أحدث إصدار"
 
-#~ msgid ""
-#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr "فشل مزامنة الشهادة %{cert_name} إلى %{env_name}، الاستجابة: %{resp}"
 
 #~ msgid "Sync config %{config_name} to %{env_name} failed, response: %{resp}"
-#~ msgstr ""
-#~ "فشل مزامنة التكوين %{config_name} إلى %{env_name}، الاستجابة: %{resp}"
+#~ msgstr "فشل مزامنة التكوين %{config_name} إلى %{env_name}، الاستجابة: %{resp}"
 
 #~ msgid ""
-#~ "If you lose your mobile phone, you can use the recovery code to reset "
-#~ "your 2FA."
+#~ "If you lose your mobile phone, you can use the recovery code to reset your "
+#~ "2FA."
 #~ msgstr ""
 #~ "إذا فقدت هاتفك المحمول، يمكنك استخدام رمز الاسترداد لإعادة تعيين المصادقة "
 #~ "الثنائية."
@@ -5994,8 +5984,7 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgid "Recovery Code:"
 #~ msgstr "رمز الاسترداد:"
 
-#~ msgid ""
-#~ "The recovery code is only displayed once, please save it in a safe place."
+#~ msgid "The recovery code is only displayed once, please save it in a safe place."
 #~ msgstr "رمز الاسترداد يُعرض مرة واحدة فقط، يرجى حفظه في مكان آمن."
 
 #~ msgid "Can't scan? Use text key binding"
@@ -6005,5 +5994,4 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgstr "اسم المستخدم أو كلمة المرور غير صحيحة"
 
 #~ msgid "Too many login failed attempts, please try again later"
-#~ msgstr ""
-#~ "عدد كبير جدًا من محاولات تسجيل الدخول الفاشلة، يرجى المحاولة مرة أخرى لاحقًا"
+#~ msgstr "عدد كبير جدًا من محاولات تسجيل الدخول الفاشلة، يرجى المحاولة مرة أخرى لاحقًا"

File diff suppressed because it is too large
+ 182 - 205
app/src/language/de_DE/app.po


+ 37 - 33
app/src/language/en/app.po

@@ -95,7 +95,7 @@ msgstr ""
 msgid "About"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:23
+#: src/views/nginx_log/NginxLogList.vue:38
 msgid "Access Log"
 msgstr ""
 
@@ -124,7 +124,7 @@ msgstr ""
 #: src/views/config/configColumns.tsx:41
 #: src/views/environments/group/columns.ts:41
 #: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/nginx_log/NginxLogList.vue:67
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:76
 #: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:105
@@ -265,7 +265,7 @@ msgstr ""
 msgid "Are you sure to reset 2FA?"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:113
+#: src/components/Notification/Notification.vue:110
 #: src/views/notification/Notification.vue:40
 msgid "Are you sure you want to clear all notifications?"
 msgstr ""
@@ -396,7 +396,7 @@ msgstr ""
 msgid "AutoCert is running, please wait..."
 msgstr ""
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:41
+#: src/components/ProcessingStatus/ProcessingStatus.vue:38
 msgid "AutoCert is running..."
 msgstr ""
 
@@ -860,12 +860,12 @@ msgid "Cleaning environment variables"
 msgstr ""
 
 #: src/components/ChatGPT/ChatMessageInput.vue:23
-#: src/components/Notification/Notification.vue:118
+#: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:71
+#: src/components/Notification/Notification.vue:68
 #: src/views/notification/Notification.vue:13
 msgid "Cleared successfully"
 msgstr ""
@@ -1059,7 +1059,7 @@ msgstr ""
 msgid "Core Upgrade"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:305
+#: src/views/dashboard/ServerAnalytic.vue:308
 msgid "CPU Status"
 msgstr ""
 
@@ -1443,7 +1443,7 @@ msgstr ""
 msgid "Disabled successfully"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:370
+#: src/views/dashboard/ServerAnalytic.vue:373
 msgid "Disk IO"
 msgstr ""
 
@@ -1740,7 +1740,7 @@ msgstr ""
 msgid "Error initializing diff viewer"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:27
+#: src/views/nginx_log/NginxLogList.vue:42
 msgid "Error Log"
 msgstr ""
 
@@ -2382,7 +2382,7 @@ msgid ""
 "processes"
 msgstr ""
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:34
+#: src/components/ProcessingStatus/ProcessingStatus.vue:31
 msgid "Indexing..."
 msgstr ""
 
@@ -2694,7 +2694,7 @@ msgid ""
 "nginx-log.html for more information."
 msgstr ""
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:87
 msgid "Log List"
 msgstr ""
 
@@ -2842,8 +2842,8 @@ msgstr ""
 msgid "Maximum worker process number:"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:226
 #: src/views/dashboard/ServerAnalytic.vue:227
+#: src/views/dashboard/ServerAnalytic.vue:228
 msgid "Memory"
 msgstr ""
 
@@ -2933,7 +2933,7 @@ msgstr ""
 #: src/views/config/configColumns.tsx:5
 #: src/views/environments/group/columns.ts:7
 #: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:36
+#: src/views/nginx_log/NginxLogList.vue:51
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:75
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:35
 #: src/views/site/site_list/columns.tsx:16
@@ -2949,19 +2949,19 @@ msgstr ""
 msgid "Need to enable the stub_status module"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:331
+#: src/views/dashboard/ServerAnalytic.vue:334
 msgid "Network"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:273
+#: src/views/dashboard/ServerAnalytic.vue:276
 msgid "Network Statistics"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:280
+#: src/views/dashboard/ServerAnalytic.vue:283
 msgid "Network Total Receive"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:286
+#: src/views/dashboard/ServerAnalytic.vue:289
 msgid "Network Total Send"
 msgstr ""
 
@@ -3213,7 +3213,7 @@ msgstr ""
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:143
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:99
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
-#: src/components/Notification/Notification.vue:111 src/language/curd.ts:38
+#: src/components/Notification/Notification.vue:108 src/language/curd.ts:38
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
@@ -3303,7 +3303,7 @@ msgstr ""
 msgid "Notification"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:109
+#: src/components/Notification/Notification.vue:106
 #: src/routes/modules/notifications.ts:10
 msgid "Notifications"
 msgstr ""
@@ -3370,7 +3370,7 @@ msgstr ""
 #: src/components/ChatGPT/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:36
-#: src/components/Notification/Notification.vue:112 src/language/curd.ts:15
+#: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
 #: src/views/backup/components/BackupCreator.vue:149
 #: src/views/notification/Notification.vue:39
 #: src/views/site/components/SiteStatusSelect.vue:123
@@ -3511,7 +3511,7 @@ msgstr ""
 #: src/language/curd.ts:59
 #: src/views/config/components/ConfigRightPanel/Basic.vue:41
 #: src/views/config/components/Delete.vue:124
-#: src/views/nginx_log/NginxLogList.vue:44
+#: src/views/nginx_log/NginxLogList.vue:59
 msgid "Path"
 msgstr ""
 
@@ -3804,11 +3804,11 @@ msgid "Read requests"
 msgstr ""
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:387
+#: src/views/dashboard/ServerAnalytic.vue:390
 msgid "Reads"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:338
+#: src/views/dashboard/ServerAnalytic.vue:341
 #: src/views/dashboard/ServerAnalytic.vue:35
 msgid "Receive"
 msgstr ""
@@ -3936,7 +3936,7 @@ msgstr ""
 msgid "Remove successfully"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:80
+#: src/components/Notification/Notification.vue:77
 msgid "Removed successfully"
 msgstr ""
 
@@ -4376,6 +4376,10 @@ msgstr ""
 msgid "Scan the QR code with your mobile phone to add the account to the app."
 msgstr ""
 
+#: src/views/nginx_log/NginxLogList.vue:100
+msgid "Scanning logs..."
+msgstr ""
+
 #: src/views/backup/AutoBackup/AutoBackup.vue:113
 msgid "Schedule"
 msgstr ""
@@ -4438,8 +4442,8 @@ msgstr ""
 msgid "Self check failed, Nginx UI may not work properly"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:348
 #: src/views/dashboard/ServerAnalytic.vue:35
+#: src/views/dashboard/ServerAnalytic.vue:351
 msgid "Send"
 msgstr ""
 
@@ -4673,8 +4677,8 @@ msgstr ""
 msgid "Stopped"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:254
-#: src/views/dashboard/ServerAnalytic.vue:255
+#: src/views/dashboard/ServerAnalytic.vue:257
+#: src/views/dashboard/ServerAnalytic.vue:258
 msgid "Storage"
 msgstr ""
 
@@ -4775,8 +4779,8 @@ msgstr ""
 msgid "Supported file type: .zip"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:240
-#: src/views/dashboard/ServerAnalytic.vue:241
+#: src/views/dashboard/ServerAnalytic.vue:242
+#: src/views/dashboard/ServerAnalytic.vue:243
 msgid "Swap"
 msgstr ""
 
@@ -5211,7 +5215,7 @@ msgstr ""
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
-#: src/views/nginx_log/NginxLogList.vue:12
+#: src/views/nginx_log/NginxLogList.vue:27
 #: src/views/notification/notificationColumns.tsx:8
 #: src/views/preference/components/ExternalNotify/columns.tsx:18
 msgid "Type"
@@ -5368,12 +5372,12 @@ msgstr ""
 msgid "Version"
 msgstr ""
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:84
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:105
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
 msgid "View"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:181
+#: src/components/Notification/Notification.vue:178
 msgid "View all notifications"
 msgstr ""
 
@@ -5503,7 +5507,7 @@ msgid "Write private.key error: {0}"
 msgstr ""
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:377
+#: src/views/dashboard/ServerAnalytic.vue:380
 msgid "Writes"
 msgstr ""
 

File diff suppressed because it is too large
+ 181 - 199
app/src/language/es/app.po


File diff suppressed because it is too large
+ 191 - 211
app/src/language/fr_FR/app.po


File diff suppressed because it is too large
+ 173 - 264
app/src/language/ja_JP/app.po


File diff suppressed because it is too large
+ 173 - 255
app/src/language/ko_KR/app.po


+ 37 - 33
app/src/language/messages.pot

@@ -98,7 +98,7 @@ msgstr ""
 msgid "About"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:23
+#: src/views/nginx_log/NginxLogList.vue:38
 msgid "Access Log"
 msgstr ""
 
@@ -128,7 +128,7 @@ msgstr ""
 #: src/views/config/configColumns.tsx:41
 #: src/views/environments/group/columns.ts:41
 #: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/nginx_log/NginxLogList.vue:67
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:76
 #: src/views/site/site_list/columns.tsx:141
@@ -271,7 +271,7 @@ msgstr ""
 msgid "Are you sure to reset 2FA?"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:113
+#: src/components/Notification/Notification.vue:110
 #: src/views/notification/Notification.vue:40
 msgid "Are you sure you want to clear all notifications?"
 msgstr ""
@@ -403,7 +403,7 @@ msgstr ""
 msgid "AutoCert is running, please wait..."
 msgstr ""
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:41
+#: src/components/ProcessingStatus/ProcessingStatus.vue:38
 msgid "AutoCert is running..."
 msgstr ""
 
@@ -834,12 +834,12 @@ msgid "Cleaning environment variables"
 msgstr ""
 
 #: src/components/ChatGPT/ChatMessageInput.vue:23
-#: src/components/Notification/Notification.vue:118
+#: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:71
+#: src/components/Notification/Notification.vue:68
 #: src/views/notification/Notification.vue:13
 msgid "Cleared successfully"
 msgstr ""
@@ -1036,7 +1036,7 @@ msgstr ""
 msgid "Core Upgrade"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:305
+#: src/views/dashboard/ServerAnalytic.vue:308
 msgid "CPU Status"
 msgstr ""
 
@@ -1423,7 +1423,7 @@ msgstr ""
 msgid "Disabled successfully"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:370
+#: src/views/dashboard/ServerAnalytic.vue:373
 msgid "Disk IO"
 msgstr ""
 
@@ -1720,7 +1720,7 @@ msgstr ""
 msgid "Error initializing diff viewer"
 msgstr ""
 
-#: src/views/nginx_log/NginxLogList.vue:27
+#: src/views/nginx_log/NginxLogList.vue:42
 msgid "Error Log"
 msgstr ""
 
@@ -2353,7 +2353,7 @@ msgstr ""
 msgid "Includes master process, worker processes, cache processes, and other Nginx processes"
 msgstr ""
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:34
+#: src/components/ProcessingStatus/ProcessingStatus.vue:31
 msgid "Indexing..."
 msgstr ""
 
@@ -2660,7 +2660,7 @@ msgid "Log file %{log_path} is not a regular file. If you are using nginx-ui in
 msgstr ""
 
 #: src/routes/modules/nginx_log.ts:39
-#: src/views/nginx_log/NginxLogList.vue:72
+#: src/views/nginx_log/NginxLogList.vue:87
 msgid "Log List"
 msgstr ""
 
@@ -2804,8 +2804,8 @@ msgstr ""
 msgid "Maximum worker process number:"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:226
 #: src/views/dashboard/ServerAnalytic.vue:227
+#: src/views/dashboard/ServerAnalytic.vue:228
 msgid "Memory"
 msgstr ""
 
@@ -2895,7 +2895,7 @@ msgstr ""
 #: src/views/config/configColumns.tsx:5
 #: src/views/environments/group/columns.ts:7
 #: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:36
+#: src/views/nginx_log/NginxLogList.vue:51
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:75
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:35
 #: src/views/site/site_list/columns.tsx:16
@@ -2911,19 +2911,19 @@ msgstr ""
 msgid "Need to enable the stub_status module"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:331
+#: src/views/dashboard/ServerAnalytic.vue:334
 msgid "Network"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:273
+#: src/views/dashboard/ServerAnalytic.vue:276
 msgid "Network Statistics"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:280
+#: src/views/dashboard/ServerAnalytic.vue:283
 msgid "Network Total Receive"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:286
+#: src/views/dashboard/ServerAnalytic.vue:289
 msgid "Network Total Send"
 msgstr ""
 
@@ -3177,7 +3177,7 @@ msgstr ""
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:143
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:99
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
-#: src/components/Notification/Notification.vue:111
+#: src/components/Notification/Notification.vue:108
 #: src/language/curd.ts:38
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
@@ -3267,7 +3267,7 @@ msgstr ""
 msgid "Notification"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:109
+#: src/components/Notification/Notification.vue:106
 #: src/routes/modules/notifications.ts:10
 msgid "Notifications"
 msgstr ""
@@ -3332,7 +3332,7 @@ msgstr ""
 #: src/components/ChatGPT/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:36
-#: src/components/Notification/Notification.vue:112
+#: src/components/Notification/Notification.vue:109
 #: src/language/curd.ts:15
 #: src/views/backup/components/BackupCreator.vue:149
 #: src/views/notification/Notification.vue:39
@@ -3473,7 +3473,7 @@ msgstr ""
 #: src/language/curd.ts:59
 #: src/views/config/components/ConfigRightPanel/Basic.vue:41
 #: src/views/config/components/Delete.vue:124
-#: src/views/nginx_log/NginxLogList.vue:44
+#: src/views/nginx_log/NginxLogList.vue:59
 msgid "Path"
 msgstr ""
 
@@ -3758,11 +3758,11 @@ msgid "Read requests"
 msgstr ""
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:387
+#: src/views/dashboard/ServerAnalytic.vue:390
 msgid "Reads"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:338
+#: src/views/dashboard/ServerAnalytic.vue:341
 #: src/views/dashboard/ServerAnalytic.vue:35
 msgid "Receive"
 msgstr ""
@@ -3886,7 +3886,7 @@ msgstr ""
 msgid "Remove successfully"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:80
+#: src/components/Notification/Notification.vue:77
 msgid "Removed successfully"
 msgstr ""
 
@@ -4327,6 +4327,10 @@ msgstr ""
 msgid "Scan the QR code with your mobile phone to add the account to the app."
 msgstr ""
 
+#: src/views/nginx_log/NginxLogList.vue:100
+msgid "Scanning logs..."
+msgstr ""
+
 #: src/views/backup/AutoBackup/AutoBackup.vue:113
 msgid "Schedule"
 msgstr ""
@@ -4391,8 +4395,8 @@ msgstr ""
 msgid "Self check failed, Nginx UI may not work properly"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:348
 #: src/views/dashboard/ServerAnalytic.vue:35
+#: src/views/dashboard/ServerAnalytic.vue:351
 msgid "Send"
 msgstr ""
 
@@ -4623,8 +4627,8 @@ msgstr ""
 msgid "Stopped"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:254
-#: src/views/dashboard/ServerAnalytic.vue:255
+#: src/views/dashboard/ServerAnalytic.vue:257
+#: src/views/dashboard/ServerAnalytic.vue:258
 msgid "Storage"
 msgstr ""
 
@@ -4718,8 +4722,8 @@ msgstr ""
 msgid "Supported file type: .zip"
 msgstr ""
 
-#: src/views/dashboard/ServerAnalytic.vue:240
-#: src/views/dashboard/ServerAnalytic.vue:241
+#: src/views/dashboard/ServerAnalytic.vue:242
+#: src/views/dashboard/ServerAnalytic.vue:243
 msgid "Swap"
 msgstr ""
 
@@ -5112,7 +5116,7 @@ msgstr ""
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
-#: src/views/nginx_log/NginxLogList.vue:12
+#: src/views/nginx_log/NginxLogList.vue:27
 #: src/views/notification/notificationColumns.tsx:8
 #: src/views/preference/components/ExternalNotify/columns.tsx:18
 msgid "Type"
@@ -5274,12 +5278,12 @@ msgid "Version"
 msgstr ""
 
 #: src/language/curd.ts:7
-#: src/views/nginx_log/NginxLogList.vue:84
+#: src/views/nginx_log/NginxLogList.vue:105
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
 msgid "View"
 msgstr ""
 
-#: src/components/Notification/Notification.vue:181
+#: src/components/Notification/Notification.vue:178
 msgid "View all notifications"
 msgstr ""
 
@@ -5397,7 +5401,7 @@ msgid "Write private.key error: {0}"
 msgstr ""
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:377
+#: src/views/dashboard/ServerAnalytic.vue:380
 msgid "Writes"
 msgstr ""
 

File diff suppressed because it is too large
+ 182 - 203
app/src/language/pt_PT/app.po


+ 188 - 203
app/src/language/ru_RU/app.po

@@ -7,24 +7,24 @@ msgstr ""
 "POT-Creation-Date: \n"
 "PO-Revision-Date: 2025-03-28 02:45+0300\n"
 "Last-Translator: Artyom Isrofilov <artyom@isrofilov.ru>\n"
-"Language-Team: Russian <https://weblate.nginxui.com/projects/nginx-ui/"
-"frontend/ru/>\n"
+"Language-Team: Russian "
+"<https://weblate.nginxui.com/projects/nginx-ui/frontend/ru/>\n"
 "Language: ru_RU\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 "X-Generator: Poedit 3.5\n"
 
 #: src/language/generate.ts:33
 msgid "[Nginx UI] ACME User: %{name}, Email: %{email}, CA Dir: %{caDir}"
-msgstr ""
-"[Nginx UI] Пользователь ACME: %{name}, Email: %{email}, Каталог CA: %{caDir}"
+msgstr "[Nginx UI] Пользователь ACME: %{name}, Email: %{email}, Каталог CA: %{caDir}"
 
 #: src/language/generate.ts:34
 msgid "[Nginx UI] Backing up current certificate for later revocation"
 msgstr ""
-"[Nginx UI] Резервное копирование текущего сертификата для последующего отзыва"
+"[Nginx UI] Резервное копирование текущего сертификата для последующего "
+"отзыва"
 
 #: src/language/generate.ts:35
 msgid "[Nginx UI] Certificate renewed successfully"
@@ -35,11 +35,10 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] Сертификат успешно отозван"
 
 #: src/language/generate.ts:37
-msgid ""
-"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr ""
-"[Nginx UI] Сертификат использовался для сервера, перезагрузка TLS-"
-"сертификата сервера"
+"[Nginx UI] Сертификат использовался для сервера, перезагрузка "
+"TLS-сертификата сервера"
 
 #: src/language/generate.ts:38
 msgid "[Nginx UI] Creating client facilitates communication with the CA server"
@@ -117,7 +116,7 @@ msgstr "Настройки 2FA"
 msgid "About"
 msgstr "О проекте"
 
-#: src/views/nginx_log/NginxLogList.vue:23
+#: src/views/nginx_log/NginxLogList.vue:38
 msgid "Access Log"
 msgstr "Журнал доступа"
 
@@ -146,7 +145,7 @@ msgstr "Действие"
 #: src/views/config/configColumns.tsx:41
 #: src/views/environments/group/columns.ts:41
 #: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/nginx_log/NginxLogList.vue:67
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:76
 #: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:105
@@ -226,8 +225,7 @@ msgstr "Расширенный режим"
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:99
 msgid "Afterwards, refresh this page and click add passkey again."
-msgstr ""
-"После этого обновите эту страницу и снова нажмите «Добавить ключ доступа»."
+msgstr "После этого обновите эту страницу и снова нажмите «Добавить ключ доступа»."
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:115
 msgid "All"
@@ -243,8 +241,8 @@ msgid ""
 "All selected subdomains must belong to the same DNS Provider, otherwise the "
 "certificate application will fail."
 msgstr ""
-"Все выбранные поддомены должны принадлежать одному и тому же DNS-провайдеру, "
-"иначе запрос сертификата завершится неудачей."
+"Все выбранные поддомены должны принадлежать одному и тому же "
+"DNS-провайдеру, иначе запрос сертификата завершится неудачей."
 
 #: src/views/preference/tabs/OpenAISettings.vue:32
 msgid "API Base Url"
@@ -290,7 +288,7 @@ msgstr "Вы уверены, что хотите сгенерировать но
 msgid "Are you sure to reset 2FA?"
 msgstr "Вы уверены, что хотите сбросить 2FA?"
 
-#: src/components/Notification/Notification.vue:113
+#: src/components/Notification/Notification.vue:110
 #: src/views/notification/Notification.vue:40
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Вы уверены, что хотите очистить все уведомления?"
@@ -425,7 +423,7 @@ msgstr "Автообновление включено для %{name}"
 msgid "AutoCert is running, please wait..."
 msgstr "AutoCert выполняется, пожалуйста, подождите..."
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:41
+#: src/components/ProcessingStatus/ProcessingStatus.vue:38
 msgid "AutoCert is running..."
 msgstr "AutoCert выполняется..."
 
@@ -501,8 +499,7 @@ msgstr ""
 "%{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid ""
-"Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
 "Задача резервного копирования %{backup_name} не выполнена при загрузке в "
 "хранилище, ошибка: %{error}"
@@ -587,7 +584,8 @@ msgstr "Кэш"
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:178
 msgid "Cache items not accessed within this time will be removed"
 msgstr ""
-"Элементы кэша, к которым не обращались в течение этого времени, будут удалены"
+"Элементы кэша, к которым не обращались в течение этого времени, будут "
+"удалены"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:350
 msgid "Cache loader processing time threshold"
@@ -812,13 +810,13 @@ msgstr "Проверить повторно"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v /"
-"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
-"run/docker.sock to communicate with the host Docker Engine via Docker Client "
-"API. This feature is used to control Nginx in another container and perform "
-"container replacement rather than binary replacement during OTA upgrades of "
-"Nginx UI to ensure container dependencies are also upgraded. If you don't "
-"need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v "
+"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
+"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
+"Client API. This feature is used to control Nginx in another container and "
+"perform container replacement rather than binary replacement during OTA "
+"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
+"you don't need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "Проверьте, существует ли /var/run/docker.sock. Если вы используете "
@@ -842,19 +840,19 @@ msgstr ""
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is obtained "
-"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
-"point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the access log path."
-"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
-"nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is "
+"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
+"does not point to a valid, existing file, an error will be reported. In "
+"this case, you need to modify the configuration file to specify the access "
+"log path.Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 msgstr ""
 "Проверьте, существует ли путь к журналу доступа nginx. По умолчанию этот "
 "путь получается из 'nginx -V'. Если его невозможно получить или полученный "
 "путь не указывает на действительный существующий файл, будет сообщена "
 "ошибка. В этом случае вам необходимо изменить файл конфигурации, чтобы "
-"указать путь к журналу доступа. Подробнее см. в документации: https://"
-"nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
+"указать путь к журналу доступа. Подробнее см. в документации: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -870,29 +868,29 @@ msgid ""
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
 "you need to modify the configuration file to specify the error log path. "
-"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
-"nginx.html#errorlogpath"
+"Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 msgstr ""
-"Проверьте, существует ли путь к журналу ошибок nginx. По умолчанию этот путь "
-"получается из 'nginx -V'. Если его невозможно получить или полученный путь "
-"не указывает на действительный существующий файл, будет сообщена ошибка. В "
-"этом случае вам нужно изменить файл конфигурации, чтобы указать путь к "
-"журналу ошибок. Подробнее см. в документации: https://nginxui.com/zh_CN/"
-"guide/config-nginx.html#errorlogpath"
+"Проверьте, существует ли путь к журналу ошибок nginx. По умолчанию этот "
+"путь получается из 'nginx -V'. Если его невозможно получить или полученный "
+"путь не указывает на действительный существующий файл, будет сообщена "
+"ошибка. В этом случае вам нужно изменить файл конфигурации, чтобы указать "
+"путь к журналу ошибок. Подробнее см. в документации: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
-"config-nginx.html#pidpath"
+"path.Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 msgstr ""
-"Проверьте, существует ли путь к PID Nginx. По умолчанию этот путь получается "
-"из команды 'nginx -V'. Если его не удается получить, будет сообщена ошибка. "
-"В этом случае вам нужно изменить конфигурационный файл, чтобы указать путь к "
-"PID Nginx. Подробнее см. в документации: https://nginxui.com/zh_CN/guide/"
-"config-nginx.html#pidpath"
+"Проверьте, существует ли путь к PID Nginx. По умолчанию этот путь "
+"получается из команды 'nginx -V'. Если его не удается получить, будет "
+"сообщена ошибка. В этом случае вам нужно изменить конфигурационный файл, "
+"чтобы указать путь к PID Nginx. Подробнее см. в документации: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx sbin path exists"
@@ -920,8 +918,8 @@ msgstr ""
 
 #: src/language/generate.ts:17
 msgid ""
-"Check if the streams-available and streams-enabled directories are under the "
-"nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under "
+"the nginx configuration directory"
 msgstr ""
 "Проверьте, находятся ли каталоги streams-available и streams-enabled в "
 "каталоге конфигурации nginx"
@@ -935,12 +933,12 @@ msgid "Cleaning environment variables"
 msgstr "Очистка переменных среды"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:23
-#: src/components/Notification/Notification.vue:118
+#: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
 msgstr "Очистить"
 
-#: src/components/Notification/Notification.vue:71
+#: src/components/Notification/Notification.vue:68
 #: src/views/notification/Notification.vue:13
 msgid "Cleared successfully"
 msgstr "Очищено успешно"
@@ -1136,7 +1134,7 @@ msgstr "Копировать коды"
 msgid "Core Upgrade"
 msgstr "Обновление ядра"
 
-#: src/views/dashboard/ServerAnalytic.vue:305
+#: src/views/dashboard/ServerAnalytic.vue:308
 msgid "CPU Status"
 msgstr "Нагрузка CPU"
 
@@ -1525,7 +1523,7 @@ msgstr "Отключено"
 msgid "Disabled successfully"
 msgstr "Отключено успешно"
 
-#: src/views/dashboard/ServerAnalytic.vue:370
+#: src/views/dashboard/ServerAnalytic.vue:373
 msgid "Disk IO"
 msgstr "Нагрузка на Диск IO"
 
@@ -1596,8 +1594,7 @@ msgstr "Домен"
 
 #: src/views/certificate/CertificateEditor.vue:109
 msgid "Domains list is empty, try to reopen Auto Cert for %{config}"
-msgstr ""
-"Список доменов пуст, попробуйте заново создать авто-сертификат для %{config}"
+msgstr "Список доменов пуст, попробуйте заново создать авто-сертификат для %{config}"
 
 #: src/language/constants.ts:27
 msgid "Download latest release error"
@@ -1825,7 +1822,7 @@ msgstr "Ошибка"
 msgid "Error initializing diff viewer"
 msgstr "Ошибка инициализации просмотрщика различий"
 
-#: src/views/nginx_log/NginxLogList.vue:27
+#: src/views/nginx_log/NginxLogList.vue:42
 msgid "Error Log"
 msgstr "Журнал ошибок"
 
@@ -2276,8 +2273,8 @@ msgid ""
 "Follow the instructions in the dialog to complete the passkey registration "
 "process."
 msgstr ""
-"Следуйте инструкциям в всплывающем окне, чтобы завершить процесс регистрации "
-"ключа доступа."
+"Следуйте инструкциям в всплывающем окне, чтобы завершить процесс "
+"регистрации ключа доступа."
 
 #: src/views/preference/tabs/NodeSettings.vue:42
 #: src/views/preference/tabs/NodeSettings.vue:54
@@ -2384,8 +2381,7 @@ msgstr "Скрыть"
 
 #: src/views/dashboard/components/PerformanceStatisticsCard.vue:87
 msgid "Higher value means better connection reuse"
-msgstr ""
-"Более высокое значение означает лучшее повторное использование соединения"
+msgstr "Более высокое значение означает лучшее повторное использование соединения"
 
 #: src/views/config/components/ConfigLeftPanel.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
@@ -2442,13 +2438,11 @@ msgstr ""
 msgid ""
 "If you want to automatically revoke the old certificate, please enable this "
 "option."
-msgstr ""
-"Если вы хотите автоматически отозвать старый сертификат, включите эту опцию."
+msgstr "Если вы хотите автоматически отозвать старый сертификат, включите эту опцию."
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
-msgstr ""
-"Если ваш браузер поддерживает WebAuthn Passkey, появится диалоговое окно."
+msgstr "Если ваш браузер поддерживает WebAuthn Passkey, появится диалоговое окно."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:113
 msgid ""
@@ -2479,7 +2473,7 @@ msgstr ""
 "Включает мастер-процесс, рабочие процессы, процессы кеширования и другие "
 "процессы Nginx"
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:34
+#: src/components/ProcessingStatus/ProcessingStatus.vue:31
 msgid "Indexing..."
 msgstr "Индексация..."
 
@@ -2636,8 +2630,8 @@ msgid ""
 "Keep your recovery codes as safe as your password. We recommend saving them "
 "with a password manager."
 msgstr ""
-"Храните ваши коды восстановления так же безопасно, как и пароль. Рекомендуем "
-"сохранить их в менеджере паролей."
+"Храните ваши коды восстановления так же безопасно, как и пароль. "
+"Рекомендуем сохранить их в менеджере паролей."
 
 #: src/views/dashboard/components/ParamsOpt/PerformanceConfig.vue:60
 msgid "Keepalive Timeout"
@@ -2791,14 +2785,15 @@ msgstr "Журнал"
 #: src/language/generate.ts:21
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
-"nginx-log.html for more information."
+"docker container, please refer to "
+"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
 msgstr ""
 "Файл журнала %{log_path} не является обычным файлом. Если вы используете "
-"nginx-ui в контейнере Docker, обратитесь к https://nginxui.com/zh_CN/guide/"
-"config-nginx-log.html для получения дополнительной информации."
+"nginx-ui в контейнере Docker, обратитесь к "
+"https://nginxui.com/zh_CN/guide/config-nginx-log.html для получения "
+"дополнительной информации."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:87
 msgid "Log List"
 msgstr "Список журналов"
 
@@ -2820,18 +2815,18 @@ msgstr "Прокрутка"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions for "
-"users who install Nginx UI on the host machine, so you don't need to modify "
-"the parameters on this page. For users who install Nginx UI using Docker "
-"containers, you can manually enable this option. The crontab task scheduler "
-"of Nginx UI will execute the logrotate command at the interval you set in "
-"minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions "
+"for users who install Nginx UI on the host machine, so you don't need to "
+"modify the parameters on this page. For users who install Nginx UI using "
+"Docker containers, you can manually enable this option. The crontab task "
+"scheduler of Nginx UI will execute the logrotate command at the interval "
+"you set in minutes."
 msgstr ""
 "Logrotate по умолчанию включен в большинстве основных дистрибутивов Linux "
 "для пользователей, которые устанавливают Nginx UI на хост-машину, поэтому "
-"вам не нужно изменять параметры на этой странице. Для пользователей, которые "
-"устанавливают Nginx UI с использованием Docker-контейнеров, вы можете "
-"вручную включить эту опцию. Планировщик задач crontab Nginx UI будет "
+"вам не нужно изменять параметры на этой странице. Для пользователей, "
+"которые устанавливают Nginx UI с использованием Docker-контейнеров, вы "
+"можете вручную включить эту опцию. Планировщик задач crontab Nginx UI будет "
 "выполнять команду logrotate с интервалом, который вы установите в минутах."
 
 #: src/views/site/components/SiteStatusSelect.vue:165
@@ -2954,8 +2949,8 @@ msgstr "Максимальный общий размер кэша"
 msgid "Maximum worker process number:"
 msgstr "Максимальное количество рабочих процессов:"
 
-#: src/views/dashboard/ServerAnalytic.vue:226
 #: src/views/dashboard/ServerAnalytic.vue:227
+#: src/views/dashboard/ServerAnalytic.vue:228
 msgid "Memory"
 msgstr "Память"
 
@@ -3045,7 +3040,7 @@ msgstr "Многострочная директива"
 #: src/views/config/configColumns.tsx:5
 #: src/views/environments/group/columns.ts:7
 #: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:36
+#: src/views/nginx_log/NginxLogList.vue:51
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:75
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:35
 #: src/views/site/site_list/columns.tsx:16
@@ -3061,19 +3056,19 @@ msgstr "Имя"
 msgid "Need to enable the stub_status module"
 msgstr "Необходимо включить модуль stub_status"
 
-#: src/views/dashboard/ServerAnalytic.vue:331
+#: src/views/dashboard/ServerAnalytic.vue:334
 msgid "Network"
 msgstr "Сеть"
 
-#: src/views/dashboard/ServerAnalytic.vue:273
+#: src/views/dashboard/ServerAnalytic.vue:276
 msgid "Network Statistics"
 msgstr "Статистика сети"
 
-#: src/views/dashboard/ServerAnalytic.vue:280
+#: src/views/dashboard/ServerAnalytic.vue:283
 msgid "Network Total Receive"
 msgstr "Всего получено"
 
-#: src/views/dashboard/ServerAnalytic.vue:286
+#: src/views/dashboard/ServerAnalytic.vue:289
 msgid "Network Total Send"
 msgstr "Всего отправлено"
 
@@ -3304,8 +3299,8 @@ msgstr "Конфигурация Nginx UI была восстановлена"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in a "
-"few seconds."
+"Nginx UI configuration has been restored and will restart automatically in "
+"a few seconds."
 msgstr ""
 "Конфигурация Nginx UI была восстановлена и автоматически перезапустится "
 "через несколько секунд."
@@ -3327,7 +3322,7 @@ msgstr "Nginx.conf включает каталог streams-enabled"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:143
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:99
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
-#: src/components/Notification/Notification.vue:111 src/language/curd.ts:38
+#: src/components/Notification/Notification.vue:108 src/language/curd.ts:38
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
@@ -3419,7 +3414,7 @@ msgstr ""
 msgid "Notification"
 msgstr "Уведомление"
 
-#: src/components/Notification/Notification.vue:109
+#: src/components/Notification/Notification.vue:106
 #: src/routes/modules/notifications.ts:10
 msgid "Notifications"
 msgstr "Уведомления"
@@ -3490,7 +3485,7 @@ msgstr "Оффлайн"
 #: src/components/ChatGPT/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:36
-#: src/components/Notification/Notification.vue:112 src/language/curd.ts:15
+#: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
 #: src/views/backup/components/BackupCreator.vue:149
 #: src/views/notification/Notification.vue:39
 #: src/views/site/components/SiteStatusSelect.vue:123
@@ -3635,7 +3630,7 @@ msgstr "Пароли не совпадают"
 #: src/language/curd.ts:59
 #: src/views/config/components/ConfigRightPanel/Basic.vue:41
 #: src/views/config/components/Delete.vue:124
-#: src/views/nginx_log/NginxLogList.vue:44
+#: src/views/nginx_log/NginxLogList.vue:59
 msgid "Path"
 msgstr "Путь"
 
@@ -3697,8 +3692,8 @@ msgid ""
 "Please enable the stub_status module to get request statistics, connection "
 "count, etc."
 msgstr ""
-"Пожалуйста, включите модуль stub_status, чтобы получать статистику запросов, "
-"количество соединений и т. д."
+"Пожалуйста, включите модуль stub_status, чтобы получать статистику "
+"запросов, количество соединений и т. д."
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:69
 msgid ""
@@ -3744,8 +3739,8 @@ msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
 msgstr ""
-"Пожалуйста, заполните учетные данные API, предоставленные вашим DNS-"
-"провайдером."
+"Пожалуйста, заполните учетные данные API, предоставленные вашим "
+"DNS-провайдером."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:57
 msgid ""
@@ -3759,8 +3754,8 @@ msgstr ""
 #: src/components/Notification/notifications.ts:190
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to prevent "
-"lockout."
+"Please generate new recovery codes in the preferences immediately to "
+"prevent lockout."
 msgstr ""
 "Пожалуйста, немедленно сгенерируйте новые коды восстановления в настройках, "
 "чтобы избежать блокировки."
@@ -3808,8 +3803,7 @@ msgid "Please log in."
 msgstr "Пожалуйста, войдите в систему."
 
 #: src/views/certificate/DNSCredential.vue:75
-msgid ""
-"Please note that the unit of time configurations below are all in seconds."
+msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Обратите внимание, что единица измерения времени в конфигурациях ниже "
 "указана в секундах."
@@ -3949,11 +3943,11 @@ msgid "Read requests"
 msgstr "Запросы на чтение"
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:387
+#: src/views/dashboard/ServerAnalytic.vue:390
 msgid "Reads"
 msgstr "Чтение"
 
-#: src/views/dashboard/ServerAnalytic.vue:338
+#: src/views/dashboard/ServerAnalytic.vue:341
 #: src/views/dashboard/ServerAnalytic.vue:35
 msgid "Receive"
 msgstr "Принято"
@@ -3975,8 +3969,8 @@ msgid ""
 "Recovery codes are used to access your account when you lose access to your "
 "2FA device. Each code can only be used once."
 msgstr ""
-"Коды восстановления используются для доступа к аккаунту при утере 2FA-"
-"устройства. Каждый код можно использовать только один раз."
+"Коды восстановления используются для доступа к аккаунту при утере "
+"2FA-устройства. Каждый код можно использовать только один раз."
 
 #: src/views/preference/tabs/CertSettings.vue:40
 msgid "Recursive Nameservers"
@@ -4065,8 +4059,7 @@ msgstr "Удаленная перезагрузка Nginx успешно вып
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:84
 msgid "Reload request failed, please check your network connection"
-msgstr ""
-"Не удалось выполнить запрос на перезагрузку, проверьте подключение к сети"
+msgstr "Не удалось выполнить запрос на перезагрузку, проверьте подключение к сети"
 
 #: src/components/NginxControl/NginxControl.vue:73
 msgid "Reloading"
@@ -4086,7 +4079,7 @@ msgstr "Удалить"
 msgid "Remove successfully"
 msgstr "Удалено успешно"
 
-#: src/components/Notification/Notification.vue:80
+#: src/components/Notification/Notification.vue:77
 msgid "Removed successfully"
 msgstr "Успешно удалено"
 
@@ -4533,6 +4526,10 @@ msgstr ""
 "Отсканируйте QR-код с помощью мобильного телефона, чтобы добавить учетную "
 "запись в приложение."
 
+#: src/views/nginx_log/NginxLogList.vue:100
+msgid "Scanning logs..."
+msgstr "Сканирование журналов..."
+
 #: src/views/backup/AutoBackup/AutoBackup.vue:113
 msgid "Schedule"
 msgstr "Расписание"
@@ -4595,8 +4592,8 @@ msgstr "Самопроверка"
 msgid "Self check failed, Nginx UI may not work properly"
 msgstr "Самопроверка не удалась, Nginx UI может работать некорректно"
 
-#: src/views/dashboard/ServerAnalytic.vue:348
 #: src/views/dashboard/ServerAnalytic.vue:35
+#: src/views/dashboard/ServerAnalytic.vue:351
 msgid "Send"
 msgstr "Отправлено"
 
@@ -4638,8 +4635,7 @@ msgstr "Ошибка установки окружения: {0}"
 
 #: src/constants/errors/cert.ts:18
 msgid "Set env flag to disable lego CNAME support error: {0}"
-msgstr ""
-"Установка флага окружения для отключения поддержки CNAME в lego ошибка: {0}"
+msgstr "Установка флага окружения для отключения поддержки CNAME в lego ошибка: {0}"
 
 #: src/views/preference/tabs/CertSettings.vue:36
 msgid ""
@@ -4667,16 +4663,16 @@ msgstr "Настройка провайдера проверки HTTP01"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
+"https://nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
 "Settings.NginxLogSettings.AccessLogPath пуст, дополнительную информацию см. "
 "на https://nginxui.com/guide/config-nginx.html"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
+"https://nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
 "Settings.NginxLogSettings.ErrorLogPath пуст, дополнительную информацию см. "
 "на https://nginxui.com/guide/config-nginx.html"
@@ -4759,8 +4755,7 @@ msgstr "Содержимое SSL-сертификата"
 
 #: src/constants/errors/system.ts:8
 msgid "SSL certificate file must be under Nginx configuration directory: {0}"
-msgstr ""
-"Файл SSL-сертификата должен находиться в каталоге конфигурации Nginx: {0}"
+msgstr "Файл SSL-сертификата должен находиться в каталоге конфигурации Nginx: {0}"
 
 #: src/constants/errors/system.ts:6
 msgid "SSL certificate file not found"
@@ -4838,8 +4833,8 @@ msgstr "Статус"
 msgid "Stopped"
 msgstr "Остановлен"
 
-#: src/views/dashboard/ServerAnalytic.vue:254
-#: src/views/dashboard/ServerAnalytic.vue:255
+#: src/views/dashboard/ServerAnalytic.vue:257
+#: src/views/dashboard/ServerAnalytic.vue:258
 msgid "Storage"
 msgstr "Хранилище"
 
@@ -4917,25 +4912,25 @@ msgstr "Воскресенье"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: https://"
-"nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
-"Поддержка связи с бэкендом через протокол Server-Sent Events. Если ваш Nginx "
-"UI используется через обратный прокси Nginx, обратитесь к этой ссылке, чтобы "
-"написать соответствующий конфигурационный файл: https://nginxui.com/guide/"
-"nginx-proxy-example.html"
+"Поддержка связи с бэкендом через протокол Server-Sent Events. Если ваш "
+"Nginx UI используется через обратный прокси Nginx, обратитесь к этой "
+"ссылке, чтобы написать соответствующий конфигурационный файл: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
-"link to write the corresponding configuration file: https://nginxui.com/"
-"guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
+"this link to write the corresponding configuration file: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "Поддерживает связь с бэкендом через протокол WebSocket. Если ваш Nginx UI "
 "используется через обратный прокси Nginx, обратитесь к этой ссылке, чтобы "
-"написать соответствующий конфигурационный файл: https://nginxui.com/guide/"
-"nginx-proxy-example.html"
+"написать соответствующий конфигурационный файл: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/language/curd.ts:51 src/language/curd.ts:55
 msgid "Support single or batch upload of files"
@@ -4950,8 +4945,8 @@ msgstr "Поддержка загрузки целых папок"
 msgid "Supported file type: .zip"
 msgstr "Поддерживаемый тип файла: .zip"
 
-#: src/views/dashboard/ServerAnalytic.vue:240
-#: src/views/dashboard/ServerAnalytic.vue:241
+#: src/views/dashboard/ServerAnalytic.vue:242
+#: src/views/dashboard/ServerAnalytic.vue:243
 msgid "Swap"
 msgstr "Своп"
 
@@ -5102,10 +5097,11 @@ msgstr "Введенные данные не являются ключом SSL 
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in "
+"settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"Путь к журналу не находится под путями в settings.NginxSettings."
-"LogDirWhiteList"
+"Путь к журналу не находится под путями в "
+"settings.NginxSettings.LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -5117,8 +5113,7 @@ msgstr ""
 "двоеточия и точки."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid ""
-"The model used for code completion, if not set, the chat model will be used."
+msgid "The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "Модель, используемая для завершения кода. Если не задана, будет "
 "использоваться чат-модель."
@@ -5166,8 +5161,8 @@ msgid ""
 "The server_name in the current configuration must be the domain name you "
 "need to get the certificate, supportmultiple domains."
 msgstr ""
-"server_name в текущей конфигурации должен быть доменным именем, для которого "
-"вам нужно получить сертификат, поддержка нескольких доменов."
+"server_name в текущей конфигурации должен быть доменным именем, для "
+"которого вам нужно получить сертификат, поддержка нескольких доменов."
 
 #: src/views/preference/tabs/CertSettings.vue:22
 #: src/views/preference/tabs/HTTPSettings.vue:14
@@ -5197,8 +5192,8 @@ msgid ""
 "your password and second factors. If you cannot find these codes, you will "
 "lose access to your account."
 msgstr ""
-"Эти коды являются последним средством для доступа к вашему аккаунту, если вы "
-"потеряете пароль и вторые факторы. Если вы не сможете найти эти коды, вы "
+"Эти коды являются последним средством для доступа к вашему аккаунту, если "
+"вы потеряете пароль и вторые факторы. Если вы не сможете найти эти коды, вы "
 "потеряете доступ к своему аккаунту."
 
 #: src/views/certificate/CertificateEditor.vue:99
@@ -5232,14 +5227,13 @@ msgid "This field should not be empty"
 msgstr "Это поле обязательно к заполнению"
 
 #: src/constants/form_errors.ts:6
-msgid ""
-"This field should only contain letters, unicode characters, numbers, and -_."
+msgid "This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "Это поле должно содержать только буквы, символы Юникода, цифры и -_."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and -"
-"_./:"
+"This field should only contain letters, unicode characters, numbers, and "
+"-_./:"
 msgstr "Это поле должно содержать только буквы, символы Unicode, цифры и -_./:"
 
 #: src/views/dashboard/NginxDashBoard.vue:155
@@ -5247,8 +5241,8 @@ msgid ""
 "This module provides Nginx request statistics, connection count, etc. data. "
 "After enabling it, you can view performance statistics"
 msgstr ""
-"Этот модуль предоставляет статистику запросов Nginx, количество соединений и "
-"другие данные. После включения вы сможете просматривать статистику "
+"Этот модуль предоставляет статистику запросов Nginx, количество соединений "
+"и другие данные. После включения вы сможете просматривать статистику "
 "производительности."
 
 #: src/views/certificate/components/RemoveCert.vue:106
@@ -5264,8 +5258,8 @@ msgid ""
 "This token will only be shown once and cannot be retrieved later. Please "
 "make sure to save it in a secure location."
 msgstr ""
-"Этот токен будет показан только один раз и не может быть восстановлен позже. "
-"Пожалуйста, сохраните его в надежном месте."
+"Этот токен будет показан только один раз и не может быть восстановлен "
+"позже. Пожалуйста, сохраните его в надежном месте."
 
 #: src/constants/form_errors.ts:4 src/language/curd.ts:42
 msgid "This value is already taken"
@@ -5281,8 +5275,8 @@ msgid ""
 "This will restore all Nginx configuration files. Nginx will restart after "
 "the restoration is complete."
 msgstr ""
-"Это восстановит все конфигурационные файлы Nginx. Nginx перезапустится после "
-"завершения восстановления."
+"Это восстановит все конфигурационные файлы Nginx. Nginx перезапустится "
+"после завершения восстановления."
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:238
 #: src/components/SystemRestore/SystemRestoreContent.vue:315
@@ -5294,8 +5288,7 @@ msgstr ""
 "после завершения восстановления."
 
 #: src/views/environments/list/BatchUpgrader.vue:183
-msgid ""
-"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Это обновит или переустановит интерфейс Nginx на %{nodeNames} до версии "
 "%{version}."
@@ -5345,15 +5338,15 @@ msgid ""
 "and restart Nginx UI."
 msgstr ""
 "Для обеспечения безопасности конфигурацию WebAuthn нельзя добавить через "
-"интерфейс. Пожалуйста, вручную настройте следующее в файле конфигурации app."
-"ini и перезапустите Nginx UI."
+"интерфейс. Пожалуйста, вручную настройте следующее в файле конфигурации "
+"app.ini и перезапустите Nginx UI."
 
 #: src/views/site/site_edit/components/Cert/IssueCert.vue:34
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and we "
-"need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and "
+"we need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
 "Чтобы убедиться, что автоматическое обновление сертификата может работать "
@@ -5367,9 +5360,9 @@ msgid ""
 "provide an OpenAI-compatible API endpoint, so just set the baseUrl to your "
 "local API."
 msgstr ""
-"Чтобы использовать локальную большую модель, разверните её с помощью ollama, "
-"vllm или lmdeploy. Они предоставляют API-эндпоинт, совместимый с OpenAI, "
-"поэтому просто установите baseUrl на ваш локальный API."
+"Чтобы использовать локальную большую модель, разверните её с помощью "
+"ollama, vllm или lmdeploy. Они предоставляют API-эндпоинт, совместимый с "
+"OpenAI, поэтому просто установите baseUrl на ваш локальный API."
 
 #: src/views/dashboard/NginxDashBoard.vue:55
 msgid "Toggle failed"
@@ -5438,7 +5431,7 @@ msgstr "Требуется двухфакторная аутентификаци
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
-#: src/views/nginx_log/NginxLogList.vue:12
+#: src/views/nginx_log/NginxLogList.vue:27
 #: src/views/notification/notificationColumns.tsx:8
 #: src/views/preference/components/ExternalNotify/columns.tsx:18
 msgid "Type"
@@ -5595,12 +5588,12 @@ msgstr "Проверьте системные требования"
 msgid "Version"
 msgstr "Версия"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:84
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:105
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
 msgid "View"
 msgstr "Просмотр"
 
-#: src/components/Notification/Notification.vue:181
+#: src/components/Notification/Notification.vue:178
 msgid "View all notifications"
 msgstr "Просмотреть все уведомления"
 
@@ -5650,11 +5643,11 @@ msgstr ""
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload the "
-"Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload "
+"the Nginx. Are you sure you want to continue?"
 msgstr ""
-"Мы удалим конфигурацию HTTPChallenge из этого файла и перезагрузим Nginx. Вы "
-"уверены, что хотите продолжить?"
+"Мы удалим конфигурацию HTTPChallenge из этого файла и перезагрузим Nginx. "
+"Вы уверены, что хотите продолжить?"
 
 #: src/views/preference/tabs/AuthSettings.vue:65
 msgid "Webauthn"
@@ -5687,8 +5680,8 @@ msgid ""
 "Pebble as CA."
 msgstr ""
 "При включении Nginx UI будет автоматически перерегистрировать пользователей "
-"при запуске. Обычно не включайте эту функцию, если только вы не находитесь в "
-"среде разработки и используете Pebble в качестве CA."
+"при запуске. Обычно не включайте эту функцию, если только вы не находитесь "
+"в среде разработки и используете Pebble в качестве CA."
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:61
 #: src/views/stream/components/RightPanel/Basic.vue:56
@@ -5696,8 +5689,8 @@ msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
 "Node Group and the nodes selected below will be synchronized."
 msgstr ""
-"При включении/отключении, удалении или сохранении этого сайта узлы, заданные "
-"в Группе узлов, и узлы, выбранные ниже, будут синхронизированы."
+"При включении/отключении, удалении или сохранении этого сайта узлы, "
+"заданные в Группе узлов, и узлы, выбранные ниже, будут синхронизированы."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5744,7 +5737,7 @@ msgid "Write private.key error: {0}"
 msgstr "Ошибка записи private.key: {0}"
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:377
+#: src/views/dashboard/ServerAnalytic.vue:380
 msgid "Writes"
 msgstr "Запись"
 
@@ -5767,8 +5760,8 @@ msgstr "Да"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a non-"
-"localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a "
+"non-localhost domain. This may expose sensitive information."
 msgstr ""
 "Вы обращаетесь к этому терминалу через небезопасное HTTP-соединение в "
 "домене, отличном от localhost. Это может раскрыть конфиденциальную "
@@ -5798,12 +5791,10 @@ msgstr "Теперь вы можете закрыть это диалогово
 msgid ""
 "You have not configured the settings of Webauthn, so you cannot add a "
 "passkey."
-msgstr ""
-"Вы не настроили параметры WebAuthn, поэтому не можете добавить ключ доступа."
+msgstr "Вы не настроили параметры WebAuthn, поэтому не можете добавить ключ доступа."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid ""
-"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
 "Вы еще не включили двухфакторную аутентификацию. Пожалуйста, включите её, "
 "чтобы сгенерировать коды восстановления."
@@ -5902,8 +5893,8 @@ msgstr "Ваши ключи доступа"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
-#~ "v /var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
+#~ "/var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
 #~ "Проверьте, существует ли /var/run/docker.sock. Если вы используете "
 #~ "официальный образ Docker Nginx UI, убедитесь, что сокет Docker подключен "
@@ -5942,8 +5933,7 @@ msgstr "Ваши ключи доступа"
 #~ msgstr "Ошибка формата %{msg}"
 
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
-#~ msgstr ""
-#~ "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации."
+#~ msgstr "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации."
 
 #, fuzzy
 #~ msgid "Access Token"
@@ -6006,16 +5996,13 @@ msgstr "Ваши ключи доступа"
 #~ "Синхронизация конфигурации %{cert_name} с %{env_name} не удалась, "
 #~ "пожалуйста, обновите удаленный Nginx UI до последней версии"
 
-#~ msgid ""
-#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
-#~ "%{resp}"
+#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
 #~ msgstr ""
-#~ "Переименование %{orig_path} в %{new_path} на %{env_name} не удалось, "
-#~ "ответ: %{resp}"
+#~ "Переименование %{orig_path} в %{new_path} на %{env_name} не удалось, ответ: "
+#~ "%{resp}"
 
 #, fuzzy
-#~ msgid ""
-#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
 #~ msgstr "Переименование %{orig_path} в %{new_path} на %{env_name} успешно"
 
 #, fuzzy
@@ -6031,20 +6018,19 @@ msgstr "Ваши ключи доступа"
 #~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, "
 #~ "пожалуйста, обновите удаленный интерфейс Nginx до последней версии"
 
-#~ msgid ""
-#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr ""
 #~ "Синхронизация сертификата %{cert_name} с %{env_name} не удалась, ответ: "
 #~ "%{resp}"
 
 #~ msgid "Sync config %{config_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr ""
-#~ "Синхронизация конфигурации %{config_name} с %{env_name} не удалась, "
-#~ "ответ: %{resp}"
+#~ "Синхронизация конфигурации %{config_name} с %{env_name} не удалась, ответ: "
+#~ "%{resp}"
 
 #~ msgid ""
-#~ "If you lose your mobile phone, you can use the recovery code to reset "
-#~ "your 2FA."
+#~ "If you lose your mobile phone, you can use the recovery code to reset your "
+#~ "2FA."
 #~ msgstr ""
 #~ "Если вы потеряете свой мобильный телефон, вы можете использовать код "
 #~ "восстановления для сброса 2FA."
@@ -6055,11 +6041,10 @@ msgstr "Ваши ключи доступа"
 #~ msgid "Recovery Code:"
 #~ msgstr "Код восстановления:"
 
-#~ msgid ""
-#~ "The recovery code is only displayed once, please save it in a safe place."
+#~ msgid "The recovery code is only displayed once, please save it in a safe place."
 #~ msgstr ""
-#~ "Код восстановления отображается только один раз, пожалуйста, сохраните "
-#~ "его в безопасном месте."
+#~ "Код восстановления отображается только один раз, пожалуйста, сохраните его "
+#~ "в безопасном месте."
 
 #~ msgid "Too many login failed attempts, please try again later"
 #~ msgstr "Слишком много неудачных попыток входа, попробуйте позже"

File diff suppressed because it is too large
+ 186 - 208
app/src/language/tr_TR/app.po


+ 189 - 199
app/src/language/uk_UA/app.po

@@ -4,11 +4,11 @@ msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
 "PO-Revision-Date: 2025-04-16 15:12+0000\n"
 "Last-Translator: sergio_from_tauri <dedysobr@gmail.com>\n"
-"Language-Team: Ukrainian <https://weblate.nginxui.com/projects/nginx-ui/"
-"frontend/uk/>\n"
+"Language-Team: Ukrainian "
+"<https://weblate.nginxui.com/projects/nginx-ui/frontend/uk/>\n"
 "Language: uk_UA\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
 "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
@@ -17,8 +17,8 @@ msgstr ""
 #: src/language/generate.ts:33
 msgid "[Nginx UI] ACME User: %{name}, Email: %{email}, CA Dir: %{caDir}"
 msgstr ""
-"[Nginx UI] Користувач ACME: %{name}, Електронна пошта: %{email}, Каталог CA: "
-"%{caDir}"
+"[Nginx UI] Користувач ACME: %{name}, Електронна пошта: %{email}, Каталог "
+"CA: %{caDir}"
 
 #: src/language/generate.ts:34
 msgid "[Nginx UI] Backing up current certificate for later revocation"
@@ -35,11 +35,10 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] Сертифікат успішно відкликано"
 
 #: src/language/generate.ts:37
-msgid ""
-"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr ""
-"[Nginx UI] Сертифікат використовувався для сервера, перезавантаження TLS-"
-"сертифіката сервера"
+"[Nginx UI] Сертифікат використовувався для сервера, перезавантаження "
+"TLS-сертифіката сервера"
 
 #: src/language/generate.ts:38
 msgid "[Nginx UI] Creating client facilitates communication with the CA server"
@@ -117,7 +116,7 @@ msgstr "2FA Налаштування"
 msgid "About"
 msgstr "Про программу"
 
-#: src/views/nginx_log/NginxLogList.vue:23
+#: src/views/nginx_log/NginxLogList.vue:38
 msgid "Access Log"
 msgstr "Логи доступу"
 
@@ -146,7 +145,7 @@ msgstr "Дія"
 #: src/views/config/configColumns.tsx:41
 #: src/views/environments/group/columns.ts:41
 #: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/nginx_log/NginxLogList.vue:67
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:76
 #: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:105
@@ -226,8 +225,7 @@ msgstr "Розширений режим"
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:99
 msgid "Afterwards, refresh this page and click add passkey again."
-msgstr ""
-"Після цього оновіть цю сторінку та натисніть «Додати ключ доступу» знову."
+msgstr "Після цього оновіть цю сторінку та натисніть «Додати ключ доступу» знову."
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:115
 msgid "All"
@@ -243,8 +241,8 @@ msgid ""
 "All selected subdomains must belong to the same DNS Provider, otherwise the "
 "certificate application will fail."
 msgstr ""
-"Усі вибрані піддомени повинні належати до одного й того самого DNS-"
-"провайдера, інакше запит на сертифікат не буде успішним."
+"Усі вибрані піддомени повинні належати до одного й того самого "
+"DNS-провайдера, інакше запит на сертифікат не буде успішним."
 
 #: src/views/preference/tabs/OpenAISettings.vue:32
 msgid "API Base Url"
@@ -290,7 +288,7 @@ msgstr "Підтверджуєте генерацію нових кодів ві
 msgid "Are you sure to reset 2FA?"
 msgstr "Ви впевнені, що хочете скинути 2FA?"
 
-#: src/components/Notification/Notification.vue:113
+#: src/components/Notification/Notification.vue:110
 #: src/views/notification/Notification.vue:40
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Ви впевнені, що бажаєте очистити всі сповіщення?"
@@ -425,7 +423,7 @@ msgstr "Автоматичне відновлення увімкнено для
 msgid "AutoCert is running, please wait..."
 msgstr "AutoCert виконується, будь ласка, зачекайте..."
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:41
+#: src/components/ProcessingStatus/ProcessingStatus.vue:38
 msgid "AutoCert is running..."
 msgstr "AutoCert виконується..."
 
@@ -456,8 +454,7 @@ msgstr "Резервна копія"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:155
 msgid "Backup file integrity check failed, it may have been tampered with"
-msgstr ""
-"Перевірка цілісності резервного файлу не вдалася, можливо, його було змінено"
+msgstr "Перевірка цілісності резервного файлу не вдалася, можливо, його було змінено"
 
 #: src/constants/errors/backup.ts:41
 msgid "Backup file not found: {0}"
@@ -482,8 +479,8 @@ msgstr "Шлях резервного копіювання не є директ
 #: src/constants/errors/backup.ts:62
 msgid "Backup path is required for custom directory backup"
 msgstr ""
-"Шлях резервного копіювання необхідний для резервного копіювання спеціального "
-"каталогу"
+"Шлях резервного копіювання необхідний для резервного копіювання "
+"спеціального каталогу"
 
 #: src/constants/errors/backup.ts:60
 msgid "Backup path not in granted access paths: {0}"
@@ -500,8 +497,7 @@ msgstr ""
 "%{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid ""
-"Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
 "Завдання резервного копіювання %{backup_name} не вдалося під час "
 "завантаження в сховище, помилка: %{error}"
@@ -585,8 +581,7 @@ msgstr "Кеш"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:178
 msgid "Cache items not accessed within this time will be removed"
-msgstr ""
-"Елементи кешу, до яких не було звернень протягом цього часу, будуть видалені"
+msgstr "Елементи кешу, до яких не було звернень протягом цього часу, будуть видалені"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:350
 msgid "Cache loader processing time threshold"
@@ -655,8 +650,7 @@ msgstr "Неможливо отримати доступ до шляху збе
 
 #: src/constants/errors/user.ts:11
 msgid "Cannot change initial user password in demo mode"
-msgstr ""
-"Не вдається змінити початковий пароль користувача в демонстраційному режимі"
+msgstr "Не вдається змінити початковий пароль користувача в демонстраційному режимі"
 
 #: src/components/ConfigHistory/DiffViewer.vue:72
 msgid "Cannot compare: Missing content"
@@ -811,24 +805,24 @@ msgstr "Перевірте ще раз"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v /"
-"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
-"run/docker.sock to communicate with the host Docker Engine via Docker Client "
-"API. This feature is used to control Nginx in another container and perform "
-"container replacement rather than binary replacement during OTA upgrades of "
-"Nginx UI to ensure container dependencies are also upgraded. If you don't "
-"need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v "
+"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
+"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
+"Client API. This feature is used to control Nginx in another container and "
+"perform container replacement rather than binary replacement during OTA "
+"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
+"you don't need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "Перевірте, чи існує /var/run/docker.sock. Якщо ви використовуєте офіційний "
 "образ Docker Nginx UI, переконайтеся, що сокет Docker змонтовано таким "
-"чином: `-v /var/run/docker.sock:/var/run/docker.sock`. Офіційний образ Nginx "
-"UI використовує /var/run/docker.sock для зв’язку з Docker Engine хоста через "
-"API Docker Client. Ця функція використовується для керування Nginx в іншому "
-"контейнері та виконання заміни контейнера замість заміни бінарного файлу під "
-"час OTA-оновлень Nginx UI, щоб гарантувати, що залежності контейнера також "
-"оновлюються. Якщо вам не потрібна ця функція, додайте змінну середовища "
-"NGINX_UI_IGNORE_DOCKER_SOCKET=true до контейнера."
+"чином: `-v /var/run/docker.sock:/var/run/docker.sock`. Офіційний образ "
+"Nginx UI використовує /var/run/docker.sock для зв’язку з Docker Engine "
+"хоста через API Docker Client. Ця функція використовується для керування "
+"Nginx в іншому контейнері та виконання заміни контейнера замість заміни "
+"бінарного файлу під час OTA-оновлень Nginx UI, щоб гарантувати, що "
+"залежності контейнера також оновлюються. Якщо вам не потрібна ця функція, "
+"додайте змінну середовища NGINX_UI_IGNORE_DOCKER_SOCKET=true до контейнера."
 
 #: src/components/SelfCheck/tasks/frontend/https-check.ts:14
 msgid ""
@@ -840,19 +834,19 @@ msgstr ""
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is obtained "
-"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
-"point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the access log path."
-"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
-"nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is "
+"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
+"does not point to a valid, existing file, an error will be reported. In "
+"this case, you need to modify the configuration file to specify the access "
+"log path.Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 msgstr ""
-"Перевірте, чи існує шлях до журналу доступу nginx. За замовчуванням цей шлях "
-"отримується з 'nginx -V'. Якщо його не вдається отримати або отриманий шлях "
-"не вказує на дійсний існуючий файл, буде повідомлено про помилку. У цьому "
-"випадку вам потрібно змінити файл конфігурації, щоб вказати шлях до журналу "
-"доступу. Докладніше див. у документації: https://nginxui.com/zh_CN/guide/"
-"config-nginx.html#accesslogpath"
+"Перевірте, чи існує шлях до журналу доступу nginx. За замовчуванням цей "
+"шлях отримується з 'nginx -V'. Якщо його не вдається отримати або отриманий "
+"шлях не вказує на дійсний існуючий файл, буде повідомлено про помилку. У "
+"цьому випадку вам потрібно змінити файл конфігурації, щоб вказати шлях до "
+"журналу доступу. Докладніше див. у документації: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
 msgid "Check if the nginx configuration directory exists"
@@ -868,29 +862,29 @@ msgid ""
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
 "you need to modify the configuration file to specify the error log path. "
-"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
-"nginx.html#errorlogpath"
+"Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 msgstr ""
-"Перевірте, чи існує шлях до журналу помилок nginx. За замовчуванням цей шлях "
-"отримується з 'nginx -V'. Якщо його не вдається отримати або отриманий шлях "
-"не вказує на дійсний існуючий файл, буде повідомлено про помилку. У цьому "
-"випадку вам потрібно змінити файл конфігурації, щоб вказати шлях до журналу "
-"помилок. Докладніше див. у документації: https://nginxui.com/zh_CN/guide/"
-"config-nginx.html#errorlogpath"
+"Перевірте, чи існує шлях до журналу помилок nginx. За замовчуванням цей "
+"шлях отримується з 'nginx -V'. Якщо його не вдається отримати або отриманий "
+"шлях не вказує на дійсний існуючий файл, буде повідомлено про помилку. У "
+"цьому випадку вам потрібно змінити файл конфігурації, щоб вказати шлях до "
+"журналу помилок. Докладніше див. у документації: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
-"config-nginx.html#pidpath"
+"path.Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 msgstr ""
-"Перевірте, чи існує шлях до PID Nginx. За замовчуванням цей шлях отримується "
-"з команди 'nginx -V'. Якщо його не вдається отримати, буде повідомлено про "
-"помилку. У цьому випадку вам потрібно змінити конфігураційний файл, щоб "
-"вказати шлях до PID Nginx. Докладніше див. у документації: https://nginxui."
-"com/zh_CN/guide/config-nginx.html#pidpath"
+"Перевірте, чи існує шлях до PID Nginx. За замовчуванням цей шлях "
+"отримується з команди 'nginx -V'. Якщо його не вдається отримати, буде "
+"повідомлено про помилку. У цьому випадку вам потрібно змінити "
+"конфігураційний файл, щоб вказати шлях до PID Nginx. Докладніше див. у "
+"документації: https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx sbin path exists"
@@ -918,8 +912,8 @@ msgstr ""
 
 #: src/language/generate.ts:17
 msgid ""
-"Check if the streams-available and streams-enabled directories are under the "
-"nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under "
+"the nginx configuration directory"
 msgstr ""
 "Перевірте, чи каталоги streams-available та streams-enabled знаходяться в "
 "каталозі конфігурації nginx"
@@ -933,12 +927,12 @@ msgid "Cleaning environment variables"
 msgstr "Змінні навколишнього середовища очищення"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:23
-#: src/components/Notification/Notification.vue:118
+#: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
 msgstr "Чіткий"
 
-#: src/components/Notification/Notification.vue:71
+#: src/components/Notification/Notification.vue:68
 #: src/views/notification/Notification.vue:13
 msgid "Cleared successfully"
 msgstr "Успішно очищено"
@@ -1134,7 +1128,7 @@ msgstr "Копіювати коди"
 msgid "Core Upgrade"
 msgstr "Оновлення ядра"
 
-#: src/views/dashboard/ServerAnalytic.vue:305
+#: src/views/dashboard/ServerAnalytic.vue:308
 msgid "CPU Status"
 msgstr "Статус процесора"
 
@@ -1233,8 +1227,8 @@ msgstr ""
 "\"Вірність\" означає точність до змісту та наміру оригінального тексту;\n"
 "\"Плавність\" означає, що переклад має бути зрозумілим та легким для "
 "сприйняття;\n"
-"\"Витонченість\" означає прагнення до культурної естетики перекладу та краси "
-"мови.\n"
+"\"Витонченість\" означає прагнення до культурної естетики перекладу та "
+"краси мови.\n"
 "Мета полягає у створенні перекладу, який був би вірним духу оригіналу,\n"
 "а також відповідав цільовій мові, культурі та естетичним уподобанням "
 "читачів.\n"
@@ -1296,8 +1290,7 @@ msgstr "Сертифікат користувацьких доменів"
 msgid ""
 "Customize the name of local node to be displayed in the environment "
 "indicator."
-msgstr ""
-"Налаштуйте назву локального вузла для відображення в індикаторі середовища."
+msgstr "Налаштуйте назву локального вузла для відображення в індикаторі середовища."
 
 #: src/views/backup/AutoBackup/components/CronEditor.vue:19
 msgid "Daily"
@@ -1332,8 +1325,7 @@ msgstr "Розшифрування не вдалося"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:150
 msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
-msgstr ""
-"Вкажіть назву та розмір зони спільної пам'яті, наприклад proxy_cache:10m"
+msgstr "Вкажіть назву та розмір зони спільної пам'яті, наприклад proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:110
 #: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
@@ -1597,7 +1589,7 @@ msgstr "Вимкнено"
 msgid "Disabled successfully"
 msgstr "Успішно вимкнено"
 
-#: src/views/dashboard/ServerAnalytic.vue:370
+#: src/views/dashboard/ServerAnalytic.vue:373
 msgid "Disk IO"
 msgstr "Дисковий ввід/вивід"
 
@@ -1668,8 +1660,7 @@ msgstr "Домен"
 
 #: src/views/certificate/CertificateEditor.vue:109
 msgid "Domains list is empty, try to reopen Auto Cert for %{config}"
-msgstr ""
-"Список доменів порожній, спробуйте знову відкрити Auto Cert для %{config}"
+msgstr "Список доменів порожній, спробуйте знову відкрити Auto Cert для %{config}"
 
 #: src/language/constants.ts:27
 msgid "Download latest release error"
@@ -1689,8 +1680,9 @@ msgid ""
 "Due to the security policies of some browsers, you cannot use passkeys on "
 "non-HTTPS websites, except when running on localhost."
 msgstr ""
-"Через політику безпеки деяких браузерів ви не можете використовувати пас-"
-"ключі на вебсайтах без HTTPS, окрім випадків, коли сайт працює на localhost."
+"Через політику безпеки деяких браузерів ви не можете використовувати "
+"пас-ключі на вебсайтах без HTTPS, окрім випадків, коли сайт працює на "
+"localhost."
 
 #: src/views/site/site_list/SiteDuplicate.vue:72
 #: src/views/site/site_list/SiteList.vue:108
@@ -1896,7 +1888,7 @@ msgstr "Помилка"
 msgid "Error initializing diff viewer"
 msgstr "Помилка ініціалізації переглядача різниць"
 
-#: src/views/nginx_log/NginxLogList.vue:27
+#: src/views/nginx_log/NginxLogList.vue:42
 msgid "Error Log"
 msgstr "Журнал помилок"
 
@@ -2347,8 +2339,8 @@ msgid ""
 "Follow the instructions in the dialog to complete the passkey registration "
 "process."
 msgstr ""
-"Дотримуйтесь інструкцій у діалоговому вікні, щоб завершити процес реєстрації "
-"ключа доступу."
+"Дотримуйтесь інструкцій у діалоговому вікні, щоб завершити процес "
+"реєстрації ключа доступу."
 
 #: src/views/preference/tabs/NodeSettings.vue:42
 #: src/views/preference/tabs/NodeSettings.vue:54
@@ -2512,13 +2504,11 @@ msgstr ""
 msgid ""
 "If you want to automatically revoke the old certificate, please enable this "
 "option."
-msgstr ""
-"Якщо ви хочете автоматично відкликати старий сертифікат, увімкніть цю опцію."
+msgstr "Якщо ви хочете автоматично відкликати старий сертифікат, увімкніть цю опцію."
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
-msgstr ""
-"Якщо ваш браузер підтримує WebAuthn Passkey, з’явиться діалогове вікно."
+msgstr "Якщо ваш браузер підтримує WebAuthn Passkey, з’явиться діалогове вікно."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:113
 msgid ""
@@ -2549,7 +2539,7 @@ msgstr ""
 "Включає головний процес, робочі процеси, процеси кешування та інші процеси "
 "Nginx"
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:34
+#: src/components/ProcessingStatus/ProcessingStatus.vue:31
 msgid "Indexing..."
 msgstr "Індексація..."
 
@@ -2706,8 +2696,8 @@ msgid ""
 "Keep your recovery codes as safe as your password. We recommend saving them "
 "with a password manager."
 msgstr ""
-"Зберігайте ваші коди відновлення так само надійно, як і пароль. Рекомендуємо "
-"зберігати їх у менеджері паролів."
+"Зберігайте ваші коди відновлення так само надійно, як і пароль. "
+"Рекомендуємо зберігати їх у менеджері паролів."
 
 #: src/views/dashboard/components/ParamsOpt/PerformanceConfig.vue:60
 msgid "Keepalive Timeout"
@@ -2756,8 +2746,7 @@ msgstr "Залиште порожнім, щоб не змінювати"
 
 #: src/views/preference/tabs/OpenAISettings.vue:41
 msgid "Leave blank for the default: https://api.openai.com/"
-msgstr ""
-"Залиште порожнім для значення за замовчуванням: https://api.openai.com/"
+msgstr "Залиште порожнім для значення за замовчуванням: https://api.openai.com/"
 
 #: src/language/curd.ts:37
 msgid "Leave blank if do not want to modify"
@@ -2862,14 +2851,15 @@ msgstr "Журнал"
 #: src/language/generate.ts:21
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
-"nginx-log.html for more information."
+"docker container, please refer to "
+"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
 msgstr ""
-"Файл журналу %{log_path} не є звичайним файлом. Якщо ви використовуєте nginx-"
-"ui у контейнері Docker, будь ласка, зверніться до https://nginxui.com/zh_CN/"
-"guide/config-nginx-log.html для отримання додаткової інформації."
+"Файл журналу %{log_path} не є звичайним файлом. Якщо ви використовуєте "
+"nginx-ui у контейнері Docker, будь ласка, зверніться до "
+"https://nginxui.com/zh_CN/guide/config-nginx-log.html для отримання "
+"додаткової інформації."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:87
 msgid "Log List"
 msgstr "Список журналів"
 
@@ -2891,16 +2881,16 @@ msgstr "Logrotate"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions for "
-"users who install Nginx UI on the host machine, so you don't need to modify "
-"the parameters on this page. For users who install Nginx UI using Docker "
-"containers, you can manually enable this option. The crontab task scheduler "
-"of Nginx UI will execute the logrotate command at the interval you set in "
-"minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions "
+"for users who install Nginx UI on the host machine, so you don't need to "
+"modify the parameters on this page. For users who install Nginx UI using "
+"Docker containers, you can manually enable this option. The crontab task "
+"scheduler of Nginx UI will execute the logrotate command at the interval "
+"you set in minutes."
 msgstr ""
 "Logrotate за замовчуванням увімкнено у більшості популярних дистрибутивів "
-"Linux для користувачів, які встановлюють Nginx UI безпосередньо на хост-"
-"машині, тому вам не потрібно змінювати параметри на цій сторінці. Для "
+"Linux для користувачів, які встановлюють Nginx UI безпосередньо на "
+"хост-машині, тому вам не потрібно змінювати параметри на цій сторінці. Для "
 "користувачів, які встановлюють Nginx UI за допомогою контейнерів Docker, ви "
 "можете вручну активувати цю опцію. Планувальник завдань crontab у Nginx UI "
 "виконуватиме команду logrotate з інтервалом, який ви встановите у хвилинах."
@@ -3025,8 +3015,8 @@ msgstr "Максимальний загальний розмір кешу"
 msgid "Maximum worker process number:"
 msgstr "Максимальна кількість робочих процесів:"
 
-#: src/views/dashboard/ServerAnalytic.vue:226
 #: src/views/dashboard/ServerAnalytic.vue:227
+#: src/views/dashboard/ServerAnalytic.vue:228
 msgid "Memory"
 msgstr "Пам'ять"
 
@@ -3116,7 +3106,7 @@ msgstr "Багаторядкова директива"
 #: src/views/config/configColumns.tsx:5
 #: src/views/environments/group/columns.ts:7
 #: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:36
+#: src/views/nginx_log/NginxLogList.vue:51
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:75
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:35
 #: src/views/site/site_list/columns.tsx:16
@@ -3132,19 +3122,19 @@ msgstr "Ім'я"
 msgid "Need to enable the stub_status module"
 msgstr "Потрібно активувати модуль stub_status"
 
-#: src/views/dashboard/ServerAnalytic.vue:331
+#: src/views/dashboard/ServerAnalytic.vue:334
 msgid "Network"
 msgstr "Мережа"
 
-#: src/views/dashboard/ServerAnalytic.vue:273
+#: src/views/dashboard/ServerAnalytic.vue:276
 msgid "Network Statistics"
 msgstr "Мережева статистика"
 
-#: src/views/dashboard/ServerAnalytic.vue:280
+#: src/views/dashboard/ServerAnalytic.vue:283
 msgid "Network Total Receive"
 msgstr "Загальний обсяг отриманих мережевих даних"
 
-#: src/views/dashboard/ServerAnalytic.vue:286
+#: src/views/dashboard/ServerAnalytic.vue:289
 msgid "Network Total Send"
 msgstr "Загальна кількість відправлених даних"
 
@@ -3375,8 +3365,8 @@ msgstr "Конфігурацію Nginx UI відновлено"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in a "
-"few seconds."
+"Nginx UI configuration has been restored and will restart automatically in "
+"a few seconds."
 msgstr ""
 "Конфігурацію Nginx UI відновлено, і вона автоматично перезавантажиться за "
 "кілька секунд."
@@ -3398,7 +3388,7 @@ msgstr "Nginx.conf включає каталог streams-enabled"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:143
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:99
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
-#: src/components/Notification/Notification.vue:111 src/language/curd.ts:38
+#: src/components/Notification/Notification.vue:108 src/language/curd.ts:38
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
@@ -3490,7 +3480,7 @@ msgstr ""
 msgid "Notification"
 msgstr "Сповіщення"
 
-#: src/components/Notification/Notification.vue:109
+#: src/components/Notification/Notification.vue:106
 #: src/routes/modules/notifications.ts:10
 msgid "Notifications"
 msgstr "Сповіщення"
@@ -3561,7 +3551,7 @@ msgstr "Офлайн"
 #: src/components/ChatGPT/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:36
-#: src/components/Notification/Notification.vue:112 src/language/curd.ts:15
+#: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
 #: src/views/backup/components/BackupCreator.vue:149
 #: src/views/notification/Notification.vue:39
 #: src/views/site/components/SiteStatusSelect.vue:123
@@ -3706,7 +3696,7 @@ msgstr "Паролі не збігаються"
 #: src/language/curd.ts:59
 #: src/views/config/components/ConfigRightPanel/Basic.vue:41
 #: src/views/config/components/Delete.vue:124
-#: src/views/nginx_log/NginxLogList.vue:44
+#: src/views/nginx_log/NginxLogList.vue:59
 msgid "Path"
 msgstr "Шлях"
 
@@ -3798,8 +3788,7 @@ msgstr "Будь ласка, введіть токен безпеки"
 #: src/components/SystemRestore/SystemRestoreContent.vue:210
 #: src/components/SystemRestore/SystemRestoreContent.vue:287
 msgid "Please enter the security token received during backup"
-msgstr ""
-"Будь ласка, введіть токен безпеки, отриманий під час резервного копіювання"
+msgstr "Будь ласка, введіть токен безпеки, отриманий під час резервного копіювання"
 
 #: src/language/curd.ts:24
 msgid "Please fill all fields correctly"
@@ -3827,8 +3816,8 @@ msgstr ""
 #: src/components/Notification/notifications.ts:190
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to prevent "
-"lockout."
+"Please generate new recovery codes in the preferences immediately to "
+"prevent lockout."
 msgstr ""
 "Будь ласка, негайно згенеруйте нові коди відновлення в налаштуваннях, щоб "
 "уникнути блокування."
@@ -3876,8 +3865,7 @@ msgid "Please log in."
 msgstr "Будь ласка, увійдіть."
 
 #: src/views/certificate/DNSCredential.vue:75
-msgid ""
-"Please note that the unit of time configurations below are all in seconds."
+msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Будь ласка, зверніть увагу, що одиницею виміру часу в наведених нижче "
 "налаштуваннях є секунди."
@@ -3889,7 +3877,8 @@ msgstr "Будь ласка, усуньте всі проблеми перед 
 #: src/views/backup/components/BackupCreator.vue:107
 msgid "Please save this security token, you will need it for restoration:"
 msgstr ""
-"Будь ласка, збережіть цей токен безпеки, він знадобиться вам для відновлення:"
+"Будь ласка, збережіть цей токен безпеки, він знадобиться вам для "
+"відновлення:"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:107
 msgid "Please select a backup file"
@@ -4016,11 +4005,11 @@ msgid "Read requests"
 msgstr "Запити на читання"
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:387
+#: src/views/dashboard/ServerAnalytic.vue:390
 msgid "Reads"
 msgstr "Читання"
 
-#: src/views/dashboard/ServerAnalytic.vue:338
+#: src/views/dashboard/ServerAnalytic.vue:341
 #: src/views/dashboard/ServerAnalytic.vue:35
 msgid "Receive"
 msgstr "Отримання"
@@ -4155,7 +4144,7 @@ msgstr "Видалити"
 msgid "Remove successfully"
 msgstr "Успішно видалено"
 
-#: src/components/Notification/Notification.vue:80
+#: src/components/Notification/Notification.vue:77
 msgid "Removed successfully"
 msgstr "Успішно видалено"
 
@@ -4280,9 +4269,9 @@ msgid ""
 "shared library memory, which will be repeated calculated for multiple "
 "processes"
 msgstr ""
-"Розмір резидентного набору: Фактична пам'ять, резидентна у фізичній пам'яті, "
-"включаючи всю пам'ять спільних бібліотек, яка буде повторно обчислюватися "
-"для кількох процесів"
+"Розмір резидентного набору: Фактична пам'ять, резидентна у фізичній "
+"пам'яті, включаючи всю пам'ять спільних бібліотек, яка буде повторно "
+"обчислюватися для кількох процесів"
 
 #: src/composables/usePerformanceMetrics.ts:109
 #: src/views/dashboard/components/PerformanceTablesCard.vue:69
@@ -4604,6 +4593,10 @@ msgstr ""
 "Відскануйте QR-код за допомогою мобільного телефону, щоб додати обліковий "
 "запис до програми."
 
+#: src/views/nginx_log/NginxLogList.vue:100
+msgid "Scanning logs..."
+msgstr "Сканування журналів..."
+
 #: src/views/backup/AutoBackup/AutoBackup.vue:113
 msgid "Schedule"
 msgstr "Розклад"
@@ -4666,8 +4659,8 @@ msgstr "Самоперевірка"
 msgid "Self check failed, Nginx UI may not work properly"
 msgstr "Самоперевірка не вдалася, інтерфейс Nginx може працювати неправильно"
 
-#: src/views/dashboard/ServerAnalytic.vue:348
 #: src/views/dashboard/ServerAnalytic.vue:35
+#: src/views/dashboard/ServerAnalytic.vue:351
 msgid "Send"
 msgstr "Надіслати"
 
@@ -4739,19 +4732,21 @@ msgstr "Налаштування провайдера HTTP01-виклику"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
+"https://nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.AccessLogPath порожній, див. https://nginxui.com/"
-"guide/config-nginx.html для отримання додаткової інформації"
+"Settings.NginxLogSettings.AccessLogPath порожній, див. "
+"https://nginxui.com/guide/config-nginx.html для отримання додаткової "
+"інформації"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
+"https://nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.ErrorLogPath порожній, див. https://nginxui.com/"
-"guide/config-nginx.html для отримання додаткової інформації"
+"Settings.NginxLogSettings.ErrorLogPath порожній, див. "
+"https://nginxui.com/guide/config-nginx.html для отримання додаткової "
+"інформації"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4831,8 +4826,7 @@ msgstr "Вміст SSL-сертифіката"
 
 #: src/constants/errors/system.ts:8
 msgid "SSL certificate file must be under Nginx configuration directory: {0}"
-msgstr ""
-"Файл SSL-сертифіката повинен знаходитися в каталозі конфігурації Nginx: {0}"
+msgstr "Файл SSL-сертифіката повинен знаходитися в каталозі конфігурації Nginx: {0}"
 
 #: src/constants/errors/system.ts:6
 msgid "SSL certificate file not found"
@@ -4910,8 +4904,8 @@ msgstr "Статус"
 msgid "Stopped"
 msgstr "Зупинено"
 
-#: src/views/dashboard/ServerAnalytic.vue:254
-#: src/views/dashboard/ServerAnalytic.vue:255
+#: src/views/dashboard/ServerAnalytic.vue:257
+#: src/views/dashboard/ServerAnalytic.vue:258
 msgid "Storage"
 msgstr "Сховище"
 
@@ -4989,25 +4983,25 @@ msgstr "Неділя"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: https://"
-"nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "Підтримка зв’язку з бекендом через протокол Server-Sent Events. Якщо ваш "
 "Nginx UI використовується через зворотний проксі Nginx, перейдіть за цим "
-"посиланням, щоб написати відповідний конфігураційний файл: https://nginxui."
-"com/guide/nginx-proxy-example.html"
+"посиланням, щоб написати відповідний конфігураційний файл: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
-"link to write the corresponding configuration file: https://nginxui.com/"
-"guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
+"this link to write the corresponding configuration file: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "Підтримка зв'язку з бекендом через протокол WebSocket. Якщо ваш Nginx UI "
-"використовується через зворотний проксі Nginx, перегляньте це посилання, щоб "
-"написати відповідний конфігураційний файл: https://nginxui.com/guide/nginx-"
-"proxy-example.html"
+"використовується через зворотний проксі Nginx, перегляньте це посилання, "
+"щоб написати відповідний конфігураційний файл: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/language/curd.ts:51 src/language/curd.ts:55
 msgid "Support single or batch upload of files"
@@ -5022,8 +5016,8 @@ msgstr "Підтримка завантаження цілих папок"
 msgid "Supported file type: .zip"
 msgstr "Підтримуваний тип файлу: .zip"
 
-#: src/views/dashboard/ServerAnalytic.vue:240
-#: src/views/dashboard/ServerAnalytic.vue:241
+#: src/views/dashboard/ServerAnalytic.vue:242
+#: src/views/dashboard/ServerAnalytic.vue:243
 msgid "Swap"
 msgstr "Своп"
 
@@ -5174,10 +5168,11 @@ msgstr "Введений текст не є ключем SSL-сертифіка
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in "
+"settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"Шлях до журналу не знаходиться серед шляхів у settings.NginxSettings."
-"LogDirWhiteList"
+"Шлях до журналу не знаходиться серед шляхів у "
+"settings.NginxSettings.LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -5189,8 +5184,7 @@ msgstr ""
 "двокрапки та крапки."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid ""
-"The model used for code completion, if not set, the chat model will be used."
+msgid "The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "Модель, яка використовується для завершення коду. Якщо вона не встановлена, "
 "буде використовуватися модель чату."
@@ -5276,7 +5270,8 @@ msgstr ""
 #: src/views/certificate/CertificateEditor.vue:99
 msgid "This Auto Cert item is invalid, please remove it."
 msgstr ""
-"Цей елемент автоматичного сертифікату є недійсним, будь ласка, видаліть його."
+"Цей елемент автоматичного сертифікату є недійсним, будь ласка, видаліть "
+"його."
 
 #: src/views/certificate/CertificateEditor.vue:89
 msgid "This certificate is managed by Nginx UI"
@@ -5305,14 +5300,13 @@ msgid "This field should not be empty"
 msgstr "Це поле не повинно бути порожнім"
 
 #: src/constants/form_errors.ts:6
-msgid ""
-"This field should only contain letters, unicode characters, numbers, and -_."
+msgid "This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "Це поле має містити лише літери, символи Unicode, цифри та -_."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and -"
-"_./:"
+"This field should only contain letters, unicode characters, numbers, and "
+"-_./:"
 msgstr "Це поле має містити лише літери, символи Unicode, цифри та -_./:"
 
 #: src/views/dashboard/NginxDashBoard.vue:155
@@ -5366,10 +5360,8 @@ msgstr ""
 "після завершення відновлення."
 
 #: src/views/environments/list/BatchUpgrader.vue:183
-msgid ""
-"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
-msgstr ""
-"Це оновить або перевстановить Nginx UI на %{nodeNames} до версії %{version}."
+msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgstr "Це оновить або перевстановить Nginx UI на %{nodeNames} до версії %{version}."
 
 #: src/views/preference/tabs/AuthSettings.vue:92
 msgid "Throttle"
@@ -5406,8 +5398,8 @@ msgid ""
 "To enable it, you need to install the Google or Microsoft Authenticator app "
 "on your mobile phone."
 msgstr ""
-"Щоб увімкнути його, вам потрібно встановити додаток Google Authenticator або "
-"Microsoft Authenticator на свій мобільний телефон."
+"Щоб увімкнути його, вам потрібно встановити додаток Google Authenticator "
+"або Microsoft Authenticator на свій мобільний телефон."
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:89
 msgid ""
@@ -5416,15 +5408,15 @@ msgid ""
 "and restart Nginx UI."
 msgstr ""
 "Для забезпечення безпеки конфігурацію WebAuthn не можна додати через "
-"інтерфейс. Будь ласка, налаштуйте вручну наступне у файлі конфігурації app."
-"ini та перезапустіть Nginx UI."
+"інтерфейс. Будь ласка, налаштуйте вручну наступне у файлі конфігурації "
+"app.ini та перезапустіть Nginx UI."
 
 #: src/views/site/site_edit/components/Cert/IssueCert.vue:34
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and we "
-"need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and "
+"we need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
 "Щоб гарантувати нормальну роботу автоматичного поновлення сертифікатів, нам "
@@ -5509,7 +5501,7 @@ msgstr "Потрібна двофакторна аутентифікація"
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
-#: src/views/nginx_log/NginxLogList.vue:12
+#: src/views/nginx_log/NginxLogList.vue:27
 #: src/views/notification/notificationColumns.tsx:8
 #: src/views/preference/components/ExternalNotify/columns.tsx:18
 msgid "Type"
@@ -5666,12 +5658,12 @@ msgstr "Перевірте системні вимоги"
 msgid "Version"
 msgstr "Версія"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:84
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:105
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
 msgid "View"
 msgstr "Переглянути"
 
-#: src/components/Notification/Notification.vue:181
+#: src/components/Notification/Notification.vue:178
 msgid "View all notifications"
 msgstr "Переглянути всі сповіщення"
 
@@ -5721,8 +5713,8 @@ msgstr ""
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload the "
-"Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload "
+"the Nginx. Are you sure you want to continue?"
 msgstr ""
 "Ми видалимо конфігурацію HTTPChallenge з цього файлу та перезавантажимо "
 "Nginx. Ви впевнені, що хочете продовжити?"
@@ -5815,7 +5807,7 @@ msgid "Write private.key error: {0}"
 msgstr "Помилка запису private.key: {0}"
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:377
+#: src/views/dashboard/ServerAnalytic.vue:380
 msgid "Writes"
 msgstr "Записи"
 
@@ -5838,8 +5830,8 @@ msgstr "Так"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a non-"
-"localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a "
+"non-localhost domain. This may expose sensitive information."
 msgstr ""
 "Ви отримуєте доступ до цього терміналу через незахищене HTTP-з’єднання в "
 "домені, який не є локальним. Це може призвести до витоку конфіденційної "
@@ -5869,15 +5861,13 @@ msgstr "Тепер ви можете закрити це діалогове ві
 msgid ""
 "You have not configured the settings of Webauthn, so you cannot add a "
 "passkey."
-msgstr ""
-"Ви не налаштували параметри WebAuthn, тому не можете додати ключ доступу."
+msgstr "Ви не налаштували параметри WebAuthn, тому не можете додати ключ доступу."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid ""
-"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
-"Ви ще не ввімкнули двофакторну аутентифікацію. Будь ласка, увімкніть її, щоб "
-"згенерувати коди відновлення."
+"Ви ще не ввімкнули двофакторну аутентифікацію. Будь ласка, увімкніть її, "
+"щоб згенерувати коди відновлення."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:94
 msgid "You have not generated recovery codes yet."
@@ -5972,12 +5962,12 @@ msgstr "Ваші ключі доступу"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
-#~ "v /var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
+#~ "/var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
-#~ "Перевірте, чи існує /var/run/docker.sock. Якщо ви використовуєте "
-#~ "офіційний Docker-образ Nginx UI, переконайтеся, що сокет Docker "
-#~ "підключено таким чином: `-v /var/run/docker.sock:/var/run/docker.sock`."
+#~ "Перевірте, чи існує /var/run/docker.sock. Якщо ви використовуєте офіційний "
+#~ "Docker-образ Nginx UI, переконайтеся, що сокет Docker підключено таким "
+#~ "чином: `-v /var/run/docker.sock:/var/run/docker.sock`."
 
 #~ msgid "Check if the nginx access log path exists"
 #~ msgstr "Перевірити, чи існує шлях до журналу доступу nginx"

+ 196 - 211
app/src/language/vi_VN/app.po

@@ -5,14 +5,13 @@ msgstr ""
 "Language-Team: none\n"
 "Language: vi_VN\n"
 "MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Type: text/plain; charset=utf-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
 
 #: src/language/generate.ts:33
 msgid "[Nginx UI] ACME User: %{name}, Email: %{email}, CA Dir: %{caDir}"
-msgstr ""
-"[Nginx UI] Người dùng ACME: %{name}, Email: %{email}, Thư mục CA: %{caDir}"
+msgstr "[Nginx UI] Người dùng ACME: %{name}, Email: %{email}, Thư mục CA: %{caDir}"
 
 #: src/language/generate.ts:34
 msgid "[Nginx UI] Backing up current certificate for later revocation"
@@ -27,11 +26,10 @@ msgid "[Nginx UI] Certificate successfully revoked"
 msgstr "[Nginx UI] Hủy chứng chỉ thành công"
 
 #: src/language/generate.ts:37
-msgid ""
-"[Nginx UI] Certificate was used for server, reloading server TLS certificate"
+msgid "[Nginx UI] Certificate was used for server, reloading server TLS certificate"
 msgstr ""
-"[Nginx UI] Chứng chỉ đã được sử dụng cho máy chủ, đang tải lại chứng chỉ TLS "
-"của máy chủ"
+"[Nginx UI] Chứng chỉ đã được sử dụng cho máy chủ, đang tải lại chứng chỉ "
+"TLS của máy chủ"
 
 #: src/language/generate.ts:38
 msgid "[Nginx UI] Creating client facilitates communication with the CA server"
@@ -109,7 +107,7 @@ msgstr "Cài đặt 2FA"
 msgid "About"
 msgstr "Tác giả"
 
-#: src/views/nginx_log/NginxLogList.vue:23
+#: src/views/nginx_log/NginxLogList.vue:38
 msgid "Access Log"
 msgstr "Nhật ký truy cập"
 
@@ -138,7 +136,7 @@ msgstr "Hành động"
 #: src/views/config/configColumns.tsx:41
 #: src/views/environments/group/columns.ts:41
 #: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/nginx_log/NginxLogList.vue:67
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:76
 #: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:105
@@ -281,7 +279,7 @@ msgstr "Bạn có chắc chắn muốn tạo mã khôi phục mới không?"
 msgid "Are you sure to reset 2FA?"
 msgstr "Bạn có chắc chắn muốn đặt lại xác thực hai yếu tố không?"
 
-#: src/components/Notification/Notification.vue:113
+#: src/components/Notification/Notification.vue:110
 #: src/views/notification/Notification.vue:40
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Bạn có chắc chắn muốn xóa tất cả thông báo không?"
@@ -317,8 +315,7 @@ msgstr "Bạn có chắc chắn muốn xóa vị trí này không?"
 
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:141
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
-msgstr ""
-"Bạn có chắc chắn muốn khởi động lại Nginx trên các nút đồng bộ sau không?"
+msgstr "Bạn có chắc chắn muốn khởi động lại Nginx trên các nút đồng bộ sau không?"
 
 #: src/language/curd.ts:26
 msgid "Are you sure you want to restore?"
@@ -413,7 +410,7 @@ msgstr "Đã bật tự động gia hạn SSL cho %{name}"
 msgid "AutoCert is running, please wait..."
 msgstr "AutoCert đang chạy, vui lòng chờ..."
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:41
+#: src/components/ProcessingStatus/ProcessingStatus.vue:38
 msgid "AutoCert is running..."
 msgstr "AutoCert đang chạy..."
 
@@ -444,8 +441,7 @@ msgstr "Sao lưu"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:155
 msgid "Backup file integrity check failed, it may have been tampered with"
-msgstr ""
-"Kiểm tra tính toàn vẹn của tập tin sao lưu thất bại, có thể đã bị can thiệp"
+msgstr "Kiểm tra tính toàn vẹn của tập tin sao lưu thất bại, có thể đã bị can thiệp"
 
 #: src/constants/errors/backup.ts:41
 msgid "Backup file not found: {0}"
@@ -481,15 +477,13 @@ msgstr "Lịch trình sao lưu"
 
 #: src/components/Notification/notifications.ts:38
 msgid "Backup task %{backup_name} completed successfully, file: %{file_path}"
-msgstr ""
-"Tác vụ sao lưu %{backup_name} đã hoàn thành thành công, tệp: %{file_path}"
+msgstr "Tác vụ sao lưu %{backup_name} đã hoàn thành thành công, tệp: %{file_path}"
 
 #: src/components/Notification/notifications.ts:34
-msgid ""
-"Backup task %{backup_name} failed during storage upload, error: %{error}"
+msgid "Backup task %{backup_name} failed during storage upload, error: %{error}"
 msgstr ""
-"Tác vụ sao lưu %{backup_name} thất bại trong quá trình tải lên lưu trữ, lỗi: "
-"%{error}"
+"Tác vụ sao lưu %{backup_name} thất bại trong quá trình tải lên lưu trữ, "
+"lỗi: %{error}"
 
 #: src/components/Notification/notifications.ts:30
 msgid "Backup task %{backup_name} failed to execute, error: %{error}"
@@ -791,13 +785,13 @@ msgstr "Kiểm tra lại"
 #: src/language/generate.ts:6
 msgid ""
 "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-"Docker Image, please make sure the docker socket is mounted like this: `-v /"
-"var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses /var/"
-"run/docker.sock to communicate with the host Docker Engine via Docker Client "
-"API. This feature is used to control Nginx in another container and perform "
-"container replacement rather than binary replacement during OTA upgrades of "
-"Nginx UI to ensure container dependencies are also upgraded. If you don't "
-"need this feature, please add the environment variable "
+"Docker Image, please make sure the docker socket is mounted like this: `-v "
+"/var/run/docker.sock:/var/run/docker.sock`. Nginx UI official image uses "
+"/var/run/docker.sock to communicate with the host Docker Engine via Docker "
+"Client API. This feature is used to control Nginx in another container and "
+"perform container replacement rather than binary replacement during OTA "
+"upgrades of Nginx UI to ensure container dependencies are also upgraded. If "
+"you don't need this feature, please add the environment variable "
 "NGINX_UI_IGNORE_DOCKER_SOCKET=true to the container."
 msgstr ""
 "Kiểm tra xem /var/run/docker.sock có tồn tại không. Nếu bạn đang sử dụng "
@@ -816,23 +810,23 @@ msgid ""
 "Check if HTTPS is enabled. Using HTTP outside localhost is insecure and "
 "prevents using Passkeys and clipboard features"
 msgstr ""
-"Kiểm tra xem HTTPS có được bật không. Sử dụng HTTP bên ngoài localhost không "
-"an toàn và ngăn chặn việc sử dụng tính năng Passkeys và clipboard"
+"Kiểm tra xem HTTPS có được bật không. Sử dụng HTTP bên ngoài localhost "
+"không an toàn và ngăn chặn việc sử dụng tính năng Passkeys và clipboard"
 
 #: src/language/generate.ts:8
 msgid ""
-"Check if the nginx access log path exists. By default, this path is obtained "
-"from 'nginx -V'. If it cannot be obtained or the obtained path does not "
-"point to a valid, existing file, an error will be reported. In this case, "
-"you need to modify the configuration file to specify the access log path."
-"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
-"nginx.html#accesslogpath"
+"Check if the nginx access log path exists. By default, this path is "
+"obtained from 'nginx -V'. If it cannot be obtained or the obtained path "
+"does not point to a valid, existing file, an error will be reported. In "
+"this case, you need to modify the configuration file to specify the access "
+"log path.Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 msgstr ""
 "Kiểm tra xem đường dẫn nhật ký truy cập nginx có tồn tại không. Theo mặc "
 "định, đường dẫn này được lấy từ 'nginx -V'. Nếu không thể lấy được hoặc "
 "đường dẫn lấy được không trỏ đến một tệp hợp lệ đang tồn tại, một lỗi sẽ "
-"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ định "
-"đường dẫn nhật ký truy cập. Tham khảo tài liệu để biết thêm chi tiết: "
+"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ "
+"định đường dẫn nhật ký truy cập. Tham khảo tài liệu để biết thêm chi tiết: "
 "https://nginxui.com/zh_CN/guide/config-nginx.html#accesslogpath"
 
 #: src/language/generate.ts:9
@@ -849,29 +843,29 @@ msgid ""
 "from 'nginx -V'. If it cannot be obtained or the obtained path does not "
 "point to a valid, existing file, an error will be reported. In this case, "
 "you need to modify the configuration file to specify the error log path. "
-"Refer to the docs for more details: https://nginxui.com/zh_CN/guide/config-"
-"nginx.html#errorlogpath"
+"Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 msgstr ""
 "Kiểm tra xem đường dẫn nhật ký lỗi của nginx có tồn tại không. Theo mặc "
 "định, đường dẫn này được lấy từ 'nginx -V'. Nếu không thể lấy được hoặc "
 "đường dẫn lấy được không trỏ đến một tệp hợp lệ đang tồn tại, một lỗi sẽ "
-"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ định "
-"đường dẫn nhật ký lỗi. Tham khảo tài liệu để biết thêm chi tiết: https://"
-"nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
+"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ "
+"định đường dẫn nhật ký lỗi. Tham khảo tài liệu để biết thêm chi tiết: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#errorlogpath"
 
 #: src/language/generate.ts:7
 msgid ""
 "Check if the nginx PID path exists. By default, this path is obtained from "
 "'nginx -V'. If it cannot be obtained, an error will be reported. In this "
 "case, you need to modify the configuration file to specify the Nginx PID "
-"path.Refer to the docs for more details: https://nginxui.com/zh_CN/guide/"
-"config-nginx.html#pidpath"
+"path.Refer to the docs for more details: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 msgstr ""
 "Kiểm tra xem đường dẫn PID của Nginx có tồn tại không. Theo mặc định, đường "
-"dẫn này được lấy từ lệnh 'nginx -V'. Nếu không thể lấy được, một lỗi sẽ được "
-"báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ định "
-"đường dẫn PID của Nginx. Tham khảo tài liệu để biết thêm chi tiết: https://"
-"nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
+"dẫn này được lấy từ lệnh 'nginx -V'. Nếu không thể lấy được, một lỗi sẽ "
+"được báo cáo. Trong trường hợp này, bạn cần sửa đổi tệp cấu hình để chỉ "
+"định đường dẫn PID của Nginx. Tham khảo tài liệu để biết thêm chi tiết: "
+"https://nginxui.com/zh_CN/guide/config-nginx.html#pidpath"
 
 #: src/language/generate.ts:12
 msgid "Check if the nginx sbin path exists"
@@ -899,8 +893,8 @@ msgstr ""
 
 #: src/language/generate.ts:17
 msgid ""
-"Check if the streams-available and streams-enabled directories are under the "
-"nginx configuration directory"
+"Check if the streams-available and streams-enabled directories are under "
+"the nginx configuration directory"
 msgstr ""
 "Kiểm tra xem các thư mục streams-available và streams-enabled có nằm trong "
 "thư mục cấu hình nginx không"
@@ -914,12 +908,12 @@ msgid "Cleaning environment variables"
 msgstr "Xoá các biến môi trường"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:23
-#: src/components/Notification/Notification.vue:118
+#: src/components/Notification/Notification.vue:115
 #: src/views/notification/Notification.vue:45
 msgid "Clear"
 msgstr "Xoá"
 
-#: src/components/Notification/Notification.vue:71
+#: src/components/Notification/Notification.vue:68
 #: src/views/notification/Notification.vue:13
 msgid "Cleared successfully"
 msgstr "Đã xóa thành công"
@@ -1113,7 +1107,7 @@ msgstr "Sao chép mã"
 msgid "Core Upgrade"
 msgstr "Cập nhật core"
 
-#: src/views/dashboard/ServerAnalytic.vue:305
+#: src/views/dashboard/ServerAnalytic.vue:308
 msgid "CPU Status"
 msgstr "Trạng thái CPU"
 
@@ -1150,8 +1144,8 @@ msgid ""
 "Create system backups including Nginx configuration and Nginx UI settings. "
 "Backup files will be automatically downloaded to your computer."
 msgstr ""
-"Tạo bản sao lưu hệ thống bao gồm cấu hình Nginx và cài đặt Nginx UI. Các tệp "
-"sao lưu sẽ tự động được tải xuống máy tính của bạn."
+"Tạo bản sao lưu hệ thống bao gồm cấu hình Nginx và cài đặt Nginx UI. Các "
+"tệp sao lưu sẽ tự động được tải xuống máy tính của bạn."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
 #: src/views/environments/group/columns.ts:29
@@ -1271,8 +1265,7 @@ msgstr "Giải mã thất bại"
 
 #: src/views/dashboard/components/ParamsOpt/ProxyCacheConfig.vue:150
 msgid "Define shared memory zone name and size, e.g. proxy_cache:10m"
-msgstr ""
-"Xác định tên và kích thước vùng bộ nhớ dùng chung, ví dụ proxy_cache:10m"
+msgstr "Xác định tên và kích thước vùng bộ nhớ dùng chung, ví dụ proxy_cache:10m"
 
 #: src/components/NgxConfigEditor/NgxServer.vue:110
 #: src/components/NgxConfigEditor/NgxUpstream.vue:134 src/language/curd.ts:9
@@ -1500,7 +1493,7 @@ msgstr "Đã tắt"
 msgid "Disabled successfully"
 msgstr "Đã tắt thành công"
 
-#: src/views/dashboard/ServerAnalytic.vue:370
+#: src/views/dashboard/ServerAnalytic.vue:373
 msgid "Disk IO"
 msgstr "Disk IO"
 
@@ -1800,7 +1793,7 @@ msgstr "Lỗi"
 msgid "Error initializing diff viewer"
 msgstr "Lỗi khởi tạo trình xem khác biệt"
 
-#: src/views/nginx_log/NginxLogList.vue:27
+#: src/views/nginx_log/NginxLogList.vue:42
 msgid "Error Log"
 msgstr "Nhật ký lỗi"
 
@@ -2419,8 +2412,7 @@ msgstr "Nếu bạn muốn tự động thu hồi chứng chỉ cũ, vui lòng b
 
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:70
 msgid "If your browser supports WebAuthn Passkey, a dialog box will appear."
-msgstr ""
-"Nếu trình duyệt của bạn hỗ trợ WebAuthn Passkey, một hộp thoại sẽ xuất hiện."
+msgstr "Nếu trình duyệt của bạn hỗ trợ WebAuthn Passkey, một hộp thoại sẽ xuất hiện."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:113
 msgid ""
@@ -2451,7 +2443,7 @@ msgstr ""
 "Bao gồm quá trình chính, quá trình worker, quá trình cache và các quá trình "
 "Nginx khác"
 
-#: src/components/ProcessingStatus/ProcessingStatus.vue:34
+#: src/components/ProcessingStatus/ProcessingStatus.vue:31
 msgid "Indexing..."
 msgstr "Đang lập chỉ mục..."
 
@@ -2763,14 +2755,15 @@ msgstr "Nhật ký"
 #: src/language/generate.ts:21
 msgid ""
 "Log file %{log_path} is not a regular file. If you are using nginx-ui in "
-"docker container, please refer to https://nginxui.com/zh_CN/guide/config-"
-"nginx-log.html for more information."
+"docker container, please refer to "
+"https://nginxui.com/zh_CN/guide/config-nginx-log.html for more information."
 msgstr ""
-"Tệp nhật ký %{log_path} không phải là tệp thông thường. Nếu bạn đang sử dụng "
-"nginx-ui trong container docker, vui lòng tham khảo https://nginxui.com/"
-"zh_CN/guide/config-nginx-log.html để biết thêm thông tin."
+"Tệp nhật ký %{log_path} không phải là tệp thông thường. Nếu bạn đang sử "
+"dụng nginx-ui trong container docker, vui lòng tham khảo "
+"https://nginxui.com/zh_CN/guide/config-nginx-log.html để biết thêm thông "
+"tin."
 
-#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:72
+#: src/routes/modules/nginx_log.ts:39 src/views/nginx_log/NginxLogList.vue:87
 msgid "Log List"
 msgstr "Danh sách nhật ký"
 
@@ -2792,19 +2785,19 @@ msgstr "Logrotate"
 
 #: src/views/preference/tabs/LogrotateSettings.vue:13
 msgid ""
-"Logrotate, by default, is enabled in most mainstream Linux distributions for "
-"users who install Nginx UI on the host machine, so you don't need to modify "
-"the parameters on this page. For users who install Nginx UI using Docker "
-"containers, you can manually enable this option. The crontab task scheduler "
-"of Nginx UI will execute the logrotate command at the interval you set in "
-"minutes."
+"Logrotate, by default, is enabled in most mainstream Linux distributions "
+"for users who install Nginx UI on the host machine, so you don't need to "
+"modify the parameters on this page. For users who install Nginx UI using "
+"Docker containers, you can manually enable this option. The crontab task "
+"scheduler of Nginx UI will execute the logrotate command at the interval "
+"you set in minutes."
 msgstr ""
 "Logrotate được kích hoạt mặc định trong hầu hết các bản phân phối Linux phổ "
-"biến dành cho người dùng cài đặt Nginx UI trực tiếp trên máy chủ, vì vậy bạn "
-"không cần phải thay đổi các tham số trên trang này. Đối với người dùng cài "
-"đặt Nginx UI bằng container Docker, bạn có thể kích hoạt thủ công tùy chọn "
-"này. Bộ lập lịch tác vụ crontab của Nginx UI sẽ thực thi lệnh logrotate theo "
-"khoảng thời gian bạn đặt (tính bằng phút)."
+"biến dành cho người dùng cài đặt Nginx UI trực tiếp trên máy chủ, vì vậy "
+"bạn không cần phải thay đổi các tham số trên trang này. Đối với người dùng "
+"cài đặt Nginx UI bằng container Docker, bạn có thể kích hoạt thủ công tùy "
+"chọn này. Bộ lập lịch tác vụ crontab của Nginx UI sẽ thực thi lệnh "
+"logrotate theo khoảng thời gian bạn đặt (tính bằng phút)."
 
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
@@ -2926,8 +2919,8 @@ msgstr "Kích thước tối đa của bộ nhớ đệm"
 msgid "Maximum worker process number:"
 msgstr "Số lượng tiến trình worker tối đa:"
 
-#: src/views/dashboard/ServerAnalytic.vue:226
 #: src/views/dashboard/ServerAnalytic.vue:227
+#: src/views/dashboard/ServerAnalytic.vue:228
 msgid "Memory"
 msgstr "Memory"
 
@@ -3017,7 +3010,7 @@ msgstr "Chỉ thị nhiều dòng"
 #: src/views/config/configColumns.tsx:5
 #: src/views/environments/group/columns.ts:7
 #: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:36
+#: src/views/nginx_log/NginxLogList.vue:51
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:75
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:35
 #: src/views/site/site_list/columns.tsx:16
@@ -3033,19 +3026,19 @@ msgstr "Tên"
 msgid "Need to enable the stub_status module"
 msgstr "Cần bật module stub_status"
 
-#: src/views/dashboard/ServerAnalytic.vue:331
+#: src/views/dashboard/ServerAnalytic.vue:334
 msgid "Network"
 msgstr "Mạng"
 
-#: src/views/dashboard/ServerAnalytic.vue:273
+#: src/views/dashboard/ServerAnalytic.vue:276
 msgid "Network Statistics"
 msgstr "Thống kê mạng"
 
-#: src/views/dashboard/ServerAnalytic.vue:280
+#: src/views/dashboard/ServerAnalytic.vue:283
 msgid "Network Total Receive"
 msgstr "Tổng lưu lượng mạng đã nhận"
 
-#: src/views/dashboard/ServerAnalytic.vue:286
+#: src/views/dashboard/ServerAnalytic.vue:289
 msgid "Network Total Send"
 msgstr "Tổng lưu lượng mạng đã gửi"
 
@@ -3276,10 +3269,11 @@ msgstr "Cấu hình Nginx UI đã được khôi phục"
 
 #: src/components/SystemRestore/SystemRestoreContent.vue:336
 msgid ""
-"Nginx UI configuration has been restored and will restart automatically in a "
-"few seconds."
+"Nginx UI configuration has been restored and will restart automatically in "
+"a few seconds."
 msgstr ""
-"Cấu hình Nginx UI đã được khôi phục và sẽ tự động khởi động lại sau vài giây."
+"Cấu hình Nginx UI đã được khôi phục và sẽ tự động khởi động lại sau vài "
+"giây."
 
 #: src/language/generate.ts:28
 msgid "Nginx.conf includes conf.d directory"
@@ -3298,7 +3292,7 @@ msgstr "Nginx.conf bao gồm thư mục streams-enabled"
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:143
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:99
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
-#: src/components/Notification/Notification.vue:111 src/language/curd.ts:38
+#: src/components/Notification/Notification.vue:108 src/language/curd.ts:38
 #: src/views/notification/Notification.vue:38
 #: src/views/preference/tabs/AuthSettings.vue:132
 #: src/views/preference/tabs/CertSettings.vue:73
@@ -3390,7 +3384,7 @@ msgstr ""
 msgid "Notification"
 msgstr "Thông báo"
 
-#: src/components/Notification/Notification.vue:109
+#: src/components/Notification/Notification.vue:106
 #: src/routes/modules/notifications.ts:10
 msgid "Notifications"
 msgstr "Thông báo"
@@ -3459,7 +3453,7 @@ msgstr "Ngoại tuyến"
 #: src/components/ChatGPT/ChatMessageInput.vue:18
 #: src/components/NgxConfigEditor/NgxServer.vue:60
 #: src/components/NgxConfigEditor/NgxUpstream.vue:36
-#: src/components/Notification/Notification.vue:112 src/language/curd.ts:15
+#: src/components/Notification/Notification.vue:109 src/language/curd.ts:15
 #: src/views/backup/components/BackupCreator.vue:149
 #: src/views/notification/Notification.vue:39
 #: src/views/site/components/SiteStatusSelect.vue:123
@@ -3571,9 +3565,9 @@ msgid ""
 "password replacement or as a 2FA method."
 msgstr ""
 "Passkey là thông tin xác thực WebAuthn dùng để xác minh danh tính của bạn "
-"thông qua chạm, nhận diện khuôn mặt, mật khẩu thiết bị hoặc mã PIN. Chúng "
-"thể được sử dụng để thay thế mật khẩu hoặc làm phương thức xác thực hai yếu "
-"tố (2FA)."
+"thông qua chạm, nhận diện khuôn mặt, mật khẩu thiết bị hoặc mã PIN. Chúng "
+"thể được sử dụng để thay thế mật khẩu hoặc làm phương thức xác thực hai "
+"yếu tố (2FA)."
 
 #: src/views/other/Login.vue:228 src/views/user/userColumns.tsx:16
 msgid "Password"
@@ -3604,7 +3598,7 @@ msgstr "Mật khẩu không khớp"
 #: src/language/curd.ts:59
 #: src/views/config/components/ConfigRightPanel/Basic.vue:41
 #: src/views/config/components/Delete.vue:124
-#: src/views/nginx_log/NginxLogList.vue:44
+#: src/views/nginx_log/NginxLogList.vue:59
 msgid "Path"
 msgstr "Đường dẫn"
 
@@ -3674,7 +3668,8 @@ msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
 "button below."
 msgstr ""
-"Vui lòng nhập tên cho khóa truy cập bạn muốn tạo và nhấp vào nút OK bên dưới."
+"Vui lòng nhập tên cho khóa truy cập bạn muốn tạo và nhấp vào nút OK bên "
+"dưới."
 
 #: src/components/PortScanner/PortScannerCompact.vue:85
 msgid "Please enter a valid port range"
@@ -3709,22 +3704,21 @@ msgstr "Vui lòng điền vào các trường cấu hình S3 bắt buộc"
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
-msgstr ""
-"Vui lòng điền thông tin xác thực API do nhà cung cấp DNS của bạn cung cấp"
+msgstr "Vui lòng điền thông tin xác thực API do nhà cung cấp DNS của bạn cung cấp"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:57
 msgid ""
 "Please first add credentials in Certification > DNS Credentials, and then "
 "select one of the credentialsbelow to request the API of the DNS provider."
 msgstr ""
-"Trước tiên, vui lòng thêm thông tin xác thực trong Chứng chỉ > Thông tin xác "
-"thực DNS, sau đó chọn nhà cung cấp DNS"
+"Trước tiên, vui lòng thêm thông tin xác thực trong Chứng chỉ > Thông tin "
+"xác thực DNS, sau đó chọn nhà cung cấp DNS"
 
 #: src/components/Notification/notifications.ts:190
 #: src/language/constants.ts:59
 msgid ""
-"Please generate new recovery codes in the preferences immediately to prevent "
-"lockout."
+"Please generate new recovery codes in the preferences immediately to "
+"prevent lockout."
 msgstr ""
 "Vui lòng tạo mã khôi phục mới trong phần tùy chọn ngay lập tức để tránh bị "
 "khóa."
@@ -3742,15 +3736,13 @@ msgstr "Vui lòng nhập tên thư mục"
 msgid ""
 "Please input name, this will be used as the filename of the new "
 "configuration!"
-msgstr ""
-"Vui lòng nhập tên, tên này sẽ được sử dụng làm tên tệp của cấu hình mới!"
+msgstr "Vui lòng nhập tên, tên này sẽ được sử dụng làm tên tệp của cấu hình mới!"
 
 #: src/views/site/site_list/SiteDuplicate.vue:33
 msgid ""
 "Please input name, this will be used as the filename of the new "
 "configuration."
-msgstr ""
-"Vui lòng nhập tên, tên này sẽ được sử dụng làm tên tệp cho cấu hình mới."
+msgstr "Vui lòng nhập tên, tên này sẽ được sử dụng làm tên tệp cho cấu hình mới."
 
 #: src/views/install/components/InstallForm.vue:25
 msgid "Please input your E-mail!"
@@ -3770,8 +3762,7 @@ msgid "Please log in."
 msgstr "Vui lòng đăng nhập."
 
 #: src/views/certificate/DNSCredential.vue:75
-msgid ""
-"Please note that the unit of time configurations below are all in seconds."
+msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr "Lưu ý đơn vị cấu hình thời gian bên dưới được tính bằng giây."
 
 #: src/views/install/components/InstallView.vue:102
@@ -3907,11 +3898,11 @@ msgid "Read requests"
 msgstr "Yêu cầu đọc"
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:387
+#: src/views/dashboard/ServerAnalytic.vue:390
 msgid "Reads"
 msgstr "Đọc"
 
-#: src/views/dashboard/ServerAnalytic.vue:338
+#: src/views/dashboard/ServerAnalytic.vue:341
 #: src/views/dashboard/ServerAnalytic.vue:35
 msgid "Receive"
 msgstr "Nhận"
@@ -4043,7 +4034,7 @@ msgstr "Xóa"
 msgid "Remove successfully"
 msgstr "Xóa thành công"
 
-#: src/components/Notification/Notification.vue:80
+#: src/components/Notification/Notification.vue:77
 msgid "Removed successfully"
 msgstr "Đã xóa thành công"
 
@@ -4169,8 +4160,8 @@ msgid ""
 "processes"
 msgstr ""
 "Kích thước tập hợp thường trú: Bộ nhớ thực tế thường trú trong bộ nhớ vật "
-"lý, bao gồm tất cả bộ nhớ thư viện dùng chung, sẽ được tính toán lặp lại cho "
-"nhiều tiến trình"
+"lý, bao gồm tất cả bộ nhớ thư viện dùng chung, sẽ được tính toán lặp lại "
+"cho nhiều tiến trình"
 
 #: src/composables/usePerformanceMetrics.ts:109
 #: src/views/dashboard/components/PerformanceTablesCard.vue:69
@@ -4264,8 +4255,8 @@ msgid ""
 "Revoking a certificate will affect any services currently using it. This "
 "action cannot be undone."
 msgstr ""
-"Việc thu hồi chứng chỉ sẽ ảnh hưởng đến bất kỳ dịch vụ nào hiện đang sử dụng "
-"nó. Hành động này không thể hoàn tác."
+"Việc thu hồi chứng chỉ sẽ ảnh hưởng đến bất kỳ dịch vụ nào hiện đang sử "
+"dụng nó. Hành động này không thể hoàn tác."
 
 #: src/views/preference/tabs/AuthSettings.vue:75
 msgid "RP Display Name"
@@ -4486,8 +4477,11 @@ msgstr "Kết quả quét"
 
 #: src/views/preference/components/AuthSettings/TOTP.vue:69
 msgid "Scan the QR code with your mobile phone to add the account to the app."
-msgstr ""
-"Quét mã QR bằng điện thoại di động của bạn để thêm tài khoản vào ứng dụng."
+msgstr "Quét mã QR bằng điện thoại di động của bạn để thêm tài khoản vào ứng dụng."
+
+#: src/views/nginx_log/NginxLogList.vue:100
+msgid "Scanning logs..."
+msgstr "Đang quét nhật ký..."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:113
 msgid "Schedule"
@@ -4549,11 +4543,10 @@ msgstr "Tự kiểm tra"
 #: src/components/SelfCheck/SelfCheckHeaderBanner.vue:37
 #: src/components/SelfCheck/SelfCheckHeaderBanner.vue:60
 msgid "Self check failed, Nginx UI may not work properly"
-msgstr ""
-"Tự kiểm tra thất bại, giao diện Nginx có thể không hoạt động bình thường"
+msgstr "Tự kiểm tra thất bại, giao diện Nginx có thể không hoạt động bình thường"
 
-#: src/views/dashboard/ServerAnalytic.vue:348
 #: src/views/dashboard/ServerAnalytic.vue:35
+#: src/views/dashboard/ServerAnalytic.vue:351
 msgid "Send"
 msgstr "Gửi"
 
@@ -4602,8 +4595,8 @@ msgid ""
 "Set the recursive nameservers to override the systems nameservers for the "
 "step of DNS challenge."
 msgstr ""
-"Đặt các máy chủ tên đệ quy để ghi đè các máy chủ tên hệ thống trong bước thử "
-"thách DNS."
+"Đặt các máy chủ tên đệ quy để ghi đè các máy chủ tên hệ thống trong bước "
+"thử thách DNS."
 
 #: src/views/site/components/SiteStatusSelect.vue:116
 msgid "set to maintenance mode"
@@ -4623,19 +4616,19 @@ msgstr "Đang thiết lập nhà cung cấp thử thách HTTP01"
 
 #: src/constants/errors/nginx_log.ts:8
 msgid ""
-"Settings.NginxLogSettings.AccessLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.AccessLogPath is empty, refer to "
+"https://nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.AccessLogPath trống, tham khảo https://nginxui.com/"
-"guide/config-nginx.html để biết thêm thông tin"
+"Settings.NginxLogSettings.AccessLogPath trống, tham khảo "
+"https://nginxui.com/guide/config-nginx.html để biết thêm thông tin"
 
 #: src/constants/errors/nginx_log.ts:7
 msgid ""
-"Settings.NginxLogSettings.ErrorLogPath is empty, refer to https://nginxui."
-"com/guide/config-nginx.html for more information"
+"Settings.NginxLogSettings.ErrorLogPath is empty, refer to "
+"https://nginxui.com/guide/config-nginx.html for more information"
 msgstr ""
-"Settings.NginxLogSettings.ErrorLogPath trống, tham khảo https://nginxui.com/"
-"guide/config-nginx.html để biết thêm thông tin"
+"Settings.NginxLogSettings.ErrorLogPath trống, tham khảo "
+"https://nginxui.com/guide/config-nginx.html để biết thêm thông tin"
 
 #: src/views/install/components/InstallView.vue:65
 msgid "Setup your Nginx UI"
@@ -4793,8 +4786,8 @@ msgstr "Trạng thái"
 msgid "Stopped"
 msgstr "Đã dừng"
 
-#: src/views/dashboard/ServerAnalytic.vue:254
-#: src/views/dashboard/ServerAnalytic.vue:255
+#: src/views/dashboard/ServerAnalytic.vue:257
+#: src/views/dashboard/ServerAnalytic.vue:258
 msgid "Storage"
 msgstr "Storage"
 
@@ -4872,25 +4865,25 @@ msgstr "Chủ nhật"
 msgid ""
 "Support communication with the backend through the Server-Sent Events "
 "protocol. If your Nginx UI is being used via an Nginx reverse proxy, please "
-"refer to this link to write the corresponding configuration file: https://"
-"nginxui.com/guide/nginx-proxy-example.html"
+"refer to this link to write the corresponding configuration file: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
 "Hỗ trợ giao tiếp với backend thông qua giao thức Server-Sent Events. Nếu "
-"Nginx UI của bạn đang được sử dụng qua proxy ngược Nginx, vui lòng tham khảo "
-"liên kết này để viết tệp cấu hình tương ứng: https://nginxui.com/guide/nginx-"
-"proxy-example.html"
+"Nginx UI của bạn đang được sử dụng qua proxy ngược Nginx, vui lòng tham "
+"khảo liên kết này để viết tệp cấu hình tương ứng: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/components/SelfCheck/tasks/frontend/websocket.ts:13
 msgid ""
 "Support communication with the backend through the WebSocket protocol. If "
-"your Nginx UI is being used via an Nginx reverse proxy, please refer to this "
-"link to write the corresponding configuration file: https://nginxui.com/"
-"guide/nginx-proxy-example.html"
+"your Nginx UI is being used via an Nginx reverse proxy, please refer to "
+"this link to write the corresponding configuration file: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 msgstr ""
-"Hỗ trợ giao tiếp với backend thông qua giao thức WebSocket. Nếu Nginx UI của "
-"bạn đang được sử dụng thông qua proxy ngược Nginx, vui lòng tham khảo liên "
-"kết này để viết tệp cấu hình tương ứng: https://nginxui.com/guide/nginx-"
-"proxy-example.html"
+"Hỗ trợ giao tiếp với backend thông qua giao thức WebSocket. Nếu Nginx UI "
+"của bạn đang được sử dụng thông qua proxy ngược Nginx, vui lòng tham khảo "
+"liên kết này để viết tệp cấu hình tương ứng: "
+"https://nginxui.com/guide/nginx-proxy-example.html"
 
 #: src/language/curd.ts:51 src/language/curd.ts:55
 msgid "Support single or batch upload of files"
@@ -4905,8 +4898,8 @@ msgstr "Hỗ trợ tải lên toàn bộ thư mục"
 msgid "Supported file type: .zip"
 msgstr "Loại tệp được hỗ trợ: .zip"
 
-#: src/views/dashboard/ServerAnalytic.vue:240
-#: src/views/dashboard/ServerAnalytic.vue:241
+#: src/views/dashboard/ServerAnalytic.vue:242
+#: src/views/dashboard/ServerAnalytic.vue:243
 msgid "Swap"
 msgstr "Swap"
 
@@ -5036,16 +5029,16 @@ msgid ""
 "since it was last issued."
 msgstr ""
 "Chứng chỉ cho tên miền sẽ được kiểm tra sau mỗi 30 phút và sẽ được gia hạn "
-"nếu đã hơn 1 tuần hoặc khoảng thời gian bạn đặt trong cài đặt kể từ lần phát "
-"hành cuối cùng."
+"nếu đã hơn 1 tuần hoặc khoảng thời gian bạn đặt trong cài đặt kể từ lần "
+"phát hành cuối cùng."
 
 #: src/views/preference/tabs/NodeSettings.vue:37
 msgid ""
 "The ICP Number should only contain letters, unicode, numbers, hyphens, "
 "dashes, colons, and dots."
 msgstr ""
-"Số ICP chỉ được chứa chữ cái, unicode, số, dấu gạch ngang, dấu gạch dài, dấu "
-"hai chấm và dấu chấm."
+"Số ICP chỉ được chứa chữ cái, unicode, số, dấu gạch ngang, dấu gạch dài, "
+"dấu hai chấm và dấu chấm."
 
 #: src/views/certificate/CertificateEditor.vue:214
 msgid "The input is not a SSL Certificate"
@@ -5057,10 +5050,11 @@ msgstr "Đầu vào không phải là Khóa Chứng chỉ SSL"
 
 #: src/constants/errors/nginx_log.ts:2
 msgid ""
-"The log path is not under the paths in settings.NginxSettings.LogDirWhiteList"
+"The log path is not under the paths in "
+"settings.NginxSettings.LogDirWhiteList"
 msgstr ""
-"Đường dẫn nhật ký không nằm trong các đường dẫn trong settings.NginxSettings."
-"LogDirWhiteList"
+"Đường dẫn nhật ký không nằm trong các đường dẫn trong "
+"settings.NginxSettings.LogDirWhiteList"
 
 #: src/views/preference/tabs/OpenAISettings.vue:23
 #: src/views/preference/tabs/OpenAISettings.vue:89
@@ -5072,8 +5066,7 @@ msgstr ""
 "dài, dấu hai chấm và dấu chấm."
 
 #: src/views/preference/tabs/OpenAISettings.vue:90
-msgid ""
-"The model used for code completion, if not set, the chat model will be used."
+msgid "The model used for code completion, if not set, the chat model will be used."
 msgstr ""
 "Mô hình được sử dụng để hoàn thành mã, nếu không được đặt, mô hình trò "
 "chuyện sẽ được sử dụng."
@@ -5103,8 +5096,8 @@ msgid ""
 "The Public Security Number should only contain letters, unicode, numbers, "
 "hyphens, dashes, colons, and dots."
 msgstr ""
-"Số Công an chỉ được chứa chữ cái, unicode, số, dấu gạch ngang, dấu gạch dài, "
-"dấu hai chấm và dấu chấm."
+"Số Công an chỉ được chứa chữ cái, unicode, số, dấu gạch ngang, dấu gạch "
+"dài, dấu hai chấm và dấu chấm."
 
 #: src/views/dashboard/Environments.vue:140
 msgid ""
@@ -5112,9 +5105,9 @@ msgid ""
 "version. To avoid potential errors, please upgrade the remote Nginx UI to "
 "match the local version."
 msgstr ""
-"Phiên bản Nginx UI từ xa không tương thích với phiên bản Nginx UI cục bộ. Để "
-"tránh các lỗi tiềm ẩn, vui lòng nâng cấp phiên bản Nginx UI từ xa để khớp "
-"với phiên bản cục bộ."
+"Phiên bản Nginx UI từ xa không tương thích với phiên bản Nginx UI cục bộ. "
+"Để tránh các lỗi tiềm ẩn, vui lòng nâng cấp phiên bản Nginx UI từ xa để "
+"khớp với phiên bản cục bộ."
 
 #: src/components/AutoCertForm/AutoCertForm.vue:44
 msgid ""
@@ -5187,14 +5180,13 @@ msgid "This field should not be empty"
 msgstr "Trường này không được để trống"
 
 #: src/constants/form_errors.ts:6
-msgid ""
-"This field should only contain letters, unicode characters, numbers, and -_."
+msgid "This field should only contain letters, unicode characters, numbers, and -_."
 msgstr "Trường này chỉ được chứa chữ cái, ký tự Unicode, số và -_."
 
 #: src/language/curd.ts:44
 msgid ""
-"This field should only contain letters, unicode characters, numbers, and -"
-"_./:"
+"This field should only contain letters, unicode characters, numbers, and "
+"-_./:"
 msgstr "Trường này chỉ được chứa chữ cái, ký tự Unicode, số và -_./:"
 
 #: src/views/dashboard/NginxDashBoard.vue:155
@@ -5202,16 +5194,16 @@ msgid ""
 "This module provides Nginx request statistics, connection count, etc. data. "
 "After enabling it, you can view performance statistics"
 msgstr ""
-"Mô-đun này cung cấp dữ liệu như thống kê yêu cầu Nginx, số lượng kết nối, v."
-"v. Sau khi bật, bạn có thể xem thống kê hiệu suất"
+"Mô-đun này cung cấp dữ liệu như thống kê yêu cầu Nginx, số lượng kết nối, "
+"v.v. Sau khi bật, bạn có thể xem thống kê hiệu suất"
 
 #: src/views/certificate/components/RemoveCert.vue:106
 msgid ""
 "This operation will only remove the certificate from the database. The "
 "certificate files on the file system will not be deleted."
 msgstr ""
-"Thao tác này sẽ chỉ xóa chứng chỉ khỏi cơ sở dữ liệu. Các tệp chứng chỉ trên "
-"hệ thống tệp sẽ không bị xóa."
+"Thao tác này sẽ chỉ xóa chứng chỉ khỏi cơ sở dữ liệu. Các tệp chứng chỉ "
+"trên hệ thống tệp sẽ không bị xóa."
 
 #: src/views/backup/components/BackupCreator.vue:141
 msgid ""
@@ -5244,12 +5236,11 @@ msgid ""
 "This will restore configuration files and database. Nginx UI will restart "
 "after the restoration is complete."
 msgstr ""
-"Thao tác này sẽ khôi phục các tệp cấu hình và cơ sở dữ liệu. Giao diện Nginx "
-"sẽ khởi động lại sau khi quá trình khôi phục hoàn tất."
+"Thao tác này sẽ khôi phục các tệp cấu hình và cơ sở dữ liệu. Giao diện "
+"Nginx sẽ khởi động lại sau khi quá trình khôi phục hoàn tất."
 
 #: src/views/environments/list/BatchUpgrader.vue:183
-msgid ""
-"This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
+msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Thao tác này sẽ nâng cấp hoặc cài đặt lại Nginx UI trên %{nodeNames} lên "
 "phiên bản %{version}."
@@ -5299,20 +5290,20 @@ msgid ""
 "and restart Nginx UI."
 msgstr ""
 "Để đảm bảo bảo mật, cấu hình WebAuthn không thể được thêm qua giao diện "
-"người dùng. Vui lòng cấu hình thủ công các mục sau trong tệp cấu hình app."
-"ini và khởi động lại Nginx UI."
+"người dùng. Vui lòng cấu hình thủ công các mục sau trong tệp cấu hình "
+"app.ini và khởi động lại Nginx UI."
 
 #: src/views/site/site_edit/components/Cert/IssueCert.vue:34
 #: src/views/site/site_edit/components/EnableTLS/EnableTLS.vue:15
 msgid ""
 "To make sure the certification auto-renewal can work normally, we need to "
-"add a location which can proxy the request from authority to backend, and we "
-"need to save this file and reload the Nginx. Are you sure you want to "
+"add a location which can proxy the request from authority to backend, and "
+"we need to save this file and reload the Nginx. Are you sure you want to "
 "continue?"
 msgstr ""
-"Để đảm bảo tính năng tự động gia hạn chứng chỉ có thể hoạt động bình thường, "
-"chúng tôi cần thêm một vị trí có thể ủy quyền yêu cầu từ cơ quan có thẩm "
-"quyền đến chương trình phụ trợ và chúng tôi cần lưu tệp này và tải lại "
+"Để đảm bảo tính năng tự động gia hạn chứng chỉ có thể hoạt động bình "
+"thường, chúng tôi cần thêm một vị trí có thể ủy quyền yêu cầu từ cơ quan có "
+"thẩm quyền đến chương trình phụ trợ và chúng tôi cần lưu tệp này và tải lại "
 "Nginx. Bạn có chắc chắn muốn Tiếp tục?"
 
 #: src/views/preference/tabs/OpenAISettings.vue:36
@@ -5392,7 +5383,7 @@ msgstr "Yêu cầu xác thực hai yếu tố"
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
-#: src/views/nginx_log/NginxLogList.vue:12
+#: src/views/nginx_log/NginxLogList.vue:27
 #: src/views/notification/notificationColumns.tsx:8
 #: src/views/preference/components/ExternalNotify/columns.tsx:18
 msgid "Type"
@@ -5549,12 +5540,12 @@ msgstr "Xác minh các yêu cầu hệ thống"
 msgid "Version"
 msgstr "Phiên bản"
 
-#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:84
+#: src/language/curd.ts:7 src/views/nginx_log/NginxLogList.vue:105
 #: src/views/site/site_edit/components/ConfigTemplate/ConfigTemplate.vue:83
 msgid "View"
 msgstr "Xem"
 
-#: src/components/Notification/Notification.vue:181
+#: src/components/Notification/Notification.vue:178
 msgid "View all notifications"
 msgstr "Xem tất cả thông báo"
 
@@ -5590,9 +5581,9 @@ msgid ""
 "you have a valid backup file and security token, and carefully select what "
 "to restore."
 msgstr ""
-"Cảnh báo: Thao tác khôi phục sẽ ghi đè lên cấu hình hiện tại. Đảm bảo bạn "
-"tệp sao lưu hợp lệ và mã bảo mật, đồng thời cẩn thận chọn nội dung cần khôi "
-"phục."
+"Cảnh báo: Thao tác khôi phục sẽ ghi đè lên cấu hình hiện tại. Đảm bảo bạn "
+"tệp sao lưu hợp lệ và mã bảo mật, đồng thời cẩn thận chọn nội dung cần "
+"khôi phục."
 
 #: src/views/certificate/DNSCredential.vue:69
 msgid ""
@@ -5604,8 +5595,8 @@ msgstr ""
 
 #: src/views/site/site_edit/components/Cert/ObtainCert.vue:140
 msgid ""
-"We will remove the HTTPChallenge configuration from this file and reload the "
-"Nginx. Are you sure you want to continue?"
+"We will remove the HTTPChallenge configuration from this file and reload "
+"the Nginx. Are you sure you want to continue?"
 msgstr ""
 "Chúng tôi sẽ xóa cấu hình HTTPChallenge khỏi tệp này và tải lại Nginx. Bạn "
 "có muốn tiếp tục không?"
@@ -5650,8 +5641,8 @@ msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
 "Node Group and the nodes selected below will be synchronized."
 msgstr ""
-"Khi bạn bật/tắt, xóa hoặc lưu trang web này, các nút được đặt trong Nhóm Nút "
-"và các nút được chọn bên dưới sẽ được đồng bộ hóa."
+"Khi bạn bật/tắt, xóa hoặc lưu trang web này, các nút được đặt trong Nhóm "
+"Nút và các nút được chọn bên dưới sẽ được đồng bộ hóa."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5696,7 +5687,7 @@ msgid "Write private.key error: {0}"
 msgstr "Lỗi ghi private.key: {0}"
 
 #: src/views/dashboard/ServerAnalytic.vue:37
-#: src/views/dashboard/ServerAnalytic.vue:377
+#: src/views/dashboard/ServerAnalytic.vue:380
 msgid "Writes"
 msgstr "Ghi"
 
@@ -5719,12 +5710,12 @@ msgstr "Có"
 
 #: src/views/terminal/Terminal.vue:132
 msgid ""
-"You are accessing this terminal over an insecure HTTP connection on a non-"
-"localhost domain. This may expose sensitive information."
+"You are accessing this terminal over an insecure HTTP connection on a "
+"non-localhost domain. This may expose sensitive information."
 msgstr ""
-"Bạn đang truy cập thiết bị đầu cuối này thông qua kết nối HTTP không an toàn "
-"trên một miền không phải localhost. Điều này có thể làm lộ thông tin nhạy "
-"cảm."
+"Bạn đang truy cập thiết bị đầu cuối này thông qua kết nối HTTP không an "
+"toàn trên một miền không phải localhost. Điều này có thể làm lộ thông tin "
+"nhạy cảm."
 
 #: src/constants/errors/config.ts:8
 msgid "You are not allowed to delete a file outside of the nginx config path"
@@ -5750,15 +5741,13 @@ msgstr "Bạn có thể đóng hộp thoại này ngay bây giờ"
 msgid ""
 "You have not configured the settings of Webauthn, so you cannot add a "
 "passkey."
-msgstr ""
-"Bạn chưa cấu hình cài đặt WebAuthn, vì vậy không thể thêm khóa truy cập."
+msgstr "Bạn chưa cấu hình cài đặt WebAuthn, vì vậy không thể thêm khóa truy cập."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:81
-msgid ""
-"You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
+msgid "You have not enabled 2FA yet. Please enable 2FA to generate recovery codes."
 msgstr ""
-"Bạn chưa bật xác thực hai yếu tố. Vui lòng bật xác thực hai yếu tố để tạo "
-"khôi phục."
+"Bạn chưa bật xác thực hai yếu tố. Vui lòng bật xác thực hai yếu tố để tạo "
+"khôi phục."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:94
 msgid "You have not generated recovery codes yet."
@@ -5853,8 +5842,8 @@ msgstr "Khóa truy cập của bạn"
 
 #~ msgid ""
 #~ "Check if /var/run/docker.sock exists. If you are using Nginx UI Official "
-#~ "Docker Image, please make sure the docker socket is mounted like this: `-"
-#~ "v /var/run/docker.sock:/var/run/docker.sock`."
+#~ "Docker Image, please make sure the docker socket is mounted like this: `-v "
+#~ "/var/run/docker.sock:/var/run/docker.sock`."
 #~ msgstr ""
 #~ "Kiểm tra xem /var/run/docker.sock có tồn tại không. Nếu bạn đang sử dụng "
 #~ "Docker Image chính thức của Nginx UI, hãy đảm bảo rằng ổ cắm Docker được "
@@ -5949,14 +5938,11 @@ msgstr "Khóa truy cập của bạn"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy
-#~ msgid ""
-#~ "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: "
-#~ "%{resp}"
+#~ msgid "Rename %{orig_path} to %{new_path} on %{env_name} failed, response: %{resp}"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy
-#~ msgid ""
-#~ "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
+#~ msgid "Rename Site %{site} to %{new_site} on %{node} error, response: %{resp}"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy
@@ -5970,8 +5956,7 @@ msgstr "Khóa truy cập của bạn"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy
-#~ msgid ""
-#~ "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
+#~ msgid "Sync Certificate %{cert_name} to %{env_name} failed, response: %{resp}"
 #~ msgstr "Nhân bản %{conf_name} thành %{node_name} thành công"
 
 #, fuzzy

File diff suppressed because it is too large
+ 173 - 237
app/src/language/zh_CN/app.po


File diff suppressed because it is too large
+ 175 - 240
app/src/language/zh_TW/app.po


+ 9 - 0
app/src/pinia/moudule/global.ts

@@ -7,6 +7,10 @@ interface ProcessingStatus {
   auto_cert_processing: boolean
 }
 
+interface NginxLogStatus {
+  scanning: boolean
+}
+
 type NginxStatusType = NginxStatus.Reloading | NginxStatus.Restarting | NginxStatus.Running | NginxStatus.Stopped
 
 export const useGlobalStore = defineStore('global', () => {
@@ -17,12 +21,17 @@ export const useGlobalStore = defineStore('global', () => {
     auto_cert_processing: false,
   })
 
+  const nginxLogStatus = ref<NginxLogStatus>({
+    scanning: false,
+  })
+
   const modules = ref<NgxModule[]>([])
   const modulesMap = ref<Record<string, NgxModule>>({})
 
   return {
     nginxStatus,
     processingStatus,
+    nginxLogStatus,
     modules,
     modulesMap,
   }

+ 1 - 1
app/src/version.json

@@ -1 +1 @@
-{"version":"2.1.10","build_id":1,"total_build":443}
+{"version":"2.1.10","build_id":3,"total_build":445}

+ 21 - 0
app/src/views/nginx_log/NginxLogList.vue

@@ -1,12 +1,27 @@
 <script setup lang="tsx">
 import type { CustomRenderArgs, StdTableColumn } from '@uozi-admin/curd'
+import { SyncOutlined } from '@ant-design/icons-vue'
 import { StdCurd } from '@uozi-admin/curd'
 import { Tag } from 'ant-design-vue'
 import nginxLog from '@/api/nginx_log'
+import { useWebSocketEventBus } from '@/composables/useWebSocketEventBus'
+import { useGlobalStore } from '@/pinia'
 
 const router = useRouter()
 const stdCurdRef = ref()
 
+// WebSocket event bus and global store
+const { subscribe } = useWebSocketEventBus()
+const globalStore = useGlobalStore()
+const { nginxLogStatus } = storeToRefs(globalStore)
+
+// Subscribe to nginx log status events
+onMounted(() => {
+  subscribe('nginx_log_status', data => {
+    nginxLogStatus.value = data
+  })
+})
+
 const columns: StdTableColumn[] = [
   {
     title: () => $gettext('Type'),
@@ -79,6 +94,12 @@ function viewLog(record: { type: string, path: string }) {
     disable-view
     disable-edit
   >
+    <template #beforeListActions>
+      <div v-if="nginxLogStatus.scanning" class="flex items-center text-blue-500">
+        <SyncOutlined spin class="mr-2" />
+        <span>{{ $gettext('Scanning logs...') }}</span>
+      </div>
+    </template>
     <template #beforeActions="{ record }">
       <AButton type="link" size="small" @click="viewLog(record)">
         {{ $gettext('View') }}

+ 1 - 4
go.mod

@@ -116,7 +116,6 @@ require (
 	github.com/cloudwego/base64x v0.1.5 // indirect
 	github.com/containerd/errdefs v1.0.0 // indirect
 	github.com/containerd/errdefs/pkg v0.3.0 // indirect
-	github.com/containerd/log v0.1.0 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/dennwc/varint v1.0.0 // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
@@ -203,11 +202,10 @@ require (
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/moby/docker-image-spec v1.3.1 // indirect
-	github.com/moby/sys/atomicwriter v0.1.0 // indirect
+	github.com/moby/sys/sequential v0.6.0 // indirect
 	github.com/moby/term v0.5.2 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
-	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
 	github.com/namedotcom/go/v4 v4.0.2 // indirect
 	github.com/nrdcg/auroradns v1.1.0 // indirect
@@ -277,7 +275,6 @@ require (
 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.62.0 // indirect
 	go.opentelemetry.io/otel v1.37.0 // indirect
-	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
 	go.opentelemetry.io/otel/metric v1.37.0 // indirect
 	go.opentelemetry.io/otel/trace v1.37.0 // indirect
 	go.uber.org/atomic v1.11.0 // indirect

+ 54 - 34
go.sum

@@ -677,6 +677,8 @@ github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go
 github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
 github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY=
 github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU=
+github.com/Netflix/go-env v0.0.0-20220526054621-78278af1949d h1:wvStE9wLpws31NiWUx+38wny1msZ/tm+eL5xmm4Y7So=
+github.com/Netflix/go-env v0.0.0-20220526054621-78278af1949d/go.mod h1:9XMFaCeRyW7fC9XJOWQ+NdAv8VLG7ys7l3x4ozEGLUQ=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
@@ -697,8 +699,32 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
+github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
+github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b/go.mod h1:fvzegU4vN3H1qMT+8wDmzjAcDONcgo2/SZ/TyfdUOFs=
+github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4 h1:iC9YFYKDGEy3n/FtqJnOkZsene9olVspKmkX5A2YBEo=
+github.com/alibabacloud-go/alibabacloud-gateway-spi v0.0.4/go.mod h1:sCavSAvdzOjul4cEqeVtvlSaSScfNsTQ+46HwlTL1hc=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.4 h1:7Q2FEyqxeZeIkwYMwRC3uphxV4i7O2eV4ETe21d6lS4=
+github.com/alibabacloud-go/darabonba-openapi/v2 v2.0.4/go.mod h1:5JHVmnHvGzR2wNdgaW1zDLQG8kOC4Uec8ubkMogW7OQ=
+github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68 h1:NqugFkGxx1TXSh/pBcU00Y6bljgDPaFdh5MUSeJ7e50=
+github.com/alibabacloud-go/debug v0.0.0-20190504072949-9472017b5c68/go.mod h1:6pb/Qy8c+lqua8cFpEy7g39NRRqOWc3rOwAy8m5Y2BY=
+github.com/alibabacloud-go/endpoint-util v1.1.0 h1:r/4D3VSw888XGaeNpP994zDUaxdgTSHBbVfZlzf6b5Q=
+github.com/alibabacloud-go/endpoint-util v1.1.0/go.mod h1:O5FuCALmCKs2Ff7JFJMudHs0I5EBgecXXxZRyswlEjE=
+github.com/alibabacloud-go/openapi-util v0.1.0 h1:0z75cIULkDrdEhkLWgi9tnLe+KhAFE/r5Pb3312/eAY=
+github.com/alibabacloud-go/openapi-util v0.1.0/go.mod h1:sQuElr4ywwFRlCCberQwKRFhRzIyG4QTP/P4y1CJ6Ws=
+github.com/alibabacloud-go/sts-20150401/v2 v2.0.1 h1:CevZp0VdG7Q+1J3qwNj+JL7ztKxsL27+tknbdTK9Y6M=
+github.com/alibabacloud-go/sts-20150401/v2 v2.0.1/go.mod h1:8wJW1xC4mVcdRXzOvWJYfCCxmvFzZ0VB9iilVjBeWBc=
+github.com/alibabacloud-go/tea v1.1.19 h1:Xroq0M+pr0mC834Djj3Fl4ZA8+GGoA0i7aWse1vmgf4=
+github.com/alibabacloud-go/tea v1.1.19/go.mod h1:nXxjm6CIFkBhwW4FQkNrolwbfon8Svy6cujmKFUq98A=
+github.com/alibabacloud-go/tea-utils v1.3.1 h1:iWQeRzRheqCMuiF3+XkfybB3kTgUXkXX+JMrqfLeB2I=
+github.com/alibabacloud-go/tea-utils v1.3.1/go.mod h1:EI/o33aBfj3hETm4RLiAxF/ThQdSngxrpF8rKUDJjPE=
+github.com/alibabacloud-go/tea-utils/v2 v2.0.1 h1:K6kwgo+UiYx+/kr6CO0PN5ACZDzE3nnn9d77215AkTs=
+github.com/alibabacloud-go/tea-utils/v2 v2.0.1/go.mod h1:U5MTY10WwlquGPS34DOeomUGBB0gXbLueiq5Trwu0C4=
+github.com/alibabacloud-go/tea-xml v1.1.2 h1:oLxa7JUXm2EDFzMg+7oRsYc+kutgCVwm+bZlhhmvW5M=
+github.com/alibabacloud-go/tea-xml v1.1.2/go.mod h1:Rq08vgCcCAjHyRi/M7xlHKUykZCEtyBy9+DPF6GgEu8=
 github.com/aliyun/aliyun-log-go-sdk v0.1.101 h1:bd+4FEhB33BLup4eG129J4fSDLqC2tAyU6mDrRCcKhU=
 github.com/aliyun/aliyun-log-go-sdk v0.1.101/go.mod h1:7QcyHasd4WLdC+lx4uCmdIBcl7WcgRHctwz8t1zAuPo=
+github.com/aliyun/credentials-go v1.1.2 h1:qU1vwGIBb3UJ8BwunHDRFtAhS6jnQLnde/yk0+Ih2GY=
+github.com/aliyun/credentials-go v1.1.2/go.mod h1:ozcZaMR5kLM7pwtCMEpVmQ242suV6qTJya2bDq4X1Tw=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/apache/arrow/go/v10 v10.0.1/go.mod h1:YvhnlEePVnBS4+0z3fhPfUy7W1Ikj0Ih0vcRo/gZ1M0=
@@ -712,6 +738,8 @@ github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj
 github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
 github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
 github.com/aws/aws-sdk-go v1.40.45/go.mod h1:585smgzpB/KqRA+K3y/NL/oYRqQvpNJYvLm+LY1U59Q=
+github.com/aws/aws-sdk-go v1.55.7 h1:UJrkFq7es5CShfBwlWAC8DA077vp8PyVbQd3lqLiztE=
+github.com/aws/aws-sdk-go v1.55.7/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
 github.com/aws/aws-sdk-go-v2 v1.9.1/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4=
 github.com/aws/aws-sdk-go-v2 v1.36.5 h1:0OF9RiEMEdDdZEMqF9MRjevyxAQcf6gY+E7vwBILFj0=
 github.com/aws/aws-sdk-go-v2 v1.36.5/go.mod h1:EYrzvCCN9CMUTa5+6lf6MM4tq3Zjp8UhSGR/cBsjai0=
@@ -744,8 +772,6 @@ github.com/aws/aws-sdk-go-v2/service/lightsail v1.43.4 h1:0WHz7LVS1JHOMaJJ2uc7vv
 github.com/aws/aws-sdk-go-v2/service/lightsail v1.43.4/go.mod h1:2VS/H/N3xtI0VxFja/1Aqy1FscPkVyju4Uq9J08L6Ms=
 github.com/aws/aws-sdk-go-v2/service/route53 v1.52.2 h1:dXHWVVPx2W2fq2PTugj8QXpJ0YTRAGx0KLPKhMBmcsY=
 github.com/aws/aws-sdk-go-v2/service/route53 v1.52.2/go.mod h1:wi1naoiPnCQG3cyjsivwPON1ZmQt/EJGxFqXzubBTAw=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.82.0 h1:JubM8CGDDFaAOmBrd8CRYNr49ZNgEAiLwGwgNMdS0nw=
-github.com/aws/aws-sdk-go-v2/service/s3 v1.82.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU=
 github.com/aws/aws-sdk-go-v2/service/s3 v1.83.0 h1:5Y75q0RPQoAbieyOuGLhjV9P3txvYgXv2lg0UwJOfmE=
 github.com/aws/aws-sdk-go-v2/service/s3 v1.83.0/go.mod h1:kUklwasNoCn5YpyAqC/97r6dzTA1SRKJfKq16SXeoDU=
 github.com/aws/aws-sdk-go-v2/service/sso v1.25.5 h1:AIRJ3lfb2w/1/8wOOSqYb9fUKGwQbtysJ2H1MofRUPg=
@@ -757,10 +783,10 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.34.0/go.mod h1:7ph2tGpfQvwzgistp2+zg
 github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
 github.com/aws/smithy-go v1.22.4 h1:uqXzVZNuNexwc/xrh6Tb56u89WDlJY6HS+KC0S4QSjw=
 github.com/aws/smithy-go v1.22.4/go.mod h1:t1ufH5HMublsJYulve2RKmHDC15xu1f26kHCp/HgceI=
-github.com/baidubce/bce-sdk-go v0.9.232 h1:nUiHzHNYpu5tmy+w8MEif9l4+940jfJOLHfGPu8KWkY=
-github.com/baidubce/bce-sdk-go v0.9.232/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
 github.com/baidubce/bce-sdk-go v0.9.233 h1:nq5PL+G2+JIkox98GN0UEkNdh8G+j4cmyJxbzoFNgec=
 github.com/baidubce/bce-sdk-go v0.9.233/go.mod h1:zbYJMQwE4IZuyrJiFO8tO8NbtYiKTFTbwh4eIsqjVdg=
+github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3 h1:6df1vn4bBlDDo4tARvBm7l6KA9iVMnE3NWizDeWSrps=
+github.com/bboreham/go-loser v0.0.0-20230920113527-fcc2c21820a3/go.mod h1:CIWtjkly68+yqLPbvwwR/fjNJA/idrtULjZWh2v1ys0=
 github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
 github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
 github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
@@ -802,7 +828,6 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
-github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -816,7 +841,10 @@ github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6D
 github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
 github.com/civo/civogo v0.6.1 h1:PFOh7rBU0vmj7LTDIv3z7l9uXG4SZyyzScCl3wyTFSc=
 github.com/civo/civogo v0.6.1/go.mod h1:LaEbkszc+9nXSh4YNG0sYXFGYqdQFmXXzQg0gESs2hc=
+github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I=
 github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
+github.com/clbanning/mxj/v2 v2.5.5 h1:oT81vUeEiQQ/DcHbzSytRngP6Ky9O+L+0Bw0zSJag9E=
+github.com/clbanning/mxj/v2 v2.5.5/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s=
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
 github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
@@ -875,8 +903,6 @@ github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5Qvfr
 github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 github.com/dnsimple/dnsimple-go/v4 v4.0.0 h1:nUCICZSyZDiiqimAAL+E8XL+0sKGks5VRki5S8XotRo=
 github.com/dnsimple/dnsimple-go/v4 v4.0.0/go.mod h1:AXT2yfAFOntJx6iMeo1J/zKBw0ggXFYBt4e97dqqPnc=
-github.com/docker/docker v28.3.0+incompatible h1:ffS62aKWupCWdvcee7nBU9fhnmknOqDPaJAMtfK0ImQ=
-github.com/docker/docker v28.3.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/docker v28.3.1+incompatible h1:20+BmuA9FXlCX4ByQ0vYJcUEnOmRM6XljDnFWR+jCyY=
 github.com/docker/docker v28.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
 github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
@@ -891,8 +917,6 @@ github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5m
 github.com/eapache/go-resiliency v1.2.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
-github.com/ebitengine/purego v0.9.0-alpha.7 h1:jvLN906GKVONohlBOCr34BxW+4KeAk1K1wfWdRRsl7Y=
-github.com/ebitengine/purego v0.9.0-alpha.7/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
 github.com/ebitengine/purego v0.9.0-alpha.8 h1:CPF4uX051zsUnPwi43RumsgSBax76KH14F8NwrKNsHU=
 github.com/ebitengine/purego v0.9.0-alpha.8/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ=
 github.com/edsrzf/mmap-go v1.0.0/go.mod h1:YO35OhQPt3KJa3ryjFM5Bs14WD66h8eGKpfaBNrHW5M=
@@ -913,8 +937,6 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
 github.com/envoyproxy/protoc-gen-validate v0.6.7/go.mod h1:dyJXwwfPK2VSqiB9Klm1J6romD608Ba7Hij42vrOBCo=
 github.com/envoyproxy/protoc-gen-validate v0.9.1/go.mod h1:OKNgG7TCp5pF4d6XftA0++PMirau2/yoOwVac3AbF2w=
 github.com/envoyproxy/protoc-gen-validate v0.10.0/go.mod h1:DRjgyB0I43LtJapqN6NiRwroiAU2PaFuvk/vjgh61ss=
-github.com/exoscale/egoscale/v3 v3.1.21 h1:ea0ET2fG2QNiDiw4Q300+w88GCQHdJYmQYSsjkDzEgg=
-github.com/exoscale/egoscale/v3 v3.1.21/go.mod h1:A53enXfm8nhVMpIYw0QxiwQ2P6AdCF4F/nVYChNEzdE=
 github.com/exoscale/egoscale/v3 v3.1.22 h1:Dq6g9MlbKjRU4cnjrZOzNJ9Bwy2L4LnJBGcsJ9U/kc8=
 github.com/exoscale/egoscale/v3 v3.1.22/go.mod h1:A53enXfm8nhVMpIYw0QxiwQ2P6AdCF4F/nVYChNEzdE=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
@@ -973,8 +995,6 @@ github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gormigrate/gormigrate/v2 v2.1.4 h1:KOPEt27qy1cNzHfMZbp9YTmEuzkY4F4wrdsJW9WFk1U=
 github.com/go-gormigrate/gormigrate/v2 v2.1.4/go.mod h1:y/6gPAH6QGAgP1UfHMiXcqGeJ88/GRQbfCReE1JJD5Y=
-github.com/go-jose/go-jose/v4 v4.1.0 h1:cYSYxd3pw5zd2FSXk2vGdn9igQU2PS8MuxrCOCl0FdY=
-github.com/go-jose/go-jose/v4 v4.1.0/go.mod h1:GG/vqmYm3Von2nYiB2vGTXzdoNKE5tix5tuc6iAd+sw=
 github.com/go-jose/go-jose/v4 v4.1.1 h1:JYhSgy4mXXzAdF3nUx3ygx347LRXJRrpgyU3adRmkAI=
 github.com/go-jose/go-jose/v4 v4.1.1/go.mod h1:BdsZGqgdO3b6tTc6LSE56wcDbMMLuPsw5d4ZD5f94kA=
 github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -1012,8 +1032,6 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
 github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
 github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
 github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
-github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
 github.com/go-playground/validator/v10 v10.27.0 h1:w8+XrWVMhGkxOaaowyKH35gFydVHOvC0/uWoy2Fzwn4=
 github.com/go-playground/validator/v10 v10.27.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
 github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
@@ -1097,6 +1115,8 @@ github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6
 github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
+github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
 github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
 github.com/google/flatbuffers v2.0.8+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
@@ -1145,8 +1165,8 @@ github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLe
 github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
 github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
-github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8 h1:FKHo8hFI3A+7w0aUQuYXQ+6EN5stWmeY/AZqtM8xk9k=
-github.com/google/pprof v0.0.0-20240727154555-813a5fbdbec8/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
+github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
 github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
 github.com/google/s2a-go v0.1.3/go.mod h1:Ej+mSEMGRnqRzjc7VtF+jdBwYG5fuJfiZ8ELkjEwM0A=
 github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
@@ -1203,8 +1223,8 @@ github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
 github.com/guregu/null/v6 v6.0.0 h1:N14VRS+4di81i1PXRiprbQJ9EM9gqBa0+KVMeS/QSjQ=
 github.com/guregu/null/v6 v6.0.0/go.mod h1:hrMIhIfrOZeLPZhROSn149tpw2gHkidAqxoXNyeX3iQ=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
@@ -1343,6 +1363,7 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9YPoQUg=
 github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
 github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
 github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
@@ -1353,6 +1374,7 @@ github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbd
 github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60=
 github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
 github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
+github.com/jpillora/backoff v1.0.0 h1:uvFg412JmmHBHw7iwprIxkPMI+sGQ4kzOWsMeHnm2EA=
 github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
 github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
 github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
@@ -1423,8 +1445,6 @@ github.com/libdns/huaweicloud v1.0.0-beta.2/go.mod h1:MQ+HiuzS6RjqBaZquZICMM9rEf
 github.com/libdns/libdns v1.0.0/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
 github.com/libdns/libdns v1.1.0 h1:9ze/tWvt7Df6sbhOJRB8jT33GHEHpEQXdtkE3hPthbU=
 github.com/libdns/libdns v1.1.0/go.mod h1:4Bj9+5CQiNMVGf87wjX4CY3HQJypUHRuLvlsfsZqLWQ=
-github.com/linode/linodego v1.52.1 h1:HJ1cz1n9n3chRP9UrtqmP91+xTi0Q5l+H/4z4tpkwgQ=
-github.com/linode/linodego v1.52.1/go.mod h1:zEN2sX+cSdp67EuRY1HJiyuLujoa7HqvVwNEcJv3iXw=
 github.com/linode/linodego v1.52.2 h1:N9ozU27To1LMSrDd8WvJZ5STSz1eGYdyLnxhAR/dIZg=
 github.com/linode/linodego v1.52.2/go.mod h1:bI949fZaVchjWyKIA08hNyvAcV6BAS+PM2op3p7PAWA=
 github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
@@ -1527,6 +1547,7 @@ github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7P
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/namedotcom/go/v4 v4.0.2 h1:4gNkPaPRG/2tqFNUUof7jAVsA6vDutFutEOd7ivnDwA=
 github.com/namedotcom/go/v4 v4.0.2/go.mod h1:J6sVueHMb0qbarPgdhrzEVhEaYp+R1SCaTGl2s6/J1Q=
@@ -1581,7 +1602,10 @@ github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
 github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
 github.com/nzdjb/go-metaname v1.0.0 h1:sNASlZC1RM3nSudtBTE1a3ZVTDyTpjqI5WXRPrdZ9Hg=
 github.com/nzdjb/go-metaname v1.0.0/go.mod h1:0GR0LshZax1Lz4VrOrfNSE4dGvTp7HGjiemdczXT2H4=
+github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
 github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
+github.com/oklog/ulid/v2 v2.1.0 h1:+9lhoxAP56we25tyYETBBY1YLA2SaoLvUFgrP2miPJU=
+github.com/oklog/ulid/v2 v2.1.0/go.mod h1:rcEKHmBBKfef9DhnvX7y1HZBYxjXb0cP5ExxNsTT1QQ=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
@@ -1625,7 +1649,6 @@ github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2
 github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/pierrec/lz4 v1.0.2-0.20190131084431-473cd7ce01a1/go.mod h1:3/3N9NVKO0jef7pBehbT1qWhCMrIgbYNnFAZCqQ5LRc=
-github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
 github.com/pierrec/lz4 v2.6.1+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
 github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
 github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
@@ -1692,6 +1715,8 @@ github.com/prometheus/procfs v0.16.1 h1:hZ15bTNuirocR6u0JZ6BAHHmwS1p8B4P6MRqxtzM
 github.com/prometheus/procfs v0.16.1/go.mod h1:teAbpZRB1iIAJYREa1LsoWUXykVXA1KlTmWl8x/U+Is=
 github.com/prometheus/prometheus v0.304.2 h1:HhjbaAwet87x8Be19PFI/5W96UMubGy3zt24kayEuh4=
 github.com/prometheus/prometheus v0.304.2/go.mod h1:ioGx2SGKTY+fLnJSQCdTHqARVldGNS8OlIe3kvp98so=
+github.com/prometheus/sigv4 v0.1.2 h1:R7570f8AoM5YnTUPFm3mjZH5q2k4D+I/phCWvZ4PXG8=
+github.com/prometheus/sigv4 v0.1.2/go.mod h1:GF9fwrvLgkQwDdQ5BXeV9XUSCH/IPNqzvAoaohfjqMU=
 github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
 github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
 github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
@@ -1733,8 +1758,6 @@ github.com/selectel/domains-go v1.1.0 h1:futG50J43ALLKQAnZk9H9yOtLGnSUh7c5hSvuC5
 github.com/selectel/domains-go v1.1.0/go.mod h1:SugRKfq4sTpnOHquslCpzda72wV8u0cMBHx0C0l+bzA=
 github.com/selectel/go-selvpcclient/v4 v4.1.0 h1:22lBp+rzg9g2MP4iiGhpVAcCt0kMv7I7uV1W3taLSvQ=
 github.com/selectel/go-selvpcclient/v4 v4.1.0/go.mod h1:eFhL1KUW159KOJVeGO7k/Uxl0TYd/sBkWXjuF5WxmYk=
-github.com/shirou/gopsutil/v4 v4.25.5 h1:rtd9piuSMGeU8g1RMXjZs9y9luK5BwtnG7dZaQUJAsc=
-github.com/shirou/gopsutil/v4 v4.25.5/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
 github.com/shirou/gopsutil/v4 v4.25.6 h1:kLysI2JsKorfaFPcYmcJqbzROzsBWEOAtw6A7dIfqXs=
 github.com/shirou/gopsutil/v4 v4.25.6/go.mod h1:PfybzyydfZcN+JMMjkF6Zb8Mq1A/VcogFFg7hj50W9c=
 github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
@@ -1832,6 +1855,8 @@ github.com/timtadh/getopt v1.0.0/go.mod h1:L3EL6YN2G0eIAhYBo9b7SB9d/kEQmdnwthIlM
 github.com/timtadh/lexmachine v0.2.2/go.mod h1:GBJvD5OAfRn/gnp92zb9KTgHLB7akKyxmVivoYCcjQI=
 github.com/timtadh/lexmachine v0.2.3 h1:ZqlfHnfMcAygtbNM5Gv7jQf8hmM8LfVzDjfCrq235NQ=
 github.com/timtadh/lexmachine v0.2.3/go.mod h1:oK1NW+93fQSIF6s+J6sXBFWsCPCFbNmrwKV1i0aqvW0=
+github.com/tjfoc/gmsm v1.3.2 h1:7JVkAn5bvUJ7HtU08iW6UiD+UTmJTIToHCfeFzkcCxM=
+github.com/tjfoc/gmsm v1.3.2/go.mod h1:HaUcFuY0auTiaHB9MHFGCPx5IaLhTUd2atbCFBQXn9w=
 github.com/tklauser/go-sysconf v0.3.15 h1:VE89k0criAymJ/Os65CSn1IXaol+1wrsFHEB8Ol49K4=
 github.com/tklauser/go-sysconf v0.3.15/go.mod h1:Dmjwr6tYFIseJw7a3dRLJfsHAMXZ3nEnL/aZY+0IuI4=
 github.com/tklauser/numcpus v0.10.0 h1:18njr6LDBk1zuna922MgdjQuJFjrdppsZG60sHGfjso=
@@ -1848,8 +1873,6 @@ github.com/ugorji/go/codec v1.3.0 h1:Qd2W2sQawAfG8XSvzwhBeoGq71zXOC/Q1E9y/wUcsUA
 github.com/ugorji/go/codec v1.3.0/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
 github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec h1:2s/ghQ8wKE+UzD/hf3P4Gd1j0JI9ncbxv+nsypPoUYI=
 github.com/ultradns/ultradns-go-sdk v1.8.0-20241010134910-243eeec/go.mod h1:BZr7Qs3ku1ckpqed8tCRSqTlp8NAeZfAVpfx4OzXMss=
-github.com/uozi-tech/cosy v1.22.2 h1:PYk8wL2/2JnT+PcFjU/P1DwgPcNDEUl3gvY9lTnkjfo=
-github.com/uozi-tech/cosy v1.22.2/go.mod h1:0cnvyE4sz1/W2NxQaOEPvgD5qkhg51rmVNVSKhMQMmQ=
 github.com/uozi-tech/cosy v1.23.1 h1:+3QMMqcvWdh0oq6VJFA4NO/nXy2ez30I0fzzqygyQjc=
 github.com/uozi-tech/cosy v1.23.1/go.mod h1:ErH1Oo8nR3IwV+ek9wM8fGPcwr2fq9avnVpyMQj4ayE=
 github.com/uozi-tech/cosy-driver-mysql v0.2.2 h1:22S/XNIvuaKGqxQPsYPXN8TZ8hHjCQdcJKVQ83Vzxoo=
@@ -1863,8 +1886,6 @@ github.com/urfave/cli/v3 v3.3.8 h1:BzolUExliMdet9NlJ/u4m5vHSotJ3PzEqSAZ1oPMa/E=
 github.com/urfave/cli/v3 v3.3.8/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
 github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
 github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
-github.com/volcengine/volc-sdk-golang v1.0.212 h1:evyoDoYTPqc1j23cnTnbHO7Vu813O2VERWQ/FVm8z+k=
-github.com/volcengine/volc-sdk-golang v1.0.212/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
 github.com/volcengine/volc-sdk-golang v1.0.213 h1:Y/OlbZfv6hTI+r4vmcvtyKZ+KEsoibm9DGeEtNlymJE=
 github.com/volcengine/volc-sdk-golang v1.0.213/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
 github.com/vultr/govultr/v3 v3.21.0 h1:G/gOmCT7MGlII+iI98DjPdt/8IytC26oNcuk0LpJ8Y4=
@@ -2020,6 +2041,8 @@ golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
 golang.org/x/exp v0.0.0-20220827204233-334a2380cb91/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
+golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o=
+golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -2770,8 +2793,6 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
 gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gorm.io/datatypes v1.2.5 h1:9UogU3jkydFVW1bIVVeoYsTpLRgwDVW3rHfJG6/Ek9I=
-gorm.io/datatypes v1.2.5/go.mod h1:I5FUdlKpLb5PMqeMQhm30CQ6jXP8Rj89xkTeCSAaAD4=
 gorm.io/datatypes v1.2.6 h1:KafLdXvFUhzNeL2ncm03Gl3eTLONQfNKZ+wJ+9Y4Nck=
 gorm.io/datatypes v1.2.6/go.mod h1:M2iO+6S3hhi4nAyYe444Pcb0dcIiOMJ7QHaUXxyiNZY=
 gorm.io/driver/mysql v1.6.0 h1:eNbLmNTpPpTOVZi8MMxCi2aaIm0ZpInbORNXDwyLGvg=
@@ -2781,9 +2802,8 @@ gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkw
 gorm.io/driver/sqlite v1.5.0/go.mod h1:kDMDfntV9u/vuMmz8APHtHF0b4nyBB7sfCieC6G8k8I=
 gorm.io/driver/sqlite v1.6.0 h1:WHRRrIiulaPiPFmDcod6prc4l2VGVWHz80KspNsxSfQ=
 gorm.io/driver/sqlite v1.6.0/go.mod h1:AO9V1qIQddBESngQUKWL9yoH93HIeA1X6V633rBwyT8=
-gorm.io/driver/sqlserver v1.5.4 h1:xA+Y1KDNspv79q43bPyjDMUgHoYHLhXYmdFcYPobg8g=
-gorm.io/driver/sqlserver v1.5.4/go.mod h1:+frZ/qYmuna11zHPlh5oc2O6ZA/lS88Keb0XSH1Zh/g=
 gorm.io/driver/sqlserver v1.6.0 h1:VZOBQVsVhkHU/NzNhRJKoANt5pZGQAS1Bwc6m6dgfnc=
+gorm.io/driver/sqlserver v1.6.0/go.mod h1:WQzt4IJo/WHKnckU9jXBLMJIVNMVeTu25dnOzehntWw=
 gorm.io/gen v0.3.27 h1:ziocAFLpE7e0g4Rum69pGfB9S6DweTxK8gAun7cU8as=
 gorm.io/gen v0.3.27/go.mod h1:9zquz2xD1f3Eb/eHq4oLn2z6vDVvQlCY5S3uMBLv4EA=
 gorm.io/gorm v1.24.7-0.20230306060331-85eaf9eeda11/go.mod h1:L4uxeKpfBml98NYqVqwAdmV1a2nBtAec/cf3fpucW/k=
@@ -2808,8 +2828,8 @@ k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
 k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
 k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
 k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
-k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
-k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
+k8s.io/client-go v0.32.3 h1:RKPVltzopkSgHS7aS98QdscAgtgah/+zmpAogooIqVU=
+k8s.io/client-go v0.32.3/go.mod h1:3v0+3k4IcT9bXTc4V2rt+d2ZPPG700Xy6Oi0Gdl2PaY=
 k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
 k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
 k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=

+ 4 - 0
internal/notification/subscribe.go

@@ -26,9 +26,13 @@ func RemoveClient(c *gin.Context) {
 }
 
 func broadcast(data *model.Notification) {
+	// Broadcast to SSE clients
 	mutex.RLock()
 	defer mutex.RUnlock()
 	for _, evtChan := range clientMap {
 		evtChan <- data
 	}
+
+	// Broadcast to WebSocket clients
+	BroadcastToWebSocket(data)
 }

+ 62 - 0
internal/notification/websocket.go

@@ -0,0 +1,62 @@
+package notification
+
+import (
+	"sync"
+
+	"github.com/0xJacky/Nginx-UI/model"
+)
+
+// WebSocketNotificationManager manages WebSocket notification subscriptions
+type WebSocketNotificationManager struct {
+	subscribers map[chan *model.Notification]struct{}
+	mutex       sync.RWMutex
+}
+
+var (
+	wsManager     *WebSocketNotificationManager
+	wsManagerOnce sync.Once
+)
+
+// GetWebSocketManager returns the singleton WebSocket notification manager
+func GetWebSocketManager() *WebSocketNotificationManager {
+	wsManagerOnce.Do(func() {
+		wsManager = &WebSocketNotificationManager{
+			subscribers: make(map[chan *model.Notification]struct{}),
+		}
+	})
+	return wsManager
+}
+
+// Subscribe adds a channel to receive notifications
+func (m *WebSocketNotificationManager) Subscribe(ch chan *model.Notification) {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	m.subscribers[ch] = struct{}{}
+}
+
+// Unsubscribe removes a channel from receiving notifications
+func (m *WebSocketNotificationManager) Unsubscribe(ch chan *model.Notification) {
+	m.mutex.Lock()
+	defer m.mutex.Unlock()
+	delete(m.subscribers, ch)
+	close(ch)
+}
+
+// Broadcast sends a notification to all subscribers
+func (m *WebSocketNotificationManager) Broadcast(data *model.Notification) {
+	m.mutex.RLock()
+	defer m.mutex.RUnlock()
+
+	for ch := range m.subscribers {
+		select {
+		case ch <- data:
+		default:
+			// Skip if channel buffer is full
+		}
+	}
+}
+
+// BroadcastToWebSocket is a convenience function to broadcast notifications
+func BroadcastToWebSocket(data *model.Notification) {
+	GetWebSocketManager().Broadcast(data)
+}

+ 2 - 0
router/routers.go

@@ -11,6 +11,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/api/cluster"
 	"github.com/0xJacky/Nginx-UI/api/config"
 	"github.com/0xJacky/Nginx-UI/api/crypto"
+	"github.com/0xJacky/Nginx-UI/api/event"
 	"github.com/0xJacky/Nginx-UI/api/external_notify"
 	"github.com/0xJacky/Nginx-UI/api/nginx"
 	nginxLog "github.com/0xJacky/Nginx-UI/api/nginx_log"
@@ -93,6 +94,7 @@ func InitRouter() {
 		{
 			analytic.InitWebSocketRouter(w)
 			certificate.InitCertificateWebSocketRouter(w)
+			event.InitRouter(w)
 			o := w.Group("", middleware.RequireSecureSession())
 			{
 				terminal.InitRouter(o)

Some files were not shown because too many files changed in this diff