浏览代码

feat(env_group): add upstream test type: local, remote, mirror

0xJacky 2 周之前
父节点
当前提交
152569a2e7

+ 1 - 1
.air.toml

@@ -15,7 +15,7 @@ full_bin = "APP_ENV=dev APP_USER=air ./tmp/main"
 # Watch these filename extensions.
 include_ext = ["go", "tpl", "tmpl", "html", "toml", "po", "conf"]
 # Ignore these filename extensions or directories.
-exclude_dir = ["assets", "tmp", "vendor", "app/node_modules", "upload", "docs", "resources", ".idea", "cmd"]
+exclude_dir = ["assets", "tmp", "vendor", "app/node_modules", "upload", "docs", "resources", ".idea", "cmd", ".go"]
 # Watch these directories if you specified.
 include_dir = []
 # Exclude files.

+ 1 - 1
.devcontainer/docker-compose.yml

@@ -5,7 +5,7 @@ services:
     container_name: nginx-ui
     volumes:
       - ../..:/workspaces:cached
-      - ./go-path:/root/go
+      - ../.go:/root/go
       - ./data/nginx:/etc/nginx
       - /var/run/docker.sock:/var/run/docker.sock
     command: sleep infinity

+ 1 - 0
.gitignore

@@ -19,3 +19,4 @@ internal/**/*.gen.go
 .devcontainer/data
 .devcontainer/casdoor.pem
 .vscode/.i18n-gettext.secret
+.go/

+ 1 - 1
api/analytic/nodes.go

@@ -107,7 +107,7 @@ func GetNodesAnalytic(c *gin.Context) {
 	defer ws.Close()
 
 	for {
-		// write
+		// Send NodeMap data to client
 		err = ws.WriteJSON(analytic.NodeMap)
 		if err != nil {
 			if helper.IsUnexpectedWebsocketError(err) {

+ 8 - 6
api/cluster/group.go

@@ -110,9 +110,10 @@ func RestartNginx(c *gin.Context) {
 func AddGroup(c *gin.Context) {
 	cosy.Core[model.EnvGroup](c).
 		SetValidRules(gin.H{
-			"name":             "required",
-			"sync_node_ids":    "omitempty",
-			"post_sync_action": "omitempty,oneof=" + model.PostSyncActionNone + " " + model.PostSyncActionReloadNginx,
+			"name":               "required",
+			"sync_node_ids":      "omitempty",
+			"post_sync_action":   "omitempty,oneof=" + model.PostSyncActionNone + " " + model.PostSyncActionReloadNginx,
+			"upstream_test_type": "omitempty,oneof=" + model.UpstreamTestLocal + " " + model.UpstreamTestRemote + " " + model.UpstreamTestMirror,
 		}).
 		Create()
 }
@@ -120,9 +121,10 @@ func AddGroup(c *gin.Context) {
 func ModifyGroup(c *gin.Context) {
 	cosy.Core[model.EnvGroup](c).
 		SetValidRules(gin.H{
-			"name":             "required",
-			"sync_node_ids":    "omitempty",
-			"post_sync_action": "omitempty,oneof=" + model.PostSyncActionNone + " " + model.PostSyncActionReloadNginx,
+			"name":               "required",
+			"sync_node_ids":      "omitempty",
+			"post_sync_action":   "omitempty,oneof=" + model.PostSyncActionNone + " " + model.PostSyncActionReloadNginx,
+			"upstream_test_type": "omitempty,oneof=" + model.UpstreamTestLocal + " " + model.UpstreamTestRemote + " " + model.UpstreamTestMirror,
 		}).
 		Modify()
 }

+ 8 - 0
app/src/api/env_group.ts

@@ -7,10 +7,18 @@ export const PostSyncAction = {
   ReloadNginx: 'reload_nginx',
 }
 
+// Upstream test types
+export const UpstreamTestType = {
+  Local: 'local',
+  Remote: 'remote',
+  Mirror: 'mirror',
+}
+
 export interface EnvGroup extends ModelBase {
   name: string
   sync_node_ids: number[]
   post_sync_action?: string
+  upstream_test_type?: string
 }
 
 const baseUrl = '/env_groups'

+ 268 - 40
app/src/components/ProxyTargets/ProxyTargets.vue

@@ -1,16 +1,77 @@
 <script setup lang="ts">
 import type { ProxyTarget } from '@/api/site'
+import { useNodeAvailabilityStore } from '@/pinia/moudule/nodeAvailability'
+import { useNodeGroupStore } from '@/pinia/moudule/nodeGroupStore'
 import { useProxyAvailabilityStore } from '@/pinia/moudule/proxyAvailability'
 
 interface Props {
   targets: ProxyTarget[]
+  envGroupId?: number
 }
 
-defineProps<Props>()
+const props = defineProps<Props>()
 
 const proxyStore = useProxyAvailabilityStore()
+const nodeStore = useNodeAvailabilityStore()
+const nodeGroupStore = useNodeGroupStore()
 
+// Initialize the stores to start monitoring
+onMounted(() => {
+  proxyStore.startMonitoring()
+  nodeGroupStore.initialize()
+})
+
+onUnmounted(() => {
+  proxyStore.stopMonitoring()
+})
+
+// Check if should show multi-node display based on group configuration
+const shouldShowMultiNodeDisplay = computed(() => {
+  if (!props.envGroupId) {
+    return false
+  }
+
+  const group = nodeGroupStore.getGroupById(props.envGroupId)
+  const testType = group?.upstream_test_type || 'local'
+  return testType === 'remote' || testType === 'mirror'
+})
+
+// eslint-disable-next-line sonarjs/cognitive-complexity
 function getTargetColor(target: ProxyTarget): string {
+  // Check if we should show multi-node display based on group configuration
+  if (shouldShowMultiNodeDisplay.value) {
+    const multiNodeStatus = proxyStore.getMultiNodeStatus(target)
+    const group = nodeGroupStore.getGroupById(props.envGroupId!)
+    const testType = group?.upstream_test_type || 'local'
+
+    // Calculate total nodes based on test type
+    const totalNodes = testType === 'remote'
+      ? (group?.sync_node_ids?.length || 0) // remote: only sync nodes
+      : (group?.sync_node_ids?.length || 0) + 1 // mirror: sync nodes + main node
+
+    let onlineCount = 0
+
+    if (multiNodeStatus) {
+      // Count online nodes from multi-node data
+      onlineCount = Object.values(multiNodeStatus).filter(status => status.online).length
+    }
+
+    // For mirror mode, also include main node status
+    if (testType === 'mirror') {
+      const mainNodeStatus = proxyStore.getAvailabilityResult(target)
+      if (mainNodeStatus && mainNodeStatus.online) {
+        onlineCount++
+      }
+    }
+
+    if (onlineCount === totalNodes)
+      return 'green'
+    if (onlineCount === 0)
+      return 'red'
+    return 'orange' // Partial online
+  }
+
+  // Fallback to single-node display
   const result = proxyStore.getAvailabilityResult(target)
   if (!result)
     return 'default'
@@ -18,6 +79,36 @@ function getTargetColor(target: ProxyTarget): string {
 }
 
 function getTargetText(target: ProxyTarget): string {
+  // Check if we should show multi-node display based on group configuration
+  if (shouldShowMultiNodeDisplay.value) {
+    const multiNodeStatus = proxyStore.getMultiNodeStatus(target)
+    const group = nodeGroupStore.getGroupById(props.envGroupId!)
+    const testType = group?.upstream_test_type || 'local'
+
+    // Calculate total nodes based on test type
+    const totalNodes = testType === 'remote'
+      ? (group?.sync_node_ids?.length || 0) // remote: only sync nodes
+      : (group?.sync_node_ids?.length || 0) + 1 // mirror: sync nodes + main node
+
+    let onlineCount = 0
+
+    if (multiNodeStatus) {
+      // Count online nodes from multi-node data
+      onlineCount = Object.values(multiNodeStatus).filter(status => status.online).length
+    }
+
+    // For mirror mode, also include main node status
+    if (testType === 'mirror') {
+      const mainNodeStatus = proxyStore.getAvailabilityResult(target)
+      if (mainNodeStatus && mainNodeStatus.online) {
+        onlineCount++
+      }
+    }
+
+    return `${target.host}:${target.port} (${onlineCount}/${totalNodes})`
+  }
+
+  // Fallback to single-node display
   const result = proxyStore.getAvailabilityResult(target)
   if (!result)
     return `${target.host}:${target.port}`
@@ -33,63 +124,200 @@ function getTargetText(target: ProxyTarget): string {
 function getTargetTitle(target: ProxyTarget): string {
   return `${$gettext('Type')}: ${target.type === 'upstream' ? $gettext('Upstream') : $gettext('Proxy Pass')}`
 }
+
+const showDetailModal = ref(false)
+const selectedTarget = ref<ProxyTarget | null>(null)
+
+function getNodeName(nodeId: string): string {
+  const node = nodeStore.nodes[Number.parseInt(nodeId)]
+  return node?.name || `Node ${nodeId}`
+}
+
+// Get all node statuses including main node for modal display
+function getAllNodeStatuses(target: ProxyTarget) {
+  const group = nodeGroupStore.getGroupById(props.envGroupId!)
+  const testType = group?.upstream_test_type || 'local'
+  const allStatuses: Array<{ nodeId: string, name: string, status: { online: boolean, latency: number }, isMainNode: boolean }> = []
+
+  // Add main node data first for local and mirror modes
+  if (testType === 'local' || testType === 'mirror') {
+    const mainNodeStatus = proxyStore.getAvailabilityResult(target)
+    if (mainNodeStatus) {
+      allStatuses.push({
+        nodeId: 'main',
+        name: $gettext('Main Node'),
+        status: {
+          online: mainNodeStatus.online,
+          latency: mainNodeStatus.latency,
+        },
+        isMainNode: true,
+      })
+    }
+  }
+
+  // Add all child nodes data (both online and offline)
+  if (group?.sync_node_ids) {
+    const multiNodeStatus = proxyStore.getMultiNodeStatus(target)
+
+    for (const nodeId of group.sync_node_ids) {
+      const nodeIdStr = nodeId.toString()
+      const nodeStatus = multiNodeStatus?.[nodeIdStr]
+
+      allStatuses.push({
+        nodeId: nodeIdStr,
+        name: getNodeName(nodeIdStr),
+        status: nodeStatus || {
+          online: false,
+          latency: 0,
+        },
+        isMainNode: false,
+      })
+    }
+  }
+
+  return allStatuses
+}
+
+function handleTargetClick(target: ProxyTarget) {
+  if (shouldShowMultiNodeDisplay.value) {
+    selectedTarget.value = target
+    showDetailModal.value = true
+  }
+}
 </script>
 
 <template>
   <div v-if="targets.length > 0" class="proxy-targets">
     <ATag
-      v-for="target in targets"
-      :key="proxyStore.getTargetKey(target)"
-      :color="getTargetColor(target)"
-      class="proxy-target-tag"
-      :bordered="false"
+      v-for="target in targets" :key="proxyStore.getTargetKey(target)" :color="getTargetColor(target)"
+      class="proxy-target-tag cursor-pointer" :class="{ clickable: shouldShowMultiNodeDisplay }" :bordered="false"
+      @click="handleTargetClick(target)"
     >
       <template #icon>
-        <ATooltip
-          :title="getTargetTitle(target)"
-          placement="bottom"
-          class="cursor-pointer"
-        >
+        <ATooltip :title="getTargetTitle(target)" placement="bottom" class="cursor-pointer">
           <span v-if="target.type === 'upstream'" class="target-type-icon">U</span>
           <span v-else class="target-type-icon">P</span>
         </ATooltip>
       </template>
       {{ getTargetText(target) }}
     </ATag>
+
+    <!-- Upstream Detail Modal -->
+    <AModal
+      v-model:open="showDetailModal"
+      :title="selectedTarget ? `${selectedTarget.host}:${selectedTarget.port} - ${$gettext('Node Status')}` : ''"
+      :footer="null" width="600px"
+    >
+      <div v-if="selectedTarget" class="upstream-detail">
+        <div class="node-status-list">
+          <div v-for="nodeInfo in getAllNodeStatuses(selectedTarget)" :key="nodeInfo.nodeId" class="node-status-item">
+            <div class="node-info">
+              <span class="node-name">{{ nodeInfo.name }}</span>
+              <ATag :color="nodeInfo.status.online ? 'green' : 'red'" class="status-tag">
+                {{ nodeInfo.status.online ? $gettext('Online') : $gettext('Offline') }}
+              </ATag>
+              <ATag v-if="nodeInfo.isMainNode" color="blue" class="main-node-tag">
+                {{ $gettext('Main') }}
+              </ATag>
+            </div>
+            <div class="node-latency">
+              <span v-if="nodeInfo.status.online">{{ nodeInfo.status.latency.toFixed(2) }}ms</span>
+              <span v-else class="text-gray-400">{{ $gettext('N/A') }}</span>
+            </div>
+          </div>
+        </div>
+      </div>
+    </AModal>
   </div>
 </template>
 
 <style scoped lang="less">
-.proxy-targets {
-  display: flex;
-  flex-wrap: wrap;
-  gap: 4px;
-  max-width: 100%;
-  overflow: hidden;
-}
+  .proxy-targets {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 4px;
+    max-width: 100%;
+    overflow: hidden;
+  }
 
-.proxy-target-tag {
-  margin-right: 4px;
-  margin-bottom: 4px;
-  font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
-  font-size: 12px;
-  max-width: 100%;
-  overflow: hidden;
-  text-overflow: ellipsis;
-  white-space: nowrap;
-
-  .target-type-icon {
-    display: inline-block;
-    width: 12px;
-    height: 12px;
-    line-height: 12px;
-    text-align: center;
-    background: rgba(255, 255, 255, 0.2);
-    border-radius: 2px;
+  .proxy-target-tag {
     margin-right: 4px;
-    font-weight: bold;
-    font-size: 10px;
-    flex-shrink: 0;
+    margin-bottom: 4px;
+    font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+    font-size: 12px;
+    max-width: 100%;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    white-space: nowrap;
+
+    &.clickable {
+      cursor: pointer;
+      transition: all 0.2s ease;
+
+      &:hover {
+        box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.07);
+      }
+    }
+
+    .target-type-icon {
+      display: inline-block;
+      width: 12px;
+      height: 12px;
+      line-height: 12px;
+      text-align: center;
+      background: rgba(255, 255, 255, 0.2);
+      border-radius: 2px;
+      margin-right: 4px;
+      font-weight: bold;
+      font-size: 10px;
+      flex-shrink: 0;
+    }
+  }
+
+  .upstream-detail {
+    .node-status-list {
+      display: flex;
+      flex-direction: column;
+      gap: 12px;
+    }
+
+    .node-status-item {
+      display: flex;
+      justify-content: space-between;
+      align-items: center;
+      padding: 12px;
+      border: 1px solid #e8e9ea;
+      border-radius: 8px;
+      background: #fafafa;
+
+      .node-info {
+        display: flex;
+        align-items: center;
+        gap: 8px;
+
+        .node-name {
+          font-weight: 500;
+          color: #333;
+        }
+
+        .status-tag {
+          font-size: 11px;
+          margin: 0;
+        }
+
+        .main-node-tag {
+          font-size: 10px;
+          margin: 0;
+        }
+      }
+
+      .node-latency {
+        font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
+        font-size: 12px;
+        font-weight: 500;
+        color: #666;
+      }
+
+    }
   }
-}
 </style>

+ 11 - 0
app/src/constants/index.ts

@@ -32,6 +32,17 @@ export enum NginxStatus {
   Stopped,
 }
 
+export const PostSyncActionMask = {
+  none: () => $gettext('No Action'),
+  reload_nginx: () => $gettext('Reload Nginx'),
+} as const
+
+export const UpstreamTestTypeMask = {
+  local: () => $gettext('Local'),
+  remote: () => $gettext('Remote'),
+  mirror: () => $gettext('Mirror'),
+} as const
+
 export const PrivateKeyTypeMask = {
   2048: 'RSA2048',
   3072: 'RSA3072',

+ 67 - 42
app/src/language/ar/app.po

@@ -141,14 +141,14 @@ msgstr "إجراء"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "الإجراءات"
@@ -763,7 +763,7 @@ msgstr "نوع الشهادة"
 msgid "Certificates"
 msgstr "شهادات"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "قائمة الشهادات"
 
@@ -1060,7 +1060,7 @@ msgstr "مسار التكوين فارغ"
 msgid "Config Template"
 msgstr "قالب التكوين"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "التكوين"
 
@@ -1181,7 +1181,7 @@ msgstr ""
 "سيتم تنزيل ملفات النسخ الاحتياطي تلقائيًا إلى جهاز الكمبيوتر الخاص بك."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1516,7 +1516,7 @@ msgstr "تم تعطيل الدفق %{name} من %{node} بنجاح"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1531,8 +1531,8 @@ msgstr "تم التعطيل بنجاح"
 msgid "Disk IO"
 msgstr "إدخال/إخراج القرص"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "بيانات اعتماد DNS"
 
@@ -1798,7 +1798,7 @@ msgstr "تفعيل TOTP"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2521,7 +2521,7 @@ msgstr ""
 msgid "Import"
 msgstr "استيراد"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "استيراد شهادة"
@@ -2843,7 +2843,7 @@ msgid "Loading data..."
 msgstr "جارٍ تحميل البيانات..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2913,9 +2913,17 @@ msgstr ""
 "يدويًا. سيقوم مجدول المهام crontab الخاص بواجهة Nginx UI بتنفيذ أمر تدوير "
 "السجلات في الفاصل الزمني الذي تحدده بالدقائق."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "رئيسي"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "العقدة الرئيسية"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "صيانة"
 
@@ -3066,6 +3074,10 @@ msgstr "دقيقة"
 msgid "Minutes"
 msgstr "دقائق"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "مرآة"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "نموذج"
@@ -3079,7 +3091,7 @@ msgstr "تم التعديل في"
 msgid "Modify"
 msgstr "تعديل"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "تعديل الشهادة"
@@ -3112,17 +3124,21 @@ msgstr "يوميًا في اليوم %{day} الساعة %{time}"
 msgid "Multi-line Directive"
 msgstr "توجيه متعدد الأسطر"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "غير متاح"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3411,8 +3427,7 @@ msgid "No"
 msgstr "لا"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "لا إجراء"
 
@@ -3441,7 +3456,7 @@ msgid "Node"
 msgstr "العقدة"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "مجموعة العقد"
@@ -3459,6 +3474,10 @@ msgstr "اسم العقدة"
 msgid "Node Secret"
 msgstr "سر العقدة"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "حالة العقدة"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "العقد"
@@ -3481,7 +3500,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "غير صالح قبل: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "ملاحظة"
 
@@ -3563,6 +3582,7 @@ msgstr "الوثيقة الرسمية"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3589,7 +3609,7 @@ msgstr "حسنًا"
 msgid "On"
 msgstr "تشغيل"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "بمجرد اكتمال التحقق، سيتم إزالة السجلات."
 
@@ -3597,6 +3617,7 @@ msgstr "بمجرد اكتمال التحقق، سيتم إزالة السجلا
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3820,7 +3841,7 @@ msgstr "يرجى ملء جميع الحقول بشكل صحيح"
 msgid "Please fill in required S3 configuration fields"
 msgstr "يرجى ملء حقول تكوين S3 المطلوبة"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3879,7 +3900,7 @@ msgstr "يرجى إدخال اسم المستخدم الخاص بك!"
 msgid "Please log in."
 msgstr "الرجاء تسجيل الدخول."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr "يرجى ملاحظة أن تكوين وحدات الوقت أدناه كلها بالثواني."
 
@@ -3940,8 +3961,7 @@ msgid "Port Scanner"
 msgstr "ماسح المنافذ"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "إجراء ما بعد المزامنة"
 
@@ -4005,7 +4025,7 @@ msgstr ""
 "إعدادات البروتوكول تتأثر فقط عند الاتصال المباشر. إذا كنت تستخدم خادم وكيل "
 "عكسي، يرجى تكوين البروتوكول بشكل منفصل في خادم الوكيل العكسي."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "مزود"
 
@@ -4017,7 +4037,7 @@ msgstr "لم يتم العثور على المزود: {0}"
 msgid "Proxy"
 msgstr "وكيل"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "مرور الوكيل"
 
@@ -4124,9 +4144,7 @@ msgid "Reload"
 msgstr "إعادة تحميل"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4164,6 +4182,10 @@ msgstr "إعادة التحميل"
 msgid "Reloading nginx"
 msgstr "إعادة تحميل nginx"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "عن بُعد"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4670,10 +4692,6 @@ msgstr "معلومات رمز الأمان"
 msgid "Select all"
 msgstr "تحديد الكل"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "اختر إجراءً بعد المزامنة"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "تم تحديد {count} ملفات"
@@ -4932,7 +4950,7 @@ msgstr "ثابت"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "الحالة"
 
@@ -5106,7 +5124,7 @@ msgstr "تمت مزامنة التكوين بنجاح"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "مزامنة العقد"
@@ -5552,7 +5570,7 @@ msgstr "الثلاثاء"
 msgid "Two-factor authentication required"
 msgstr "يتطلب المصادقة الثنائية"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5589,13 +5607,13 @@ msgstr "تم التحديث بنجاح"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5633,7 +5651,7 @@ msgstr "تحميل الملفات"
 msgid "Upload Folders"
 msgstr "تحميل المجلدات"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "أعلى التيار"
 
@@ -5641,6 +5659,10 @@ msgstr "أعلى التيار"
 msgid "Upstream Name"
 msgstr "اسم المنبع"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "نوع اختبار المنبع"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "مدة التشغيل:"
@@ -5761,7 +5783,7 @@ msgstr ""
 "تحذير: ستقوم عملية الاستعادة بالكتابة فوق التكوينات الحالية. تأكد من أن "
 "لديك ملف نسخ احتياطي صالحًا ورمزًا أمنيًا، واختر بعناية ما تريد استعادته."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -5943,6 +5965,9 @@ msgstr "رموزك القديمة لن تعمل بعد الآن."
 msgid "Your passkeys"
 msgstr "مفاتيح المرور الخاصة بك"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "اختر إجراءً بعد المزامنة"
+
 #~ msgid "Link Start"
 #~ msgstr "ابدأ الرابط"
 

+ 67 - 42
app/src/language/de_DE/app.po

@@ -142,14 +142,14 @@ msgstr "Aktion"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "Aktionen"
@@ -775,7 +775,7 @@ msgstr "Zertifikatstyp"
 msgid "Certificates"
 msgstr "Zertifikate"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "Zertifikatsliste"
 
@@ -1075,7 +1075,7 @@ msgstr "Konfigurationspfad ist leer"
 msgid "Config Template"
 msgstr "Konfigurationsvorlage"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "Konfiguration"
 
@@ -1199,7 +1199,7 @@ msgstr ""
 "Computer heruntergeladen."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1536,7 +1536,7 @@ msgstr "Stream %{name} von %{node} erfolgreich deaktiviert"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1551,8 +1551,8 @@ msgstr "Erfolgreich deaktiviert"
 msgid "Disk IO"
 msgstr "Festplatten-IO"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "DNS-Zugangsdaten"
 
@@ -1818,7 +1818,7 @@ msgstr "TOTP aktivieren"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2550,7 +2550,7 @@ msgstr ""
 msgid "Import"
 msgstr "Import"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "Zertifikat importieren"
@@ -2872,7 +2872,7 @@ msgid "Loading data..."
 msgstr "Daten werden geladen..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2942,9 +2942,17 @@ msgstr ""
 "aktivieren. Der Crontab-Aufgabenplaner von Nginx UI führt den "
 "Logrotate-Befehl in dem von dir in Minuten festgelegten Intervall aus."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "Haupt"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "Hauptknoten"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "Wartung"
 
@@ -3096,6 +3104,10 @@ msgstr "Minute"
 msgid "Minutes"
 msgstr "Minuten"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "Spiegel"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "Modell"
@@ -3109,7 +3121,7 @@ msgstr "Geändert am"
 msgid "Modify"
 msgstr "Ändern"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "Zertifikat ändern"
@@ -3142,17 +3154,21 @@ msgstr "Monatlich am %{day}. um %{time}"
 msgid "Multi-line Directive"
 msgstr "Mehrzeilige Direktive"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "N/V"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3443,8 +3459,7 @@ msgid "No"
 msgstr "Nein"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "Keine Aktion"
 
@@ -3473,7 +3488,7 @@ msgid "Node"
 msgstr "Node"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "Node-Gruppe"
@@ -3491,6 +3506,10 @@ msgstr "Knotenname"
 msgid "Node Secret"
 msgstr "Node-Secret"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "Knotenstatus"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "Knoten"
@@ -3513,7 +3532,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "Nich gültig vor: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "Notiz"
 
@@ -3598,6 +3617,7 @@ msgstr "Offizielle Dokumentation"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3624,7 +3644,7 @@ msgstr "OK"
 msgid "On"
 msgstr "Ein"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Sobaöd die Überprüfung abgeschlossen ist, werden die Einträge entfernt."
 
@@ -3632,6 +3652,7 @@ msgstr "Sobaöd die Überprüfung abgeschlossen ist, werden die Einträge entfer
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3857,7 +3878,7 @@ msgstr "Bitte füllen Sie alle Felder korrekt aus"
 msgid "Please fill in required S3 configuration fields"
 msgstr "Bitte füllen Sie die erforderlichen S3-Konfigurationsfelder aus"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3925,7 +3946,7 @@ msgstr "Bitte gib deinen Benutzernamen ein!"
 msgid "Please log in."
 msgstr "Bitte melden Sie sich an."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Bitte beachte, dass die Zeiteinheiten der unten aufgeführten "
@@ -3990,8 +4011,7 @@ msgid "Port Scanner"
 msgstr "Port-Scanner"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Aktion nach der Synchronisierung"
 
@@ -4056,7 +4076,7 @@ msgstr ""
 "eines Reverse Proxys konfigurieren Sie das Protokoll bitte separat im "
 "Reverse Proxy."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "Anbieter"
 
@@ -4068,7 +4088,7 @@ msgstr "Anbieter nicht gefunden: {0}"
 msgid "Proxy"
 msgstr "Proxy"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "Proxy-Weiterleitung"
 
@@ -4178,9 +4198,7 @@ msgid "Reload"
 msgstr "Neu laden"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4220,6 +4238,10 @@ msgstr "Lade neu"
 msgid "Reloading nginx"
 msgstr "Lade Nginx neu"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "Remote"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4729,10 +4751,6 @@ msgstr "Sicherheitstoken-Informationen"
 msgid "Select all"
 msgstr "Alle auswählen"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "Aktion nach der Synchronisierung auswählen"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "Ausgewählte {count} Dateien"
@@ -4999,7 +5017,7 @@ msgstr "Statisch"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "Status"
 
@@ -5178,7 +5196,7 @@ msgstr "Konfiguration erfolgreich synchronisiert"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "Synchrone Knoten"
@@ -5640,7 +5658,7 @@ msgstr "Dienstag"
 msgid "Two-factor authentication required"
 msgstr "Zwei-Faktor-Authentifizierung erforderlich"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5677,13 +5695,13 @@ msgstr "Erfolgreich aktualisiert"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5721,7 +5739,7 @@ msgstr "Dateien hochladen"
 msgid "Upload Folders"
 msgstr "Ordner hochladen"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "Upstream"
 
@@ -5729,6 +5747,10 @@ msgstr "Upstream"
 msgid "Upstream Name"
 msgstr "Upstream-Name"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "Upstream-Testtyp"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "Uptime:"
@@ -5851,7 +5873,7 @@ msgstr ""
 "und ein Sicherheitstoken haben, und wählen Sie sorgfältig aus, was "
 "wiederhergestellt werden soll."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -6045,6 +6067,9 @@ msgstr "Ihre alten Codes funktionieren nicht mehr."
 msgid "Your passkeys"
 msgstr "Deine Passkeys"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "Aktion nach der Synchronisierung auswählen"
+
 #~ msgid "Link Start"
 #~ msgstr "Link Start"
 

+ 64 - 42
app/src/language/en/app.po

@@ -125,14 +125,14 @@ msgstr ""
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr ""
@@ -738,7 +738,7 @@ msgstr ""
 msgid "Certificates"
 msgstr ""
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr ""
 
@@ -1000,7 +1000,7 @@ msgstr ""
 msgid "Config Template"
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr ""
 
@@ -1119,7 +1119,7 @@ msgid ""
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1454,7 +1454,7 @@ msgstr ""
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1469,8 +1469,8 @@ msgstr ""
 msgid "Disk IO"
 msgstr ""
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr ""
 
@@ -1730,7 +1730,7 @@ msgstr ""
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2449,7 +2449,7 @@ msgstr ""
 msgid "Import"
 msgstr ""
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr ""
@@ -2765,7 +2765,7 @@ msgid "Loading data..."
 msgstr ""
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2826,9 +2826,17 @@ msgid ""
 "minutes."
 msgstr ""
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr ""
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr ""
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr ""
 
@@ -2977,6 +2985,10 @@ msgstr ""
 msgid "Minutes"
 msgstr ""
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr ""
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr ""
@@ -2990,7 +3002,7 @@ msgstr ""
 msgid "Modify"
 msgstr ""
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr ""
@@ -3023,17 +3035,21 @@ msgstr ""
 msgid "Multi-line Directive"
 msgstr ""
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr ""
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3322,8 +3338,7 @@ msgid "No"
 msgstr ""
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr ""
 
@@ -3352,7 +3367,7 @@ msgid "Node"
 msgstr ""
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr ""
@@ -3370,6 +3385,10 @@ msgstr ""
 msgid "Node Secret"
 msgstr ""
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr ""
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr ""
@@ -3392,7 +3411,7 @@ msgid "Not Valid Before: %{date}"
 msgstr ""
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr ""
 
@@ -3470,6 +3489,7 @@ msgstr ""
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3496,7 +3516,7 @@ msgstr ""
 msgid "On"
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr ""
 
@@ -3504,6 +3524,7 @@ msgstr ""
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3722,7 +3743,7 @@ msgstr ""
 msgid "Please fill in required S3 configuration fields"
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3779,7 +3800,7 @@ msgstr ""
 msgid "Please log in."
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid ""
 "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
@@ -3841,8 +3862,7 @@ msgid "Port Scanner"
 msgstr ""
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr ""
 
@@ -3903,7 +3923,7 @@ msgid ""
 "reverse proxy, please configure the protocol separately in the reverse proxy."
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr ""
 
@@ -3915,7 +3935,7 @@ msgstr ""
 msgid "Proxy"
 msgstr ""
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr ""
 
@@ -4020,9 +4040,7 @@ msgid "Reload"
 msgstr ""
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4060,6 +4078,10 @@ msgstr ""
 msgid "Reloading nginx"
 msgstr ""
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr ""
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4562,10 +4584,6 @@ msgstr ""
 msgid "Select all"
 msgstr ""
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr ""
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr ""
@@ -4818,7 +4836,7 @@ msgstr ""
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr ""
 
@@ -4984,7 +5002,7 @@ msgstr ""
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr ""
@@ -5391,7 +5409,7 @@ msgstr ""
 msgid "Two-factor authentication required"
 msgstr ""
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5428,13 +5446,13 @@ msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5472,7 +5490,7 @@ msgstr ""
 msgid "Upload Folders"
 msgstr ""
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr ""
 
@@ -5480,6 +5498,10 @@ msgstr ""
 msgid "Upstream Name"
 msgstr ""
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr ""
@@ -5598,7 +5620,7 @@ msgid ""
 "to restore."
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."

+ 67 - 42
app/src/language/es/app.po

@@ -147,14 +147,14 @@ msgstr "Acción"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "Acciones"
@@ -785,7 +785,7 @@ msgstr "Tipo de certificado"
 msgid "Certificates"
 msgstr "Certificados"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "Lista de Certificados"
 
@@ -1082,7 +1082,7 @@ msgstr "La ruta de configuración está vacía"
 msgid "Config Template"
 msgstr "Plantilla de configuración"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "Configuración"
 
@@ -1206,7 +1206,7 @@ msgstr ""
 "automáticamente en tu computadora."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1545,7 +1545,7 @@ msgstr "Deshabilitar el flujo %{name} desde %{node} con éxito"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1560,8 +1560,8 @@ msgstr "Desactivado con éxito"
 msgid "Disk IO"
 msgstr "I/O del disco"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "Credenciales de DNS"
 
@@ -1825,7 +1825,7 @@ msgstr "Habilitar TOTP"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2557,7 +2557,7 @@ msgstr ""
 msgid "Import"
 msgstr "Importar"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "Importar Certificado"
@@ -2879,7 +2879,7 @@ msgid "Loading data..."
 msgstr "Cargando datos..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2951,9 +2951,17 @@ msgstr ""
 "de Nginx UI ejecutará el comando logrotate en el intervalo que establezca "
 "en minutos."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "Principal"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "Nodo principal"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "Mantenimiento"
 
@@ -3104,6 +3112,10 @@ msgstr "Minuto"
 msgid "Minutes"
 msgstr "Minutos"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "Espejo"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "Modelo"
@@ -3117,7 +3129,7 @@ msgstr "Modificado el"
 msgid "Modify"
 msgstr "Modificar"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "Modificar Certificado"
@@ -3150,17 +3162,21 @@ msgstr "Mensualmente el día %{day} a las %{time}"
 msgid "Multi-line Directive"
 msgstr "Directiva multilínea"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "N/A"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3451,8 +3467,7 @@ msgid "No"
 msgstr "No"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "Sin acción"
 
@@ -3481,7 +3496,7 @@ msgid "Node"
 msgstr "Nodo"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "Grupo de nodos"
@@ -3499,6 +3514,10 @@ msgstr "Nombre del nodo"
 msgid "Node Secret"
 msgstr "Secreto del nodo"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "Estado del nodo"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "Nodos"
@@ -3521,7 +3540,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "No válido antes: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "Nota"
 
@@ -3606,6 +3625,7 @@ msgstr "Documentación oficial"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3632,7 +3652,7 @@ msgstr "OK"
 msgid "On"
 msgstr "Encendido"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Una vez que se complete la verificación, los registros se eliminarán."
 
@@ -3640,6 +3660,7 @@ msgstr "Una vez que se complete la verificación, los registros se eliminarán."
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3868,7 +3889,7 @@ msgstr "Por favor, complete todos los campos correctamente"
 msgid "Please fill in required S3 configuration fields"
 msgstr "Por favor, complete los campos de configuración de S3 requeridos"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3936,7 +3957,7 @@ msgstr "¡Por favor ingrese su nombre de usuario!"
 msgid "Please log in."
 msgstr "Por favor, inicie sesión."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Tenga en cuenta que las siguientes configuraciones de unidades de tiempo "
@@ -4001,8 +4022,7 @@ msgid "Port Scanner"
 msgstr "Escáner de puertos"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Acción posterior a la sincronización"
 
@@ -4067,7 +4087,7 @@ msgstr ""
 "directamente. Si utiliza un proxy inverso, configure el protocolo por "
 "separado en el proxy inverso."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "Proveedor"
 
@@ -4079,7 +4099,7 @@ msgstr "Proveedor no encontrado: {0}"
 msgid "Proxy"
 msgstr "Proxy"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "Pase de Proxy"
 
@@ -4189,9 +4209,7 @@ msgid "Reload"
 msgstr "Recargar"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4229,6 +4247,10 @@ msgstr "Recargando"
 msgid "Reloading nginx"
 msgstr "Recargando Nginx"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "Remoto"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4738,10 +4760,6 @@ msgstr "Información del token de seguridad"
 msgid "Select all"
 msgstr "Seleccionar todo"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "Seleccionar una acción después de sincronizar"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "Seleccionados {count} archivos"
@@ -5008,7 +5026,7 @@ msgstr "Estático"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "Estado"
 
@@ -5185,7 +5203,7 @@ msgstr "Configuración de sincronización exitosa"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "Nodos de sincronización"
@@ -5646,7 +5664,7 @@ msgstr "Martes"
 msgid "Two-factor authentication required"
 msgstr "Se requiere autenticación de dos factores"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5683,13 +5701,13 @@ msgstr "Actualización exitosa"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5727,7 +5745,7 @@ msgstr "Subir archivos"
 msgid "Upload Folders"
 msgstr "Subir carpetas"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "Aguas arriba"
 
@@ -5735,6 +5753,10 @@ msgstr "Aguas arriba"
 msgid "Upstream Name"
 msgstr "Nombre de la Transmisión"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "Tipo de prueba de upstream"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "Tiempo encendido:"
@@ -5856,7 +5878,7 @@ msgstr ""
 "actuales. Asegúrese de tener un archivo de respaldo válido y un token de "
 "seguridad, y seleccione cuidadosamente qué restaurar."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -6048,6 +6070,9 @@ msgstr "Tus códigos antiguos ya no funcionarán."
 msgid "Your passkeys"
 msgstr "Sus llaves de acceso"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "Seleccionar una acción después de sincronizar"
+
 #~ msgid "Link Start"
 #~ msgstr "Iniciar conexión"
 

+ 67 - 42
app/src/language/fr_FR/app.po

@@ -147,14 +147,14 @@ msgstr "Action"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "Actions"
@@ -779,7 +779,7 @@ msgstr "Type de certificat"
 msgid "Certificates"
 msgstr "Certificats"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "Liste des certificats"
 
@@ -1080,7 +1080,7 @@ msgstr "Le chemin de configuration est vide"
 msgid "Config Template"
 msgstr "Modèle de configuration"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "Configuration"
 
@@ -1204,7 +1204,7 @@ msgstr ""
 "téléchargés sur votre ordinateur."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1543,7 +1543,7 @@ msgstr "Désactivation du flux %{name} depuis %{node} réussie"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1558,8 +1558,8 @@ msgstr "Désactivé avec succès"
 msgid "Disk IO"
 msgstr "E/S disque"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "Identifiants DNS"
 
@@ -1821,7 +1821,7 @@ msgstr "Activer TOTP"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2557,7 +2557,7 @@ msgstr ""
 msgid "Import"
 msgstr "Importer"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "Importer un certificat"
@@ -2879,7 +2879,7 @@ msgid "Loading data..."
 msgstr "Chargement des données..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2951,9 +2951,17 @@ msgstr ""
 "planificateur de tâches crontab de Nginx UI exécutera la commande logrotate "
 "à l'intervalle que vous avez défini en minutes."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "Principal"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "Nœud principal"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "Maintenance"
 
@@ -3104,6 +3112,10 @@ msgstr "Minute"
 msgid "Minutes"
 msgstr "Minutes"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "Miroir"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "Modèle"
@@ -3117,7 +3129,7 @@ msgstr "Modifié le"
 msgid "Modify"
 msgstr "Modifier"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "Modifier le certificat"
@@ -3150,17 +3162,21 @@ msgstr "Mensuellement le jour %{day} à %{time}"
 msgid "Multi-line Directive"
 msgstr "Directive multiligne"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "N/D"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3451,8 +3467,7 @@ msgid "No"
 msgstr "Non"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "Aucune action"
 
@@ -3481,7 +3496,7 @@ msgid "Node"
 msgstr "Nœud"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "Groupe de nœuds"
@@ -3499,6 +3514,10 @@ msgstr "Nom du nœud"
 msgid "Node Secret"
 msgstr "Secret du nœud"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "État du nœud"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "Nœuds"
@@ -3521,7 +3540,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "Non valide avant : %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "Note"
 
@@ -3605,6 +3624,7 @@ msgstr "Documentation officielle"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3631,7 +3651,7 @@ msgstr "OK"
 msgid "On"
 msgstr "Activé"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Une fois la vérification terminée, les enregistrements seront supprimés."
 
@@ -3639,6 +3659,7 @@ msgstr "Une fois la vérification terminée, les enregistrements seront supprim
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3867,7 +3888,7 @@ msgstr "Veuillez remplir tous les champs correctement"
 msgid "Please fill in required S3 configuration fields"
 msgstr "Veuillez remplir les champs de configuration S3 requis"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3935,7 +3956,7 @@ msgstr "Veuillez saisir votre nom d'utilisateur !"
 msgid "Please log in."
 msgstr "Veuillez vous connecter."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Veuillez noter que les unités de temps des configurations ci-dessous sont "
@@ -4000,8 +4021,7 @@ msgid "Port Scanner"
 msgstr "Scanner de ports"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Action post-synchronisation"
 
@@ -4066,7 +4086,7 @@ msgstr ""
 "directe. Si vous utilisez un proxy inverse, veuillez configurer le "
 "protocole séparément dans le proxy inverse."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "Fournisseur"
 
@@ -4078,7 +4098,7 @@ msgstr "Fournisseur introuvable : {0}"
 msgid "Proxy"
 msgstr "Proxy"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "Passe de Proxy"
 
@@ -4188,9 +4208,7 @@ msgid "Reload"
 msgstr "Recharger"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4230,6 +4248,10 @@ msgstr "Rechargement"
 msgid "Reloading nginx"
 msgstr "Rechargement de nginx"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "Distant"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4739,10 +4761,6 @@ msgstr "Informations sur le jeton de sécurité"
 msgid "Select all"
 msgstr "Tout sélectionner"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "Sélectionner une action après la synchronisation"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "{count} fichiers sélectionnés"
@@ -5009,7 +5027,7 @@ msgstr "Statique"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "Statut"
 
@@ -5188,7 +5206,7 @@ msgstr "Synchronisation de la configuration réussie"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "Nœuds de synchronisation"
@@ -5656,7 +5674,7 @@ msgstr "Mardi"
 msgid "Two-factor authentication required"
 msgstr "Authentification à deux facteurs requise"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5693,13 +5711,13 @@ msgstr "Mise à jour réussie"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5737,7 +5755,7 @@ msgstr "Téléverser des fichiers"
 msgid "Upload Folders"
 msgstr "Télécharger des dossiers"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "Amont"
 
@@ -5745,6 +5763,10 @@ msgstr "Amont"
 msgid "Upstream Name"
 msgstr "Nom de l'amont"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "Type de test en amont"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "Disponibilité :"
@@ -5866,7 +5888,7 @@ msgstr ""
 "actuelles. Assurez-vous d'avoir un fichier de sauvegarde valide et un jeton "
 "de sécurité, et sélectionnez soigneusement ce qu'il faut restaurer."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -6061,6 +6083,9 @@ msgstr "Vos anciens codes ne fonctionneront plus."
 msgid "Your passkeys"
 msgstr "Vos clés d'accès"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "Sélectionner une action après la synchronisation"
+
 #~ msgid "Link Start"
 #~ msgstr "Démarrer la liaison"
 

+ 67 - 42
app/src/language/ja_JP/app.po

@@ -141,14 +141,14 @@ msgstr "操作"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "操作"
@@ -754,7 +754,7 @@ msgstr "証明書の種類"
 msgid "Certificates"
 msgstr "証明書"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "証明書リスト"
 
@@ -1036,7 +1036,7 @@ msgstr "設定パスが空です"
 msgid "Config Template"
 msgstr "設定テンプレート"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "設定"
 
@@ -1155,7 +1155,7 @@ msgid ""
 msgstr "Nginx 設定と Nginx UI 設定を含むシステムバックアップを作成します。バックアップファイルは自動的にコンピュータにダウンロードされます。"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1490,7 +1490,7 @@ msgstr "ストリーム %{name} を %{node} から無効化しました"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1505,8 +1505,8 @@ msgstr "無効化に成功しました"
 msgid "Disk IO"
 msgstr "ディスク IO"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "DNS 認証情報"
 
@@ -1765,7 +1765,7 @@ msgstr "TOTP を有効にする"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2484,7 +2484,7 @@ msgstr "ドメインにCNAMEレコードがあり、証明書を取得できな
 msgid "Import"
 msgstr "インポート"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "証明書をインポート"
@@ -2800,7 +2800,7 @@ msgid "Loading data..."
 msgstr "データを読み込んでいます..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2867,9 +2867,17 @@ msgstr ""
 "Nginx UI をインストールするユーザーは、このオプションを手動で有効にすることができます。Nginx UI の crontab "
 "タスクスケジューラは、設定した間隔(分単位)で logrotate コマンドを実行します。"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "メイン"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "メインノード"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "メンテナンス"
 
@@ -3020,6 +3028,10 @@ msgstr "分"
 msgid "Minutes"
 msgstr "分"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "ミラー"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "モデル"
@@ -3033,7 +3045,7 @@ msgstr "更新日時"
 msgid "Modify"
 msgstr "変更"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "証明書を変更"
@@ -3066,17 +3078,21 @@ msgstr "毎月%{day}日%{time}に"
 msgid "Multi-line Directive"
 msgstr "複数行ディレクティブ"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "該当なし"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3365,8 +3381,7 @@ msgid "No"
 msgstr "いいえ"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "アクションなし"
 
@@ -3395,7 +3410,7 @@ msgid "Node"
 msgstr "ノード"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "ノードグループ"
@@ -3413,6 +3428,10 @@ msgstr "ノード名"
 msgid "Node Secret"
 msgstr "ノードシークレット"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "ノードステータス"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "ノード"
@@ -3435,7 +3454,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "有効開始日: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "注記"
 
@@ -3513,6 +3532,7 @@ msgstr "公式ドキュメント"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3539,7 +3559,7 @@ msgstr "OK"
 msgid "On"
 msgstr "オン"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "検証が完了すると、レコードは削除されます。"
 
@@ -3547,6 +3567,7 @@ msgstr "検証が完了すると、レコードは削除されます。"
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3767,7 +3788,7 @@ msgstr "すべての項目を正しく入力してください"
 msgid "Please fill in required S3 configuration fields"
 msgstr "必要なS3設定項目を入力してください"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3826,7 +3847,7 @@ msgstr "ユーザー名を入力してください!"
 msgid "Please log in."
 msgstr "ログインしてください。"
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr "以下の時間設定の単位はすべて秒であることに注意してください。"
 
@@ -3887,8 +3908,7 @@ msgid "Port Scanner"
 msgstr "ポートスキャナー"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "同期後のアクション"
 
@@ -3950,7 +3970,7 @@ msgid ""
 "proxy."
 msgstr "プロトコル設定は直接接続時にのみ有効です。リバースプロキシを使用している場合は、リバースプロキシで個別にプロトコルを設定してください。"
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "プロバイダー"
 
@@ -3962,7 +3982,7 @@ msgstr "プロバイダーが見つかりません: {0}"
 msgid "Proxy"
 msgstr "プロキシ"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "プロキシパス"
 
@@ -4067,9 +4087,7 @@ msgid "Reload"
 msgstr "再読み込み"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4107,6 +4125,10 @@ msgstr "再読み込み中"
 msgid "Reloading nginx"
 msgstr "nginx をリロード中"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "リモート"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4609,10 +4631,6 @@ msgstr "セキュリティトークン情報"
 msgid "Select all"
 msgstr "すべて選択"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "同期後のアクションを選択"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "選択された {count} ファイル"
@@ -4869,7 +4887,7 @@ msgstr "静的"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "ステータス"
 
@@ -5041,7 +5059,7 @@ msgstr "設定の同期に成功しました"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "同期ノード"
@@ -5458,7 +5476,7 @@ msgstr "火曜日"
 msgid "Two-factor authentication required"
 msgstr "二要素認証が必要です"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5495,13 +5513,13 @@ msgstr "更新に成功しました"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5539,7 +5557,7 @@ msgstr "ファイルをアップロード"
 msgid "Upload Folders"
 msgstr "フォルダをアップロード"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "アップストリーム"
 
@@ -5547,6 +5565,10 @@ msgstr "アップストリーム"
 msgid "Upstream Name"
 msgstr "アップストリーム名"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "アップストリームテストタイプ"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "稼働時間:"
@@ -5665,7 +5687,7 @@ msgid ""
 "to restore."
 msgstr "警告: 復元操作は現在の設定を上書きします。有効なバックアップファイルとセキュリティトークンがあることを確認し、復元する内容を慎重に選択してください。"
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -5836,6 +5858,9 @@ msgstr "以前のコードはもう使えません。"
 msgid "Your passkeys"
 msgstr "あなたのパスキー"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "同期後のアクションを選択"
+
 #~ msgid "Link Start"
 #~ msgstr "リンクスタート"
 

+ 67 - 42
app/src/language/ko_KR/app.po

@@ -139,14 +139,14 @@ msgstr "작업"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "작업"
@@ -753,7 +753,7 @@ msgstr "인증서 유형"
 msgid "Certificates"
 msgstr "인증서"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "인증서 목록"
 
@@ -1033,7 +1033,7 @@ msgstr "설정 경로가 비어 있습니다"
 msgid "Config Template"
 msgstr "설정 템플릿"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "구성"
 
@@ -1152,7 +1152,7 @@ msgid ""
 msgstr "Nginx 구성 및 Nginx UI 설정을 포함한 시스템 백업을 생성합니다. 백업 파일은 자동으로 컴퓨터에 다운로드됩니다."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1487,7 +1487,7 @@ msgstr "스트림 %{name}을(를) %{node}에서 비활성화했습니다"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1502,8 +1502,8 @@ msgstr "성공적으로 비활성화됨"
 msgid "Disk IO"
 msgstr "디스크 IO"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "DNS 인증 정보"
 
@@ -1764,7 +1764,7 @@ msgstr "TOTP 활성화"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2483,7 +2483,7 @@ msgstr "도메인에 CNAME 레코드가 있고 인증서를 얻을 수 없는 
 msgid "Import"
 msgstr "가져오기"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "인증서 가져오기"
@@ -2799,7 +2799,7 @@ msgid "Loading data..."
 msgstr "데이터를 불러오는 중..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2865,9 +2865,17 @@ msgstr ""
 "페이지의 매개 변수를 수정할 필요가 없습니다. 도커 컨테이너를 사용하여 Nginx UI를 설치하는사용자는이 옵션을 수동으로 활성화할 수 "
 "있습니다. Nginx UI의 크론탭 작업 스케줄러는설정한 간격 (분 단위)에서 logrotate 명령을 실행합니다."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "메인"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "메인 노드"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "유지보수"
 
@@ -3016,6 +3024,10 @@ msgstr "분"
 msgid "Minutes"
 msgstr "분"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "미러"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "모델"
@@ -3029,7 +3041,7 @@ msgstr "수정일시"
 msgid "Modify"
 msgstr "수정"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "인증서 수정"
@@ -3062,17 +3074,21 @@ msgstr "매월 %{day}일 %{time}에"
 msgid "Multi-line Directive"
 msgstr "여러 줄 지시문"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "해당 없음"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3361,8 +3377,7 @@ msgid "No"
 msgstr "아니요"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "작업 없음"
 
@@ -3391,7 +3406,7 @@ msgid "Node"
 msgstr "노드"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "노드 그룹"
@@ -3409,6 +3424,10 @@ msgstr "노드 이름"
 msgid "Node Secret"
 msgstr "노드 시크릿"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "노드 상태"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "노드"
@@ -3431,7 +3450,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "유효 시작일: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "참고"
 
@@ -3509,6 +3528,7 @@ msgstr "공식 문서"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3535,7 +3555,7 @@ msgstr "확인"
 msgid "On"
 msgstr "켜짐"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "검증이 완료되면, 레코드는 제거됩니다."
 
@@ -3543,6 +3563,7 @@ msgstr "검증이 완료되면, 레코드는 제거됩니다."
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3763,7 +3784,7 @@ msgstr "모든 필드를 올바르게 작성해 주세요"
 msgid "Please fill in required S3 configuration fields"
 msgstr "필수 S3 구성 필드를 입력해 주세요"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3820,7 +3841,7 @@ msgstr "사용자 이름을 입력해주세요!"
 msgid "Please log in."
 msgstr "로그인해 주세요."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr "아래의 시간 설정 단위는 모두 초 단위임을 유의해주세요."
 
@@ -3881,8 +3902,7 @@ msgid "Port Scanner"
 msgstr "포트 스캐너"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "동기화 후 작업"
 
@@ -3944,7 +3964,7 @@ msgid ""
 "proxy."
 msgstr "프로토콜 설정은 직접 연결할 때만 적용됩니다. 리버스 프록시를 사용하는 경우 리버스 프록시에서 별도로 프로토콜을 구성하세요."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "제공자"
 
@@ -3956,7 +3976,7 @@ msgstr "공급자를 찾을 수 없음: {0}"
 msgid "Proxy"
 msgstr "프록시"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "프록시 패스"
 
@@ -4061,9 +4081,7 @@ msgid "Reload"
 msgstr "리로드"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4101,6 +4119,10 @@ msgstr "리로딩 중"
 msgid "Reloading nginx"
 msgstr "Nginx 리로딩 중"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "원격"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4605,10 +4627,6 @@ msgstr "보안 토큰 정보"
 msgid "Select all"
 msgstr "모두 선택"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "동기화 후 작업 선택"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "선택된 {count} 파일"
@@ -4865,7 +4883,7 @@ msgstr "정적"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "상태"
 
@@ -5037,7 +5055,7 @@ msgstr "구성 동기화 성공"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "동기화 노드"
@@ -5452,7 +5470,7 @@ msgstr "화요일"
 msgid "Two-factor authentication required"
 msgstr "2단계 인증이 필요합니다"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5489,13 +5507,13 @@ msgstr "성공적으로 업데이트되었습니다"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5533,7 +5551,7 @@ msgstr "파일 업로드"
 msgid "Upload Folders"
 msgstr "폴더 업로드"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "업스트림"
 
@@ -5541,6 +5559,10 @@ msgstr "업스트림"
 msgid "Upstream Name"
 msgstr "업스트림 이름"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "업스트림 테스트 유형"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "가동 시간:"
@@ -5659,7 +5681,7 @@ msgid ""
 "to restore."
 msgstr "경고: 복원 작업은 현재 구성을 덮어씁니다. 유효한 백업 파일과 보안 토큰이 있는지 확인하고 복원할 내용을 신중하게 선택하십시오."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -5832,6 +5854,9 @@ msgstr "이전 코드는 더 이상 작동하지 않습니다."
 msgid "Your passkeys"
 msgstr "귀하의 패스키"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "동기화 후 작업 선택"
+
 #~ msgid "Link Start"
 #~ msgstr "링크 시작"
 

+ 64 - 40
app/src/language/messages.pot

@@ -128,14 +128,14 @@ msgstr ""
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159
+#: src/views/site/site_list/columns.tsx:160
 #: src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
@@ -744,7 +744,7 @@ msgstr ""
 msgid "Certificates"
 msgstr ""
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr ""
 
@@ -977,7 +977,7 @@ msgstr ""
 msgid "Config Template"
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr ""
 
@@ -1095,7 +1095,7 @@ msgid "Create system backups including Nginx configuration and Nginx UI settings
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1432,7 +1432,7 @@ msgstr ""
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145
+#: src/views/site/site_list/columns.tsx:146
 #: src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
@@ -1448,8 +1448,8 @@ msgstr ""
 msgid "Disk IO"
 msgstr ""
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr ""
 
@@ -1707,7 +1707,7 @@ msgstr ""
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141
+#: src/views/site/site_list/columns.tsx:142
 #: src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
@@ -2421,7 +2421,7 @@ msgstr ""
 msgid "Import"
 msgstr ""
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr ""
@@ -2733,6 +2733,7 @@ msgstr ""
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
 #: src/components/NodeSelector/NodeSelector.vue:61
+#: src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2786,9 +2787,17 @@ msgstr ""
 msgid "Logrotate, by default, is enabled in most mainstream Linux distributions for users who install Nginx UI on the host machine, so you don't need to modify the parameters on this page. For users who install Nginx UI using Docker containers, you can manually enable this option. The crontab task scheduler of Nginx UI will execute the logrotate command at the interval you set in minutes."
 msgstr ""
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr ""
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr ""
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr ""
 
@@ -2938,6 +2947,10 @@ msgstr ""
 msgid "Minutes"
 msgstr ""
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr ""
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr ""
@@ -2951,7 +2964,7 @@ msgstr ""
 msgid "Modify"
 msgstr ""
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr ""
@@ -2984,17 +2997,21 @@ msgstr ""
 msgid "Multi-line Directive"
 msgstr ""
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr ""
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3287,8 +3304,7 @@ msgid "No"
 msgstr ""
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr ""
 
@@ -3317,7 +3333,7 @@ msgid "Node"
 msgstr ""
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90
+#: src/views/site/site_list/columns.tsx:91
 #: src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
@@ -3336,6 +3352,10 @@ msgstr ""
 msgid "Node Secret"
 msgstr ""
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr ""
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr ""
@@ -3358,7 +3378,7 @@ msgid "Not Valid Before: %{date}"
 msgstr ""
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr ""
 
@@ -3432,6 +3452,7 @@ msgstr ""
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3459,7 +3480,7 @@ msgstr ""
 msgid "On"
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr ""
 
@@ -3467,6 +3488,7 @@ msgstr ""
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3681,7 +3703,7 @@ msgstr ""
 msgid "Please fill in required S3 configuration fields"
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid "Please fill in the API authentication credentials provided by your DNS provider."
 msgstr ""
 
@@ -3730,7 +3752,7 @@ msgstr ""
 msgid "Please log in."
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 
@@ -3791,8 +3813,7 @@ msgid "Port Scanner"
 msgstr ""
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr ""
 
@@ -3853,7 +3874,7 @@ msgstr ""
 msgid "Protocol configuration only takes effect when directly connecting. If using reverse proxy, please configure the protocol separately in the reverse proxy."
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr ""
 
@@ -3865,7 +3886,7 @@ msgstr ""
 msgid "Proxy"
 msgstr ""
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr ""
 
@@ -3969,8 +3990,7 @@ msgstr ""
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4008,6 +4028,10 @@ msgstr ""
 msgid "Reloading nginx"
 msgstr ""
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr ""
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4512,10 +4536,6 @@ msgstr ""
 msgid "Select all"
 msgstr ""
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr ""
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr ""
@@ -4765,7 +4785,7 @@ msgstr ""
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119
+#: src/views/site/site_list/columns.tsx:120
 #: src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr ""
@@ -4929,7 +4949,7 @@ msgstr ""
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr ""
@@ -5290,7 +5310,7 @@ msgstr ""
 msgid "Two-factor authentication required"
 msgstr ""
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5327,13 +5347,13 @@ msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:113
 #: src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
@@ -5373,7 +5393,7 @@ msgstr ""
 msgid "Upload Folders"
 msgstr ""
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr ""
 
@@ -5381,6 +5401,10 @@ msgstr ""
 msgid "Upstream Name"
 msgstr ""
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr ""
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr ""
@@ -5500,7 +5524,7 @@ msgstr ""
 msgid "Warning: Restore operation will overwrite current configurations. Make sure you have a valid backup file and security token, and carefully select what to restore."
 msgstr ""
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid "We will add one or more TXT records to the DNS records of your domain for ownership verification."
 msgstr ""
 

+ 67 - 42
app/src/language/pt_PT/app.po

@@ -141,14 +141,14 @@ msgstr "Acção"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "Ações"
@@ -771,7 +771,7 @@ msgstr "Tipo de certificado"
 msgid "Certificates"
 msgstr "Certificados"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "Lista de Certificados"
 
@@ -1069,7 +1069,7 @@ msgstr "O caminho de configuração está vazio"
 msgid "Config Template"
 msgstr "Modelo de Configuração"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "Configuração"
 
@@ -1193,7 +1193,7 @@ msgstr ""
 "automaticamente para o seu computador."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1530,7 +1530,7 @@ msgstr "Desativar o fluxo %{name} de %{node} com sucesso"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1545,8 +1545,8 @@ msgstr "Desactivado com sucesso"
 msgid "Disk IO"
 msgstr "E/S de Disco"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "Credenciais DNS"
 
@@ -1808,7 +1808,7 @@ msgstr "Ativar TOTP"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2536,7 +2536,7 @@ msgstr ""
 msgid "Import"
 msgstr "Importar"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "Importar Certificados"
@@ -2858,7 +2858,7 @@ msgid "Loading data..."
 msgstr "A carregar dados..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2929,9 +2929,17 @@ msgstr ""
 "activar manualmente esta opção. O agendador de tarefas crontab do Nginx UI "
 "executará o comando logrotate no intervalo que definir em minutos."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "Principal"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "Nó principal"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "Manutenção"
 
@@ -3082,6 +3090,10 @@ msgstr "Minuto"
 msgid "Minutes"
 msgstr "Minutos"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "Espelho"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "Modelo"
@@ -3095,7 +3107,7 @@ msgstr "Modificado em"
 msgid "Modify"
 msgstr "Modificar"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "Modificar Certificado"
@@ -3128,17 +3140,21 @@ msgstr "Mensalmente no dia %{day} às %{time}"
 msgid "Multi-line Directive"
 msgstr "Diretiva Multilinha"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "N/D"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3429,8 +3445,7 @@ msgid "No"
 msgstr "Não"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "Sem ação"
 
@@ -3459,7 +3474,7 @@ msgid "Node"
 msgstr "Nó"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "Grupo de nós"
@@ -3477,6 +3492,10 @@ msgstr "Nome do nó"
 msgid "Node Secret"
 msgstr "Segredo do Nó"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "Estado do Nó"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "Nós"
@@ -3499,7 +3518,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "Não Válido Antes de: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "Nota"
 
@@ -3583,6 +3602,7 @@ msgstr "Documentação oficial"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3609,7 +3629,7 @@ msgstr "OK"
 msgid "On"
 msgstr "Ligado"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Assim que a verificação estiver concluída, os registos serão removidos."
 
@@ -3617,6 +3637,7 @@ msgstr "Assim que a verificação estiver concluída, os registos serão removid
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3843,7 +3864,7 @@ msgstr "Por favor, preencha todos os campos corretamente"
 msgid "Please fill in required S3 configuration fields"
 msgstr "Por favor, preencha os campos de configuração do S3 necessários"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3910,7 +3931,7 @@ msgstr "Por favor introduza o seu nome de utilizador!"
 msgid "Please log in."
 msgstr "Por favor, faça login."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr "Note que as definições da unidade de tempo abaixo estão todas em segundos."
 
@@ -3973,8 +3994,7 @@ msgid "Port Scanner"
 msgstr "Scanner de portas"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Ação pós-sincronização"
 
@@ -4039,7 +4059,7 @@ msgstr ""
 "estiver a usar um proxy inverso, configure o protocolo separadamente no "
 "proxy inverso."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "Provedor"
 
@@ -4051,7 +4071,7 @@ msgstr "Fornecedor não encontrado: {0}"
 msgid "Proxy"
 msgstr "Proxy"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "Passe de Proxy"
 
@@ -4160,9 +4180,7 @@ msgid "Reload"
 msgstr "Recarregar"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4200,6 +4218,10 @@ msgstr "Recarregando"
 msgid "Reloading nginx"
 msgstr "Recarregando Nginx"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "Remoto"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4711,10 +4733,6 @@ msgstr "Informações do token de segurança"
 msgid "Select all"
 msgstr "Selecionar tudo"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "Selecionar uma ação após sincronização"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "{count} ficheiros selecionados"
@@ -4979,7 +4997,7 @@ msgstr "Estático"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "Estado"
 
@@ -5155,7 +5173,7 @@ msgstr "Sucesso na configuração da sincronização"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "Nós de sincronização"
@@ -5615,7 +5633,7 @@ msgstr "Terça-feira"
 msgid "Two-factor authentication required"
 msgstr "Autenticação de dois fatores necessária"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5652,13 +5670,13 @@ msgstr "Atualização bem-sucedida"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5696,7 +5714,7 @@ msgstr "Carregar ficheiros"
 msgid "Upload Folders"
 msgstr "Carregar pastas"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "A montante"
 
@@ -5704,6 +5722,10 @@ msgstr "A montante"
 msgid "Upstream Name"
 msgstr "Nome do Upstream"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "Tipo de teste de upstream"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "Uptime:"
@@ -5825,7 +5847,7 @@ msgstr ""
 "Certifique-se de que tem um ficheiro de cópia de segurança válido e um "
 "token de segurança, e selecione cuidadosamente o que restaurar."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -6016,6 +6038,9 @@ msgstr "Os seus códigos antigos não funcionarão mais."
 msgid "Your passkeys"
 msgstr "As suas chaves de acesso"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "Selecionar uma ação após sincronização"
+
 #~ msgid "Link Start"
 #~ msgstr "Início do link"
 

+ 67 - 42
app/src/language/ru_RU/app.po

@@ -145,14 +145,14 @@ msgstr "Действие"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "Действия"
@@ -777,7 +777,7 @@ msgstr "Тип сертификата"
 msgid "Certificates"
 msgstr "Сертификаты"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "Список сертификатов"
 
@@ -1074,7 +1074,7 @@ msgstr "Путь конфигурации пуст"
 msgid "Config Template"
 msgstr "Шаблон конфигурации"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "Конфигурация"
 
@@ -1198,7 +1198,7 @@ msgstr ""
 "компьютер."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1533,7 +1533,7 @@ msgstr "Поток %{name} отключен от %{node} успешно"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1548,8 +1548,8 @@ msgstr "Отключено успешно"
 msgid "Disk IO"
 msgstr "Нагрузка на Диск IO"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "DNS учетные данные"
 
@@ -1811,7 +1811,7 @@ msgstr "Включить TOTP"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2541,7 +2541,7 @@ msgstr ""
 msgid "Import"
 msgstr "Импорт"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "Импортировать сертификат"
@@ -2863,7 +2863,7 @@ msgid "Loading data..."
 msgstr "Загрузка данных..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2934,9 +2934,17 @@ msgstr ""
 "можете вручную включить эту опцию. Планировщик задач crontab Nginx UI будет "
 "выполнять команду logrotate с интервалом, который вы установите в минутах."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "Основной"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "Главный узел"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "Техническое обслуживание"
 
@@ -3087,6 +3095,10 @@ msgstr "Минута"
 msgid "Minutes"
 msgstr "Минуты"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "Зеркало"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "Модель"
@@ -3100,7 +3112,7 @@ msgstr "Изменено"
 msgid "Modify"
 msgstr "Изменить"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "Изменить сертификат"
@@ -3133,17 +3145,21 @@ msgstr "Ежемесячно в день %{day} в %{time}"
 msgid "Multi-line Directive"
 msgstr "Многострочная директива"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "Н/Д"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3434,8 +3450,7 @@ msgid "No"
 msgstr "Нет"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "Нет действия"
 
@@ -3464,7 +3479,7 @@ msgid "Node"
 msgstr "Узел"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "Группа узлов"
@@ -3482,6 +3497,10 @@ msgstr "Имя узла"
 msgid "Node Secret"
 msgstr "Секрет узла"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "Статус узла"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "Узлы"
@@ -3504,7 +3523,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "Действителен до: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "Заметка"
 
@@ -3588,6 +3607,7 @@ msgstr "Официальная документация"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3614,7 +3634,7 @@ msgstr "ОК"
 msgid "On"
 msgstr "Вкл"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "После завершения проверки записи будут удалены."
 
@@ -3622,6 +3642,7 @@ msgstr "После завершения проверки записи будут
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3850,7 +3871,7 @@ msgstr "Пожалуйста, заполните все поля правиль
 msgid "Please fill in required S3 configuration fields"
 msgstr "Пожалуйста, заполните обязательные поля конфигурации S3"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3918,7 +3939,7 @@ msgstr "Введите ваше имя пользователя!"
 msgid "Please log in."
 msgstr "Пожалуйста, войдите в систему."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Обратите внимание, что единица измерения времени в конфигурациях ниже "
@@ -3983,8 +4004,7 @@ msgid "Port Scanner"
 msgstr "Сканер портов"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Действие после синхронизации"
 
@@ -4049,7 +4069,7 @@ msgstr ""
 "использовании обратного прокси настройте протокол отдельно в обратном "
 "прокси."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "Провайдер"
 
@@ -4061,7 +4081,7 @@ msgstr "Поставщик не найден: {0}"
 msgid "Proxy"
 msgstr "Прокси"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "Прокси-передача"
 
@@ -4170,9 +4190,7 @@ msgid "Reload"
 msgstr "Перегрузить"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4210,6 +4228,10 @@ msgstr "Перезагружается"
 msgid "Reloading nginx"
 msgstr "Перезагружается nginx"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "Удаленный"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4719,10 +4741,6 @@ msgstr "Информация о токене безопасности"
 msgid "Select all"
 msgstr "Выбрать все"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "Выберите действие после синхронизации"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "Выбрано {count} файлов"
@@ -4981,7 +4999,7 @@ msgstr "Статический"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "Статус"
 
@@ -5157,7 +5175,7 @@ msgstr "Синхронизация конфигурации успешна"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "Синхронизированные узлы"
@@ -5614,7 +5632,7 @@ msgstr "Вторник"
 msgid "Two-factor authentication required"
 msgstr "Требуется двухфакторная аутентификация"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5651,13 +5669,13 @@ msgstr "Успешно обновлено"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5695,7 +5713,7 @@ msgstr "Загрузить файлы"
 msgid "Upload Folders"
 msgstr "Загрузить папки"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "Восходящий поток"
 
@@ -5703,6 +5721,10 @@ msgstr "Восходящий поток"
 msgid "Upstream Name"
 msgstr "Имя Upstream"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "Тип теста апстрима"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "Аптайм:"
@@ -5824,7 +5846,7 @@ msgstr ""
 "Убедитесь, что у вас есть действительный файл резервной копии и токен "
 "безопасности, и тщательно выберите, что восстанавливать."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -6012,6 +6034,9 @@ msgstr "Ваши старые коды больше не будут работа
 msgid "Your passkeys"
 msgstr "Ваши ключи доступа"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "Выберите действие после синхронизации"
+
 #~ msgid "Link Start"
 #~ msgstr "Начало ссылки"
 

+ 67 - 42
app/src/language/tr_TR/app.po

@@ -143,14 +143,14 @@ msgstr "Eylem"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "İşlemler"
@@ -765,7 +765,7 @@ msgstr "Sertifika Türü"
 msgid "Certificates"
 msgstr "Sertifikalar"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "Sertifika Listesi"
 
@@ -1065,7 +1065,7 @@ msgstr "Yapılandırma yolu boş"
 msgid "Config Template"
 msgstr "Yapılandırma Şablonu"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "Yapılandırma"
 
@@ -1188,7 +1188,7 @@ msgstr ""
 "oluşturun. Yedek dosyaları otomatik olarak bilgisayarınıza indirilecektir."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1525,7 +1525,7 @@ msgstr "Akış %{name}, %{node} üzerinden başarıyla devre dışı bırakıld
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1540,8 +1540,8 @@ msgstr "Başarıyla devre dışı bırakıldı"
 msgid "Disk IO"
 msgstr "Disk IO"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "DNS Kimlik Bilgileri"
 
@@ -1805,7 +1805,7 @@ msgstr "TOTP'yi Etkinleştir"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2537,7 +2537,7 @@ msgstr ""
 msgid "Import"
 msgstr "İçe Aktar"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "Sertifika İçe Aktar"
@@ -2859,7 +2859,7 @@ msgid "Loading data..."
 msgstr "Veriler yükleniyor..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2929,9 +2929,17 @@ msgstr ""
 "olarak etkinleştirebilir. Nginx UI'nin crontab görev zamanlayıcısı, "
 "belirlediğiniz dakika aralığında logrotate komutunu çalıştıracaktır."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "Ana"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "Ana Düğüm"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "Bakım"
 
@@ -3082,6 +3090,10 @@ msgstr "Dakika"
 msgid "Minutes"
 msgstr "Dakika"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "Ayna"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "Model"
@@ -3095,7 +3107,7 @@ msgstr "Değiştirilme Tarihi"
 msgid "Modify"
 msgstr "Değiştir"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "Sertifikayı Düzenle"
@@ -3128,17 +3140,21 @@ msgstr "Her ayın %{day} günü %{time} saatinde"
 msgid "Multi-line Directive"
 msgstr "Çok Satırlı Yönergeler"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "Yok"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3429,8 +3445,7 @@ msgid "No"
 msgstr "Hayır"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "Eylem Yok"
 
@@ -3459,7 +3474,7 @@ msgid "Node"
 msgstr "Düğüm"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "Düğüm Grubu"
@@ -3477,6 +3492,10 @@ msgstr "Düğüm adı"
 msgid "Node Secret"
 msgstr "Düğüm Sırrı"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "Düğüm Durumu"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "Düğümler"
@@ -3499,7 +3518,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "Geçerlilik Başlangıç Tarihi: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "Not"
 
@@ -3583,6 +3602,7 @@ msgstr "Resmi Belge"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3609,7 +3629,7 @@ msgstr "Tamam"
 msgid "On"
 msgstr "Açık"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Doğrulama tamamlandığında, kayıtlar kaldırılacaktır."
 
@@ -3617,6 +3637,7 @@ msgstr "Doğrulama tamamlandığında, kayıtlar kaldırılacaktır."
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3842,7 +3863,7 @@ msgstr "Lütfen tüm alanları doğru şekilde doldurun"
 msgid "Please fill in required S3 configuration fields"
 msgstr "Lütfen gerekli S3 yapılandırma alanlarını doldurun"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3908,7 +3929,7 @@ msgstr "Lütfen kullanıcı adınızı girin!"
 msgid "Please log in."
 msgstr "Lütfen giriş yapın."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Lütfen aşağıdaki zaman yapılandırmalarının birimlerinin saniye cinsinden "
@@ -3973,8 +3994,7 @@ msgid "Port Scanner"
 msgstr "Port Tarayıcı"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Senkronizasyon Sonrası İşlem"
 
@@ -4038,7 +4058,7 @@ msgstr ""
 "Protokol yapılandırması yalnızca doğrudan bağlantı sırasında geçerlidir. "
 "Ters proxy kullanıyorsanız, protokolü ters proxyda ayrı olarak yapılandırın."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "Sağlayıcı"
 
@@ -4050,7 +4070,7 @@ msgstr "Sağlayıcı bulunamadı: {0}"
 msgid "Proxy"
 msgstr "Proxy"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "Proxy Geçişi"
 
@@ -4159,9 +4179,7 @@ msgid "Reload"
 msgstr "Yeniden Yükle"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4199,6 +4217,10 @@ msgstr "Yeniden Yükleniyor"
 msgid "Reloading nginx"
 msgstr "nginx yeniden yükleniyor"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "Uzak"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4715,10 +4737,6 @@ msgstr "Güvenlik Belirteci Bilgileri"
 msgid "Select all"
 msgstr "Tümünü seç"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "Senkronizasyon sonrası eylem seçin"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "Seçilen {count} dosya"
@@ -4979,7 +4997,7 @@ msgstr "Statik"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "Durum"
 
@@ -5157,7 +5175,7 @@ msgstr "Yapılandırma Başarıyla Senkronize Edildi"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "Senkronizasyon Düğümleri"
@@ -5613,7 +5631,7 @@ msgstr "Salı"
 msgid "Two-factor authentication required"
 msgstr "İki faktörlü kimlik doğrulama gerekiyor"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5650,13 +5668,13 @@ msgstr "Başarıyla güncellendi"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5694,7 +5712,7 @@ msgstr "Dosyaları Yükle"
 msgid "Upload Folders"
 msgstr "Klasörleri Yükle"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "Yukarı Akış"
 
@@ -5702,6 +5720,10 @@ msgstr "Yukarı Akış"
 msgid "Upstream Name"
 msgstr "Yukarı Akış Adı"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "Yukarı Akış Test Türü"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "Çalışma Süresi:"
@@ -5823,7 +5845,7 @@ msgstr ""
 "Geçerli bir yedekleme dosyasına ve güvenlik belirtecine sahip olduğunuzdan "
 "emin olun ve neyi geri yükleyeceğinizi dikkatlice seçin."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -6013,6 +6035,9 @@ msgstr "Eski kodlarınız artık çalışmayacak."
 msgid "Your passkeys"
 msgstr "Geçiş Anahtarlarınız"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "Senkronizasyon sonrası eylem seçin"
+
 #~ msgid "Link Start"
 #~ msgstr "Bağlantı Başlat"
 

+ 67 - 42
app/src/language/uk_UA/app.po

@@ -145,14 +145,14 @@ msgstr "Дія"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "Дії"
@@ -773,7 +773,7 @@ msgstr "Тип сертифіката"
 msgid "Certificates"
 msgstr "Сертифікати"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "Список сертифікатів"
 
@@ -1068,7 +1068,7 @@ msgstr "Конфігурація порожній"
 msgid "Config Template"
 msgstr "Шаблон конфігурації"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "Конфігурація"
 
@@ -1192,7 +1192,7 @@ msgstr ""
 "комп’ютер."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1599,7 +1599,7 @@ msgstr "Потік %{name} успішно вимкнено з %{node}"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1614,8 +1614,8 @@ msgstr "Успішно вимкнено"
 msgid "Disk IO"
 msgstr "Дисковий ввід/вивід"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "DNS облікові дані"
 
@@ -1877,7 +1877,7 @@ msgstr "Увімкнути TOTP"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2607,7 +2607,7 @@ msgstr ""
 msgid "Import"
 msgstr "Імпорт"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "Імпортувати сертифікат"
@@ -2929,7 +2929,7 @@ msgid "Loading data..."
 msgstr "Завантаження даних..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -3000,9 +3000,17 @@ msgstr ""
 "можете вручну активувати цю опцію. Планувальник завдань crontab у Nginx UI "
 "виконуватиме команду logrotate з інтервалом, який ви встановите у хвилинах."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "Головний"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "Головний вузол"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "Технічне обслуговування"
 
@@ -3153,6 +3161,10 @@ msgstr "Хвилина"
 msgid "Minutes"
 msgstr "Хвилини"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "Дзеркало"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "Модель"
@@ -3166,7 +3178,7 @@ msgstr "Змінено"
 msgid "Modify"
 msgstr "Змінити"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "Редагувати сертифікат"
@@ -3199,17 +3211,21 @@ msgstr "Щомісяця %{day} числа о %{time}"
 msgid "Multi-line Directive"
 msgstr "Багаторядкова директива"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "Н/Д"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3500,8 +3516,7 @@ msgid "No"
 msgstr "Ні"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "Без дії"
 
@@ -3530,7 +3545,7 @@ msgid "Node"
 msgstr "Вузол"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "Група вузлів"
@@ -3548,6 +3563,10 @@ msgstr "Ім’я вузла"
 msgid "Node Secret"
 msgstr "Секрет вузла"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "Стан вузла"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "Вузли"
@@ -3570,7 +3589,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "Не дійсний до: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "Примітка"
 
@@ -3654,6 +3673,7 @@ msgstr "Офіційна документація"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3680,7 +3700,7 @@ msgstr "Гаразд"
 msgid "On"
 msgstr "Увімкнено"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Після завершення перевірки записи будуть видалені."
 
@@ -3688,6 +3708,7 @@ msgstr "Після завершення перевірки записи буду
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3914,7 +3935,7 @@ msgstr "Будь ласка, заповніть усі поля правильн
 msgid "Please fill in required S3 configuration fields"
 msgstr "Будь ласка, заповніть обов’язкові поля конфігурації S3"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3980,7 +4001,7 @@ msgstr "Будь ласка, введіть ваше ім'я користува
 msgid "Please log in."
 msgstr "Будь ласка, увійдіть."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr ""
 "Будь ласка, зверніть увагу, що одиницею виміру часу в наведених нижче "
@@ -4045,8 +4066,7 @@ msgid "Port Scanner"
 msgstr "Сканер портів"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Дія після синхронізації"
 
@@ -4111,7 +4131,7 @@ msgstr ""
 "використовуєте зворотний проксі, налаштуйте протокол окремо у зворотному "
 "проксі."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "Провайдер"
 
@@ -4123,7 +4143,7 @@ msgstr "Постачальника не знайдено: {0}"
 msgid "Proxy"
 msgstr "Проксі"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "Проксі-передача"
 
@@ -4233,9 +4253,7 @@ msgid "Reload"
 msgstr "Перезавантажити"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4275,6 +4293,10 @@ msgstr "Перезавантаження"
 msgid "Reloading nginx"
 msgstr "Перезавантаження nginx"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "Віддалено"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4786,10 +4808,6 @@ msgstr "Інформація про токен безпеки"
 msgid "Select all"
 msgstr "Вибрати все"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "Виберіть дію після синхронізації"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "Вибрано {count} файлів"
@@ -5052,7 +5070,7 @@ msgstr "Статичний"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "Статус"
 
@@ -5228,7 +5246,7 @@ msgstr "Успішна синхронізація конфігурації"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "Синхронізовані вузли"
@@ -5684,7 +5702,7 @@ msgstr "Вівторок"
 msgid "Two-factor authentication required"
 msgstr "Потрібна двофакторна аутентифікація"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5721,13 +5739,13 @@ msgstr "Успішно оновлено"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5765,7 +5783,7 @@ msgstr "Завантажити файли"
 msgid "Upload Folders"
 msgstr "Завантажити папки"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "Вгору за течією"
 
@@ -5773,6 +5791,10 @@ msgstr "Вгору за течією"
 msgid "Upstream Name"
 msgstr "Назва апстріму"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "Тип тестування апстриму"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "Час роботи:"
@@ -5894,7 +5916,7 @@ msgstr ""
 "Переконайтеся, що у вас є дійсний файл резервної копії та токен безпеки, і "
 "ретельно виберіть, що відновлювати."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -6081,6 +6103,9 @@ msgstr "Ваші старі коди більше не працюватимут
 msgid "Your passkeys"
 msgstr "Ваші ключі доступу"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "Виберіть дію після синхронізації"
+
 #~ msgid "Link Start"
 #~ msgstr "Почати зв’язок"
 

+ 67 - 42
app/src/language/vi_VN/app.po

@@ -136,14 +136,14 @@ msgstr "Hành động"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "Hành động"
@@ -753,7 +753,7 @@ msgstr "Loại chứng chỉ"
 msgid "Certificates"
 msgstr "Chứng chỉ"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "Danh sách chứng chỉ"
 
@@ -1047,7 +1047,7 @@ msgstr "Đường dẫn cấu hình trống"
 msgid "Config Template"
 msgstr "Mẫu cấu hình"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "Cấu hình"
 
@@ -1168,7 +1168,7 @@ msgstr ""
 "tệp sao lưu sẽ tự động được tải xuống máy tính của bạn."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1503,7 +1503,7 @@ msgstr "Đã vô hiệu hóa luồng %{name} từ %{node} thành công"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1518,8 +1518,8 @@ msgstr "Đã tắt thành công"
 msgid "Disk IO"
 msgstr "Disk IO"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "Xác thực DNS"
 
@@ -1782,7 +1782,7 @@ msgstr "Bật TOTP"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2507,7 +2507,7 @@ msgstr ""
 msgid "Import"
 msgstr "Nhập"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "Nhập chứng chỉ"
@@ -2829,7 +2829,7 @@ msgid "Loading data..."
 msgstr "Đang tải dữ liệu..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2900,9 +2900,17 @@ msgstr ""
 "chọn này. Bộ lập lịch tác vụ crontab của Nginx UI sẽ thực thi lệnh "
 "logrotate theo khoảng thời gian bạn đặt (tính bằng phút)."
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "Chính"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "Nút chính"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "Bảo trì"
 
@@ -3053,6 +3061,10 @@ msgstr "Phút"
 msgid "Minutes"
 msgstr "Phút"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "Gương"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "Mô hình"
@@ -3066,7 +3078,7 @@ msgstr "Đã sửa đổi lúc"
 msgid "Modify"
 msgstr "Sửa đổi"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "Sửa đổi chứng chỉ"
@@ -3099,17 +3111,21 @@ msgstr "Hàng tháng vào ngày %{day} lúc %{time}"
 msgid "Multi-line Directive"
 msgstr "Chỉ thị nhiều dòng"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "Không có"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3400,8 +3416,7 @@ msgid "No"
 msgstr "Không"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "Không hành động"
 
@@ -3430,7 +3445,7 @@ msgid "Node"
 msgstr "Nút"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "Nhóm nút"
@@ -3448,6 +3463,10 @@ msgstr "Tên nút"
 msgid "Node Secret"
 msgstr "Bí mật nút"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "Trạng thái nút"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "Nút"
@@ -3470,7 +3489,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "Không hợp lệ trước: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "Ghi chú"
 
@@ -3552,6 +3571,7 @@ msgstr "Tài liệu chính thức"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3578,7 +3598,7 @@ msgstr "Đồng ý"
 msgid "On"
 msgstr "Bật"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Sau khi quá trình xác minh hoàn tất, bản ghi sẽ bị xóa."
 
@@ -3586,6 +3606,7 @@ msgstr "Sau khi quá trình xác minh hoàn tất, bản ghi sẽ bị xóa."
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3812,7 +3833,7 @@ msgstr "Vui lòng điền đầy đủ và chính xác tất cả các trường
 msgid "Please fill in required S3 configuration fields"
 msgstr "Vui lòng điền vào các trường cấu hình S3 bắt buộc"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3873,7 +3894,7 @@ msgstr "Vui lòng nhập username!"
 msgid "Please log in."
 msgstr "Vui lòng đăng nhập."
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr "Lưu ý đơn vị cấu hình thời gian bên dưới được tính bằng giây."
 
@@ -3934,8 +3955,7 @@ msgid "Port Scanner"
 msgstr "Trình quét cổng"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Hành động sau đồng bộ"
 
@@ -3999,7 +4019,7 @@ msgstr ""
 "Cấu hình giao thức chỉ có hiệu lực khi kết nối trực tiếp. Nếu sử dụng proxy "
 "ngược, vui lòng cấu hình giao thức riêng trong proxy ngược."
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "Nhà cung cấp"
 
@@ -4011,7 +4031,7 @@ msgstr "Không tìm thấy nhà cung cấp: {0}"
 msgid "Proxy"
 msgstr "Proxy"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "Chuyển tiếp Proxy"
 
@@ -4120,9 +4140,7 @@ msgid "Reload"
 msgstr "Tải lại"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4160,6 +4178,10 @@ msgstr "Đang tải lại"
 msgid "Reloading nginx"
 msgstr "Tải lại nginx"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "Từ xa"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4667,10 +4689,6 @@ msgstr "Thông tin mã bảo mật"
 msgid "Select all"
 msgstr "Chọn tất cả"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "Chọn hành động sau khi đồng bộ"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "Đã chọn {count} tệp"
@@ -4929,7 +4947,7 @@ msgstr "Tĩnh"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "Trạng thái"
 
@@ -5105,7 +5123,7 @@ msgstr "Đồng bộ cấu hình thành công"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "Nút đồng bộ"
@@ -5561,7 +5579,7 @@ msgstr "Thứ Ba"
 msgid "Two-factor authentication required"
 msgstr "Yêu cầu xác thực hai yếu tố"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5598,13 +5616,13 @@ msgstr "Cập nhật thành công"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5642,7 +5660,7 @@ msgstr "Tải lên tệp"
 msgid "Upload Folders"
 msgstr "Tải lên thư mục"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "Ngược dòng"
 
@@ -5650,6 +5668,10 @@ msgstr "Ngược dòng"
 msgid "Upstream Name"
 msgstr "Tên Upstream"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "Loại kiểm tra upstream"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "Thời gian hoạt động:"
@@ -5771,7 +5793,7 @@ msgstr ""
 "có tệp sao lưu hợp lệ và mã bảo mật, đồng thời cẩn thận chọn nội dung cần "
 "khôi phục."
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -5956,6 +5978,9 @@ msgstr "Mã cũ của bạn sẽ không còn hoạt động nữa."
 msgid "Your passkeys"
 msgstr "Khóa truy cập của bạn"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "Chọn hành động sau khi đồng bộ"
+
 #~ msgid "Link Start"
 #~ msgstr "Liên kết bắt đầu"
 

+ 68 - 43
app/src/language/zh_CN/app.po

@@ -140,14 +140,14 @@ msgstr "操作"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "操作"
@@ -751,7 +751,7 @@ msgstr "证书类型"
 msgid "Certificates"
 msgstr "证书"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "证书列表"
 
@@ -1027,7 +1027,7 @@ msgstr "配置路径为空"
 msgid "Config Template"
 msgstr "配置模板"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "配置"
 
@@ -1146,7 +1146,7 @@ msgid ""
 msgstr "创建系统备份,包括 Nginx 配置和 Nginx UI 设置。备份文件将自动下载到你的电脑。"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1481,7 +1481,7 @@ msgstr "在 %{node} 上禁用 %{name} 成功"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1496,8 +1496,8 @@ msgstr "禁用成功"
 msgid "Disk IO"
 msgstr "磁盘 IO"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "DNS 凭证"
 
@@ -1756,7 +1756,7 @@ msgstr "启用 TOTP"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2475,7 +2475,7 @@ msgstr "如果您的域名有 CNAME 记录且无法获取证书,则需要启
 msgid "Import"
 msgstr "导入"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "导入证书"
@@ -2791,7 +2791,7 @@ msgid "Loading data..."
 msgstr "正在加载数据..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2857,9 +2857,17 @@ msgstr ""
 "定时任务,因此您无需修改本页面的参数。对于使用 Docker 容器安装 Nginx 用户界面的用户,您可以手动启用该选项。Nginx UI "
 "的定时任务任务调度器将按照您设置的时间间隔(以分钟为单位)执行 logrotate 命令。"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "主"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "主节点"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "维护模式"
 
@@ -3008,6 +3016,10 @@ msgstr "分钟"
 msgid "Minutes"
 msgstr "分钟"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "镜像"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "模型"
@@ -3021,7 +3033,7 @@ msgstr "修改时间"
 msgid "Modify"
 msgstr "修改"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "修改证书"
@@ -3054,17 +3066,21 @@ msgstr "每月%{day}日%{time}"
 msgid "Multi-line Directive"
 msgstr "多行指令"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "不适用"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3353,8 +3369,7 @@ msgid "No"
 msgstr "取消"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "无操作"
 
@@ -3383,7 +3398,7 @@ msgid "Node"
 msgstr "节点"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "节点组"
@@ -3391,7 +3406,7 @@ msgstr "节点组"
 #: src/routes/modules/environments.ts:33
 #: src/views/environments/group/EnvGroup.vue:19
 msgid "Node Groups"
-msgstr "环境组"
+msgstr "节点组"
 
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
@@ -3401,6 +3416,10 @@ msgstr "节点名称"
 msgid "Node Secret"
 msgstr "节点密钥"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "节点状态"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "节点"
@@ -3423,7 +3442,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "此前无效: %{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "注意"
 
@@ -3501,6 +3520,7 @@ msgstr "官方文档"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3527,7 +3547,7 @@ msgstr "确定"
 msgid "On"
 msgstr "开启"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "一旦验证完成,这些记录将被删除。"
 
@@ -3535,6 +3555,7 @@ msgstr "一旦验证完成,这些记录将被删除。"
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3753,7 +3774,7 @@ msgstr "请正确填写所有字段"
 msgid "Please fill in required S3 configuration fields"
 msgstr "请填写必填的 S3 配置字段"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3810,7 +3831,7 @@ msgstr "请输入您的用户名!"
 msgid "Please log in."
 msgstr "请登录。"
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr "请注意,下面的时间单位配置均以秒为单位。"
 
@@ -3871,8 +3892,7 @@ msgid "Port Scanner"
 msgstr "端口检测"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "同步后操作"
 
@@ -3934,7 +3954,7 @@ msgid ""
 "proxy."
 msgstr "协议配置仅在直接连接时生效。如果使用反向代理,请在反向代理中单独配置协议。"
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "提供商"
 
@@ -3946,7 +3966,7 @@ msgstr "未找到提供商:{0}"
 msgid "Proxy"
 msgstr "代理"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "代理传递"
 
@@ -4051,9 +4071,7 @@ msgid "Reload"
 msgstr "重载"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4091,6 +4109,10 @@ msgstr "重载中"
 msgid "Reloading nginx"
 msgstr "正在重载 Nginx"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "远程"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4593,10 +4615,6 @@ msgstr "安全令牌信息"
 msgid "Select all"
 msgstr "全选"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "选择同步后的操作"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "已选择 {count} 个文件"
@@ -4853,7 +4871,7 @@ msgstr "静态"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "状态"
 
@@ -5023,7 +5041,7 @@ msgstr "同步配置成功"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "同步节点"
@@ -5432,7 +5450,7 @@ msgstr "星期二"
 msgid "Two-factor authentication required"
 msgstr "需要两步验证"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5469,13 +5487,13 @@ msgstr "更新成功"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5513,7 +5531,7 @@ msgstr "上传文件"
 msgid "Upload Folders"
 msgstr "上传文件夹"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "上游"
 
@@ -5521,6 +5539,10 @@ msgstr "上游"
 msgid "Upstream Name"
 msgstr "Upstream 名称"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "上游测试类型"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "运行时间:"
@@ -5639,7 +5661,7 @@ msgid ""
 "to restore."
 msgstr "警告:还原操作将覆盖当前配置。请确保您有有效的备份文件和安全令牌,并仔细选择要还原的内容。"
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -5808,6 +5830,9 @@ msgstr "您的旧代码将不再有效。"
 msgid "Your passkeys"
 msgstr "你的 Passkeys"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "选择同步后的操作"
+
 #~ msgid "Link Start"
 #~ msgstr "链接"
 

+ 67 - 42
app/src/language/zh_TW/app.po

@@ -144,14 +144,14 @@ msgstr "操作"
 #: src/views/backup/AutoBackup/AutoBackup.vue:273
 #: src/views/certificate/ACMEUser.vue:90
 #: src/views/certificate/CertificateList/certColumns.tsx:92
-#: src/views/certificate/DNSCredential.vue:44
+#: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:71
+#: src/views/environments/group/columns.ts:84
 #: src/views/environments/list/envColumns.tsx:96
 #: src/views/nginx_log/NginxLogList.vue:68
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:73
-#: src/views/site/site_list/columns.tsx:159 src/views/stream/columns.tsx:123
+#: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
 #: src/views/user/userColumns.tsx:58
 msgid "Actions"
 msgstr "操作"
@@ -755,7 +755,7 @@ msgstr "證書類型"
 msgid "Certificates"
 msgstr "憑證"
 
-#: src/routes/modules/certificates.ts:28
+#: src/routes/modules/certificates.ts:36
 msgid "Certificates List"
 msgstr "憑證列表"
 
@@ -1031,7 +1031,7 @@ msgstr "設定路徑為空"
 msgid "Config Template"
 msgstr "配置模板"
 
-#: src/views/certificate/DNSCredential.vue:25
+#: src/views/certificate/DNSCredential.vue:52
 msgid "Configuration"
 msgstr "配置"
 
@@ -1150,7 +1150,7 @@ msgid ""
 msgstr "建立系統備份,包括 Nginx 設定與 Nginx UI 設定。備份檔案將自動下載至您的電腦。"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:59
+#: src/views/environments/group/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:68
@@ -1485,7 +1485,7 @@ msgstr "已成功從 %{node} 停用串流 %{name}"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:162
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:62
-#: src/views/site/site_list/columns.tsx:145 src/views/stream/columns.tsx:112
+#: src/views/site/site_list/columns.tsx:146 src/views/stream/columns.tsx:112
 #: src/views/stream/components/StreamEditor.vue:32
 #: src/views/user/userColumns.tsx:39
 msgid "Disabled"
@@ -1500,8 +1500,8 @@ msgstr "成功停用"
 msgid "Disk IO"
 msgstr "磁碟 IO"
 
-#: src/routes/modules/certificates.ts:56
-#: src/views/certificate/DNSCredential.vue:52
+#: src/routes/modules/certificates.ts:28
+#: src/views/certificate/DNSCredential.vue:79
 msgid "DNS Credentials"
 msgstr "DNS 認證"
 
@@ -1760,7 +1760,7 @@ msgstr "啟用 TOTP"
 #: src/views/preference/tabs/NodeSettings.vue:30
 #: src/views/site/components/SiteStatusSelect.vue:159
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:56
-#: src/views/site/site_list/columns.tsx:141 src/views/stream/columns.tsx:108
+#: src/views/site/site_list/columns.tsx:142 src/views/stream/columns.tsx:108
 #: src/views/stream/components/RightPanel/Basic.vue:24
 #: src/views/stream/components/StreamEditor.vue:26
 #: src/views/user/userColumns.tsx:36
@@ -2479,7 +2479,7 @@ msgstr "如果您的域名有 CNAME 記錄且無法取得證書,您需要啟
 msgid "Import"
 msgstr "匯入"
 
-#: src/routes/modules/certificates.ts:46
+#: src/routes/modules/certificates.ts:54
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Import Certificate"
 msgstr "匯入憑證"
@@ -2795,7 +2795,7 @@ msgid "Loading data..."
 msgstr "資料載入中…"
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2861,9 +2861,17 @@ msgstr ""
 "logrotate,因此您無需修改此頁面的參數。對於使用 Docker 容器安裝 Nginx UI 的使用者,您可以手動啟用此選項。Nginx UI "
 "的 crontab 任務排程器將按照您設定的分鐘間隔執行 logrotate 命令。"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:220
+msgid "Main"
+msgstr "主"
+
+#: src/components/ProxyTargets/ProxyTargets.vue:148
+msgid "Main Node"
+msgstr "主節點"
+
 #: src/views/site/components/SiteStatusSelect.vue:165
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:68
-#: src/views/site/site_list/columns.tsx:149
+#: src/views/site/site_list/columns.tsx:150
 msgid "Maintenance"
 msgstr "維護"
 
@@ -3012,6 +3020,10 @@ msgstr "分鐘"
 msgid "Minutes"
 msgstr "分鐘"
 
+#: src/constants/index.ts:43
+msgid "Mirror"
+msgstr "鏡像"
+
 #: src/views/preference/tabs/OpenAISettings.vue:20
 msgid "Model"
 msgstr "模型"
@@ -3025,7 +3037,7 @@ msgstr "修改於"
 msgid "Modify"
 msgstr "修改"
 
-#: src/routes/modules/certificates.ts:36
+#: src/routes/modules/certificates.ts:44
 #: src/views/certificate/CertificateEditor.vue:86
 msgid "Modify Certificate"
 msgstr "修改憑證"
@@ -3058,17 +3070,21 @@ msgstr "每月%{day}日%{time}"
 msgid "Multi-line Directive"
 msgstr "多行指令"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:225
+msgid "N/A"
+msgstr "不適用"
+
 #: src/components/NgxConfigEditor/NgxUpstream.vue:199
 #: src/views/backup/AutoBackup/AutoBackup.vue:11
 #: src/views/certificate/ACMEUser.vue:11
 #: src/views/certificate/CertificateList/certColumns.tsx:9
 #: src/views/certificate/components/CertificateBasicInfo.vue:23
-#: src/views/certificate/DNSCredential.vue:9
+#: src/views/certificate/DNSCredential.vue:17
 #: src/views/config/components/ConfigRightPanel/Basic.vue:34
 #: src/views/config/components/Delete.vue:123
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:17
-#: src/views/environments/group/columns.ts:8
+#: src/views/environments/group/columns.ts:9
 #: src/views/environments/list/envColumns.tsx:8
 #: src/views/nginx_log/NginxLogList.vue:52
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
@@ -3357,8 +3373,7 @@ msgid "No"
 msgstr "取消"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/views/environments/group/columns.ts:49
-#: src/views/environments/group/EnvGroup.vue:47
+#: src/constants/index.ts:36
 msgid "No Action"
 msgstr "無行動"
 
@@ -3387,7 +3402,7 @@ msgid "Node"
 msgstr "節點"
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: src/views/site/site_list/columns.tsx:90 src/views/stream/columns.tsx:58
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
 #: src/views/stream/components/RightPanel/Basic.vue:39
 msgid "Node Group"
 msgstr "節點群組"
@@ -3405,6 +3420,10 @@ msgstr "節點名稱"
 msgid "Node Secret"
 msgstr "節點金鑰"
 
+#: src/components/ProxyTargets/ProxyTargets.vue:208
+msgid "Node Status"
+msgstr "節點狀態"
+
 #: src/routes/modules/environments.ts:25
 msgid "Nodes"
 msgstr "節點"
@@ -3427,7 +3446,7 @@ msgid "Not Valid Before: %{date}"
 msgstr "此前無效:%{date}"
 
 #: src/components/AutoCertForm/AutoCertForm.vue:39
-#: src/views/certificate/DNSCredential.vue:62
+#: src/views/certificate/DNSCredential.vue:89
 msgid "Note"
 msgstr "備註"
 
@@ -3505,6 +3524,7 @@ msgstr "官方文件"
 #: src/components/NgxConfigEditor/NgxUpstream.vue:151
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:106
 #: src/views/environments/list/envColumns.tsx:55
 msgid "Offline"
@@ -3531,7 +3551,7 @@ msgstr "確定"
 msgid "On"
 msgstr "開啟"
 
-#: src/views/certificate/DNSCredential.vue:72
+#: src/views/certificate/DNSCredential.vue:99
 msgid "Once the verification is complete, the records will be removed."
 msgstr "驗證完成後,記錄將被刪除。"
 
@@ -3539,6 +3559,7 @@ msgstr "驗證完成後,記錄將被刪除。"
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
+#: src/components/ProxyTargets/ProxyTargets.vue:217
 #: src/views/dashboard/Environments.vue:99
 #: src/views/environments/list/envColumns.tsx:51
 msgid "Online"
@@ -3759,7 +3780,7 @@ msgstr "請正確填寫所有欄位"
 msgid "Please fill in required S3 configuration fields"
 msgstr "請填寫必填的 S3 配置欄位"
 
-#: src/views/certificate/DNSCredential.vue:66
+#: src/views/certificate/DNSCredential.vue:93
 msgid ""
 "Please fill in the API authentication credentials provided by your DNS "
 "provider."
@@ -3816,7 +3837,7 @@ msgstr "請輸入您的使用者名稱!"
 msgid "Please log in."
 msgstr "請登入。"
 
-#: src/views/certificate/DNSCredential.vue:75
+#: src/views/certificate/DNSCredential.vue:102
 msgid "Please note that the unit of time configurations below are all in seconds."
 msgstr "請注意,以下時間設定單位均為秒。"
 
@@ -3877,8 +3898,7 @@ msgid "Port Scanner"
 msgstr "端口掃描器"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:45
-#: src/views/environments/group/EnvGroup.vue:39
+#: src/views/environments/group/columns.ts:46
 msgid "Post-sync Action"
 msgstr "同步後動作"
 
@@ -3940,7 +3960,7 @@ msgid ""
 "proxy."
 msgstr "協議配置僅在直接連接時生效。如果使用反向代理,請在反向代理中單獨配置協議。"
 
-#: src/views/certificate/DNSCredential.vue:17
+#: src/views/certificate/DNSCredential.vue:26
 msgid "Provider"
 msgstr "供應商"
 
@@ -3952,7 +3972,7 @@ msgstr "未找到提供者:{0}"
 msgid "Proxy"
 msgstr "代理伺服器"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Proxy Pass"
 msgstr "代理傳遞"
 
@@ -4057,9 +4077,7 @@ msgid "Reload"
 msgstr "重新載入"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104
-#: src/views/environments/group/columns.ts:52
-#: src/views/environments/group/EnvGroup.vue:50
+#: src/components/EnvGroupTabs/EnvGroupTabs.vue:104 src/constants/index.ts:37
 #: src/views/environments/list/Environment.vue:209
 #: src/views/environments/list/Environment.vue:217
 msgid "Reload Nginx"
@@ -4097,6 +4115,10 @@ msgstr "重新載入中"
 msgid "Reloading nginx"
 msgstr "正在重新載入 Nginx"
 
+#: src/constants/index.ts:42
+msgid "Remote"
+msgstr "遠端"
+
 #: src/views/certificate/components/DNSIssueCertificate.vue:146
 #: src/views/preference/tabs/AuthSettings.vue:137
 msgid "Remove"
@@ -4599,10 +4621,6 @@ msgstr "安全代碼資訊"
 msgid "Select all"
 msgstr "全選"
 
-#: src/views/environments/group/EnvGroup.vue:42
-msgid "Select an action after sync"
-msgstr "同步後選擇操作"
-
 #: src/language/curd.ts:59
 msgid "Selected {count} files"
 msgstr "已選擇 {count} 個檔案"
@@ -4859,7 +4877,7 @@ msgstr "靜態"
 #: src/views/dashboard/components/ModulesTable.vue:96
 #: src/views/environments/list/envColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
-#: src/views/site/site_list/columns.tsx:119 src/views/stream/columns.tsx:87
+#: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
 msgstr "狀態"
 
@@ -5029,7 +5047,7 @@ msgstr "同步設定成功"
 
 #: src/components/EnvGroupRender/EnvGroupRender.vue:53
 #: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:16
+#: src/views/environments/group/columns.ts:17
 #: src/views/environments/group/EnvGroup.vue:31
 msgid "Sync Nodes"
 msgstr "同步節點"
@@ -5438,7 +5456,7 @@ msgstr "星期二"
 msgid "Two-factor authentication required"
 msgstr "需要多重因素驗證"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 #: src/views/certificate/CertificateList/certColumns.tsx:24
 #: src/views/config/components/Delete.vue:122
 #: src/views/dashboard/components/ModulesTable.vue:83
@@ -5475,13 +5493,13 @@ msgstr "更新成功"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:236
 #: src/views/certificate/ACMEUser.vue:83
-#: src/views/certificate/DNSCredential.vue:38
+#: src/views/certificate/DNSCredential.vue:65
 #: src/views/config/components/ConfigRightPanel/Basic.vue:54
 #: src/views/config/configColumns.tsx:43
-#: src/views/environments/group/columns.ts:65
+#: src/views/environments/group/columns.ts:78
 #: src/views/environments/list/envColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
-#: src/views/site/site_list/columns.tsx:112 src/views/stream/columns.tsx:80
+#: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
 #: src/views/user/userColumns.tsx:52
 msgid "Updated at"
@@ -5519,7 +5537,7 @@ msgstr "上傳檔案"
 msgid "Upload Folders"
 msgstr "上傳資料夾"
 
-#: src/components/ProxyTargets/ProxyTargets.vue:34
+#: src/components/ProxyTargets/ProxyTargets.vue:125
 msgid "Upstream"
 msgstr "上游"
 
@@ -5527,6 +5545,10 @@ msgstr "上游"
 msgid "Upstream Name"
 msgstr "Upstream 名稱"
 
+#: src/views/environments/group/columns.ts:59
+msgid "Upstream Test Type"
+msgstr "上游測試類型"
+
 #: src/views/dashboard/ServerAnalytic.vue:183
 msgid "Uptime:"
 msgstr "運作時間:"
@@ -5645,7 +5667,7 @@ msgid ""
 "to restore."
 msgstr "警告:恢復操作將覆蓋目前設定。請確保您擁有有效的備份檔案和安全令牌,並謹慎選擇要恢復的內容。"
 
-#: src/views/certificate/DNSCredential.vue:69
+#: src/views/certificate/DNSCredential.vue:96
 msgid ""
 "We will add one or more TXT records to the DNS records of your domain for "
 "ownership verification."
@@ -5814,6 +5836,9 @@ msgstr "您的舊代碼將不再有效。"
 msgid "Your passkeys"
 msgstr "您的通行金鑰"
 
+#~ msgid "Select an action after sync"
+#~ msgstr "同步後選擇操作"
+
 #~ msgid "Link Start"
 #~ msgstr "連結開始"
 

+ 91 - 0
app/src/pinia/moudule/nodeGroupStore.ts

@@ -0,0 +1,91 @@
+import type { EnvGroup } from '@/api/env_group'
+import { defineStore } from 'pinia'
+import env_group from '@/api/env_group'
+
+export const useNodeGroupStore = defineStore('nodeGroup', () => {
+  const envGroups = ref<EnvGroup[]>([])
+  const envGroupMap = ref<Record<number, EnvGroup>>({})
+  const isLoading = ref(false)
+  const isInitialized = ref(false)
+  const lastUpdateTime = ref<string>('')
+
+  // Initialize the store with data
+  async function initialize() {
+    if (isInitialized.value) {
+      return
+    }
+
+    await loadAll()
+    isInitialized.value = true
+  }
+
+  // Load all environment groups by cycling through pages
+  async function loadAll() {
+    if (isLoading.value) {
+      return
+    }
+
+    isLoading.value = true
+
+    try {
+      const allGroups: EnvGroup[] = []
+      let currentPage = 1
+      let hasMorePages = true
+
+      while (hasMorePages) {
+        const response = await env_group.getList({
+          page: currentPage,
+          page_size: 100, // Use a reasonable page size
+        })
+
+        const pageData = response.data || []
+        allGroups.push(...pageData)
+
+        // Check if there are more pages
+        if (response.pagination) {
+          hasMorePages = currentPage < response.pagination.total_pages
+        }
+        else {
+          // Fallback: if no pagination info, check if we got a full page
+          hasMorePages = pageData.length === 100
+        }
+
+        currentPage++
+      }
+
+      envGroups.value = allGroups
+      lastUpdateTime.value = new Date().toISOString()
+      envGroupMap.value = allGroups.reduce((acc, group) => {
+        acc[group.id] = group
+        return acc
+      }, {} as Record<number, EnvGroup>)
+    }
+    catch (error) {
+      console.error('Failed to load environment groups:', error)
+    }
+    finally {
+      isLoading.value = false
+    }
+  }
+
+  // Get environment group by ID
+  function getGroupById(id: number): EnvGroup | undefined {
+    return envGroupMap.value[id]
+  }
+
+  // Refresh all data
+  async function refresh() {
+    await loadAll()
+  }
+
+  return {
+    envGroups: readonly(envGroups),
+    isLoading: readonly(isLoading),
+    isInitialized: readonly(isInitialized),
+    lastUpdateTime: readonly(lastUpdateTime),
+    initialize,
+    loadAll,
+    getGroupById,
+    refresh,
+  }
+})

+ 143 - 0
app/src/pinia/moudule/proxyAvailability.ts

@@ -2,19 +2,40 @@ import type ReconnectingWebSocket from 'reconnecting-websocket'
 import type { ProxyTarget } from '@/api/site'
 import type { UpstreamAvailabilityResponse, UpstreamStatus } from '@/api/upstream'
 import { defineStore } from 'pinia'
+import analytic from '@/api/analytic'
 import upstream from '@/api/upstream'
+import { useNodeAvailabilityStore } from './nodeAvailability'
+
+// Extended types for multi-node support
+export interface NodeUpstreamStatus {
+  online: boolean
+  latency: number
+}
+
+export interface MultiNodeUpstreamStatus {
+  [nodeId: number]: NodeUpstreamStatus
+}
+
+export interface UpstreamStatusMap {
+  [targetKey: string]: MultiNodeUpstreamStatus
+}
 
 // Alias for consistency with existing code
 export type ProxyAvailabilityResult = UpstreamStatus
 
 export const useProxyAvailabilityStore = defineStore('proxyAvailability', () => {
   const availabilityResults = ref<Record<string, ProxyAvailabilityResult>>({})
+  const upstreamStatusMap = ref<UpstreamStatusMap>({})
   const websocket = shallowRef<ReconnectingWebSocket | WebSocket>()
+  const nodeAnalyticsWebsocket = shallowRef<ReconnectingWebSocket | WebSocket>()
   const isConnected = ref(false)
+  const isNodeAnalyticsConnected = ref(false)
   const isInitialized = ref(false)
   const lastUpdateTime = ref<string>('')
   const targetCount = ref(0)
 
+  const nodeStore = useNodeAvailabilityStore()
+
   function getTargetKey(target: ProxyTarget): string {
     return `${target.host}:${target.port}`
   }
@@ -32,6 +53,7 @@ export const useProxyAvailabilityStore = defineStore('proxyAvailability', () =>
       availabilityResults.value = data.results || {}
       lastUpdateTime.value = data.last_update_time || ''
       targetCount.value = data.target_count || 0
+
       isInitialized.value = true
     }
     catch (error) {
@@ -85,10 +107,70 @@ export const useProxyAvailabilityStore = defineStore('proxyAvailability', () =>
     }
   }
 
+  // Connect to node analytics WebSocket for multi-node upstream data
+  function connectNodeAnalyticsWebSocket() {
+    if (nodeAnalyticsWebsocket.value && isNodeAnalyticsConnected.value) {
+      return
+    }
+
+    // Close existing connection if any
+    if (nodeAnalyticsWebsocket.value) {
+      nodeAnalyticsWebsocket.value.close()
+    }
+
+    try {
+      // Create new WebSocket connection to node analytics
+      const ws = analytic.nodes()
+      nodeAnalyticsWebsocket.value = ws
+
+      ws.onopen = () => {
+        isNodeAnalyticsConnected.value = true
+      }
+
+      ws.onmessage = (e: MessageEvent) => {
+        try {
+          const nodeData = JSON.parse(e.data)
+
+          // Process each node's data
+          for (const [nodeIdStr, nodeInfo] of Object.entries(nodeData)) {
+            const nodeId = Number.parseInt(nodeIdStr)
+            if (nodeInfo && typeof nodeInfo === 'object' && 'upstream_status_map' in nodeInfo) {
+              const upstreamData = nodeInfo.upstream_status_map as Record<string, NodeUpstreamStatus>
+              updateUpstreamStatusMapFromNode(nodeId, upstreamData)
+            }
+          }
+
+          lastUpdateTime.value = new Date().toISOString()
+        }
+        catch (error) {
+          console.error('Failed to parse node analytics WebSocket message:', error)
+        }
+      }
+
+      ws.onclose = () => {
+        isNodeAnalyticsConnected.value = false
+      }
+
+      ws.onerror = error => {
+        console.error('Node analytics WebSocket error:', error)
+        isNodeAnalyticsConnected.value = false
+      }
+    }
+    catch (error) {
+      console.error('Failed to create node analytics WebSocket connection:', error)
+    }
+  }
+
   // Start monitoring (initialize + WebSocket)
   async function startMonitoring() {
+    // Initialize node store first
+    if (!nodeStore.isInitialized) {
+      nodeStore.initialize()
+    }
+
     await initialize()
     connectWebSocket()
+    connectNodeAnalyticsWebSocket()
   }
 
   // Stop monitoring and cleanup
@@ -98,6 +180,11 @@ export const useProxyAvailabilityStore = defineStore('proxyAvailability', () =>
       websocket.value = undefined
       isConnected.value = false
     }
+    if (nodeAnalyticsWebsocket.value) {
+      nodeAnalyticsWebsocket.value.close()
+      nodeAnalyticsWebsocket.value = undefined
+      isNodeAnalyticsConnected.value = false
+    }
   }
 
   // Get availability result for a specific target
@@ -117,6 +204,56 @@ export const useProxyAvailabilityStore = defineStore('proxyAvailability', () =>
     return Object.keys(availabilityResults.value)
   }
 
+  // Update upstream status map from node data
+  function updateUpstreamStatusMapFromNode(nodeId: number, upstreamData: Record<string, NodeUpstreamStatus>) {
+    if (!upstreamData)
+      return
+
+    for (const [targetKey, status] of Object.entries(upstreamData)) {
+      if (!upstreamStatusMap.value[targetKey]) {
+        upstreamStatusMap.value[targetKey] = {}
+      }
+
+      // Update the status for this specific node
+      upstreamStatusMap.value[targetKey][nodeId] = {
+        online: status.online,
+        latency: status.latency,
+      }
+    }
+  }
+
+  // Get multi-node status for a target
+  function getMultiNodeStatus(target: ProxyTarget): MultiNodeUpstreamStatus | undefined {
+    const key = getTargetKey(target)
+    return upstreamStatusMap.value[key]
+  }
+
+  // Get aggregated status for a target (online nodes / total nodes)
+  function getAggregatedStatus(target: ProxyTarget): { online: number, total: number, testType: string } {
+    const multiNodeStatus = getMultiNodeStatus(target)
+    if (!multiNodeStatus) {
+      // Fallback to single-node status
+      const singleStatus = getAvailabilityResult(target)
+      if (singleStatus) {
+        return {
+          online: singleStatus.online ? 1 : 0,
+          total: 1,
+          testType: 'local',
+        }
+      }
+      return { online: 0, total: 0, testType: 'local' }
+    }
+
+    const statuses = Object.values(multiNodeStatus)
+    const onlineCount = statuses.filter(status => status.online).length
+
+    return {
+      online: onlineCount,
+      total: statuses.length,
+      testType: 'multi-node',
+    }
+  }
+
   // Auto-cleanup WebSocket on page unload
   if (typeof window !== 'undefined') {
     window.addEventListener('beforeunload', () => {
@@ -126,7 +263,9 @@ export const useProxyAvailabilityStore = defineStore('proxyAvailability', () =>
 
   return {
     availabilityResults: readonly(availabilityResults),
+    upstreamStatusMap: readonly(upstreamStatusMap),
     isConnected: readonly(isConnected),
+    isNodeAnalyticsConnected: readonly(isNodeAnalyticsConnected),
     isInitialized: readonly(isInitialized),
     lastUpdateTime: readonly(lastUpdateTime),
     targetCount: readonly(targetCount),
@@ -134,9 +273,13 @@ export const useProxyAvailabilityStore = defineStore('proxyAvailability', () =>
     startMonitoring,
     stopMonitoring,
     connectWebSocket,
+    connectNodeAnalyticsWebSocket,
     getAvailabilityResult,
     hasAvailabilityData,
     getAllTargets,
     getTargetKey,
+    updateUpstreamStatusMapFromNode,
+    getMultiNodeStatus,
+    getAggregatedStatus,
   }
 })

+ 8 - 8
app/src/routes/modules/certificates.ts

@@ -20,6 +20,14 @@ export const certificatesRoutes: RouteRecordRaw[] = [
           name: () => $gettext('ACME User'),
         },
       },
+      {
+        path: 'dns_credential',
+        name: 'DNS Credentials',
+        component: () => import('@/views/certificate/DNSCredential.vue'),
+        meta: {
+          name: () => $gettext('DNS Credentials'),
+        },
+      },
       {
         path: 'list',
         name: 'Certificates List',
@@ -48,14 +56,6 @@ export const certificatesRoutes: RouteRecordRaw[] = [
           lastRouteName: 'Certificates List',
         },
       },
-      {
-        path: 'dns_credential',
-        name: 'DNS Credentials',
-        component: () => import('@/views/certificate/DNSCredential.vue'),
-        meta: {
-          name: () => $gettext('DNS Credentials'),
-        },
-      },
     ],
   },
 ]

+ 1 - 19
app/src/views/environments/group/EnvGroup.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { UpdateOrderRequest } from '@/api/curd'
 import { StdCurd } from '@uozi-admin/curd'
-import env_group, { PostSyncAction } from '@/api/env_group'
+import env_group from '@/api/env_group'
 import NodeSelector from '@/components/NodeSelector'
 import columns from '@/views/environments/group/columns'
 
@@ -34,24 +34,6 @@ async function handleDragEnd(data: UpdateOrderRequest) {
         v-model:target="record.sync_node_ids"
         hidden-local
       />
-
-      <AForm class="mt-4" layout="vertical">
-        <AFormItem :label="$gettext('Post-sync Action')">
-          <ASelect
-            v-model:value="record.post_sync_action"
-            :placeholder="$gettext('Select an action after sync')"
-            :default-value="PostSyncAction.ReloadNginx"
-            class="w-full"
-          >
-            <ASelectOption :value="PostSyncAction.None">
-              {{ $gettext('No Action') }}
-            </ASelectOption>
-            <ASelectOption :value="PostSyncAction.ReloadNginx">
-              {{ $gettext('Reload Nginx') }}
-            </ASelectOption>
-          </ASelect>
-        </AFormItem>
-      </AForm>
     </template>
   </StdCurd>
 </template>

+ 23 - 10
app/src/views/environments/group/columns.ts

@@ -1,6 +1,7 @@
 import type { StdTableColumn } from '@uozi-admin/curd'
-import { datetimeRender } from '@uozi-admin/curd'
-import { PostSyncAction } from '@/api/env_group'
+import { datetimeRender, maskRender } from '@uozi-admin/curd'
+import { PostSyncAction, UpstreamTestType } from '@/api/env_group'
+import { PostSyncActionMask, UpstreamTestTypeMask } from '@/constants'
 import { useNodeAvailabilityStore } from '@/pinia/moudule/nodeAvailability'
 
 const columns: StdTableColumn[] = [{
@@ -44,14 +45,26 @@ const columns: StdTableColumn[] = [{
 }, {
   title: () => $gettext('Post-sync Action'),
   dataIndex: 'post_sync_action',
-  customRender: ({ text }) => {
-    if (!text || text === PostSyncAction.None) {
-      return $gettext('No Action')
-    }
-    else if (text === PostSyncAction.ReloadNginx) {
-      return $gettext('Reload Nginx')
-    }
-    return text
+  customRender: maskRender(PostSyncActionMask),
+  edit: {
+    type: 'select',
+    select: {
+      mask: PostSyncActionMask,
+      defaultValue: PostSyncAction.ReloadNginx,
+    },
+  },
+  pure: true,
+  width: 150,
+}, {
+  title: () => $gettext('Upstream Test Type'),
+  dataIndex: 'upstream_test_type',
+  customRender: maskRender(UpstreamTestTypeMask),
+  edit: {
+    type: 'select',
+    select: {
+      mask: UpstreamTestTypeMask,
+      defaultValue: UpstreamTestType.Local,
+    },
   },
   pure: true,
   width: 150,

+ 1 - 0
app/src/views/site/site_list/columns.tsx

@@ -81,6 +81,7 @@ const columns: StdTableColumn[] = [{
   customRender: ({ record }: CustomRenderArgs) => {
     if (record.proxy_targets && record.proxy_targets.length > 0) {
       return h(ProxyTargets, {
+        envGroupId: record.env_group_id,
         targets: record.proxy_targets,
       })
     }

+ 9 - 7
internal/analytic/node.go

@@ -10,6 +10,7 @@ import (
 	"time"
 
 	"github.com/0xJacky/Nginx-UI/internal/transport"
+	"github.com/0xJacky/Nginx-UI/internal/upstream"
 	"github.com/0xJacky/Nginx-UI/internal/version"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/shirou/gopsutil/v4/load"
@@ -26,13 +27,14 @@ type NodeInfo struct {
 }
 
 type NodeStat struct {
-	AvgLoad       *load.AvgStat      `json:"avg_load"`
-	CPUPercent    float64            `json:"cpu_percent"`
-	MemoryPercent float64            `json:"memory_percent"`
-	DiskPercent   float64            `json:"disk_percent"`
-	Network       net.IOCountersStat `json:"network"`
-	Status        bool               `json:"status"`
-	ResponseAt    time.Time          `json:"response_at"`
+	AvgLoad           *load.AvgStat                        `json:"avg_load"`
+	CPUPercent        float64                              `json:"cpu_percent"`
+	MemoryPercent     float64                              `json:"memory_percent"`
+	DiskPercent       float64                              `json:"disk_percent"`
+	Network           net.IOCountersStat                   `json:"network"`
+	Status            bool                                 `json:"status"`
+	ResponseAt        time.Time                            `json:"response_at"`
+	UpstreamStatusMap map[string]*upstream.Status `json:"upstream_status_map"`
 }
 
 type Node struct {

+ 2 - 8
internal/analytic/node_record.go

@@ -681,26 +681,20 @@ func nodeAnalyticRecord(env *model.Environment, ctx context.Context) error {
 						env.ID, oldVersion, fullNode.Version)
 				}
 
-				// This is a complete Node with version info - update everything
+				// Update complete Node with version info
 				NodeMap[env.ID].NodeInfo = fullNode.NodeInfo
 				NodeMap[env.ID].NodeStat = fullNode.NodeStat
 				// Ensure status and response time are set
 				NodeMap[env.ID].NodeStat.Status = true
 				NodeMap[env.ID].NodeStat.ResponseAt = time.Now()
-
-				logger.Debugf("nodeAnalyticRecord: Updated complete Node info for environment ID: %d, Version: %s, Status: %t",
-					env.ID, fullNode.Version, NodeMap[env.ID].NodeStat.Status)
 			} else {
 				// Fall back to NodeStat only
 				var nodeStat NodeStat
 				if err := json.Unmarshal(rawMsg, &nodeStat); err == nil {
-					// set online
+					// Set node online status
 					nodeStat.Status = true
 					nodeStat.ResponseAt = time.Now()
-
 					NodeMap[env.ID].NodeStat = nodeStat
-					logger.Debugf("nodeAnalyticRecord: Updated NodeStat for environment ID: %d, Status: %t",
-						env.ID, nodeStat.Status)
 				} else {
 					logger.Debugf("nodeAnalyticRecord: Failed to unmarshal message for environment ID: %d, error: %v", env.ID, err)
 				}

+ 17 - 5
internal/analytic/node_stat.go

@@ -5,6 +5,7 @@ import (
 	"runtime"
 	"time"
 
+	"github.com/0xJacky/Nginx-UI/internal/upstream"
 	"github.com/shirou/gopsutil/v4/cpu"
 	"github.com/shirou/gopsutil/v4/load"
 	"github.com/uozi-tech/cosy/logger"
@@ -43,11 +44,22 @@ func GetNodeStat() (data NodeStat) {
 		return
 	}
 
+	// Get upstream status for current node
+	upstreamService := upstream.GetUpstreamService()
+	
+	// Ensure upstream availability test is performed if targets exist
+	if upstreamService.GetTargetCount() > 0 {
+		upstreamService.PerformAvailabilityTest()
+	}
+	
+	upstreamStatusMap := upstreamService.GetAvailabilityMap()
+
 	return NodeStat{
-		AvgLoad:       loadAvg,
-		CPUPercent:    math.Min((cpuUserUsage+cpuSystemUsage)*100, 100),
-		MemoryPercent: memory.Pressure,
-		DiskPercent:   diskStat.Percentage,
-		Network:       *network,
+		AvgLoad:           loadAvg,
+		CPUPercent:        math.Min((cpuUserUsage+cpuSystemUsage)*100, 100),
+		MemoryPercent:     memory.Pressure,
+		DiskPercent:       diskStat.Percentage,
+		Network:           *network,
+		UpstreamStatusMap: upstreamStatusMap,
 	}
 }

+ 15 - 4
model/env_group.go

@@ -8,11 +8,22 @@ const (
 	PostSyncActionReloadNginx = "reload_nginx"
 )
 
+// UpstreamTestType defines the type of upstream test
+const (
+	// UpstreamTestLocal indicates local upstream test
+	UpstreamTestLocal = "local"
+	// UpstreamTestRemote indicates remote upstream test
+	UpstreamTestRemote = "remote"
+	// UpstreamTestMirror indicates mirror upstream test
+	UpstreamTestMirror = "mirror"
+)
+
 // EnvGroup represents a group of environments that can be synced across nodes
 type EnvGroup struct {
 	Model
-	Name           string   `json:"name"`
-	SyncNodeIds    []uint64 `json:"sync_node_ids" gorm:"serializer:json"`
-	OrderID        int      `json:"-" gorm:"default:0"`
-	PostSyncAction string   `json:"post_sync_action" gorm:"default:'reload_nginx'"`
+	Name             string   `json:"name"`
+	SyncNodeIds      []uint64 `json:"sync_node_ids" gorm:"serializer:json"`
+	OrderID          int      `json:"-" gorm:"default:0"`
+	PostSyncAction   string   `json:"post_sync_action" gorm:"default:'reload_nginx'"`
+	UpstreamTestType string   `json:"upstream_test_type" gorm:"default:'local'"`
 }