Browse Source

feat: add port scanning #904

Jacky 1 month ago
parent
commit
beccf9db85

+ 175 - 0
api/system/port_scan.go

@@ -0,0 +1,175 @@
+package system
+
+import (
+	"fmt"
+	"net"
+	"os/exec"
+	"strconv"
+	"strings"
+	"time"
+
+	"github.com/gin-gonic/gin"
+	"github.com/uozi-tech/cosy/logger"
+)
+
+type PortScanRequest struct {
+	StartPort int `json:"start_port" binding:"required,min=1,max=65535"`
+	EndPort   int `json:"end_port" binding:"required,min=1,max=65535"`
+	Page      int `json:"page" binding:"required,min=1"`
+	PageSize  int `json:"page_size" binding:"required,min=1,max=1000"`
+}
+
+type PortInfo struct {
+	Port    int    `json:"port"`
+	Status  string `json:"status"`
+	Process string `json:"process"`
+}
+
+type PortScanResponse struct {
+	Data     []PortInfo `json:"data"`
+	Total    int        `json:"total"`
+	Page     int        `json:"page"`
+	PageSize int        `json:"page_size"`
+}
+
+func PortScan(c *gin.Context) {
+	var req PortScanRequest
+	if err := c.ShouldBindJSON(&req); err != nil {
+		c.JSON(400, gin.H{"message": err.Error()})
+		return
+	}
+
+	if req.StartPort > req.EndPort {
+		c.JSON(400, gin.H{"message": "Start port must be less than or equal to end port"})
+		return
+	}
+
+	// Calculate pagination
+	totalPorts := req.EndPort - req.StartPort + 1
+	startIndex := (req.Page - 1) * req.PageSize
+	endIndex := startIndex + req.PageSize
+
+	if startIndex >= totalPorts {
+		c.JSON(200, PortScanResponse{
+			Data:     []PortInfo{},
+			Total:    totalPorts,
+			Page:     req.Page,
+			PageSize: req.PageSize,
+		})
+		return
+	}
+
+	if endIndex > totalPorts {
+		endIndex = totalPorts
+	}
+
+	// Calculate actual port range for this page
+	actualStartPort := req.StartPort + startIndex
+	actualEndPort := req.StartPort + endIndex - 1
+
+	var ports []PortInfo
+
+	// Get listening ports info
+	listeningPorts := getListeningPorts()
+
+	// Scan ports in the current page range
+	for port := actualStartPort; port <= actualEndPort; port++ {
+		portInfo := PortInfo{
+			Port:    port,
+			Status:  "closed",
+			Process: "",
+		}
+
+		// Check if port is listening
+		if processInfo, exists := listeningPorts[port]; exists {
+			portInfo.Status = "listening"
+			portInfo.Process = processInfo
+		} else {
+			// Quick check if port is open but not in listening list
+			if isPortOpen(port) {
+				portInfo.Status = "open"
+			}
+		}
+
+		ports = append(ports, portInfo)
+	}
+
+	c.JSON(200, PortScanResponse{
+		Data:     ports,
+		Total:    totalPorts,
+		Page:     req.Page,
+		PageSize: req.PageSize,
+	})
+}
+
+func isPortOpen(port int) bool {
+	timeout := time.Millisecond * 100
+	conn, err := net.DialTimeout("tcp", fmt.Sprintf("localhost:%d", port), timeout)
+	if err != nil {
+		return false
+	}
+	defer conn.Close()
+	return true
+}
+
+func getListeningPorts() map[int]string {
+	ports := make(map[int]string)
+
+	// Try netstat first
+	if cmd := exec.Command("netstat", "-tlnp"); cmd.Err == nil {
+		if output, err := cmd.Output(); err == nil {
+			lines := strings.Split(string(output), "\n")
+			for _, line := range lines {
+				if strings.Contains(line, "LISTEN") {
+					fields := strings.Fields(line)
+					if len(fields) >= 4 {
+						address := fields[3]
+						process := ""
+						if len(fields) >= 7 {
+							process = fields[6]
+						}
+
+						// Extract port from address (format: 0.0.0.0:port or :::port)
+						if colonIndex := strings.LastIndex(address, ":"); colonIndex != -1 {
+							portStr := address[colonIndex+1:]
+							if port, err := strconv.Atoi(portStr); err == nil {
+								ports[port] = process
+							}
+						}
+					}
+				}
+			}
+			return ports
+		}
+	}
+
+	// Fallback to ss command
+	if cmd := exec.Command("ss", "-tlnp"); cmd.Err == nil {
+		if output, err := cmd.Output(); err == nil {
+			lines := strings.Split(string(output), "\n")
+			for _, line := range lines {
+				if strings.Contains(line, "LISTEN") {
+					fields := strings.Fields(line)
+					if len(fields) >= 4 {
+						address := fields[3]
+						process := ""
+						if len(fields) >= 6 {
+							process = fields[5]
+						}
+
+						// Extract port from address
+						if colonIndex := strings.LastIndex(address, ":"); colonIndex != -1 {
+							portStr := address[colonIndex+1:]
+							if port, err := strconv.Atoi(portStr); err == nil {
+								ports[port] = process
+							}
+						}
+					}
+				}
+			}
+		}
+	}
+
+	logger.Debug("Found listening ports: %v", ports)
+	return ports
+}

+ 1 - 0
api/system/router.go

@@ -24,6 +24,7 @@ func InitPrivateRouter(r *gin.RouterGroup) {
 	r.GET("upgrade/current", GetCurrentVersion)
 
 	r.GET("system/processing", GetProcessingStatus)
+	r.POST("system/port_scan", PortScan)
 }
 
 func InitSelfCheckRouter(r *gin.RouterGroup) {

+ 2 - 0
app/components.d.ts

@@ -97,6 +97,8 @@ declare module 'vue' {
     NotificationNotification: typeof import('./src/components/Notification/Notification.vue')['default']
     OTPInputOTPInput: typeof import('./src/components/OTPInput/OTPInput.vue')['default']
     PageHeaderPageHeader: typeof import('./src/components/PageHeader/PageHeader.vue')['default']
+    PortScannerPortScanner: typeof import('./src/components/PortScanner/PortScanner.vue')['default']
+    PortScannerPortScannerCompact: typeof import('./src/components/PortScanner/PortScannerCompact.vue')['default']
     ProcessingStatusProcessingStatus: typeof import('./src/components/ProcessingStatus/ProcessingStatus.vue')['default']
     ReactiveFromNowReactiveFromNow: typeof import('./src/components/ReactiveFromNow/ReactiveFromNow.vue')['default']
     RouterLink: typeof import('vue-router')['RouterLink']

+ 27 - 0
app/src/api/port_scan.ts

@@ -0,0 +1,27 @@
+import { http } from '@uozi-admin/request'
+
+export interface PortScanRequest {
+  start_port: number
+  end_port: number
+  page: number
+  page_size: number
+}
+
+export interface PortInfo {
+  port: number
+  status: string
+  process: string
+}
+
+export interface PortScanResponse {
+  data: PortInfo[]
+  total: number
+  page: number
+  page_size: number
+}
+
+const portScan = {
+  scan: (data: PortScanRequest) => http.post<PortScanResponse>('/system/port_scan', data),
+}
+
+export default portScan

+ 282 - 0
app/src/components/PortScanner/PortScannerCompact.vue

@@ -0,0 +1,282 @@
+<script setup lang="ts">
+import type { PortInfo, PortScanRequest } from '@/api/port_scan'
+import { Badge, message } from 'ant-design-vue'
+import { computed, reactive, ref } from 'vue'
+import portScan from '@/api/port_scan'
+
+interface FormData {
+  startPort: number
+  endPort: number
+}
+
+const loading = ref(false)
+const formData = reactive<FormData>({
+  startPort: 80,
+  endPort: 8080,
+})
+
+const tableData = ref<PortInfo[]>([])
+const pagination = reactive({
+  current: 1,
+  pageSize: 20,
+  total: 0,
+  showSizeChanger: false,
+  showQuickJumper: false,
+  simple: true,
+  size: 'small' as const,
+})
+
+const columns = [
+  {
+    title: $gettext('Port'),
+    dataIndex: 'port',
+    key: 'port',
+    width: 60,
+  },
+  {
+    title: $gettext('Status'),
+    dataIndex: 'status',
+    key: 'status',
+    width: 80,
+    customRender: ({ text }: { text: string }) => {
+      const statusMap = {
+        listening: { color: 'orange', text: $gettext('Listening') },
+        open: { color: 'blue', text: $gettext('Open') },
+        closed: { color: 'green', text: $gettext('Closed') },
+      }
+      const status = statusMap[text as keyof typeof statusMap] || { status: 'error', text: $gettext('Unknown') }
+      return h(Badge, {
+        color: status.color,
+        text: h('span', { style: 'font-size: 11px;' }, status.text),
+      })
+    },
+  },
+  {
+    title: $gettext('Process'),
+    dataIndex: 'process',
+    key: 'process',
+    ellipsis: true,
+    customRender: ({ text }: { text: string }) => {
+      if (!text)
+        return '-'
+
+      // Extract process name from format like "1234/nginx: master process" or "1234/nginx"
+      // Use a more specific regex to avoid backtracking issues
+      const match = text.match(/^\d+\/([^:]+)/)
+      if (match) {
+        const processName = match[1].trim()
+        return h('span', { title: text, style: 'font-size: 12px;' }, processName)
+      }
+
+      // Fallback: if no match, show first 10 characters
+      return h('span', { title: text, style: 'font-size: 12px;' }, text.substring(0, 10))
+    },
+  },
+]
+
+const isFormValid = computed(() => {
+  return formData.startPort >= 1
+    && formData.endPort <= 65535
+    && formData.startPort <= formData.endPort
+})
+
+async function scanPorts() {
+  if (!isFormValid.value) {
+    message.error($gettext('Please enter a valid port range'))
+    return
+  }
+
+  loading.value = true
+  pagination.current = 1
+
+  try {
+    await loadData()
+    message.success($gettext('Scan completed'))
+  }
+  catch (error) {
+    console.error('Port scan failed:', error)
+    message.error($gettext('Scan failed'))
+  }
+  finally {
+    loading.value = false
+  }
+}
+
+async function loadData() {
+  const request: PortScanRequest = {
+    start_port: formData.startPort,
+    end_port: formData.endPort,
+    page: pagination.current,
+    page_size: pagination.pageSize,
+  }
+
+  const response = await portScan.scan(request)
+  tableData.value = response.data
+  pagination.total = response.total
+}
+
+async function handleTableChange(pag: { current?: number, pageSize?: number }) {
+  if (pag.current) {
+    pagination.current = pag.current
+  }
+
+  if (pagination.total > 0) {
+    loading.value = true
+    try {
+      await loadData()
+    }
+    finally {
+      loading.value = false
+    }
+  }
+}
+
+function quickScan(start: number, end: number) {
+  formData.startPort = start
+  formData.endPort = end
+  scanPorts()
+}
+</script>
+
+<template>
+  <div class="port-scanner-compact">
+    <div class="scan-form">
+      <ASpace direction="vertical" size="small" style="width: 100%">
+        <ARow :gutter="8">
+          <ACol :span="11">
+            <AInputNumber
+              v-model:value="formData.startPort"
+              :min="1"
+              :max="65535"
+              :placeholder="$gettext('Start')"
+              size="small"
+              style="width: 100%"
+            />
+          </ACol>
+          <ACol :span="2" class="text-center">
+            <span style="line-height: 24px;">-</span>
+          </ACol>
+          <ACol :span="11">
+            <AInputNumber
+              v-model:value="formData.endPort"
+              :min="1"
+              :max="65535"
+              :placeholder="$gettext('End')"
+              size="small"
+              style="width: 100%"
+            />
+          </ACol>
+        </ARow>
+
+        <AButton
+          type="primary"
+          size="small"
+          :loading="loading"
+          :disabled="!isFormValid"
+          block
+          @click="scanPorts"
+        >
+          {{ $gettext('Scan Ports') }}
+        </AButton>
+
+        <div class="quick-actions">
+          <ASpace size="small" wrap>
+            <AButton size="small" @click="quickScan(80, 443)">
+              Web
+            </AButton>
+            <AButton size="small" @click="quickScan(20, 22)">
+              SSH/FTP
+            </AButton>
+            <AButton size="small" @click="quickScan(3306, 5432)">
+              DB
+            </AButton>
+            <AButton size="small" @click="quickScan(1, 1024)">
+              {{ $gettext('System') }}
+            </AButton>
+          </ASpace>
+        </div>
+      </ASpace>
+    </div>
+
+    <div v-if="pagination.total > 0" class="scan-results">
+      <ADivider style="margin: 12px 0;">
+        <span style="font-size: 12px; color: #666;">
+          {{ $gettext('Scan Results') }} ({{ pagination.total }})
+        </span>
+      </ADivider>
+
+      <ATable
+        :columns="columns"
+        :data-source="tableData"
+        :pagination="pagination"
+        :loading="loading"
+        size="small"
+        :scroll="{ y: 300 }"
+        @change="handleTableChange"
+      />
+    </div>
+  </div>
+</template>
+
+<style scoped lang="less">
+.port-scanner-compact {
+  .scan-form {
+    padding: 8px 0;
+  }
+
+  .quick-actions {
+    :deep(.ant-btn) {
+      font-size: 11px;
+      height: 20px;
+      padding: 0 6px;
+    }
+  }
+
+  .scan-results {
+    :deep(.ant-table) {
+      font-size: 12px;
+
+      .ant-table-thead > tr > th {
+        padding: 4px 8px;
+        font-size: 11px;
+        background-color: var(--ant-color-fill-alter);
+      }
+
+      .ant-table-tbody > tr > td {
+        padding: 4px 8px;
+      }
+
+      .ant-pagination {
+        margin: 8px 0 0 0;
+        text-align: center;
+
+        .ant-pagination-item,
+        .ant-pagination-prev,
+        .ant-pagination-next {
+          min-width: 24px;
+          height: 24px;
+          line-height: 22px;
+          font-size: 12px;
+        }
+      }
+    }
+
+    // Custom styling for badge status indicators
+    :deep(.ant-badge) {
+      .ant-badge-status-dot {
+        width: 8px;
+        height: 8px;
+      }
+
+      .ant-badge-status-text {
+        margin-left: 6px;
+        font-size: 11px;
+      }
+    }
+  }
+
+  .text-center {
+    text-align: center;
+  }
+}
+</style>

+ 1 - 0
app/src/components/PortScanner/index.ts

@@ -0,0 +1 @@
+export { default as PortScannerCompact } from './PortScannerCompact.vue'

+ 59 - 6
app/src/language/ar/app.po

@@ -457,8 +457,8 @@ msgid "Base information"
 msgstr "المعلومات الأساسية"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "أساسي"
 
@@ -716,8 +716,8 @@ msgstr "المسار المتغير"
 msgid "Channel"
 msgstr "القناة"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "محادثة"
 
@@ -897,10 +897,14 @@ msgstr "حجم مخزن طلب جسم العميل"
 msgid "Client request header buffer size"
 msgstr "حجم مخزن رأس طلب العميل"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "إغلاق"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "مغلق"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "إكمال الكود غير مفعّل"
@@ -961,7 +965,7 @@ msgstr "ملف إدخال التكوين غير موجود"
 msgid "Config path is empty"
 msgstr "مسار التكوين فارغ"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "قالب التكوين"
 
@@ -1673,6 +1677,10 @@ msgstr "تم التفعيل بنجاح"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "تشفير الموقع باستخدام Let's Encrypt"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "النهاية"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "تم تنظيف متغيرات البيئة"
@@ -2533,6 +2541,10 @@ msgstr "ابدأ الرابط"
 msgid "List"
 msgstr "قائمة"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "يستمع"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "متوسط التحميل:"
@@ -3289,6 +3301,10 @@ msgstr "متصل"
 msgid "Only zip files are allowed"
 msgstr "يُسمح فقط بملفات zip"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "مفتوح"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "أوبن أي آي"
@@ -3464,6 +3480,10 @@ msgid ""
 "button below."
 msgstr "يرجى إدخال اسم لمفتاح المرور الذي ترغب في إنشائه ثم انقر على زر موافق أدناه."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "الرجاء إدخال نطاق منافذ صالح"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "يرجى إدخال رمز OTP:"
@@ -3582,10 +3602,16 @@ msgstr "يرجى اختيار عقدة واحدة على الأقل للترقي
 msgid "Please type \"Revoke\" to confirm"
 msgstr "يرجى كتابة \"إلغاء\" للتأكيد"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "المنفذ"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "ماسح المنافذ"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3605,6 +3631,10 @@ msgstr "تفضيل"
 msgid "Preparing lego configurations"
 msgstr "تحضير تكوينات Lego"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "العملية"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "توزيع العمليات"
@@ -4195,6 +4225,22 @@ msgstr "تم الحفظ بنجاح"
 msgid "Sbin path not exist"
 msgstr "مسار sbin غير موجود"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "تم المسح"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "فشل المسح"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "مسح المنافذ"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "نتائج المسح"
+
 #: 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 "امسح رمز الاستجابة السريعة بهاتفك المحمول لإضافة الحساب إلى التطبيق."
@@ -4461,6 +4507,10 @@ msgstr "تسجيل الدخول عبر SSO"
 msgid "Stable"
 msgstr "مستقر"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "بداية"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4471,6 +4521,7 @@ msgstr "بدء الاستعادة"
 msgid "Static"
 msgstr "ثابت"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4656,6 +4707,7 @@ msgstr "مزامنة إلى"
 msgid "Synchronization"
 msgstr "مزامنة"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "نظام"
@@ -5055,6 +5107,7 @@ msgstr "يتطلب المصادقة الثنائية"
 msgid "Type"
 msgstr "نوع"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "غير معروف"

+ 59 - 6
app/src/language/de_DE/app.po

@@ -467,8 +467,8 @@ msgid "Base information"
 msgstr "Basisinformationen"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Basis"
 
@@ -718,8 +718,8 @@ msgstr "Geänderter Pfad"
 msgid "Channel"
 msgstr "Kanal"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Chat"
 
@@ -907,10 +907,14 @@ msgstr "Puffergröße für den Anforderungskörper des Clients"
 msgid "Client request header buffer size"
 msgstr "Größe des Puffers für Client-Anfrageheader"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "Schließen"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "Geschlossen"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "Code-Vervollständigung ist nicht aktiviert"
@@ -971,7 +975,7 @@ msgstr "Konfigurations-Eingabedatei existiert nicht"
 msgid "Config path is empty"
 msgstr "Konfigurationspfad ist leer"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "Konfigurationsvorlage"
 
@@ -1693,6 +1697,10 @@ msgstr "Erfolgreich aktiviert"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Webseite mit Let's Encrypt verschlüsseln"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "Ende"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "Umgebungsvariablen gesäubert"
@@ -2560,6 +2568,10 @@ msgstr "Link Start"
 msgid "List"
 msgstr "Liste"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "Lauschend"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "Durchschnittliche Last:"
@@ -3322,6 +3334,10 @@ msgstr "Online"
 msgid "Only zip files are allowed"
 msgstr "Nur ZIP-Dateien sind erlaubt"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "Offen"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3499,6 +3515,10 @@ msgstr ""
 "Bitte gib einen Namen für den Passkey ein, den du erstellen möchtest, und "
 "klicke auf die Schaltfläche OK."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "Bitte geben Sie einen gültigen Portbereich ein"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "Bitte gib den OTP-Code ein:"
@@ -3630,10 +3650,16 @@ msgstr "Bitte wähle mindestens einen Knoten zum Upgrade aus"
 msgid "Please type \"Revoke\" to confirm"
 msgstr "Bitte geben Sie \"Widerrufen\" ein, um zu bestätigen"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "Port"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "Port-Scanner"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3653,6 +3679,10 @@ msgstr "Einstellungen"
 msgid "Preparing lego configurations"
 msgstr "Lego-Konfigurationen vorbereiten"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "Prozess"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "Prozessverteilung"
@@ -4251,6 +4281,22 @@ msgstr "Speichern erfolgreich"
 msgid "Sbin path not exist"
 msgstr "Sbin-Pfad existiert nicht"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "Scan abgeschlossen"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "Scan fehlgeschlagen"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "Ports scannen"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "Scan-Ergebnisse"
+
 #: 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 "Scanne den QR-Code mit deinem Handy, um das Konto zur App hinzuzufügen."
@@ -4523,6 +4569,10 @@ msgstr "SSO-Anmeldung"
 msgid "Stable"
 msgstr "Stabil"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "Start"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4533,6 +4583,7 @@ msgstr "Wiederherstellung starten"
 msgid "Static"
 msgstr "Statisch"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4723,6 +4774,7 @@ msgstr "Synchronisieren mit"
 msgid "Synchronization"
 msgstr "Synchronisation"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "System"
@@ -5130,6 +5182,7 @@ msgstr "Zwei-Faktor-Authentifizierung erforderlich"
 msgid "Type"
 msgstr "Typ"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "Unbekannt"

+ 59 - 6
app/src/language/en/app.po

@@ -441,8 +441,8 @@ msgid "Base information"
 msgstr ""
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr ""
 
@@ -690,8 +690,8 @@ msgstr ""
 msgid "Channel"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr ""
 
@@ -840,10 +840,14 @@ msgstr ""
 msgid "Client request header buffer size"
 msgstr ""
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr ""
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr ""
@@ -904,7 +908,7 @@ msgstr ""
 msgid "Config path is empty"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr ""
 
@@ -1613,6 +1617,10 @@ msgstr ""
 msgid "Encrypt website with Let's Encrypt"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr ""
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr ""
@@ -2463,6 +2471,10 @@ msgstr ""
 msgid "List"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr ""
@@ -3204,6 +3216,10 @@ msgstr ""
 msgid "Only zip files are allowed"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr ""
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr ""
@@ -3374,6 +3390,10 @@ msgid ""
 "button below."
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr ""
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr ""
@@ -3491,10 +3511,16 @@ msgstr ""
 msgid "Please type \"Revoke\" to confirm"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr ""
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr ""
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3514,6 +3540,10 @@ msgstr ""
 msgid "Preparing lego configurations"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr ""
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr ""
@@ -4098,6 +4128,22 @@ msgstr ""
 msgid "Sbin path not exist"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr ""
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr ""
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr ""
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr ""
+
 #: 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 ""
@@ -4358,6 +4404,10 @@ msgstr ""
 msgid "Stable"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr ""
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4368,6 +4418,7 @@ msgstr ""
 msgid "Static"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4547,6 +4598,7 @@ msgstr ""
 msgid "Synchronization"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr ""
@@ -4903,6 +4955,7 @@ msgstr ""
 msgid "Type"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr ""

+ 59 - 6
app/src/language/es/app.po

@@ -474,8 +474,8 @@ msgid "Base information"
 msgstr "Información general"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Básico"
 
@@ -731,8 +731,8 @@ msgstr "Ruta cambiada"
 msgid "Channel"
 msgstr "Canal"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Chat"
 
@@ -916,10 +916,14 @@ msgstr "Tamaño del búfer del cuerpo de la solicitud del cliente"
 msgid "Client request header buffer size"
 msgstr "Tamaño del búfer de cabecera de solicitud del cliente"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "Cerrar"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "Cerrado"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "La finalización de código no está habilitada"
@@ -980,7 +984,7 @@ msgstr "El archivo de entrada de configuración no existe"
 msgid "Config path is empty"
 msgstr "La ruta de configuración está vacía"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "Plantilla de configuración"
 
@@ -1702,6 +1706,10 @@ msgstr "Habilitado con éxito"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Encriptar sitio web con Let's Encrypt"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "Fin"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "Variables de entorno limpiadas"
@@ -2567,6 +2575,10 @@ msgstr "Iniciar conexión"
 msgid "List"
 msgstr "Lista"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "Escuchando"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "Promedios de carga:"
@@ -3330,6 +3342,10 @@ msgstr "En línea"
 msgid "Only zip files are allowed"
 msgstr "Solo se permiten archivos ZIP"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "Abierto"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3508,6 +3524,10 @@ msgstr ""
 "Ingrese un nombre para la llave de acceso que desea crear y a continuación "
 "haga clic en el botón Aceptar."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "Por favor, introduzca un rango de puertos válido"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "Por favor, ingrese el código OTP:"
@@ -3641,10 +3661,16 @@ msgstr "Seleccione al menos un nodo para actualizar"
 msgid "Please type \"Revoke\" to confirm"
 msgstr "Por favor, escriba \"Revocar\" para confirmar"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "Puerto"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "Escáner de puertos"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3664,6 +3690,10 @@ msgstr "Configuración"
 msgid "Preparing lego configurations"
 msgstr "Preparar la configuración de LEGO"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "Proceso"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "Distribución de procesos"
@@ -4258,6 +4288,22 @@ msgstr "Guardado con éxito"
 msgid "Sbin path not exist"
 msgstr "La ruta de sbin no existe"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "Escaneo completado"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "Escaneo fallido"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "Escanear puertos"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "Resultados del escaneo"
+
 #: 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 ""
@@ -4532,6 +4578,10 @@ msgstr "Acceso SSO"
 msgid "Stable"
 msgstr "Estable"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "Inicio"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4542,6 +4592,7 @@ msgstr "Iniciar restauración"
 msgid "Static"
 msgstr "Estático"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4730,6 +4781,7 @@ msgstr "Sincronizar con"
 msgid "Synchronization"
 msgstr "Sincronización"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "Sistema"
@@ -5138,6 +5190,7 @@ msgstr "Se requiere autenticación de dos factores"
 msgid "Type"
 msgstr "Tipo"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "Desconocido"

+ 59 - 6
app/src/language/fr_FR/app.po

@@ -472,8 +472,8 @@ msgid "Base information"
 msgstr "Information générale"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Basique"
 
@@ -722,8 +722,8 @@ msgstr "Chemin modifié"
 msgid "Channel"
 msgstr "Canal"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Chat"
 
@@ -910,10 +910,14 @@ msgstr "Taille du tampon du corps de la requête client"
 msgid "Client request header buffer size"
 msgstr "Taille du tampon d'en-tête de requête client"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "Fermer"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "Fermé"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "La complétion de code n'est pas activée"
@@ -976,7 +980,7 @@ msgstr "Le fichier d'entrée de configuration n'existe pas"
 msgid "Config path is empty"
 msgstr "Le chemin de configuration est vide"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "Modèle de configuration"
 
@@ -1696,6 +1700,10 @@ msgstr "Activé avec succès"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Crypter le site Web avec Let's Encrypt"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "Fin"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "Variables d'environnement nettoyées"
@@ -2565,6 +2573,10 @@ msgstr "Démarrer la liaison"
 msgid "List"
 msgstr "Liste"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "En écoute"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "Charge moyenne :"
@@ -3327,6 +3339,10 @@ msgstr "En ligne"
 msgid "Only zip files are allowed"
 msgstr "Seuls les fichiers ZIP sont autorisés"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "Ouvert"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3507,6 +3523,10 @@ msgstr ""
 "Veuillez entrer un nom pour la clé d'accès que vous souhaitez créer et "
 "cliquer sur le bouton OK ci-dessous."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "Veuillez entrer une plage de ports valide"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "Veuillez entrer le code OTP :"
@@ -3638,10 +3658,16 @@ msgstr "Veuillez sélectionner au moins un nœud à mettre à niveau"
 msgid "Please type \"Revoke\" to confirm"
 msgstr "Veuillez taper \"Révoquer\" pour confirmer"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "Port"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "Scanner de ports"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3661,6 +3687,10 @@ msgstr "Préférence"
 msgid "Preparing lego configurations"
 msgstr "Préparation des configurations Lego"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "Processus"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "Répartition des processus"
@@ -4257,6 +4287,22 @@ msgstr "Enregistré avec succès"
 msgid "Sbin path not exist"
 msgstr "Le chemin sbin n'existe pas"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "Analyse terminée"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "Échec de l'analyse"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "Scanner les ports"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "Résultats du scan"
+
 #: 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 ""
@@ -4531,6 +4577,10 @@ msgstr "Connexion SSO"
 msgid "Stable"
 msgstr "Stable"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "Début"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4541,6 +4591,7 @@ msgstr "Démarrer la restauration"
 msgid "Static"
 msgstr "Statique"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4731,6 +4782,7 @@ msgstr "Synchroniser vers"
 msgid "Synchronization"
 msgstr "Synchronisation"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "Système"
@@ -5146,6 +5198,7 @@ msgstr "Authentification à deux facteurs requise"
 msgid "Type"
 msgstr "Type"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "Inconnu"

+ 59 - 6
app/src/language/ja_JP/app.po

@@ -458,8 +458,8 @@ msgid "Base information"
 msgstr "基本情報"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "基本"
 
@@ -707,8 +707,8 @@ msgstr "変更されたパス"
 msgid "Channel"
 msgstr "チャンネル"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "チャット"
 
@@ -879,10 +879,14 @@ msgstr "クライアントリクエストボディのバッファサイズ"
 msgid "Client request header buffer size"
 msgstr "クライアントリクエストヘッダーバッファサイズ"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "閉じる"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "閉じました"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "コード補完が有効になっていません"
@@ -943,7 +947,7 @@ msgstr "設定エントリファイルが存在しません"
 msgid "Config path is empty"
 msgstr "設定パスが空です"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "設定テンプレート"
 
@@ -1651,6 +1655,10 @@ msgstr "有効化に成功しました"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Let's Encryptでウェブサイトを暗号化"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "終了"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "環境変数をクリーンアップしました"
@@ -2501,6 +2509,10 @@ msgstr "リンクスタート"
 msgid "List"
 msgstr "リスト"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "リスニング"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "平均負荷:"
@@ -3250,6 +3262,10 @@ msgstr "オンライン"
 msgid "Only zip files are allowed"
 msgstr "ZIPファイルのみ許可されています"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "開いている"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3422,6 +3438,10 @@ msgid ""
 "button below."
 msgstr "作成したいパスキーの名前を入力し、下のOKボタンをクリックしてください。"
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "有効なポート範囲を入力してください"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "OTPコードを入力してください:"
@@ -3540,10 +3560,16 @@ msgstr "少なくとも1つのノードを選択してアップグレードし
 msgid "Please type \"Revoke\" to confirm"
 msgstr "確認のために「取り消す」と入力してください"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "ポート"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "ポートスキャナー"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3563,6 +3589,10 @@ msgstr "設定"
 msgid "Preparing lego configurations"
 msgstr "Lego 設定を準備中"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "プロセス"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "プロセス分布"
@@ -4147,6 +4177,22 @@ msgstr "正常に保存されました"
 msgid "Sbin path not exist"
 msgstr "sbin パスが存在しません"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "スキャン完了"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "スキャン失敗"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "ポートをスキャン"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "スキャン結果"
+
 #: 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 "スマートフォンでQRコードをスキャンして、アプリにアカウントを追加します。"
@@ -4411,6 +4457,10 @@ msgstr "SSOログイン"
 msgid "Stable"
 msgstr "安定版"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "開始"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4421,6 +4471,7 @@ msgstr "復元を開始"
 msgid "Static"
 msgstr "静的"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4606,6 +4657,7 @@ msgstr "同期先"
 msgid "Synchronization"
 msgstr "同期"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "システム"
@@ -4972,6 +5024,7 @@ msgstr "二要素認証が必要です"
 msgid "Type"
 msgstr "タイプ"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "不明"

+ 59 - 6
app/src/language/ko_KR/app.po

@@ -456,8 +456,8 @@ msgid "Base information"
 msgstr "기본 정보"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "기본"
 
@@ -706,8 +706,8 @@ msgstr "변경된 경로"
 msgid "Channel"
 msgstr "채널"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "채팅"
 
@@ -875,10 +875,14 @@ msgstr "클라이언트 요청 본문 버퍼 크기"
 msgid "Client request header buffer size"
 msgstr "클라이언트 요청 헤더 버퍼 크기"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "닫기"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "닫힘"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "코드 완성이 활성화되지 않았습니다"
@@ -939,7 +943,7 @@ msgstr "구성 항목 파일이 존재하지 않습니다"
 msgid "Config path is empty"
 msgstr "설정 경로가 비어 있습니다"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "설정 템플릿"
 
@@ -1649,6 +1653,10 @@ msgstr "성공적으로 활성화됨"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Let's Encrypt로 웹사이트 암호화"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "끝"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "환경 변수가 정리되었습니다"
@@ -2499,6 +2507,10 @@ msgstr "링크 시작"
 msgid "List"
 msgstr "목록"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "수신 중"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "평균 부하:"
@@ -3245,6 +3257,10 @@ msgstr "온라인"
 msgid "Only zip files are allowed"
 msgstr "ZIP 파일만 허용됩니다"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "열림"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "오픈AI"
@@ -3417,6 +3433,10 @@ msgid ""
 "button below."
 msgstr "생성하려는 패스키의 이름을 입력하고 아래의 확인 버튼을 클릭하세요."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "유효한 포트 범위를 입력하세요"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "OTP 코드를 입력해 주세요:"
@@ -3533,10 +3553,16 @@ msgstr "업그레이드할 노드를 최소한 하나 이상 선택해 주세요
 msgid "Please type \"Revoke\" to confirm"
 msgstr "확인하려면 \"Revoke\"를 입력하세요"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "포트"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "포트 스캐너"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3556,6 +3582,10 @@ msgstr "환경설정"
 msgid "Preparing lego configurations"
 msgstr "Lego 설정 준비 중"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "프로세스"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "프로세스 분포"
@@ -4142,6 +4172,22 @@ msgstr "성공적으로 저장됨"
 msgid "Sbin path not exist"
 msgstr "sbin 경로가 존재하지 않습니다"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "스캔 완료"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "스캔 실패"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "포트 스캔"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "스캔 결과"
+
 #: 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 "휴대폰으로 QR 코드를 스캔하여 앱에 계정을 추가하세요."
@@ -4406,6 +4452,10 @@ msgstr "SSO 로그인"
 msgid "Stable"
 msgstr "안정적"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "시작"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4416,6 +4466,7 @@ msgstr "복원 시작"
 msgid "Static"
 msgstr "정적"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4601,6 +4652,7 @@ msgstr "동기화 대상"
 msgid "Synchronization"
 msgstr "동기화"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "시스템"
@@ -4965,6 +5017,7 @@ msgstr "2단계 인증이 필요합니다"
 msgid "Type"
 msgstr "유형"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "알 수 없음"

+ 59 - 6
app/src/language/messages.pot

@@ -453,8 +453,8 @@ msgid "Base information"
 msgstr ""
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr ""
 
@@ -700,8 +700,8 @@ msgstr ""
 msgid "Channel"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr ""
 
@@ -820,11 +820,15 @@ msgstr ""
 msgid "Client request header buffer size"
 msgstr ""
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169
+#: src/components/ConfigHistory/ConfigHistory.vue:170
 #: src/language/curd.ts:14
 msgid "Close"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr ""
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr ""
@@ -885,7 +889,7 @@ msgstr ""
 msgid "Config path is empty"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr ""
 
@@ -1602,6 +1606,10 @@ msgstr ""
 msgid "Encrypt website with Let's Encrypt"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr ""
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr ""
@@ -2441,6 +2449,10 @@ msgstr ""
 msgid "List"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr ""
@@ -3183,6 +3195,10 @@ msgstr ""
 msgid "Only zip files are allowed"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr ""
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr ""
@@ -3350,6 +3366,10 @@ msgstr ""
 msgid "Please enter a name for the passkey you wish to create and click the OK button below."
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr ""
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr ""
@@ -3458,10 +3478,16 @@ msgstr ""
 msgid "Please type \"Revoke\" to confirm"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr ""
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr ""
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3483,6 +3509,10 @@ msgstr ""
 msgid "Preparing lego configurations"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr ""
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr ""
@@ -4065,6 +4095,22 @@ msgstr ""
 msgid "Sbin path not exist"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr ""
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr ""
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr ""
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr ""
+
 #: 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 ""
@@ -4323,6 +4369,10 @@ msgstr ""
 msgid "Stable"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr ""
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4333,6 +4383,7 @@ msgstr ""
 msgid "Static"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4512,6 +4563,7 @@ msgstr ""
 msgid "Synchronization"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr ""
@@ -4822,6 +4874,7 @@ msgstr ""
 msgid "Type"
 msgstr ""
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr ""

+ 59 - 6
app/src/language/pt_PT/app.po

@@ -466,8 +466,8 @@ msgid "Base information"
 msgstr "Informação base"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Básico"
 
@@ -719,8 +719,8 @@ msgstr "Caminho Alterado"
 msgid "Channel"
 msgstr "Canal"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Chat"
 
@@ -905,10 +905,14 @@ msgstr "Tamanho do buffer do corpo da solicitação do cliente"
 msgid "Client request header buffer size"
 msgstr "Tamanho do buffer de cabeçalho de pedido do cliente"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "Fechar"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "Fechado"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "A conclusão de código não está ativada"
@@ -969,7 +973,7 @@ msgstr "O ficheiro de entrada de configuração não existe"
 msgid "Config path is empty"
 msgstr "O caminho de configuração está vazio"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "Modelo de Configuração"
 
@@ -1687,6 +1691,10 @@ msgstr "Activado com sucesso"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Encriptar website com Let's Encrypt"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "Fim"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "Variáveis de ambiente limpas"
@@ -2552,6 +2560,10 @@ msgstr "Início do link"
 msgid "List"
 msgstr "Lista"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "A escutar"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "Média de Carga:"
@@ -3313,6 +3325,10 @@ msgstr "On-line"
 msgid "Only zip files are allowed"
 msgstr "Apenas ficheiros ZIP são permitidos"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "Aberto"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3491,6 +3507,10 @@ msgstr ""
 "Por favor, insira um nome para a chave de acesso que deseja criar e clique "
 "no botão OK abaixo."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "Por favor, insira um intervalo de portas válido"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "Por favor, insira o código OTP:"
@@ -3619,10 +3639,16 @@ msgstr "Por favor, selecione pelo menos um nó para atualizar"
 msgid "Please type \"Revoke\" to confirm"
 msgstr "Por favor, digite \"Revogar\" para confirmar"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "Porta"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "Scanner de portas"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3642,6 +3668,10 @@ msgstr "Preferencia"
 msgid "Preparing lego configurations"
 msgstr "Preparando configurações lego"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "Processo"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "Distribuição de processos"
@@ -4237,6 +4267,22 @@ msgstr "Salvo com sucesso"
 msgid "Sbin path not exist"
 msgstr "O caminho sbin não existe"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "Digitalização concluída"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "Falha na verificação"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "Escanear portas"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "Resultados da verificação"
+
 #: 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 ""
@@ -4511,6 +4557,10 @@ msgstr "Autenticação SSO"
 msgid "Stable"
 msgstr "Estável"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "Início"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4521,6 +4571,7 @@ msgstr "Iniciar restauro"
 msgid "Static"
 msgstr "Estático"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4708,6 +4759,7 @@ msgstr "Sincronizar para"
 msgid "Synchronization"
 msgstr "Sincronização"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "Sistema"
@@ -5113,6 +5165,7 @@ msgstr "Autenticação de dois fatores necessária"
 msgid "Type"
 msgstr "Tipo"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "Desconhecido"

+ 59 - 6
app/src/language/ru_RU/app.po

@@ -470,8 +470,8 @@ msgid "Base information"
 msgstr "Основная информация"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Основные"
 
@@ -723,8 +723,8 @@ msgstr "Путь изменён"
 msgid "Channel"
 msgstr "Канал"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Чат"
 
@@ -908,10 +908,14 @@ msgstr "Размер буфера тела запроса клиента"
 msgid "Client request header buffer size"
 msgstr "Размер буфера заголовков запроса клиента"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "Закрыть"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "Закрыто"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "Автодополнение кода не включено"
@@ -972,7 +976,7 @@ msgstr "Файл входа конфигурации не существует"
 msgid "Config path is empty"
 msgstr "Путь конфигурации пуст"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "Шаблон конфигурации"
 
@@ -1688,6 +1692,10 @@ msgstr "Активировано успешно"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Использовать для сайта Let's Encrypt"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "Конец"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "Переменные окружения очищены"
@@ -2551,6 +2559,10 @@ msgstr "Начало ссылки"
 msgid "List"
 msgstr "Список"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "Ожидает"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "Средняя нагрузка:"
@@ -3312,6 +3324,10 @@ msgstr "Онлайн"
 msgid "Only zip files are allowed"
 msgstr "Разрешены только ZIP-файлы"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "Открыт"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3490,6 +3506,10 @@ msgstr ""
 "Пожалуйста, введите имя для ключа доступа, который вы хотите создать, и "
 "нажмите кнопку OK ниже."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "Пожалуйста, введите допустимый диапазон портов"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "Пожалуйста, введите код OTP:"
@@ -3623,10 +3643,16 @@ msgstr "Пожалуйста, выберите хотя бы один узел"
 msgid "Please type \"Revoke\" to confirm"
 msgstr "Пожалуйста, введите \"Отозвать\" для подтверждения"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "Порт"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "Сканер портов"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3646,6 +3672,10 @@ msgstr "Настройки"
 msgid "Preparing lego configurations"
 msgstr "Подготовка конфигураций Lego"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "Процесс"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "Распределение процессов"
@@ -4239,6 +4269,22 @@ msgstr "Успешно сохранено"
 msgid "Sbin path not exist"
 msgstr "Путь sbin не существует"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "Сканирование завершено"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "Сканирование не удалось"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "Сканировать порты"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "Результаты сканирования"
+
 #: 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 ""
@@ -4507,6 +4553,10 @@ msgstr "SSO Вход"
 msgid "Stable"
 msgstr "Стабильный"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "Начало"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4517,6 +4567,7 @@ msgstr "Начать восстановление"
 msgid "Static"
 msgstr "Статический"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4704,6 +4755,7 @@ msgstr "Синхронизировать с"
 msgid "Synchronization"
 msgstr "Синхронизация"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "Система"
@@ -5110,6 +5162,7 @@ msgstr "Требуется двухфакторная аутентификаци
 msgid "Type"
 msgstr "Тип"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "Неизвестно"

+ 59 - 6
app/src/language/tr_TR/app.po

@@ -462,8 +462,8 @@ msgid "Base information"
 msgstr "Temel bilgiler"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Temel"
 
@@ -713,8 +713,8 @@ msgstr "Değişen Dosya Yolu"
 msgid "Channel"
 msgstr "Kanal"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Sohbet"
 
@@ -901,10 +901,14 @@ msgstr "İstemci istek gövdesi tampon boyutu"
 msgid "Client request header buffer size"
 msgstr "İstemci istek başlığı arabellek boyutu"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "Kapat"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "Kapalı"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "Kod tamamlama etkin değil"
@@ -965,7 +969,7 @@ msgstr "Yapılandırma giriş dosyası mevcut değil"
 msgid "Config path is empty"
 msgstr "Yapılandırma yolu boş"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "Yapılandırma Şablonu"
 
@@ -1684,6 +1688,10 @@ msgstr "Başarıyla etkinleştirildi"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Let's Encrypt ile web sitesini şifreleyin"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "Son"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "Ortam değişkenleri temizlendi"
@@ -2551,6 +2559,10 @@ msgstr "Bağlantı Başlat"
 msgid "List"
 msgstr "Liste"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "Dinliyor"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "Yük Ortalaması:"
@@ -3311,6 +3323,10 @@ msgstr "Çevrimiçi"
 msgid "Only zip files are allowed"
 msgstr "Sadece ZIP dosyalarına izin verilir"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "Açık"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3488,6 +3504,10 @@ msgstr ""
 "Oluşturmak istediğiniz anahtar için bir ad girin ve aşağıdaki Tamam "
 "butonuna tıklayın."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "Lütfen geçerli bir port aralığı girin"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "Lütfen OTP kodunu girin:"
@@ -3617,10 +3637,16 @@ msgstr "Lütfen yükseltmek için en az bir düğüm seçin"
 msgid "Please type \"Revoke\" to confirm"
 msgstr "Onaylamak için \"İptal Et\" yazın"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "Port"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "Port Tarayıcı"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3640,6 +3666,10 @@ msgstr "Tercih"
 msgid "Preparing lego configurations"
 msgstr "Lego yapılandırmaları hazırlanıyor"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "Süreç"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "Süreç Dağılımı"
@@ -4242,6 +4272,22 @@ msgstr "Başarıyla kaydedildi"
 msgid "Sbin path not exist"
 msgstr "Sbin yolu mevcut değil"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "Tarama tamamlandı"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "Tarama başarısız"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "Portları Tara"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "Tarama Sonuçları"
+
 #: 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 "Hesabı uygulamaya eklemek için telefonunuzla QR kodunu tarayın."
@@ -4508,6 +4554,10 @@ msgstr "SSO Girişi"
 msgid "Stable"
 msgstr "Kararlı"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "Başla"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4518,6 +4568,7 @@ msgstr "Geri Yüklemeyi Başlat"
 msgid "Static"
 msgstr "Statik"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4707,6 +4758,7 @@ msgstr "Senkronize Et"
 msgid "Synchronization"
 msgstr "Senkronizasyon"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "Sistem"
@@ -5112,6 +5164,7 @@ msgstr "İki faktörlü kimlik doğrulama gerekiyor"
 msgid "Type"
 msgstr "Tür"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "Bilinmeyen"

+ 59 - 6
app/src/language/uk_UA/app.po

@@ -468,8 +468,8 @@ msgid "Base information"
 msgstr "Основна інформація"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Базові"
 
@@ -718,8 +718,8 @@ msgstr "Змінений шлях"
 msgid "Channel"
 msgstr "Канал"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Чат"
 
@@ -902,10 +902,14 @@ msgstr "Розмір буфера тіла запиту клієнта"
 msgid "Client request header buffer size"
 msgstr "Розмір буфера заголовка запиту клієнта"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "Закрити"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "Закрито"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "Автозавершення коду не ввімкнено"
@@ -966,7 +970,7 @@ msgstr "Вхідний файл конфігурації не існує"
 msgid "Config path is empty"
 msgstr "Конфігурація порожній"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "Шаблон конфігурації"
 
@@ -1754,6 +1758,10 @@ msgstr "Успішно ввімкнено"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Зашифрувати вебсайт за допомогою Let's Encrypt"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "Кінець"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "Змінні середовища очищено"
@@ -2617,6 +2625,10 @@ msgstr "Почати зв’язок"
 msgid "List"
 msgstr "Список"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "Прослуховує"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "Середнє навантаження:"
@@ -3378,6 +3390,10 @@ msgstr "Онлайн"
 msgid "Only zip files are allowed"
 msgstr "Дозволені лише zip-файли"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "Відкрито"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3556,6 +3572,10 @@ msgstr ""
 "Будь ласка, введіть назву для ключа доступу, який ви хочете створити, і "
 "натисніть кнопку OK нижче."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "Будь ласка, введіть дійсний діапазон портів"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "Будь ласка, введіть OTP-код:"
@@ -3685,10 +3705,16 @@ msgstr "Будь ласка, виберіть принаймні один вуз
 msgid "Please type \"Revoke\" to confirm"
 msgstr "Будь ласка, введіть \"Скасувати\" для підтвердження"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "Порт"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "Сканер портів"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3708,6 +3734,10 @@ msgstr "Налаштування"
 msgid "Preparing lego configurations"
 msgstr "Підготовка конфігурацій Lego"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "Процес"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "Розподіл процесів"
@@ -4306,6 +4336,22 @@ msgstr "Успішно збережено"
 msgid "Sbin path not exist"
 msgstr "Шлях sbin не існує"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "Сканування завершено"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "Сканування не вдалося"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "Сканувати порти"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "Результати сканування"
+
 #: 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 ""
@@ -4576,6 +4622,10 @@ msgstr "Вхід через SSO"
 msgid "Stable"
 msgstr "Стабільна"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "Початок"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4586,6 +4636,7 @@ msgstr "Почати відновлення"
 msgid "Static"
 msgstr "Статичний"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4773,6 +4824,7 @@ msgstr "Синхронізувати з"
 msgid "Synchronization"
 msgstr "Синхронізація"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "Система"
@@ -5178,6 +5230,7 @@ msgstr "Потрібна двофакторна аутентифікація"
 msgid "Type"
 msgstr "Тип"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "Невідомо"

+ 59 - 6
app/src/language/vi_VN/app.po

@@ -453,8 +453,8 @@ msgid "Base information"
 msgstr "Thông tin"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "Cơ bản"
 
@@ -702,8 +702,8 @@ msgstr "Đường dẫn đã thay đổi"
 msgid "Channel"
 msgstr "Kênh"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "Trò chuyện"
 
@@ -885,10 +885,14 @@ msgstr "Kích thước bộ đệm nội dung yêu cầu của máy khách"
 msgid "Client request header buffer size"
 msgstr "Kích thước bộ đệm tiêu đề yêu cầu của máy khách"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "Đóng"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "Đã đóng"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "Hoàn thành mã không được bật"
@@ -949,7 +953,7 @@ msgstr "Tệp nhập cấu hình không tồn tại"
 msgid "Config path is empty"
 msgstr "Đường dẫn cấu hình trống"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "Mẫu cấu hình"
 
@@ -1663,6 +1667,10 @@ msgstr "Đã bật"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Bảo mật trang web với Let's Encrypt"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "Kết thúc"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "Đã dọn dẹp biến môi trường"
@@ -2525,6 +2533,10 @@ msgstr "Liên kết bắt đầu"
 msgid "List"
 msgstr "Danh sách"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "Đang lắng nghe"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "Tải trung bình:"
@@ -3284,6 +3296,10 @@ msgstr "Trực tuyến"
 msgid "Only zip files are allowed"
 msgstr "Chỉ cho phép tệp zip"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "Mở"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3462,6 +3478,10 @@ 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."
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "Vui lòng nhập một phạm vi cổng hợp lệ"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "Vui lòng nhập mã OTP:"
@@ -3582,10 +3602,16 @@ msgstr "Vui lòng chọn ít nhất một nút để nâng cấp"
 msgid "Please type \"Revoke\" to confirm"
 msgstr "Vui lòng nhập \"Thu hồi\" để xác nhận"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "Cổng"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "Trình quét cổng"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3605,6 +3631,10 @@ msgstr "Cài đặt"
 msgid "Preparing lego configurations"
 msgstr "Chuẩn bị cấu hình Lego"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "Quá trình"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "Phân bổ quy trình"
@@ -4198,6 +4228,22 @@ msgstr "Lưu thành công"
 msgid "Sbin path not exist"
 msgstr "Đường dẫn sbin không tồn tại"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "Quét hoàn tất"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "Quét thất bại"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "Quét cổng"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+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."
@@ -4464,6 +4510,10 @@ msgstr "Đăng nhập SSO"
 msgid "Stable"
 msgstr "Ổn định"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "Bắt đầu"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4474,6 +4524,7 @@ msgstr "Bắt đầu khôi phục"
 msgid "Static"
 msgstr "Tĩnh"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4661,6 +4712,7 @@ msgstr "Đồng bộ tới"
 msgid "Synchronization"
 msgstr "Đồng bộ hóa"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "Thông tin"
@@ -5066,6 +5118,7 @@ msgstr "Yêu cầu xác thực hai yếu tố"
 msgid "Type"
 msgstr "Loại"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "Không xác định"

+ 59 - 6
app/src/language/zh_CN/app.po

@@ -457,8 +457,8 @@ msgid "Base information"
 msgstr "基本信息"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "基本"
 
@@ -704,8 +704,8 @@ msgstr "变更后的路径"
 msgid "Channel"
 msgstr "通道"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "聊天"
 
@@ -869,10 +869,14 @@ msgstr "客户端请求体缓冲区大小"
 msgid "Client request header buffer size"
 msgstr "客户端请求头缓冲区大小"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "关闭"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "已关闭"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "代码补全未启用"
@@ -933,7 +937,7 @@ msgstr "配置入口文件不存在"
 msgid "Config path is empty"
 msgstr "配置路径为空"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "配置模板"
 
@@ -1641,6 +1645,10 @@ msgstr "启用成功"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "用 Let's Encrypt 对网站进行加密"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "结束"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "环境变量已清理"
@@ -2491,6 +2499,10 @@ msgstr "链接"
 msgid "List"
 msgstr "列表"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "监听中"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "系统负载:"
@@ -3237,6 +3249,10 @@ msgstr "在线"
 msgid "Only zip files are allowed"
 msgstr "只允许使用zip文件"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "开放"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3407,6 +3423,10 @@ msgid ""
 "button below."
 msgstr "请为您要创建的 Passkey 输入一个名称,然后单击下面的 \"确定 \"按钮。"
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "请输入有效的端口范围"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "请输入 OTP:"
@@ -3523,10 +3543,16 @@ msgstr "请至少选择一个节点进行升级"
 msgid "Please type \"Revoke\" to confirm"
 msgstr "请键入 \"撤销 \"确认"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "端口"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "端口检测"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3546,6 +3572,10 @@ msgstr "偏好设置"
 msgid "Preparing lego configurations"
 msgstr "正在准备 Lego 的配置"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "进程"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "进程分布"
@@ -4130,6 +4160,22 @@ msgstr "保存成功"
 msgid "Sbin path not exist"
 msgstr "Sbin 路径不存在"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "扫描完成"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "扫描失败"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "扫描端口"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "扫描结果"
+
 #: 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 "用手机扫描二维码,将账户添加到应用程序中。"
@@ -4394,6 +4440,10 @@ msgstr "SSO 登录"
 msgid "Stable"
 msgstr "稳定"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "开始"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4404,6 +4454,7 @@ msgstr "开始还原"
 msgid "Static"
 msgstr "静态"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4587,6 +4638,7 @@ msgstr "同步到"
 msgid "Synchronization"
 msgstr "同步"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "系统"
@@ -4945,6 +4997,7 @@ msgstr "需要两步验证"
 msgid "Type"
 msgstr "类型"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "未知"

+ 59 - 6
app/src/language/zh_TW/app.po

@@ -461,8 +461,8 @@ msgid "Base information"
 msgstr "基本資訊"
 
 #: src/views/config/ConfigEditor.vue:300
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
-#: src/views/stream/components/RightPanel/RightPanel.vue:19
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:31
+#: src/views/stream/components/RightPanel/RightPanel.vue:20
 msgid "Basic"
 msgstr "基本"
 
@@ -708,8 +708,8 @@ msgstr "變更後路徑"
 msgid "Channel"
 msgstr "通道"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:40
-#: src/views/stream/components/RightPanel/RightPanel.vue:22
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:41
+#: src/views/stream/components/RightPanel/RightPanel.vue:23
 msgid "Chat"
 msgstr "聊天"
 
@@ -873,10 +873,14 @@ msgstr "Client 請求主體緩衝區大小"
 msgid "Client request header buffer size"
 msgstr "Client 請求標頭緩衝區大小"
 
-#: src/components/ConfigHistory/ConfigHistory.vue:169 src/language/curd.ts:14
+#: src/components/ConfigHistory/ConfigHistory.vue:170 src/language/curd.ts:14
 msgid "Close"
 msgstr "關閉"
 
+#: src/components/PortScanner/PortScannerCompact.vue:45
+msgid "Closed"
+msgstr "已關閉"
+
 #: src/constants/errors/llm.ts:2
 msgid "Code completion is not enabled"
 msgstr "程式碼補全未啟用"
@@ -937,7 +941,7 @@ msgstr "配置入口文件不存在"
 msgid "Config path is empty"
 msgstr "設定路徑為空"
 
-#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:36
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:37
 msgid "Config Template"
 msgstr "配置模板"
 
@@ -1645,6 +1649,10 @@ msgstr "成功啟用"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "用 Let's Encrypt 對網站進行加密"
 
+#: src/components/PortScanner/PortScannerCompact.vue:164
+msgid "End"
+msgstr "結束"
+
 #: src/language/constants.ts:22
 msgid "Environment variables cleaned"
 msgstr "環境變數已清理"
@@ -2495,6 +2503,10 @@ msgstr "連結開始"
 msgid "List"
 msgstr "列表"
 
+#: src/components/PortScanner/PortScannerCompact.vue:43
+msgid "Listening"
+msgstr "監聽中"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Load Average:"
 msgstr "負載平均值:"
@@ -3241,6 +3253,10 @@ msgstr "線上"
 msgid "Only zip files are allowed"
 msgstr "只允許壓縮檔"
 
+#: src/components/PortScanner/PortScannerCompact.vue:44
+msgid "Open"
+msgstr "開放"
+
 #: src/views/preference/Preference.vue:100
 msgid "OpenAI"
 msgstr "OpenAI"
@@ -3413,6 +3429,10 @@ msgid ""
 "button below."
 msgstr "請輸入您希望建立的通行金鑰名稱,並點選下面的確定按鈕。"
 
+#: src/components/PortScanner/PortScannerCompact.vue:85
+msgid "Please enter a valid port range"
+msgstr "請輸入有效的端口範圍"
+
 #: src/components/TwoFA/Authorization.vue:85
 msgid "Please enter the OTP code:"
 msgstr "請輸入 OTP 代碼:"
@@ -3529,10 +3549,16 @@ msgstr "請至少選擇一個節點進行升級"
 msgid "Please type \"Revoke\" to confirm"
 msgstr "請輸入「撤銷」以確認"
 
+#: src/components/PortScanner/PortScannerCompact.vue:31
 #: src/views/preference/tabs/ServerSettings.vue:22
 msgid "Port"
 msgstr "監聽埠"
 
+#: src/views/site/site_edit/components/RightPanel/RightPanel.vue:44
+#: src/views/stream/components/RightPanel/RightPanel.vue:26
+msgid "Port Scanner"
+msgstr "端口掃描器"
+
 #: src/views/environments/group/columns.ts:15
 #: src/views/environments/group/EnvGroup.vue:39
 msgid "Post-sync Action"
@@ -3552,6 +3578,10 @@ msgstr "偏好設定"
 msgid "Preparing lego configurations"
 msgstr "準備 Lego 設定"
 
+#: src/components/PortScanner/PortScannerCompact.vue:55
+msgid "Process"
+msgstr "進程"
+
 #: src/views/dashboard/components/ProcessDistributionCard.vue:26
 msgid "Process Distribution"
 msgstr "行程分布"
@@ -4136,6 +4166,22 @@ msgstr "儲存成功"
 msgid "Sbin path not exist"
 msgstr "sbin 路徑不存在"
 
+#: src/components/PortScanner/PortScannerCompact.vue:94
+msgid "Scan completed"
+msgstr "掃描完成"
+
+#: src/components/PortScanner/PortScannerCompact.vue:98
+msgid "Scan failed"
+msgstr "掃描失敗"
+
+#: src/components/PortScanner/PortScannerCompact.vue:179
+msgid "Scan Ports"
+msgstr "掃描端口"
+
+#: src/components/PortScanner/PortScannerCompact.vue:204
+msgid "Scan Results"
+msgstr "掃描結果"
+
 #: 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 "用手機掃描二維碼將賬戶新增到應用程式中。"
@@ -4400,6 +4446,10 @@ msgstr "SSO 登入"
 msgid "Stable"
 msgstr "穩定"
 
+#: src/components/PortScanner/PortScannerCompact.vue:151
+msgid "Start"
+msgstr "開始"
+
 #: src/components/SystemRestore/SystemRestoreContent.vue:246
 #: src/components/SystemRestore/SystemRestoreContent.vue:323
 msgid "Start Restore"
@@ -4410,6 +4460,7 @@ msgstr "開始恢復"
 msgid "Static"
 msgstr "靜態"
 
+#: src/components/PortScanner/PortScannerCompact.vue:37
 #: src/views/certificate/ACMEUser.vue:60
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
@@ -4593,6 +4644,7 @@ msgstr "同步到"
 msgid "Synchronization"
 msgstr "同步"
 
+#: src/components/PortScanner/PortScannerCompact.vue:194
 #: src/routes/modules/system.ts:11
 msgid "System"
 msgstr "系統"
@@ -4951,6 +5003,7 @@ msgstr "需要多重因素驗證"
 msgid "Type"
 msgstr "類型"
 
+#: src/components/PortScanner/PortScannerCompact.vue:47
 #: src/composables/useNginxPerformance.ts:18
 msgid "Unknown"
 msgstr "未知"

+ 4 - 0
app/src/views/site/site_edit/components/RightPanel/RightPanel.vue

@@ -1,4 +1,5 @@
 <script setup lang="ts">
+import { PortScannerCompact } from '@/components/PortScanner'
 import { useSiteEditorStore } from '../SiteEditor/store'
 import Basic from './Basic.vue'
 import Chat from './Chat.vue'
@@ -40,6 +41,9 @@ watch(advanceMode, val => {
         <ATabPane key="chat" :tab="$gettext('Chat')">
           <Chat />
         </ATabPane>
+        <ATabPane key="port-scanner" :tab="$gettext('Port Scanner')">
+          <PortScannerCompact />
+        </ATabPane>
       </ATabs>
     </ACard>
   </div>

+ 4 - 0
app/src/views/stream/components/RightPanel/RightPanel.vue

@@ -1,4 +1,5 @@
 <script setup lang="ts">
+import { PortScannerCompact } from '@/components/PortScanner'
 import Basic from './Basic.vue'
 import Chat from './Chat.vue'
 
@@ -22,6 +23,9 @@ const activeKey = ref('basic')
         <ATabPane key="chat" :tab="$gettext('Chat')">
           <Chat />
         </ATabPane>
+        <ATabPane key="port-scanner" :tab="$gettext('Port Scanner')">
+          <PortScannerCompact />
+        </ATabPane>
       </ATabs>
     </ACard>
   </div>