Răsfoiți Sursa

refactor: rename env to node, env group to namespace

0xJacky 7 luni în urmă
părinte
comite
261c76686e
100 a modificat fișierele cu 3823 adăugiri și 3143 ștergeri
  1. 52 0
      api/analytic/analytic.go
  2. 1 0
      api/analytic/router.go
  3. 0 101
      api/cluster/environment.go
  4. 58 58
      api/cluster/namespace.go
  5. 8 8
      api/cluster/nginx.go
  6. 79 23
      api/cluster/node.go
  7. 18 20
      api/cluster/router.go
  8. 25 25
      api/cluster/websocket.go
  9. 20 20
      api/config/list.go
  10. 4 4
      api/sites/list.go
  11. 2 2
      api/sites/site.go
  12. 15 15
      api/streams/streams.go
  13. 3 2
      app/components.d.ts
  14. 3 3
      app/package.json
  15. 208 192
      app/pnpm-lock.yaml
  16. 0 24
      app/src/api/environment.ts
  17. 5 5
      app/src/api/namespace.ts
  18. 26 5
      app/src/api/node.ts
  19. 3 3
      app/src/api/site.ts
  20. 3 3
      app/src/api/stream.ts
  21. 0 1
      app/src/components/EnvGroupRender/index.ts
  22. 0 3
      app/src/components/EnvGroupTabs/index.ts
  23. 0 3
      app/src/components/EnvIndicator/index.ts
  24. 10 10
      app/src/components/NamespaceRender/NamespaceRender.vue
  25. 1 0
      app/src/components/NamespaceRender/index.ts
  26. 10 10
      app/src/components/NamespaceTabs/NamespaceTabs.vue
  27. 3 0
      app/src/components/NamespaceTabs/index.ts
  28. 11 11
      app/src/components/NodeIndicator/NodeIndicator.vue
  29. 1 0
      app/src/components/NodeIndicator/index.ts
  30. 4 4
      app/src/components/ProxyTargets/ProxyTargets.vue
  31. 17 17
      app/src/components/SyncNodesPreview/SyncNodesPreview.vue
  32. 4 4
      app/src/components/UpstreamCards/UpstreamCards.vue
  33. 3 3
      app/src/components/UpstreamDetailModal/UpstreamDetailModal.vue
  34. 2 2
      app/src/composables/useSSE.ts
  35. 10 10
      app/src/composables/useUpstreamStatus.ts
  36. 169 142
      app/src/language/ar/app.po
  37. 8 1
      app/src/language/curd.ts
  38. 169 142
      app/src/language/de_DE/app.po
  39. 159 138
      app/src/language/en/app.po
  40. 170 143
      app/src/language/es/app.po
  41. 169 142
      app/src/language/fr_FR/app.po
  42. 169 142
      app/src/language/ja_JP/app.po
  43. 169 142
      app/src/language/ko_KR/app.po
  44. 174 127
      app/src/language/messages.pot
  45. 169 142
      app/src/language/pt_PT/app.po
  46. 171 143
      app/src/language/ru_RU/app.po
  47. 170 143
      app/src/language/tr_TR/app.po
  48. 169 142
      app/src/language/uk_UA/app.po
  49. 170 143
      app/src/language/vi_VN/app.po
  50. 169 142
      app/src/language/zh_CN/app.po
  51. 169 142
      app/src/language/zh_TW/app.po
  52. 2 2
      app/src/layouts/SideBar.vue
  53. 2 2
      app/src/lib/http/interceptors.ts
  54. 1 1
      app/src/lib/websocket/index.ts
  55. 61 26
      app/src/pinia/moudule/nodeAvailability.ts
  56. 12 12
      app/src/pinia/moudule/nodeGroupStore.ts
  57. 5 5
      app/src/pinia/moudule/settings.ts
  58. 4 2
      app/src/routes/index.ts
  59. 0 38
      app/src/routes/modules/environments.ts
  60. 14 0
      app/src/routes/modules/namespaces.ts
  61. 20 0
      app/src/routes/modules/nodes.ts
  62. 1 1
      app/src/version.json
  63. 5 5
      app/src/views/dashboard/Nodes.vue
  64. 2 2
      app/src/views/dashboard/ServerDashBoard.vue
  65. 1 3
      app/src/views/dashboard/components/NodeAnalyticItem.vue
  66. 5 5
      app/src/views/namespace/Namespace.vue
  67. 1 1
      app/src/views/namespace/columns.ts
  68. 3 3
      app/src/views/node/BatchUpgrader.vue
  69. 7 8
      app/src/views/node/Node.vue
  70. 0 0
      app/src/views/node/nodeColumns.tsx
  71. 4 0
      app/src/views/preference/Preference.vue
  72. 84 87
      app/src/views/preference/tabs/AuthSettings.vue
  73. 8 8
      app/src/views/site/site_edit/components/RightPanel/Basic.vue
  74. 1 1
      app/src/views/site/site_edit/components/SiteEditor/SiteEditor.vue
  75. 1 1
      app/src/views/site/site_edit/components/SiteEditor/store.ts
  76. 9 9
      app/src/views/site/site_list/SiteList.vue
  77. 10 10
      app/src/views/site/site_list/columns.tsx
  78. 9 9
      app/src/views/stream/StreamList.vue
  79. 9 9
      app/src/views/stream/columns.tsx
  80. 8 8
      app/src/views/stream/components/RightPanel/Basic.vue
  81. 1 1
      app/src/views/stream/components/StreamEditor.vue
  82. 1 1
      app/src/views/stream/store.ts
  83. 13 13
      internal/analytic/node.go
  84. 71 71
      internal/analytic/node_record.go
  85. 11 11
      internal/cert/sync.go
  86. 0 0
      internal/cluster/.db
  87. 3 3
      internal/cluster/cluster.go
  88. 2 2
      internal/config/config.go
  89. 2 2
      internal/config/config_list.go
  90. 18 18
      internal/config/generic_list.go
  91. 33 33
      internal/config/sync.go
  92. 4 4
      internal/middleware/proxy.go
  93. 4 4
      internal/middleware/proxy_ws.go
  94. 6 6
      internal/migrate/1.site_category_to_env_group.go
  95. 91 0
      internal/migrate/5.rename_env_groups_to_namespaces.go
  96. 109 0
      internal/migrate/6.rename_environments_to_nodes.go
  97. 3 1
      internal/migrate/migrate.go
  98. 3 1
      internal/self_check/test_cases/no-http-sites-enabled-fixed.conf
  99. 5 5
      internal/site/list.go
  100. 2 2
      internal/site/maintenance.go

+ 52 - 0
api/analytic/analytic.go

@@ -9,6 +9,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
 	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/kernel"
+	"github.com/0xJacky/Nginx-UI/internal/version"
 	"github.com/shirou/gopsutil/v4/cpu"
 	"github.com/shirou/gopsutil/v4/host"
 	"github.com/shirou/gopsutil/v4/load"
@@ -162,3 +163,54 @@ func GetAnalyticInit(c *gin.Context) {
 		LoadAvg: loadAvg,
 	})
 }
+
+func GetNode(c *gin.Context) {
+	cpuInfo, err := cpu.Info()
+	if err != nil {
+		logger.Error(err)
+	}
+
+	memory, err := analytic.GetMemoryStat()
+	if err != nil {
+		logger.Error(err)
+	}
+
+	diskStat, err := analytic.GetDiskStat()
+	if err != nil {
+		logger.Error(err)
+	}
+
+	hostInfo, err := host.Info()
+	if err != nil {
+		logger.Error(err)
+		hostInfo = &host.InfoStat{}
+	}
+
+	switch hostInfo.Platform {
+	case "ubuntu":
+		hostInfo.Platform = "Ubuntu"
+	case "centos":
+		hostInfo.Platform = "CentOS"
+	}
+
+	runtimeInfo, err := version.GetRuntimeInfo()
+	if err != nil {
+		logger.Error("Failed to get runtime info:", err)
+		runtimeInfo = version.RuntimeInfo{
+			OS:   fmt.Sprintf("%s %s", hostInfo.Platform, hostInfo.PlatformVersion),
+			Arch: runtime.GOARCH,
+		}
+	}
+
+	ver := version.GetVersionInfo()
+
+	nodeInfo := analytic.NodeInfo{
+		NodeRuntimeInfo: runtimeInfo,
+		Version:         ver.Version,
+		CPUNum:          len(cpuInfo),
+		MemoryTotal:     memory.Total,
+		DiskTotal:       diskStat.Total,
+	}
+
+	c.JSON(http.StatusOK, nodeInfo)
+}

+ 1 - 0
api/analytic/router.go

@@ -12,4 +12,5 @@ func InitWebSocketRouter(r *gin.RouterGroup) {
 
 func InitRouter(r *gin.RouterGroup) {
 	r.GET("analytic/init", GetAnalyticInit)
+	r.GET("node", GetNode)
 }

+ 0 - 101
api/cluster/environment.go

@@ -1,101 +0,0 @@
-package cluster
-
-import (
-	"context"
-	"net/http"
-
-	"github.com/0xJacky/Nginx-UI/internal/analytic"
-	"github.com/0xJacky/Nginx-UI/internal/cluster"
-	"github.com/0xJacky/Nginx-UI/model"
-	"github.com/0xJacky/Nginx-UI/query"
-	"github.com/0xJacky/Nginx-UI/settings"
-	"github.com/gin-gonic/gin"
-	"github.com/spf13/cast"
-	"github.com/uozi-tech/cosy"
-	"gorm.io/gorm"
-)
-
-func GetEnvironment(c *gin.Context) {
-	id := cast.ToUint64(c.Param("id"))
-
-	envQuery := query.Environment
-
-	env, err := envQuery.FirstByID(id)
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
-
-	c.JSON(http.StatusOK, analytic.GetNode(env))
-}
-
-func GetEnvironmentList(c *gin.Context) {
-	core := cosy.Core[model.Environment](c).
-		SetFussy("name")
-
-	// fix for sqlite
-	if c.Query("enabled") != "" {
-		core.GormScope(func(tx *gorm.DB) *gorm.DB {
-			return tx.Where("enabled = ?", cast.ToInt(cast.ToBool(c.Query("enabled"))))
-		})
-	}
-
-	core.SetTransformer(func(m *model.Environment) any {
-		return analytic.GetNode(m)
-	})
-
-	data, ok := core.ListAllData()
-	if !ok {
-		return
-	}
-
-	c.JSON(http.StatusOK, model.DataList{
-		Data: data,
-	})
-}
-
-func AddEnvironment(c *gin.Context) {
-	cosy.Core[model.Environment](c).SetValidRules(gin.H{
-		"name":    "required",
-		"url":     "required,url",
-		"token":   "required",
-		"enabled": "omitempty,boolean",
-	}).ExecutedHook(func(c *cosy.Ctx[model.Environment]) {
-		go analytic.RestartRetrieveNodesStatus()
-	}).Create()
-}
-
-func EditEnvironment(c *gin.Context) {
-	cosy.Core[model.Environment](c).SetValidRules(gin.H{
-		"name":    "required",
-		"url":     "required,url",
-		"token":   "required",
-		"enabled": "omitempty,boolean",
-	}).ExecutedHook(func(c *cosy.Ctx[model.Environment]) {
-		go analytic.RestartRetrieveNodesStatus()
-	}).Modify()
-}
-
-func DeleteEnvironment(c *gin.Context) {
-	cosy.Core[model.Environment](c).
-		ExecutedHook(func(c *cosy.Ctx[model.Environment]) {
-			go analytic.RestartRetrieveNodesStatus()
-		}).Destroy()
-}
-
-func LoadEnvironmentFromSettings(c *gin.Context) {
-	err := settings.ReloadCluster()
-	if err != nil {
-		cosy.ErrHandler(c, err)
-		return
-	}
-
-	ctx := context.Background()
-	cluster.RegisterPredefinedNodes(ctx)
-
-	go analytic.RestartRetrieveNodesStatus()
-
-	c.JSON(http.StatusOK, gin.H{
-		"message": "ok",
-	})
-}

+ 58 - 58
api/cluster/group.go → api/cluster/namespace.go

@@ -10,71 +10,105 @@ import (
 	"gorm.io/gorm"
 )
 
-type APIRespEnvGroup struct {
-	model.EnvGroup
-	SyncNodes []*model.Environment `json:"sync_nodes,omitempty" gorm:"-"`
+type APIRespNamespace struct {
+	model.Namespace
+	SyncNodes []*model.Node `json:"sync_nodes,omitempty" gorm:"-"`
 }
 
-func GetGroup(c *gin.Context) {
-	cosy.Core[model.EnvGroup](c).
-		SetTransformer(func(m *model.EnvGroup) any {
+func GetNamespace(c *gin.Context) {
+	cosy.Core[model.Namespace](c).
+		SetTransformer(func(m *model.Namespace) any {
 			db := cosy.UseDB(c)
 
-			var nodes []*model.Environment
+			var nodes []*model.Node
 			if len(m.SyncNodeIds) > 0 {
-				db.Model(&model.Environment{}).
+				db.Model(&model.Node{}).
 					Where("id IN (?)", m.SyncNodeIds).
 					Find(&nodes)
 			}
 
-			return &APIRespEnvGroup{
-				EnvGroup:  *m,
+			return &APIRespNamespace{
+				Namespace: *m,
 				SyncNodes: nodes,
 			}
 		}).
 		Get()
 }
 
-func GetGroupList(c *gin.Context) {
-	cosy.Core[model.EnvGroup](c).GormScope(func(tx *gorm.DB) *gorm.DB {
+func GetNamespaceList(c *gin.Context) {
+	cosy.Core[model.Namespace](c).GormScope(func(tx *gorm.DB) *gorm.DB {
 		return tx.Order("order_id ASC")
 	}).
 		SetScan(func(tx *gorm.DB) any {
-			var groups []*APIRespEnvGroup
+			var namespaces []*APIRespNamespace
 
 			var nodeIDs []uint64
-			tx.Find(&groups)
+			tx.Find(&namespaces)
 
-			for _, group := range groups {
-				nodeIDs = append(nodeIDs, group.SyncNodeIds...)
+			for _, namespace := range namespaces {
+				nodeIDs = append(nodeIDs, namespace.SyncNodeIds...)
 			}
 
-			var nodes []*model.Environment
+			var nodes []*model.Node
 			nodeIDs = lo.Uniq(nodeIDs)
 			if len(nodeIDs) > 0 {
 				db := cosy.UseDB(c)
-				db.Model(&model.Environment{}).
+				db.Model(&model.Node{}).
 					Where("id IN (?)", nodeIDs).
 					Find(&nodes)
 			}
 
-			nodeMap := lo.SliceToMap(nodes, func(node *model.Environment) (uint64, *model.Environment) {
+			nodeMap := lo.SliceToMap(nodes, func(node *model.Node) (uint64, *model.Node) {
 				return node.ID, node
 			})
 
-			for _, group := range groups {
-				for _, nodeID := range group.SyncNodeIds {
+			for _, namespace := range namespaces {
+				for _, nodeID := range namespace.SyncNodeIds {
 					if node, ok := nodeMap[nodeID]; ok {
-						group.SyncNodes = append(group.SyncNodes, node)
+						namespace.SyncNodes = append(namespace.SyncNodes, node)
 					}
 				}
 			}
 
-			return groups
+			return namespaces
 		}).
 		PagingList()
 }
 
+func AddNamespace(c *gin.Context) {
+	cosy.Core[model.Namespace](c).
+		SetValidRules(gin.H{
+			"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()
+}
+
+func ModifyNamespace(c *gin.Context) {
+	cosy.Core[model.Namespace](c).
+		SetValidRules(gin.H{
+			"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()
+}
+
+func DeleteNamespace(c *gin.Context) {
+	cosy.Core[model.Namespace](c).Destroy()
+}
+
+func RecoverNamespace(c *gin.Context) {
+	cosy.Core[model.Namespace](c).Recover()
+}
+
+func UpdateNamespacesOrder(c *gin.Context) {
+	cosy.Core[model.Namespace](c).UpdateOrder()
+}
+
 func ReloadNginx(c *gin.Context) {
 	var json struct {
 		NodeIDs []uint64 `json:"node_ids" binding:"required"`
@@ -105,38 +139,4 @@ func RestartNginx(c *gin.Context) {
 	c.JSON(http.StatusOK, gin.H{
 		"message": "ok",
 	})
-}
-
-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,
-			"upstream_test_type": "omitempty,oneof=" + model.UpstreamTestLocal + " " + model.UpstreamTestRemote + " " + model.UpstreamTestMirror,
-		}).
-		Create()
-}
-
-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,
-			"upstream_test_type": "omitempty,oneof=" + model.UpstreamTestLocal + " " + model.UpstreamTestRemote + " " + model.UpstreamTestMirror,
-		}).
-		Modify()
-}
-
-func DeleteGroup(c *gin.Context) {
-	cosy.Core[model.EnvGroup](c).Destroy()
-}
-
-func RecoverGroup(c *gin.Context) {
-	cosy.Core[model.EnvGroup](c).Recover()
-}
-
-func UpdateGroupsOrder(c *gin.Context) {
-	cosy.Core[model.EnvGroup](c).UpdateOrder()
-}
+}

+ 8 - 8
api/cluster/nginx.go

@@ -23,10 +23,10 @@ func syncReload(nodeIDs []uint64) {
 		return
 	}
 
-	e := query.Environment
-	nodes, err := e.Where(e.ID.In(nodeIDs...)).Find()
+	n := query.Node
+	nodes, err := n.Where(n.ID.In(nodeIDs...)).Find()
 	if err != nil {
-		logger.Error("Failed to get environment nodes:", err)
+		logger.Error("Failed to get nodes:", err)
 		return
 	}
 
@@ -34,7 +34,7 @@ func syncReload(nodeIDs []uint64) {
 	wg.Add(len(nodes))
 
 	for _, node := range nodes {
-		go func(node *model.Environment) {
+		go func(node *model.Node) {
 			defer func() {
 				if err := recover(); err != nil {
 					buf := make([]byte, 1024)
@@ -77,10 +77,10 @@ func syncRestart(nodeIDs []uint64) {
 		return
 	}
 
-	e := query.Environment
-	nodes, err := e.Where(e.ID.In(nodeIDs...)).Find()
+	n := query.Node
+	nodes, err := n.Where(n.ID.In(nodeIDs...)).Find()
 	if err != nil {
-		logger.Error("Failed to get environment nodes:", err)
+		logger.Error("Failed to get nodes:", err)
 		return
 	}
 
@@ -88,7 +88,7 @@ func syncRestart(nodeIDs []uint64) {
 	wg.Add(len(nodes))
 
 	for _, node := range nodes {
-		go func(node *model.Environment) {
+		go func(node *model.Node) {
 			defer func() {
 				if err := recover(); err != nil {
 					buf := make([]byte, 1024)

+ 79 - 23
api/cluster/node.go

@@ -1,45 +1,101 @@
 package cluster
 
 import (
+	"context"
 	"net/http"
 
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
-	"github.com/0xJacky/Nginx-UI/internal/version"
+	"github.com/0xJacky/Nginx-UI/internal/cluster"
+	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/query"
+	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
-	"github.com/shirou/gopsutil/v4/cpu"
+	"github.com/spf13/cast"
 	"github.com/uozi-tech/cosy"
+	"gorm.io/gorm"
 )
 
-func GetCurrentNode(c *gin.Context) {
-	if _, ok := c.Get("Secret"); !ok {
-		c.JSON(http.StatusNotAcceptable, gin.H{
-			"message": "node secret not exist",
+func GetNode(c *gin.Context) {
+	id := cast.ToUint64(c.Param("id"))
+
+	nodeQuery := query.Node
+
+	node, err := nodeQuery.FirstByID(id)
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
+
+	c.JSON(http.StatusOK, analytic.GetNode(node))
+}
+
+func GetNodeList(c *gin.Context) {
+	core := cosy.Core[model.Node](c).
+		SetFussy("name")
+
+	// fix for sqlite
+	if c.Query("enabled") != "" {
+		core.GormScope(func(tx *gorm.DB) *gorm.DB {
+			return tx.Where("enabled = ?", cast.ToInt(cast.ToBool(c.Query("enabled"))))
 		})
+	}
+
+	core.SetTransformer(func(m *model.Node) any {
+		return analytic.GetNode(m)
+	})
+
+	data, ok := core.ListAllData()
+	if !ok {
 		return
 	}
 
-	runtimeInfo, err := version.GetRuntimeInfo()
+	c.JSON(http.StatusOK, model.DataList{
+		Data: data,
+	})
+}
+
+func AddNode(c *gin.Context) {
+	cosy.Core[model.Node](c).SetValidRules(gin.H{
+		"name":    "required",
+		"url":     "required,url",
+		"token":   "required",
+		"enabled": "omitempty,boolean",
+	}).ExecutedHook(func(c *cosy.Ctx[model.Node]) {
+		go analytic.RestartRetrieveNodesStatus()
+	}).Create()
+}
+
+func EditNode(c *gin.Context) {
+	cosy.Core[model.Node](c).SetValidRules(gin.H{
+		"name":    "required",
+		"url":     "required,url",
+		"token":   "required",
+		"enabled": "omitempty,boolean",
+	}).ExecutedHook(func(c *cosy.Ctx[model.Node]) {
+		go analytic.RestartRetrieveNodesStatus()
+	}).Modify()
+}
+
+func DeleteNode(c *gin.Context) {
+	cosy.Core[model.Node](c).
+		ExecutedHook(func(c *cosy.Ctx[model.Node]) {
+			go analytic.RestartRetrieveNodesStatus()
+		}).Destroy()
+}
+
+func LoadNodeFromSettings(c *gin.Context) {
+	err := settings.ReloadCluster()
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return
 	}
-	cpuInfo, _ := cpu.Info()
-	memory, _ := analytic.GetMemoryStat()
-	ver := version.GetVersionInfo()
-	diskUsage, _ := analytic.GetDiskStat()
-
-	nodeInfo := analytic.NodeInfo{
-		NodeRuntimeInfo: runtimeInfo,
-		CPUNum:          len(cpuInfo),
-		MemoryTotal:     memory.Total,
-		DiskTotal:       diskUsage.Total,
-		Version:         ver.Version,
-	}
 
-	stat := analytic.GetNodeStat()
+	ctx := context.Background()
+	cluster.RegisterPredefinedNodes(ctx)
+
+	go analytic.RestartRetrieveNodesStatus()
 
-	c.JSON(http.StatusOK, analytic.Node{
-		NodeInfo: nodeInfo,
-		NodeStat: stat,
+	c.JSON(http.StatusOK, gin.H{
+		"message": "ok",
 	})
 }

+ 18 - 20
api/cluster/router.go

@@ -3,31 +3,29 @@ package cluster
 import "github.com/gin-gonic/gin"
 
 func InitRouter(r *gin.RouterGroup) {
-	// Environment
-	r.GET("environments", GetEnvironmentList)
-	r.POST("environments/load_from_settings", LoadEnvironmentFromSettings)
-	envGroup := r.Group("environments")
+	// Node
+	r.GET("nodes", GetNodeList)
+	r.POST("nodes/load_from_settings", LoadNodeFromSettings)
+	nodeGroup := r.Group("nodes")
 	{
-		envGroup.GET("/:id", GetEnvironment)
-		envGroup.POST("", AddEnvironment)
-		envGroup.POST("/:id", EditEnvironment)
-		envGroup.DELETE("/:id", DeleteEnvironment)
+		nodeGroup.GET("/:id", GetNode)
+		nodeGroup.POST("", AddNode)
+		nodeGroup.POST("/:id", EditNode)
+		nodeGroup.DELETE("/:id", DeleteNode)
 	}
-	// Node
-	r.GET("node", GetCurrentNode)
 
-	r.POST("environments/reload_nginx", ReloadNginx)
-	r.POST("environments/restart_nginx", RestartNginx)
+	r.POST("nodes/reload_nginx", ReloadNginx)
+	r.POST("nodes/restart_nginx", RestartNginx)
 
-	r.GET("env_groups", GetGroupList)
-	r.GET("env_groups/:id", GetGroup)
-	r.POST("env_groups", AddGroup)
-	r.POST("env_groups/:id", ModifyGroup)
-	r.DELETE("env_groups/:id", DeleteGroup)
-	r.POST("env_groups/:id/recover", RecoverGroup)
-	r.POST("env_groups/order", UpdateGroupsOrder)
+	r.GET("namespaces", GetNamespaceList)
+	r.GET("namespaces/:id", GetNamespace)
+	r.POST("namespaces", AddNamespace)
+	r.POST("namespaces/:id", ModifyNamespace)
+	r.DELETE("namespaces/:id", DeleteNamespace)
+	r.POST("namespaces/:id/recover", RecoverNamespace)
+	r.POST("namespaces/order", UpdateNamespacesOrder)
 }
 
 func InitWebSocketRouter(r *gin.RouterGroup) {
-	r.GET("environments/enabled", GetAllEnabledEnvironmentWS)
+	r.GET("nodes/enabled", GetAllEnabledNodeWS)
 }

+ 25 - 25
api/cluster/websocket.go

@@ -24,7 +24,7 @@ type WebSocketMessage struct {
 	Data  interface{} `json:"data"`
 }
 
-// Client represents a WebSocket client connection for cluster environment monitoring
+// Client represents a WebSocket client connection for cluster node monitoring
 type Client struct {
 	conn   *websocket.Conn
 	send   chan WebSocketMessage
@@ -68,7 +68,7 @@ func (h *Hub) run() {
 			h.mutex.Lock()
 			h.clients[client] = true
 			h.mutex.Unlock()
-			logger.Debug("Cluster environment client connected, total clients:", len(h.clients))
+			logger.Debug("Cluster node client connected, total clients:", len(h.clients))
 
 		case client := <-h.unregister:
 			h.mutex.Lock()
@@ -77,7 +77,7 @@ func (h *Hub) run() {
 				close(client.send)
 			}
 			h.mutex.Unlock()
-			logger.Debug("Cluster environment client disconnected, total clients:", len(h.clients))
+			logger.Debug("Cluster node client disconnected, total clients:", len(h.clients))
 
 		case message := <-h.broadcast:
 			h.mutex.RLock()
@@ -123,7 +123,7 @@ func (h *Hub) BroadcastMessage(event string, data any) {
 	select {
 	case h.broadcast <- message:
 	default:
-		logger.Warn("Cluster environment broadcast channel full, message dropped")
+		logger.Warn("Cluster node broadcast channel full, message dropped")
 	}
 }
 
@@ -136,13 +136,13 @@ var upgrader = websocket.Upgrader{
 	WriteBufferSize: 1024,
 }
 
-type respEnvironment struct {
-	*model.Environment
+type respNode struct {
+	*model.Node
 	Status bool `json:"status"`
 }
 
-// GetAllEnabledEnvironmentWS handles WebSocket connections for real-time environment monitoring
-func GetAllEnabledEnvironmentWS(c *gin.Context) {
+// GetAllEnabledNodeWS handles WebSocket connections for real-time node monitoring
+func GetAllEnabledNodeWS(c *gin.Context) {
 	ws, err := upgrader.Upgrade(c.Writer, c.Request, nil)
 	if err != nil {
 		logger.Error("Failed to upgrade connection:", err)
@@ -163,34 +163,34 @@ func GetAllEnabledEnvironmentWS(c *gin.Context) {
 	hub := GetHub()
 	hub.register <- client
 
-	// Start goroutines for handling environment monitoring
-	go client.handleEnvironmentMonitoring()
+	// Start goroutines for handling node monitoring
+	go client.handleNodeMonitoring()
 
 	// Start write and read pumps
 	go client.writePump()
 	client.readPump()
 }
 
-// handleEnvironmentMonitoring monitors environment status and sends updates
-func (c *Client) handleEnvironmentMonitoring() {
+// handleNodeMonitoring monitors node status and sends updates
+func (c *Client) handleNodeMonitoring() {
 	interval := 10 * time.Second
 	heartbeatInterval := 30 * time.Second
 
-	getEnvironmentData := func() (interface{}, bool) {
-		// Query environments directly from database
-		var environments []model.Environment
-		err := model.UseDB().Where("enabled = ?", true).Find(&environments).Error
+	getNodeData := func() (interface{}, bool) {
+		// Query nodes directly from database
+		var nodes []model.Node
+		err := model.UseDB().Where("enabled = ?", true).Find(&nodes).Error
 		if err != nil {
-			logger.Error("Failed to query environments:", err)
+			logger.Error("Failed to query nodes:", err)
 			return nil, false
 		}
 
-		// Transform environments to response format
-		var result []respEnvironment
-		for _, env := range environments {
-			result = append(result, respEnvironment{
-				Environment: &env,
-				Status:      analytic.GetNode(&env).Status,
+		// Transform nodes to response format
+		var result []respNode
+		for _, node := range nodes {
+			result = append(result, respNode{
+				Node:   &node,
+				Status: analytic.GetNode(&node).Status,
 			})
 		}
 
@@ -208,7 +208,7 @@ func (c *Client) handleEnvironmentMonitoring() {
 	var dataHash string
 
 	// Send initial data
-	data, ok := getEnvironmentData()
+	data, ok := getNodeData()
 	if ok {
 		dataHash = getHash(data)
 		c.sendMessage("message", data)
@@ -222,7 +222,7 @@ func (c *Client) handleEnvironmentMonitoring() {
 	for {
 		select {
 		case <-ticker.C:
-			data, ok := getEnvironmentData()
+			data, ok := getNodeData()
 			if !ok {
 				return
 			}

+ 20 - 20
api/config/list.go

@@ -18,8 +18,8 @@ import (
 // ConfigFileEntity represents a generic configuration file entity
 type ConfigFileEntity struct {
 	path       string
-	envGroupID uint64
-	envGroup   *model.EnvGroup
+	namespaceID uint64
+	namespace   *model.Namespace
 }
 
 // GetPath implements ConfigEntity interface
@@ -27,21 +27,21 @@ func (c *ConfigFileEntity) GetPath() string {
 	return c.path
 }
 
-// GetEnvGroupID implements ConfigEntity interface
-func (c *ConfigFileEntity) GetEnvGroupID() uint64 {
-	return c.envGroupID
+// GetNamespaceID implements ConfigEntity interface
+func (c *ConfigFileEntity) GetNamespaceID() uint64 {
+	return c.namespaceID
 }
 
-// GetEnvGroup implements ConfigEntity interface
-func (c *ConfigFileEntity) GetEnvGroup() *model.EnvGroup {
-	return c.envGroup
+// GetNamespace implements ConfigEntity interface
+func (c *ConfigFileEntity) GetNamespace() *model.Namespace {
+	return c.namespace
 }
 
 func GetConfigs(c *gin.Context) {
 	search := c.Query("search")
 	sortBy := c.Query("sort_by")
 	order := c.DefaultQuery("order", "desc")
-	envGroupIDStr := c.Query("env_group_id")
+	namespaceIDStr := c.Query("env_group_id")
 
 	// Get directory parameter
 	encodedDir := c.DefaultQuery("dir", "/")
@@ -56,10 +56,10 @@ func GetConfigs(c *gin.Context) {
 	}
 
 	// Parse env_group_id
-	var envGroupID uint64
-	if envGroupIDStr != "" {
-		if id, err := strconv.ParseUint(envGroupIDStr, 10, 64); err == nil {
-			envGroupID = id
+	var namespaceID uint64
+	if namespaceIDStr != "" {
+		if id, err := strconv.ParseUint(namespaceIDStr, 10, 64); err == nil {
+			namespaceID = id
 		}
 	}
 
@@ -68,7 +68,7 @@ func GetConfigs(c *gin.Context) {
 		Search:      search,
 		OrderBy:     sortBy,
 		Sort:        order,
-		EnvGroupID:  envGroupID,
+		NamespaceID:  namespaceID,
 		IncludeDirs: true, // Keep directories for the list.go endpoint
 	}
 
@@ -88,11 +88,11 @@ func GetConfigs(c *gin.Context) {
 		}
 
 		// For generic config files, we don't have database records
-		// so envGroupID and envGroup will be 0 and nil
+		// so namespaceID and namespace will be 0 and nil
 		entity := &ConfigFileEntity{
 			path:       filepath.Join(nginx.GetConfPath(dir), file.Name()),
-			envGroupID: 0,
-			envGroup:   nil,
+			namespaceID: 0,
+			namespace:   nil,
 		}
 		entities = append(entities, entity)
 	}
@@ -122,15 +122,15 @@ func GetConfigs(c *gin.Context) {
 
 // createConfigBuilder creates a custom config builder for generic config files
 func createConfigBuilder(dir string) config.ConfigBuilder {
-	return func(fileName string, fileInfo os.FileInfo, status config.ConfigStatus, envGroupID uint64, envGroup *model.EnvGroup) config.Config {
+	return func(fileName string, fileInfo os.FileInfo, status config.ConfigStatus, namespaceID uint64, namespace *model.Namespace) config.Config {
 		return config.Config{
 			Name:       fileName,
 			ModifiedAt: fileInfo.ModTime(),
 			Size:       fileInfo.Size(),
 			IsDir:      fileInfo.IsDir(),
 			Status:     status,
-			EnvGroupID: envGroupID,
-			EnvGroup:   envGroup,
+			NamespaceID: namespaceID,
+			Namespace:   namespace,
 			Dir:        dir,
 		}
 	}

+ 4 - 4
api/sites/list.go

@@ -18,14 +18,14 @@ func GetSiteList(c *gin.Context) {
 		Status:     c.Query("status"),
 		OrderBy:    c.Query("sort_by"),
 		Sort:       c.DefaultQuery("order", "desc"),
-		EnvGroupID: cast.ToUint64(c.Query("env_group_id")),
+		NamespaceID: cast.ToUint64(c.Query("env_group_id")),
 	}
 
 	// Get sites from database
 	s := query.Site
-	sTx := s.Preload(s.EnvGroup)
-	if options.EnvGroupID != 0 {
-		sTx = sTx.Where(s.EnvGroupID.Eq(options.EnvGroupID))
+	sTx := s.Preload(s.Namespace)
+	if options.NamespaceID != 0 {
+		sTx = sTx.Where(s.NamespaceID.Eq(options.NamespaceID))
 	}
 
 	sites, err := sTx.Find()

+ 2 - 2
api/sites/site.go

@@ -132,7 +132,7 @@ func SaveSite(c *gin.Context) {
 
 	var json struct {
 		Content     string   `json:"content" binding:"required"`
-		EnvGroupID  uint64   `json:"env_group_id"`
+		NamespaceID  uint64   `json:"env_group_id"`
 		SyncNodeIDs []uint64 `json:"sync_node_ids"`
 		Overwrite   bool     `json:"overwrite"`
 		PostAction  string   `json:"post_action"`
@@ -142,7 +142,7 @@ func SaveSite(c *gin.Context) {
 		return
 	}
 
-	err := site.Save(name, json.Content, json.Overwrite, json.EnvGroupID, json.SyncNodeIDs, json.PostAction)
+	err := site.Save(name, json.Content, json.Overwrite, json.NamespaceID, json.SyncNodeIDs, json.PostAction)
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return

+ 15 - 15
api/streams/streams.go

@@ -26,8 +26,8 @@ type Stream struct {
 	Config       string               `json:"config"`
 	Tokenized    *nginx.NgxConfig     `json:"tokenized,omitempty"`
 	Filepath     string               `json:"filepath"`
-	EnvGroupID   uint64               `json:"env_group_id"`
-	EnvGroup     *model.EnvGroup      `json:"env_group,omitempty"`
+	NamespaceID  uint64               `json:"namespace_id"`
+	Namespace    *model.Namespace     `json:"namespace,omitempty"`
 	SyncNodeIDs  []uint64             `json:"sync_node_ids" gorm:"serializer:json"`
 	ProxyTargets []config.ProxyTarget `json:"proxy_targets,omitempty"`
 }
@@ -72,29 +72,29 @@ func GetStreams(c *gin.Context) {
 		Status:     c.Query("status"),
 		OrderBy:    c.Query("order_by"),
 		Sort:       c.DefaultQuery("sort", "desc"),
-		EnvGroupID: cast.ToUint64(c.Query("env_group_id")),
+		NamespaceID: cast.ToUint64(c.Query("namespace_id")),
 	}
 
 	// Get streams from database
 	s := query.Stream
-	eg := query.EnvGroup
+	ns := query.Namespace
 
 	// Get environment groups for association
-	envGroups, err := eg.Find()
+	namespaces, err := ns.Find()
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return
 	}
 
 	// Create environment group map for quick lookup
-	envGroupMap := lo.SliceToMap(envGroups, func(item *model.EnvGroup) (uint64, *model.EnvGroup) {
+	namespaceMap := lo.SliceToMap(namespaces, func(item *model.Namespace) (uint64, *model.Namespace) {
 		return item.ID, item
 	})
 
 	// Get streams with optional filtering
 	var streams []*model.Stream
-	if options.EnvGroupID != 0 {
-		streams, err = s.Where(s.EnvGroupID.Eq(options.EnvGroupID)).Find()
+	if options.NamespaceID != 0 {
+		streams, err = s.Where(s.NamespaceID.Eq(options.NamespaceID)).Find()
 	} else {
 		streams, err = s.Find()
 	}
@@ -105,8 +105,8 @@ func GetStreams(c *gin.Context) {
 
 	// Associate streams with their environment groups
 	for _, stream := range streams {
-		if stream.EnvGroupID > 0 {
-			stream.EnvGroup = envGroupMap[stream.EnvGroupID]
+		if stream.NamespaceID > 0 {
+			stream.Namespace = namespaceMap[stream.NamespaceID]
 		}
 	}
 
@@ -139,8 +139,8 @@ func GetStream(c *gin.Context) {
 		Status:       info.Status,
 		Name:         name,
 		Filepath:     info.Path,
-		EnvGroupID:   info.Model.EnvGroupID,
-		EnvGroup:     info.Model.EnvGroup,
+		NamespaceID:  info.Model.NamespaceID,
+		Namespace:    info.Model.Namespace,
 		SyncNodeIDs:  info.Model.SyncNodeIDs,
 		ProxyTargets: buildStreamProxyTargets(name),
 	}
@@ -160,7 +160,7 @@ func SaveStream(c *gin.Context) {
 
 	var json struct {
 		Content     string   `json:"content" binding:"required"`
-		EnvGroupID  uint64   `json:"env_group_id"`
+		NamespaceID uint64   `json:"namespace_id"`
 		SyncNodeIDs []uint64 `json:"sync_node_ids"`
 		Overwrite   bool     `json:"overwrite"`
 		PostAction  string   `json:"post_action"`
@@ -172,7 +172,7 @@ func SaveStream(c *gin.Context) {
 	}
 
 	// Save stream configuration using internal logic
-	err := stream.SaveStreamConfig(name, json.Content, json.EnvGroupID, json.SyncNodeIDs, json.Overwrite, json.PostAction)
+	err := stream.SaveStreamConfig(name, json.Content, json.NamespaceID, json.SyncNodeIDs, json.Overwrite, json.PostAction)
 	if err != nil {
 		cosy.ErrHandler(c, err)
 		return
@@ -245,7 +245,7 @@ func RenameStream(c *gin.Context) {
 
 func BatchUpdateStreams(c *gin.Context) {
 	cosy.Core[model.Stream](c).SetValidRules(gin.H{
-		"env_group_id": "required",
+		"namespace_id": "required",
 	}).SetItemKey("path").
 		BeforeExecuteHook(func(ctx *cosy.Ctx[model.Stream]) {
 			effectedPath := make([]string, len(ctx.BatchEffectedIDs))

+ 3 - 2
app/components.d.ts

@@ -81,12 +81,12 @@ declare module 'vue' {
     CodeEditorCodeEditor: typeof import('./src/components/CodeEditor/CodeEditor.vue')['default']
     ConfigHistoryConfigHistory: typeof import('./src/components/ConfigHistory/ConfigHistory.vue')['default']
     ConfigHistoryDiffViewer: typeof import('./src/components/ConfigHistory/DiffViewer.vue')['default']
-    EnvGroupRenderEnvGroupRender: typeof import('./src/components/EnvGroupRender/EnvGroupRender.vue')['default']
-    EnvGroupTabsEnvGroupTabs: typeof import('./src/components/EnvGroupTabs/EnvGroupTabs.vue')['default']
     EnvIndicatorEnvIndicator: typeof import('./src/components/EnvIndicator/EnvIndicator.vue')['default']
     FooterToolbarFooterToolBar: typeof import('./src/components/FooterToolbar/FooterToolBar.vue')['default']
     ICPICP: typeof import('./src/components/ICP/ICP.vue')['default']
     LogoLogo: typeof import('./src/components/Logo/Logo.vue')['default']
+    NamespaceRenderNamespaceRender: typeof import('./src/components/NamespaceRender/NamespaceRender.vue')['default']
+    NamespaceTabsNamespaceTabs: typeof import('./src/components/NamespaceTabs/NamespaceTabs.vue')['default']
     NginxControlNginxControl: typeof import('./src/components/NginxControl/NginxControl.vue')['default']
     NgxConfigEditorDirectiveDirectiveAdd: typeof import('./src/components/NgxConfigEditor/directive/DirectiveAdd.vue')['default']
     NgxConfigEditorDirectiveDirectiveDocuments: typeof import('./src/components/NgxConfigEditor/directive/DirectiveDocuments.vue')['default']
@@ -99,6 +99,7 @@ declare module 'vue' {
     NgxConfigEditorNgxServer: typeof import('./src/components/NgxConfigEditor/NgxServer.vue')['default']
     NgxConfigEditorNgxUpstream: typeof import('./src/components/NgxConfigEditor/NgxUpstream.vue')['default']
     NodeCardNodeCard: typeof import('./src/components/NodeCard/NodeCard.vue')['default']
+    NodeIndicatorNodeIndicator: typeof import('./src/components/NodeIndicator/NodeIndicator.vue')['default']
     NodeSelectorNodeSelector: typeof import('./src/components/NodeSelector/NodeSelector.vue')['default']
     NotificationNotification: typeof import('./src/components/Notification/Notification.vue')['default']
     OTPInputOTPInput: typeof import('./src/components/OTPInput/OTPInput.vue')['default']

+ 3 - 3
app/package.json

@@ -18,7 +18,7 @@
     "@fingerprintjs/fingerprintjs": "^4.6.2",
     "@formkit/auto-animate": "^0.8.2",
     "@simplewebauthn/browser": "^13.1.2",
-    "@uozi-admin/curd": "^4.9.6",
+    "@uozi-admin/curd": "^4.10.2",
     "@uozi-admin/request": "^2.8.4",
     "@vue/reactivity": "^3.5.18",
     "@vue/shared": "^3.5.18",
@@ -33,7 +33,7 @@
     "axios": "^1.11.0",
     "dayjs": "^1.11.13",
     "highlight.js": "^11.11.1",
-    "jsencrypt": "^3.3.2",
+    "jsencrypt": "^3.5.3",
     "lodash": "^4.17.21",
     "marked": "^16.1.2",
     "marked-highlight": "^2.2.2",
@@ -83,7 +83,7 @@
     "unplugin-auto-import": "^20.0.0",
     "unplugin-vue-components": "^29.0.0",
     "unplugin-vue-define-options": "^1.5.5",
-    "vite": "^7.1.1",
+    "vite": "^7.1.2",
     "vite-plugin-inspect": "^11.3.2",
     "vite-svg-loader": "^5.1.0",
     "vue-tsc": "^3.0.5"

Fișier diff suprimat deoarece este prea mare
+ 208 - 192
app/pnpm-lock.yaml


+ 0 - 24
app/src/api/environment.ts

@@ -1,24 +0,0 @@
-import type { ModelBase } from '@/api/curd'
-import { extendCurdApi, http, useCurdApi } from '@uozi-admin/request'
-
-export interface Environment extends ModelBase {
-  name: string
-  url: string
-  token: string
-  status?: boolean
-}
-
-export interface Node {
-  id: number
-  name: string
-  token: string
-  response_at?: Date
-}
-
-const baseUrl = '/environments'
-
-const environment = extendCurdApi(useCurdApi<Environment>(baseUrl), {
-  load_from_settings: () => http.post(`${baseUrl}/load_from_settings`),
-})
-
-export default environment

+ 5 - 5
app/src/api/env_group.ts → app/src/api/namespace.ts

@@ -14,19 +14,19 @@ export const UpstreamTestType = {
   Mirror: 'mirror',
 }
 
-export interface EnvGroup extends ModelBase {
+export interface Namespace extends ModelBase {
   name: string
   sync_node_ids: number[]
   post_sync_action?: string
   upstream_test_type?: string
 }
 
-const baseUrl = '/env_groups'
+const baseUrl = '/namespaces'
 
-const env_group = extendCurdApi(useCurdApi<EnvGroup>(baseUrl), {
+const namespace = extendCurdApi(useCurdApi<Namespace>(baseUrl), {
   updateOrder(data: UpdateOrderRequest) {
-    return http.post('/env_groups/order', data)
+    return http.post('/namespaces/order', data)
   },
 })
 
-export default env_group
+export default namespace

+ 26 - 5
app/src/api/node.ts

@@ -1,14 +1,35 @@
-import { http } from '@uozi-admin/request'
+import type { ModelBase } from '@/api/curd'
+import { extendCurdApi, http, useCurdApi } from '@uozi-admin/request'
+
+export interface Node extends ModelBase {
+  name: string
+  url: string
+  token: string
+  status?: boolean
+  response_at?: Date
+}
+
+export interface NodeInfo {
+  id: number
+  name: string
+  token: string
+  response_at?: Date
+}
+
+const baseUrl = '/nodes'
 
 function reloadNginx(nodeIds: number[]) {
-  return http.post('/environments/reload_nginx', { node_ids: nodeIds })
+  return http.post('/nodes/reload_nginx', { node_ids: nodeIds })
 }
 
 function restartNginx(nodeIds: number[]) {
-  return http.post('/environments/restart_nginx', { node_ids: nodeIds })
+  return http.post('/nodes/restart_nginx', { node_ids: nodeIds })
 }
 
-export default {
+const nodeApi = extendCurdApi(useCurdApi<Node>(baseUrl), {
+  load_from_settings: () => http.post(`${baseUrl}/load_from_settings`),
   reloadNginx,
   restartNginx,
-}
+})
+
+export default nodeApi

+ 3 - 3
app/src/api/site.ts

@@ -1,6 +1,6 @@
 import type { CertificateInfo } from '@/api/cert'
 import type { ModelBase } from '@/api/curd'
-import type { EnvGroup } from '@/api/env_group'
+import type { Namespace } from '@/api/namespace'
 import type { NgxConfig } from '@/api/ngx'
 import type { ConfigStatus, PrivateKeyType } from '@/constants'
 import { extendCurdApi, http, useCurdApi } from '@uozi-admin/request'
@@ -23,8 +23,8 @@ export interface Site extends ModelBase {
   auto_cert: boolean
   tokenized?: NgxConfig
   cert_info?: Record<number, CertificateInfo[]>
-  env_group_id: number
-  env_group?: EnvGroup
+  namespace_id: number
+  namespace?: Namespace
   sync_node_ids: number[]
   urls?: string[]
   proxy_targets?: ProxyTarget[]

+ 3 - 3
app/src/api/stream.ts

@@ -1,4 +1,4 @@
-import type { EnvGroup } from './env_group'
+import type { Namespace } from './namespace'
 import type { NgxConfig } from '@/api/ngx'
 import type { ChatComplicationMessage } from '@/api/openai'
 import type { ProxyTarget, SiteStatus } from '@/api/site'
@@ -13,8 +13,8 @@ export interface Stream {
   config: string
   chatgpt_messages: ChatComplicationMessage[]
   tokenized?: NgxConfig
-  env_group_id: number
-  env_group?: EnvGroup
+  namespace_id: number
+  namespace?: Namespace
   sync_node_ids: number[]
   proxy_targets?: ProxyTarget[]
 }

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

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

+ 0 - 3
app/src/components/EnvGroupTabs/index.ts

@@ -1,3 +0,0 @@
-import EnvGroupTabs from './EnvGroupTabs.vue'
-
-export default EnvGroupTabs

+ 0 - 3
app/src/components/EnvIndicator/index.ts

@@ -1,3 +0,0 @@
-import EnvIndicator from './EnvIndicator.vue'
-
-export default EnvIndicator

+ 10 - 10
app/src/components/EnvGroupRender/EnvGroupRender.vue → app/src/components/NamespaceRender/NamespaceRender.vue

@@ -1,9 +1,9 @@
 <script setup lang="ts">
-import type { EnvGroup } from '@/api/env_group'
+import type { Namespace } from '@/api/namespace'
 import NodeCard from '@/components/NodeCard'
 
 defineProps<{
-  envGroup: EnvGroup | null
+  namespace: Namespace | null
 }>()
 
 const modalVisible = ref(false)
@@ -18,17 +18,17 @@ function handleCancel() {
 </script>
 
 <template>
-  <div v-if="envGroup">
+  <div v-if="namespace">
     <span
       class="cursor-pointer text-blue-500 hover:text-blue-700"
       @click="showModal"
     >
-      {{ envGroup.name }}
+      {{ namespace.name }}
     </span>
 
     <AModal
       v-model:open="modalVisible"
-      :title="envGroup.name"
+      :title="namespace.name"
       :footer="null"
       width="680px"
       @cancel="handleCancel"
@@ -37,27 +37,27 @@ function handleCancel() {
         <div class="mb-4">
           <strong class="text-gray-900 dark:text-gray-100">{{ $gettext('Post-sync Action') }}:</strong>
           <span class="ml-2 text-gray-700 dark:text-gray-300">
-            <template v-if="!envGroup.post_sync_action || envGroup.post_sync_action === 'none'">
+            <template v-if="!namespace.post_sync_action || namespace.post_sync_action === 'none'">
               {{ $gettext('No Action') }}
             </template>
-            <template v-else-if="envGroup.post_sync_action === 'reload_nginx'">
+            <template v-else-if="namespace.post_sync_action === 'reload_nginx'">
               {{ $gettext('Reload Nginx') }}
             </template>
             <template v-else>
-              {{ envGroup.post_sync_action }}
+              {{ namespace.post_sync_action }}
             </template>
           </span>
         </div>
 
         <div>
           <strong class="text-gray-900 dark:text-gray-100">{{ $gettext('Sync Nodes') }}</strong>
-          <div v-if="!envGroup.sync_node_ids || envGroup.sync_node_ids.length === 0" class="mt-2 text-gray-400 dark:text-gray-500">
+          <div v-if="!namespace.sync_node_ids || namespace.sync_node_ids.length === 0" class="mt-2 text-gray-400 dark:text-gray-500">
             {{ $gettext('No nodes selected') }}
           </div>
           <div v-else class="mt-2">
             <div class="grid grid-cols-1 sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-3">
               <NodeCard
-                v-for="nodeId in envGroup.sync_node_ids"
+                v-for="nodeId in namespace.sync_node_ids"
                 :key="nodeId"
                 :node-id="nodeId"
                 size="sm"

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

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

+ 10 - 10
app/src/components/EnvGroupTabs/EnvGroupTabs.vue → app/src/components/NamespaceTabs/NamespaceTabs.vue

@@ -1,11 +1,11 @@
 <script setup lang="ts">
-import type { EnvGroup } from '@/api/env_group'
+import type { Namespace } from '@/api/namespace'
 import { message } from 'ant-design-vue'
 import nodeApi from '@/api/node'
 import { useNodeAvailabilityStore } from '@/pinia/moudule/nodeAvailability'
 
 const props = defineProps<{
-  envGroups: EnvGroup[]
+  namespaces: Namespace[]
 }>()
 
 const modelValue = defineModel<string | number>('activeKey')
@@ -17,28 +17,28 @@ const loading = ref({
 })
 
 // Get the current Node Group data
-const currentEnvGroup = computed(() => {
+const currentNamespace = computed(() => {
   if (!modelValue.value || modelValue.value === 0)
     return null
-  return props.envGroups.find(g => g.id === Number(modelValue.value))
+  return props.namespaces.find(g => g.id === Number(modelValue.value))
 })
 
 // Get the list of nodes in the current group
 const syncNodes = computed(() => {
-  if (!currentEnvGroup.value)
+  if (!currentNamespace.value)
     return []
 
-  if (!currentEnvGroup.value.sync_node_ids)
+  if (!currentNamespace.value.sync_node_ids)
     return []
 
-  return currentEnvGroup.value.sync_node_ids
+  return currentNamespace.value.sync_node_ids
     .map(id => nodeStore.getNodeStatus(id))
     .filter((node): node is NonNullable<typeof node> => Boolean(node))
 })
 
 // Handle reload Nginx on all sync nodes
 async function handleReloadNginx() {
-  if (!currentEnvGroup.value || !syncNodes.value.length)
+  if (!currentNamespace.value || !syncNodes.value.length)
     return
 
   const nodeIds = syncNodes.value.map(node => node.id)
@@ -58,7 +58,7 @@ async function handleReloadNginx() {
 
 // Handle restart Nginx on all sync nodes
 async function handleRestartNginx() {
-  if (!currentEnvGroup.value || !syncNodes.value.length)
+  if (!currentNamespace.value || !syncNodes.value.length)
     return
 
   const nodeIds = syncNodes.value.map(node => node.id)
@@ -81,7 +81,7 @@ async function handleRestartNginx() {
   <div>
     <ATabs :active-key="modelValue" @update:active-key="modelValue = $event">
       <ATabPane :key="0" :tab="$gettext('All')" />
-      <ATabPane v-for="c in envGroups" :key="c.id" :tab="c.name" />
+      <ATabPane v-for="c in namespaces" :key="c.id" :tab="c.name" />
     </ATabs>
 
     <!-- Display node information -->

+ 3 - 0
app/src/components/NamespaceTabs/index.ts

@@ -0,0 +1,3 @@
+import NamespaceTabs from './NamespaceTabs.vue'
+
+export default NamespaceTabs

+ 11 - 11
app/src/components/EnvIndicator/EnvIndicator.vue → app/src/components/NodeIndicator/NodeIndicator.vue

@@ -6,19 +6,19 @@ import { useSettingsStore } from '@/pinia'
 
 const settingsStore = useSettingsStore()
 
-const { environment } = storeToRefs(settingsStore)
+const { node } = storeToRefs(settingsStore)
 const router = useRouter()
 
-async function clear_env() {
+async function clear_node() {
   await router.push('/dashboard')
-  settingsStore.clear_environment()
+  settingsStore.clear_node()
 }
 
 const is_local = computed(() => {
-  return environment.value.id === 0
+  return node.value.id === 0
 })
 
-const node_id = computed(() => environment.value.id)
+const node_id = computed(() => node.value.id)
 
 watch(node_id, async () => {
   await router.push('/dashboard')
@@ -34,17 +34,17 @@ const { server_name } = storeToRefs(useSettingsStore())
       <DatabaseOutlined />
       <span
         v-if="is_local"
-        class="env-name"
+        class="node-name"
       >
         {{ server_name || $gettext('Local') }}
       </span>
       <span
         v-else
-        class="env-name"
+        class="node-name"
       >
-        {{ environment.name }}
+        {{ node.name }}
       </span>
-      <ATag @click="clear_env">
+      <ATag @click="clear_node">
         <DashboardOutlined v-if="is_local" />
         <CloseOutlined v-else />
       </ATag>
@@ -54,7 +54,7 @@ const { server_name } = storeToRefs(useSettingsStore())
 
 <style scoped lang="less">
 .ant-layout-sider-collapsed {
-  .ant-tag, .env-name {
+  .ant-tag, .node-name {
     display: none;
   }
 
@@ -79,7 +79,7 @@ const { server_name } = storeToRefs(useSettingsStore())
     align-items: center;
     justify-content: space-between;
 
-    .env-name {
+    .node-name {
       max-width: 85px;
       text-overflow: ellipsis;
       white-space: nowrap;

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

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

+ 4 - 4
app/src/components/ProxyTargets/ProxyTargets.vue

@@ -6,19 +6,19 @@ import { useUpstreamStatus } from '@/composables/useUpstreamStatus'
 
 interface Props {
   targets: ProxyTarget[]
-  envGroupId?: number
+  namespaceId?: number
 }
 
 const props = defineProps<Props>()
 
-const envGroupIdRef = computed(() => props.envGroupId)
+const namespaceIdRef = computed(() => props.namespaceId)
 const {
   shouldShowMultiNodeDisplay,
   getTargetColor,
   getTargetText,
   getTargetTitle,
   proxyStore,
-} = useUpstreamStatus(envGroupIdRef)
+} = useUpstreamStatus(namespaceIdRef)
 
 const showDetailModal = ref(false)
 const selectedTarget = ref<ProxyTarget | null>(null)
@@ -51,7 +51,7 @@ function handleTargetClick(target: ProxyTarget) {
     <UpstreamDetailModal
       v-model:open="showDetailModal"
       :target="selectedTarget"
-      :env-group-id="envGroupId"
+      :namespace-id="namespaceId"
     />
   </div>
 </template>

+ 17 - 17
app/src/components/SyncNodesPreview/SyncNodesPreview.vue

@@ -1,39 +1,39 @@
 <script setup lang="ts">
-import type { EnvGroup } from '@/api/env_group'
-import envGroup from '@/api/env_group'
+import type { Namespace } from '@/api/namespace'
+import namespace from '@/api/namespace'
 import NodeCard from '@/components/NodeCard'
 
 const props = defineProps<{
-  envGroupId?: number | null
+  namespaceId?: number | null
   syncNodeIds?: number[]
 }>()
 
-// Get environment group info
-const envGroupInfo = ref<EnvGroup | null>(null)
+// Get namespace info
+const namespaceInfo = ref<Namespace | null>(null)
 
-watch(() => props.envGroupId, async newEnvGroupId => {
-  if (!newEnvGroupId) {
-    envGroupInfo.value = null
+watch(() => props.namespaceId, async newNamespaceId => {
+  if (!newNamespaceId) {
+    namespaceInfo.value = null
     return
   }
 
   try {
-    const response = await envGroup.getItem(newEnvGroupId)
-    envGroupInfo.value = response
+    const response = await namespace.getItem(newNamespaceId)
+    namespaceInfo.value = response
   }
   catch (error) {
-    console.error('Failed to fetch env group:', error)
-    envGroupInfo.value = null
+    console.error('Failed to fetch namespace:', error)
+    namespaceInfo.value = null
   }
 }, { immediate: true })
 
-// Merge nodes from env group and manually selected nodes
+// Merge nodes from namespace and manually selected nodes
 const allSyncNodeIds = computed(() => {
-  const envGroupNodes = envGroupInfo.value?.sync_node_ids || []
+  const namespaceNodes = namespaceInfo.value?.sync_node_ids || []
   const manualNodes = props.syncNodeIds || []
 
   // Merge and deduplicate
-  const allNodes = [...new Set([...envGroupNodes, ...manualNodes])]
+  const allNodes = [...new Set([...namespaceNodes, ...manualNodes])]
   return allNodes
 })
 </script>
@@ -55,8 +55,8 @@ const allSyncNodeIds = computed(() => {
       />
     </div>
 
-    <div v-if="envGroupInfo" class="mt-2 text-xs text-gray-500 dark:text-gray-400">
-      {{ $gettext('* Includes nodes from group %{groupName} and manually selected nodes', { groupName: envGroupInfo.name }) }}
+    <div v-if="namespaceInfo" class="mt-2 text-xs text-gray-500 dark:text-gray-400">
+      {{ $gettext('* Includes nodes from group %{groupName} and manually selected nodes', { groupName: namespaceInfo.name }) }}
     </div>
   </div>
 </template>

+ 4 - 4
app/src/components/UpstreamCards/UpstreamCards.vue

@@ -6,19 +6,19 @@ import { useUpstreamStatus } from '@/composables/useUpstreamStatus'
 
 interface Props {
   targets: ProxyTarget[]
-  envGroupId?: number
+  namespaceId?: number
 }
 
 const props = defineProps<Props>()
 
-const envGroupIdRef = computed(() => props.envGroupId)
+const namespaceIdRef = computed(() => props.namespaceId)
 const {
   shouldShowMultiNodeDisplay,
   getTargetColor,
   getTargetText,
   getTargetTitle,
   proxyStore,
-} = useUpstreamStatus(envGroupIdRef)
+} = useUpstreamStatus(namespaceIdRef)
 
 const showDetailModal = ref(false)
 const selectedTarget = ref<ProxyTarget | null>(null)
@@ -82,7 +82,7 @@ function getCardStatusColor(target: ProxyTarget): string {
     <UpstreamDetailModal
       v-model:open="showDetailModal"
       :target="selectedTarget"
-      :env-group-id="envGroupId"
+      :namespace-id="namespaceId"
     />
   </div>
 </template>

+ 3 - 3
app/src/components/UpstreamDetailModal/UpstreamDetailModal.vue

@@ -6,7 +6,7 @@ import { useUpstreamStatus } from '@/composables/useUpstreamStatus'
 interface Props {
   open: boolean
   target: ProxyTarget | null
-  envGroupId?: number
+  namespaceId?: number
 }
 
 const props = defineProps<Props>()
@@ -14,8 +14,8 @@ defineEmits<{
   'update:open': [value: boolean]
 }>()
 
-const envGroupIdRef = computed(() => props.envGroupId)
-const { getAllNodeStatuses, getStatusSummary } = useUpstreamStatus(envGroupIdRef)
+const namespaceIdRef = computed(() => props.namespaceId)
+const { getAllNodeStatuses, getStatusSummary } = useUpstreamStatus(namespaceIdRef)
 </script>
 
 <template>

+ 2 - 2
app/src/composables/useSSE.ts

@@ -83,8 +83,8 @@ export function useSSE() {
       headers.Authorization = token.value
     }
 
-    if (settings.environment.id) {
-      headers['X-Node-ID'] = settings.environment.id.toString()
+    if (settings.node.id) {
+      headers['X-Node-ID'] = settings.node.id.toString()
     }
 
     const sse = new SSE(fullUrl, {

+ 10 - 10
app/src/composables/useUpstreamStatus.ts

@@ -1,11 +1,11 @@
 // Composable for managing upstream status logic shared between components
-import type { EnvGroup } from '@/api/env_group'
+import type { Namespace } from '@/api/namespace'
 import type { ProxyTarget } from '@/api/site'
 import { useNodeAvailabilityStore } from '@/pinia/moudule/nodeAvailability'
 import { useNodeGroupStore } from '@/pinia/moudule/nodeGroupStore'
 import { useProxyAvailabilityStore } from '@/pinia/moudule/proxyAvailability'
 
-export function useUpstreamStatus(envGroupId?: Ref<number | undefined>) {
+export function useUpstreamStatus(namespaceId?: Ref<number | undefined>) {
   const proxyStore = useProxyAvailabilityStore()
   const nodeStore = useNodeAvailabilityStore()
   const nodeGroupStore = useNodeGroupStore()
@@ -22,11 +22,11 @@ export function useUpstreamStatus(envGroupId?: Ref<number | undefined>) {
 
   // Check if should show multi-node display based on group configuration
   const shouldShowMultiNodeDisplay = computed(() => {
-    if (!envGroupId?.value) {
+    if (!namespaceId?.value) {
       return false
     }
 
-    const group = nodeGroupStore.getGroupById(envGroupId.value)
+    const group = nodeGroupStore.getGroupById(namespaceId.value)
     const testType = group?.upstream_test_type || 'local'
     return testType === 'remote' || testType === 'mirror'
   })
@@ -46,7 +46,7 @@ export function useUpstreamStatus(envGroupId?: Ref<number | undefined>) {
 
   // Helper function to get color for multi-node display
   function getMultiNodeColor(target: ProxyTarget): string {
-    const group = nodeGroupStore.getGroupById(envGroupId!.value!)
+    const group = nodeGroupStore.getGroupById(namespaceId!.value!)
     const testType = group?.upstream_test_type || 'local'
     const totalNodes = calculateTotalNodes(group, testType)
     const onlineCount = calculateOnlineCount(target, group, testType)
@@ -59,14 +59,14 @@ export function useUpstreamStatus(envGroupId?: Ref<number | undefined>) {
   }
 
   // Calculate total nodes based on test type
-  function calculateTotalNodes(group: EnvGroup | undefined, testType: string): number {
+  function calculateTotalNodes(group: Namespace | undefined, testType: string): number {
     return testType === 'remote'
       ? (group?.sync_node_ids?.length || 0) // remote: only sync nodes
       : (group?.sync_node_ids?.length || 0) + 1 // mirror: sync nodes + main node
   }
 
   // Calculate online nodes count
-  function calculateOnlineCount(target: ProxyTarget, group: EnvGroup | undefined, testType: string): number {
+  function calculateOnlineCount(target: ProxyTarget, group: Namespace | undefined, testType: string): number {
     const multiNodeStatus = proxyStore.getMultiNodeStatus(target)
     let onlineCount = 0
 
@@ -119,7 +119,7 @@ export function useUpstreamStatus(envGroupId?: Ref<number | undefined>) {
       }
     }
 
-    const group = nodeGroupStore.getGroupById(envGroupId!.value!)
+    const group = nodeGroupStore.getGroupById(namespaceId!.value!)
     const testType = group?.upstream_test_type || 'local'
     const totalNodes = calculateTotalNodes(group, testType)
     const onlineCount = calculateOnlineCount(target, group, testType)
@@ -140,10 +140,10 @@ export function useUpstreamStatus(envGroupId?: Ref<number | undefined>) {
 
   // Get all node statuses for modal display
   function getAllNodeStatuses(target: ProxyTarget) {
-    if (!envGroupId?.value)
+    if (!namespaceId?.value)
       return []
 
-    const group = nodeGroupStore.getGroupById(envGroupId.value)
+    const group = nodeGroupStore.getGroupById(namespaceId.value)
     const testType = group?.upstream_test_type || 'local'
     const allStatuses: Array<{ nodeId: string, name: string, status: { online: boolean, latency: number }, isMainNode: boolean }> = []
 

+ 169 - 142
app/src/language/ar/app.po

@@ -100,6 +100,11 @@ msgstr "[Nginx UI] كتابة مفتاح الشهادة الخاص إلى الق
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] كتابة الشهادة على القرص"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "تم نسخ {label} إلى الحافظة"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* يتضمن عقدًا من مجموعة %{groupName} وعقدًا مختارة يدويًا"
@@ -130,7 +135,7 @@ msgid "Access Logs"
 msgstr "سجلات الدخول"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "مستخدم ACME"
 
@@ -142,10 +147,8 @@ msgstr "إجراء"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -227,7 +230,7 @@ msgstr "الوضع المتقدم"
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr "بعد ذلك، قم بتحديث هذه الصفحة وانقر على إضافة مفتاح مرور مرة أخرى."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "الكل"
 
@@ -272,6 +275,10 @@ msgstr "نوع API"
 msgid "App"
 msgstr "التطبيق"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "تطبيق"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "أرك"
@@ -310,7 +317,7 @@ msgstr "هل أنت متأكد أنك تريد الحذف نهائيًا؟"
 msgid "Are you sure you want to delete?"
 msgstr "هل أنت متأكد أنك تريد الحذف؟"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr "هل أنت متأكد أنك تريد إعادة تحميل Nginx على عقد المزامنة التالية؟"
 
@@ -326,7 +333,7 @@ msgstr "هل أنت متأكد أنك تريد إزالة هذا العنصر؟"
 msgid "Are you sure you want to remove this location?"
 msgstr "هل أنت متأكد أنك تريد إزالة هذا المكان؟"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr "هل أنت متأكد أنك تريد إعادة تشغيل Nginx على عقد المزامنة التالية؟"
 
@@ -397,16 +404,15 @@ msgstr "فشل النسخ الاحتياطي التلقائي"
 msgid "Auto Backup Storage Failed"
 msgstr "فشل تخزين النسخ الاحتياطي التلقائي"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "التحديث التلقائي"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "تم تعطيل التحديث التلقائي"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "تمكين التحديث التلقائي"
 
@@ -553,7 +559,7 @@ msgstr "تحرير المجموعة"
 msgid "Batch Modify"
 msgstr "تعديل متعدد"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "ترقية متعددة"
 
@@ -806,8 +812,7 @@ msgstr[5] "الشهادات المعدلة"
 msgid "Changed Path"
 msgstr "المسار المتغير"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "القناة"
 
@@ -1017,6 +1022,10 @@ msgstr "إكمال الكود غير مفعّل"
 msgid "Code Completion Model"
 msgstr "نموذج إكمال التعليمات البرمجية"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "إعدادات العمود"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "أمر"
@@ -1108,6 +1117,10 @@ msgstr "التكوينات"
 msgid "Configure SSL"
 msgstr "تكوين SSL"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "تأكيد الحذف"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "تأكيد كلمة المرور الجديدة"
@@ -1120,7 +1133,7 @@ msgstr "متصل"
 msgid "Connection error, trying to reconnect..."
 msgstr "خطأ في الاتصال، جاري محاولة إعادة الاتصال..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "تم فقدان الاتصال، يرجى تحديث الصفحة."
 
@@ -1201,7 +1214,7 @@ msgstr ""
 "سيتم تنزيل ملفات النسخ الاحتياطي تلقائيًا إلى جهاز الكمبيوتر الخاص بك."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1433,7 +1446,7 @@ msgstr "تفاصيل"
 msgid "Dev"
 msgstr "تطوير"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "التطوير"
 
@@ -1533,8 +1546,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "تم تعطيل الدفق %{name} من %{node} بنجاح"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1641,16 +1653,15 @@ msgstr "خطأ في تنزيل الإصدار الأخير"
 msgid "Downloading latest release"
 msgstr "تنزيل الإصدار الأحدث"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "قم بإسقاط ملف الشهادة هنا"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "قم بإسقاط ملف المفتاح الخاص هنا"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "تمكين وضع التشغيل التجريبي"
 
@@ -1822,8 +1833,7 @@ msgid "Enable TOTP"
 msgstr "تفعيل TOTP"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1880,13 +1890,11 @@ msgstr "تكوين البيئة فارغ"
 msgid "Environment variables cleaned"
 msgstr "تم تنظيف متغيرات البيئة"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "البيئات"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "خطأ"
@@ -2037,6 +2045,11 @@ msgstr "فشل في نسخ محتوى الملف: {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "فشل في نسخ دليل تكوين Nginx: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "فشل النسخ إلى الحافظة"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "فشل إنشاء نسخة احتياطية"
@@ -2483,8 +2496,7 @@ msgstr "فشل الحصول على البيانات"
 msgid "Get dns credential error: {0}"
 msgstr "خطأ في الحصول على بيانات اعتماد DNS: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "خطأ في الحصول على معلومات الإصدار"
 
@@ -2530,7 +2542,7 @@ msgstr "القيمة الأعلى تعني إعادة استخدام أفضل ل
 msgid "History"
 msgstr "السجل"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "الصفحة الرئيسية"
 
@@ -2593,7 +2605,7 @@ msgid "Import"
 msgstr "استيراد"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "استيراد شهادة"
 
@@ -2617,7 +2629,7 @@ msgstr "جاري الفهرسة..."
 msgid "Indicator"
 msgstr "المؤشر"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "معلومات"
 
@@ -2852,10 +2864,10 @@ msgstr "اتركه فارغًا إذا لم يكن مطلوبًا من قبل م
 msgid "Leave blank if you don't need this."
 msgstr "اتركه فارغًا إذا لم تكن بحاجة إلى ذلك."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "تركه فارغًا لن يغير شيئًا"
 
@@ -2888,11 +2900,11 @@ msgstr "يستمع"
 msgid "Load Average:"
 msgstr "متوسط التحميل:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "تحميل من الإعدادات"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "تم التحميل بنجاح"
 
@@ -2922,7 +2934,7 @@ msgid "Loading data..."
 msgstr "جارٍ تحميل البيانات..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2942,7 +2954,7 @@ msgstr "مكان"
 msgid "Locations"
 msgstr "أماكن"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "سجل"
 
@@ -3150,7 +3162,7 @@ msgstr "دقيقة"
 msgid "Minutes"
 msgstr "دقائق"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "مرآة"
 
@@ -3168,7 +3180,7 @@ msgid "Modify"
 msgstr "تعديل"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "تعديل الشهادة"
 
@@ -3213,15 +3225,15 @@ msgstr "غير متاح"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3238,6 +3250,18 @@ msgstr "اسم"
 msgid "Name or content"
 msgstr "الاسم أو المحتوى"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "مساحة الاسم"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "مساحات الأسماء"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "يجب تمكين وحدة stub_status"
@@ -3430,7 +3454,7 @@ msgstr "أمر إعادة تحميل Nginx"
 msgid "Nginx reload failed: {0}"
 msgstr "فشل إعادة تحميل Nginx: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "تم إرسال عمليات إعادة تحميل Nginx إلى العقد البعيدة"
 
@@ -3442,7 +3466,7 @@ msgstr "تم إعادة تحميل Nginx بنجاح"
 msgid "Nginx Restart Command"
 msgstr "أمر إعادة تشغيل Nginx"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "تم إرسال عمليات إعادة تشغيل Nginx إلى العقد البعيدة"
 
@@ -3494,8 +3518,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "يتضمن Nginx.conf دليل streams-enabled"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3507,8 +3531,8 @@ msgstr "يتضمن Nginx.conf دليل streams-enabled"
 msgid "No"
 msgstr "لا"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "لا إجراء"
 
@@ -3516,7 +3540,7 @@ msgstr "لا إجراء"
 msgid "No data"
 msgstr "لا توجد بيانات"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "لم يتم تحديد أي عقد"
 
@@ -3544,17 +3568,6 @@ msgstr "لا توجد مصادر علوية مهيأة"
 msgid "Node"
 msgstr "العقدة"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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 "مجموعة العقد"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "مجموعات العقد"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "اسم العقدة"
@@ -3567,7 +3580,7 @@ msgstr "سر العقدة"
 msgid "Node Status"
 msgstr "حالة العقدة"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "العقد"
 
@@ -3606,6 +3619,11 @@ msgstr ""
 "يرجى ملاحظة أنه إذا كان ملف التكوين يتضمن تكوينات أو شهادات أخرى، فيرجى "
 "مزامنتها مع العقد البعيدة مسبقًا."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "لا يوجد شيء للنسخ"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "إشعار"
@@ -3671,12 +3689,11 @@ msgstr "إيقاف"
 msgid "Official Document"
 msgstr "الوثيقة الرسمية"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "غير متصل"
 
@@ -3705,13 +3722,12 @@ msgstr "تشغيل"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "بمجرد اكتمال التحقق، سيتم إزالة السجلات."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "متصل"
 
@@ -3858,7 +3874,7 @@ msgstr "مورد الحمولة فارغ"
 msgid "Pending"
 msgstr "قيد الانتظار"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "نفذ"
 
@@ -3902,6 +3918,10 @@ msgstr ""
 "يرجى تمكين وحدة stub_status للحصول على إحصائيات الطلبات وعدد الاتصالات وما "
 "إلى ذلك."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "الرجاء إدخال"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -4036,17 +4056,15 @@ msgstr "الرجاء تحديد ملف %{type} صالح (%{extensions})"
 msgid "Please select at least one item"
 msgstr "الرجاء تحديد عنصر واحد على الأقل"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "الرجاء تحديد عقدة واحدة على الأقل لإعادة تحميل Nginx"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "الرجاء تحديد عقدة واحدة على الأقل لإعادة تشغيل Nginx"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "يرجى اختيار عقدة واحدة على الأقل للترقية"
 
@@ -4072,13 +4090,12 @@ msgstr "يجب أن يكون المنفذ 80 مفتوحًا للتحقق من ت
 msgid "Port Scanner"
 msgstr "ماسح المنافذ"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "إجراء ما بعد المزامنة"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "ما قبل الإصدار"
@@ -4216,6 +4233,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr "خوادم الأسماء التكرارية"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "تحديث"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "إعادة توليد الاستجابة"
@@ -4267,10 +4288,9 @@ msgstr "ملاحظة الإصدار"
 msgid "Reload"
 msgstr "إعادة تحميل"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "إعادة تحميل Nginx"
 
@@ -4294,7 +4314,7 @@ msgstr "خطأ في إعادة تحميل Nginx البعيد"
 msgid "Reload Remote Nginx Success"
 msgstr "إعادة تحميل Nginx البعيد بنجاح"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "فشل طلب إعادة التحميل، يرجى التحقق من اتصال الشبكة لديك"
 
@@ -4306,7 +4326,7 @@ msgstr "إعادة التحميل"
 msgid "Reloading nginx"
 msgstr "إعادة تحميل nginx"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "عن بُعد"
 
@@ -4457,9 +4477,8 @@ msgstr "الردود"
 msgid "Restart"
 msgstr "إعادة تشغيل"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "إعادة تشغيل Nginx"
 
@@ -4479,7 +4498,7 @@ msgstr "خطأ في إعادة تشغيل Nginx البعيد"
 msgid "Restart Remote Nginx Success"
 msgstr "إعادة تشغيل Nginx البعيد بنجاح"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "فشل طلب إعادة التشغيل، يرجى التحقق من اتصال الشبكة لديك"
 
@@ -4854,7 +4873,7 @@ msgstr "إرسال رسالة اختبار"
 msgid "Server"
 msgstr "الخادم"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "خطأ في الخادم"
 
@@ -5010,7 +5029,8 @@ msgstr "وقت الانتظار بين تكرارات مدير الذاكرة ا
 msgid "Sponsor"
 msgstr "راعي"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "محتوى شهادة SSL"
 
@@ -5022,15 +5042,20 @@ msgstr "يجب أن يكون ملف شهادة SSL ضمن دليل تكوين Ng
 msgid "SSL certificate file not found"
 msgstr "لم يتم العثور على ملف شهادة SSL"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "محتوى مفتاح شهادة SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "مسار مفتاح شهادة SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "مسار شهادة SSL"
@@ -5059,8 +5084,7 @@ msgstr "مسار مفتاح SSL مطلوب عند تمكين HTTPS"
 msgid "SSO Login"
 msgstr "تسجيل الدخول عبر SSO"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "مستقر"
@@ -5084,7 +5108,7 @@ msgstr "ثابت"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5162,7 +5186,7 @@ msgstr "منفذ حالة ستاب"
 msgid "Stub_status is not enabled"
 msgstr "لم يتم تمكين Stub_status"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5251,10 +5275,9 @@ msgstr "خطأ في تزامن التكوين"
 msgid "Sync Config Success"
 msgstr "تمت مزامنة التكوين بنجاح"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "مزامنة العقد"
 
@@ -5269,7 +5292,7 @@ msgstr "معاينة المزامنة"
 msgid "Sync strategy"
 msgstr "استراتيجية المزامنة"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "مزامنة إلى"
 
@@ -5291,7 +5314,7 @@ msgstr "نسخ احتياطي للنظام"
 msgid "System Check"
 msgstr "فحص النظام"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "مستخدم النظام الأولي"
 
@@ -5351,11 +5374,11 @@ msgid ""
 "dashes, colons, and dots."
 msgstr "يجب أن يحتوي رقم ICP على أحرف، يونيكود، أرقام، شرطات، نقاط، ونقطتين فقط."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "الإدخال ليس شهادة SSL"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "المدخل ليس مفتاح شهادة SSL"
 
@@ -5392,11 +5415,11 @@ msgstr "يجب أن يحتوي اسم العقدة على أحرف، يونيك
 msgid "The parameter of server_name is required"
 msgstr "معلمة server_name مطلوبة"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "المسار موجود، لكن الملف ليس شهادة"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "المسار موجود، لكن الملف ليس مفتاحًا خاصًا"
 
@@ -5469,9 +5492,9 @@ msgstr "يتم إدارة هذه الشهادة بواسطة Nginx UI"
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr "هذا الدليل محمي ولا يمكن حذفه لأمان النظام."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "هذا الحقل مطلوب"
 
@@ -5575,7 +5598,7 @@ msgstr ""
 "سيؤدي هذا إلى استعادة ملفات التكوين وقاعدة البيانات. سيعاد تشغيل واجهة "
 "Nginx بعد اكتمال الاستعادة."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "سيتم ترقية أو إعادة تثبيت Nginx UI على %{nodeNames} إلى %{version}."
 
@@ -5605,6 +5628,11 @@ msgstr ""
 msgid "Title"
 msgstr "عنوان"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "لتأكيد الحذف"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "لتأكيد الإلغاء، يرجى كتابة \"إلغاء\" في الحقل أدناه:"
@@ -5766,9 +5794,8 @@ msgstr "تم التحديث بنجاح"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5776,14 +5803,13 @@ msgstr "تم التحديث بنجاح"
 msgid "Updated at"
 msgstr "محدث في"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "ترقية"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "تمت ترقية Nginx UI على %{node} بنجاح 🎉"
 
@@ -5791,8 +5817,7 @@ msgstr "تمت ترقية Nginx UI على %{node} بنجاح 🎉"
 msgid "Upgraded successfully"
 msgstr "تم الترقية بنجاح"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "جارٍ ترقية Nginx UI، يرجى الانتظار..."
 
@@ -5816,7 +5841,7 @@ msgstr "أعلى التيار"
 msgid "Upstream Name"
 msgstr "اسم المنبع"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "نوع اختبار المنبع"
 
@@ -5824,7 +5849,7 @@ msgstr "نوع اختبار المنبع"
 msgid "Uptime:"
 msgstr "مدة التشغيل:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "عنوان URL"
 
@@ -5892,7 +5917,7 @@ msgstr "التحقق من سلامة ملف النسخ الاحتياطي"
 msgid "Verify system requirements"
 msgstr "تحقق من متطلبات النظام"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "إصدار"
 
@@ -5905,8 +5930,7 @@ msgstr "عرض"
 msgid "View all notifications"
 msgstr "عرض جميع التنبيهات"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "عرض على GitHub"
 
@@ -5923,7 +5947,7 @@ msgstr "تمت المشاهدة"
 msgid "Waiting processes"
 msgstr "عمليات الانتظار"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -6006,10 +6030,10 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
 "عند تمكين/تعطيل أو حذف أو حفظ هذا الموقع، سيتم مزامنة العقد المحددة في "
-"مجموعة العقد والعقد المحددة أدناه."
+"مساحة الاسم والعقد المحددة أدناه."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -6040,7 +6064,7 @@ msgstr "عمليات العامل"
 msgid "Workers"
 msgstr "العمال"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "مساحة العمل"
@@ -6066,8 +6090,8 @@ msgstr "كتابة مفتاح الشهادة الخاص إلى القرص"
 msgid "Writing certificate to disk"
 msgstr "كتابة الشهادة إلى القرص"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -6075,7 +6099,7 @@ msgstr "كتابة الشهادة إلى القرص"
 msgid "Yes"
 msgstr "نعم"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6136,6 +6160,12 @@ msgstr "رموزك القديمة لن تعمل بعد الآن."
 msgid "Your passkeys"
 msgstr "مفاتيح المرور الخاصة بك"
 
+#~ msgid "Node Group"
+#~ msgstr "مجموعة العقد"
+
+#~ msgid "Node Groups"
+#~ msgstr "مجموعات العقد"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "تحقق مما إذا كان دليل conf.d موجودًا"
 
@@ -6194,9 +6224,6 @@ msgstr "مفاتيح المرور الخاصة بك"
 #~ msgid "Last Backup Error"
 #~ msgstr "خطأ آخر نسخة احتياطية"
 
-#~ msgid "Apply"
-#~ msgstr "تطبيق"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "تم تطبيق الإجراء المجمع بنجاح"
 

+ 8 - 1
app/src/language/curd.ts

@@ -60,5 +60,12 @@ export const translations = {
     processing: $gettext('Processing {count}/{total}'),
     path: $gettext('Path'),
     size: $gettext('Size')
-  }
+  },
+  'Column Settings': $gettext('Column Settings'),
+  Apply: $gettext('Apply'),
+  'Confirm Delete': $gettext('Confirm Delete'),
+  'Please Input': $gettext('Please enter'),
+  'to comfirm delete': $gettext('to confirm deletion'),
+  'to confirm deletion': $gettext('to confirm deletion'),
+  refresh: $gettext('Refresh')
 }

+ 169 - 142
app/src/language/de_DE/app.po

@@ -99,6 +99,11 @@ msgstr "[Nginx UI] Schreibe privaten Zertifikatsschlüssel auf die Festplatte"
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] Zertifikat wird auf die Festplatte geschrieben"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} in die Zwischenablage kopiert"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* Enthält Knoten aus der Gruppe %{groupName} und manuell ausgewählte Knoten"
@@ -129,7 +134,7 @@ msgid "Access Logs"
 msgstr "Zugriffslog"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "ACME-Benutzer"
 
@@ -141,10 +146,8 @@ msgstr "Aktion"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -228,7 +231,7 @@ msgstr ""
 "Aktualisieren Sie anschließend diese Seite und klicken Sie erneut auf "
 "\"Passkey hinzufügen\"."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "Alle"
 
@@ -275,6 +278,10 @@ msgstr "API-Typ"
 msgid "App"
 msgstr "App"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "Anwenden"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "Arch"
@@ -313,7 +320,7 @@ msgstr "Sind Sie sicher, dass Sie dauerhaft löschen möchten?"
 msgid "Are you sure you want to delete?"
 msgstr "Sind Sie sicher, dass Sie löschen möchten?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 "Sind Sie sicher, dass Sie Nginx auf den folgenden Sync-Knoten neu laden "
@@ -331,7 +338,7 @@ msgstr "Möchten Sie dieses Element wirklich entfernen?"
 msgid "Are you sure you want to remove this location?"
 msgstr "Sind Sie sicher, dass Sie diesen Standort entfernen möchten?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr ""
 "Sind Sie sicher, dass Sie Nginx auf den folgenden Synchronisationsknoten "
@@ -404,16 +411,15 @@ msgstr "Automatische Sicherung fehlgeschlagen"
 msgid "Auto Backup Storage Failed"
 msgstr "Automatische Sicherungsspeicherung fehlgeschlagen"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "Automatische Aktualisierung"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "Automatisches Aktualisieren deaktiviert"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "Automatisches Aktualisieren aktiviert"
 
@@ -568,7 +574,7 @@ msgstr "Stapelverarbeitung"
 msgid "Batch Modify"
 msgstr "Stapelverarbeitung"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "Stapel-Upgrade"
 
@@ -813,8 +819,7 @@ msgstr[0] "Geändertes Zertifikat"
 msgid "Changed Path"
 msgstr "Geänderter Pfad"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "Kanal"
 
@@ -1034,6 +1039,10 @@ msgstr "Code-Vervollständigung ist nicht aktiviert"
 msgid "Code Completion Model"
 msgstr "Code-Vervollständigungsmodell"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "Spalteneinstellungen"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "Befehl"
@@ -1125,6 +1134,10 @@ msgstr "Konfigurationen"
 msgid "Configure SSL"
 msgstr "SSL konfigurieren"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "Löschen bestätigen"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "Neues Passwort bestätigen"
@@ -1137,7 +1150,7 @@ msgstr "Verbunden"
 msgid "Connection error, trying to reconnect..."
 msgstr "Verbindungsfehler, versuche erneut zu verbinden..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "Ver"
 
@@ -1221,7 +1234,7 @@ msgstr ""
 "Computer heruntergeladen."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1455,7 +1468,7 @@ msgstr "Details"
 msgid "Dev"
 msgstr "Entwicklung"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "Entwicklung"
 
@@ -1555,8 +1568,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "Stream %{name} von %{node} erfolgreich deaktiviert"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1662,16 +1674,15 @@ msgstr "Fehler beim Herunterladen der neuesten Version"
 msgid "Downloading latest release"
 msgstr "Neueste Version wird heruntergeladen"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "Zertifikatsdatei hier ablegen"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "Private Schlüsseldatei hier ablegen"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "Dry-Run-Modus aktiviert"
 
@@ -1844,8 +1855,7 @@ msgid "Enable TOTP"
 msgstr "TOTP aktivieren"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1904,13 +1914,11 @@ msgstr "Die Umgebungskonfiguration ist leer"
 msgid "Environment variables cleaned"
 msgstr "Umgebungsvariablen gesäubert"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "Umgebungen"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "Fehler"
@@ -2063,6 +2071,11 @@ msgstr "Fehler beim Kopieren des Dateiinhalts: {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Fehler beim Kopieren des Nginx-Konfigurationsverzeichnisses: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "In die Zwischenablage kopieren fehlgeschlagen"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "Sicherungskopie konnte nicht erstellt werden"
@@ -2512,8 +2525,7 @@ msgstr "Datenabruf fehlgeschlagen"
 msgid "Get dns credential error: {0}"
 msgstr "Fehler beim Abrufen der DNS-Anmeldeinformationen: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "Fehler beim Abrufen der Release-Informationen"
 
@@ -2559,7 +2571,7 @@ msgstr "Ein höherer Wert bedeutet eine bessere Wiederverwendung der Verbindung"
 msgid "History"
 msgstr "Verlauf"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "Startseite"
 
@@ -2627,7 +2639,7 @@ msgid "Import"
 msgstr "Import"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "Zertifikat importieren"
 
@@ -2651,7 +2663,7 @@ msgstr "Indizierung läuft..."
 msgid "Indicator"
 msgstr "Indikator"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "Information"
 
@@ -2886,10 +2898,10 @@ msgstr "Leer lassen, falls nicht von Ihrem ACME-Anbieter benötigt"
 msgid "Leave blank if you don't need this."
 msgstr "Lassen Sie dieses Feld leer, wenn Sie es nicht benötigen."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "Leer lassen ändert nichts"
 
@@ -2922,11 +2934,11 @@ msgstr "Lauschend"
 msgid "Load Average:"
 msgstr "Durchschnittliche Last:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "Aus Einstellungen laden"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "Erfolgreich geladen"
 
@@ -2956,7 +2968,7 @@ msgid "Loading data..."
 msgstr "Daten werden geladen..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2976,7 +2988,7 @@ msgstr "Ort"
 msgid "Locations"
 msgstr "Orte"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "Protokoll"
 
@@ -3185,7 +3197,7 @@ msgstr "Minute"
 msgid "Minutes"
 msgstr "Minuten"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "Spiegel"
 
@@ -3203,7 +3215,7 @@ msgid "Modify"
 msgstr "Ändern"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "Zertifikat ändern"
 
@@ -3248,15 +3260,15 @@ msgstr "N/V"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3273,6 +3285,18 @@ msgstr "Name"
 msgid "Name or content"
 msgstr "Name oder Inhalt"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "Namensraum"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "Namensräume"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "Das stub_status-Modul muss aktiviert werden"
@@ -3465,7 +3489,7 @@ msgstr "Befehl zum Neuladen von Nginx"
 msgid "Nginx reload failed: {0}"
 msgstr "Nginx-Neustart fehlgeschlagen: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Die Nginx-Neuladevorgänge wurden an die entfernten Knoten gesendet"
 
@@ -3477,7 +3501,7 @@ msgstr "Nginx erfolgreich neu geladen"
 msgid "Nginx Restart Command"
 msgstr "Beffehl zum Neustarten von Nginx"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Die Nginx-Neustart-Operationen wurden an die entfernten Knoten gesendet"
 
@@ -3531,8 +3555,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf enthält das streams-enabled-Verzeichnis"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3544,8 +3568,8 @@ msgstr "Nginx.conf enthält das streams-enabled-Verzeichnis"
 msgid "No"
 msgstr "Nein"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "Keine Aktion"
 
@@ -3553,7 +3577,7 @@ msgstr "Keine Aktion"
 msgid "No data"
 msgstr "Keine Daten"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "Keine Knoten ausgewählt"
 
@@ -3581,17 +3605,6 @@ msgstr "Keine Upstreams konfiguriert"
 msgid "Node"
 msgstr "Node"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "Knotengruppen"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "Knotenname"
@@ -3604,7 +3617,7 @@ msgstr "Node-Secret"
 msgid "Node Status"
 msgstr "Knotenstatus"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "Knoten"
 
@@ -3644,6 +3657,11 @@ msgstr ""
 "Zertifikate enthält, synchronisiere sie bitte im Voraus mit den "
 "Remote-Knoten."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "Nichts zu kopieren"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "Benachrichtigung"
@@ -3711,12 +3729,11 @@ msgstr "Aus"
 msgid "Official Document"
 msgstr "Offizielle Dokumentation"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "Offline"
 
@@ -3745,13 +3762,12 @@ msgstr "Ein"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Sobaöd die Überprüfung abgeschlossen ist, werden die Einträge entfernt."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "Online"
 
@@ -3898,7 +3914,7 @@ msgstr "Die Nutzlast-Ressource ist null"
 msgid "Pending"
 msgstr "Ausstehend"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "Ausführen"
 
@@ -3942,6 +3958,10 @@ msgstr ""
 "Bitte aktivieren Sie das stub_status-Modul, um Anforderungsstatistiken, "
 "Verbindungsanzahl usw. zu erhalten."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "Bitte eingeben"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -4091,17 +4111,15 @@ msgstr "Bitte wählen Sie eine gültige %{type}-Datei aus (%{extensions})"
 msgid "Please select at least one item"
 msgstr "Bitte wählen Sie mindestens einen Artikel aus"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Bitte wählen Sie mindestens einen Knoten aus, um Nginx neu zu laden"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Bitte wählen Sie mindestens einen Knoten aus, um Nginx neu zu starten"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "Bitte wähle mindestens einen Knoten zum Upgrade aus"
 
@@ -4127,13 +4145,12 @@ msgstr "Port 80 muss für die HTTP-01-Challenge-Validierung geöffnet sein"
 msgid "Port Scanner"
 msgstr "Port-Scanner"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Aktion nach der Synchronisierung"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "Vorabversion"
@@ -4273,6 +4290,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr "Rekursive Nameserver"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "Aktualisieren"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Auffrischen der Antwort"
@@ -4326,10 +4347,9 @@ msgstr "Änderungsprotokoll"
 msgid "Reload"
 msgstr "Neu laden"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Nginx neu laden"
 
@@ -4353,7 +4373,7 @@ msgstr "Fehler beim Neuladen von Remote-Nginx"
 msgid "Reload Remote Nginx Success"
 msgstr "Neustart von Remote-Nginx erfolgreich"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr ""
 "Die Neulade-Anfrage ist fehlgeschlagen, bitte überprüfen Sie Ihre "
@@ -4367,7 +4387,7 @@ msgstr "Lade neu"
 msgid "Reloading nginx"
 msgstr "Lade Nginx neu"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "Remote"
 
@@ -4519,9 +4539,8 @@ msgstr "Antworten"
 msgid "Restart"
 msgstr "Neustart"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Nginx neu starten"
 
@@ -4541,7 +4560,7 @@ msgstr "Fehler beim Neustart von Remote-Nginx"
 msgid "Restart Remote Nginx Success"
 msgstr "Neustart von Remote-Nginx erfolgreich"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr ""
 "Neustart-Anforderung fehlgeschlagen, bitte überprüfen Sie Ihre "
@@ -4921,7 +4940,7 @@ msgstr "Testnachricht senden"
 msgid "Server"
 msgstr "Server"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "Serverfehler"
 
@@ -5079,7 +5098,8 @@ msgstr "Wartezeit zwischen den Iterationen des Cache-Managers"
 msgid "Sponsor"
 msgstr "Sponsor"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "SSL-Zertifikatsinhalt"
 
@@ -5093,15 +5113,20 @@ msgstr ""
 msgid "SSL certificate file not found"
 msgstr "SSL-Zertifikatsdatei nicht gefunden"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "SSL-Zertifikatsschlüsselinhalt"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "SSL-Zertifikatsschlüssel-Pfad"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "SSL-Zertifikatspfad"
@@ -5132,8 +5157,7 @@ msgstr "Der SSL-Schlüsselpfad ist erforderlich, wenn HTTPS aktiviert ist"
 msgid "SSO Login"
 msgstr "SSO-Anmeldung"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "Stabil"
@@ -5157,7 +5181,7 @@ msgstr "Statisch"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5235,7 +5259,7 @@ msgstr "Stub-Status-Port"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status ist nicht aktiviert"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5327,10 +5351,9 @@ msgstr "Fehler beim Synchronisieren der Konfiguration"
 msgid "Sync Config Success"
 msgstr "Konfiguration erfolgreich synchronisiert"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "Synchrone Knoten"
 
@@ -5345,7 +5368,7 @@ msgstr "Synchronisierungsvorschau"
 msgid "Sync strategy"
 msgstr "Synchronisierungsstrategie"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "Synchronisieren mit"
 
@@ -5367,7 +5390,7 @@ msgstr "System-Backup"
 msgid "System Check"
 msgstr "Systemprüfung"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "System-Startbenutzer"
 
@@ -5430,11 +5453,11 @@ msgstr ""
 "Die ICP-Nummer sollte nur Buchstaben, Unicode, Zahlen, Bindestriche, "
 "Doppelpunkte und Punkte enthalten."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "Die Eingabe ist kein SSL-Zertifikat"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "Die Eingabe ist kein SSL-Zertifikatsschlüssel"
 
@@ -5473,11 +5496,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr "Der Parameter server_name ist erforderlich"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "Der Pfad existiert, aber die Datei ist kein Zertifikat"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "Der Pfad existiert, aber die Datei ist kein privater Schlüssel"
 
@@ -5553,9 +5576,9 @@ msgstr ""
 "Dieses Verzeichnis ist geschützt und kann aus Sicherheitsgründen nicht "
 "gelöscht werden."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "Dieses Feld ist erforderlich"
 
@@ -5664,7 +5687,7 @@ msgstr ""
 "Dadurch werden Konfigurationsdateien und Datenbank wiederhergestellt. Die "
 "Nginx UI wird nach Abschluss der Wiederherstellung neu gestartet."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Dies wird das Nginx UI auf %{nodeNames} auf %{version} aktualisieren oder "
@@ -5696,6 +5719,11 @@ msgstr ""
 msgid "Title"
 msgstr "Titel"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "Löschung bestätigen"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr ""
@@ -5860,9 +5888,8 @@ msgstr "Erfolgreich aktualisiert"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5870,14 +5897,13 @@ msgstr "Erfolgreich aktualisiert"
 msgid "Updated at"
 msgstr "Aktualisiert am"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Upgrade"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "Nginx UI auf %{node} erfolgreich aktualisiert 🎉"
 
@@ -5885,8 +5911,7 @@ msgstr "Nginx UI auf %{node} erfolgreich aktualisiert 🎉"
 msgid "Upgraded successfully"
 msgstr "Erfolgreich aktualisiert"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Upgrade von Nginx UI, bitte warten..."
 
@@ -5910,7 +5935,7 @@ msgstr "Upstream"
 msgid "Upstream Name"
 msgstr "Upstream-Name"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "Upstream-Testtyp"
 
@@ -5918,7 +5943,7 @@ msgstr "Upstream-Testtyp"
 msgid "Uptime:"
 msgstr "Uptime:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5986,7 +6011,7 @@ msgstr "Backup-Dateiintegrität überprüfen"
 msgid "Verify system requirements"
 msgstr "Überprüfen Sie die Systemanforderungen"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "Version"
 
@@ -5999,8 +6024,7 @@ msgstr "Anzeigen"
 msgid "View all notifications"
 msgstr "Alle Benachrichtigungen anzeigen"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "Auf GitHub anzeigen"
 
@@ -6017,7 +6041,7 @@ msgstr "Angesehen"
 msgid "Waiting processes"
 msgstr "Warteverfahren"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -6106,10 +6130,10 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
 "Wenn Sie diese Website aktivieren/deaktivieren, löschen oder speichern, "
-"werden die im Node Group festgelegten Knoten und die unten ausgewählten "
+"werden die im Namespace festgelegten Knoten und die unten ausgewählten "
 "Knoten synchronisiert."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
@@ -6145,7 +6169,7 @@ msgstr "Worker-Prozesse"
 msgid "Workers"
 msgstr "Worker"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "Arbeitsplatz"
@@ -6171,8 +6195,8 @@ msgstr "Scrheibe Zertifikat-Privatschlüssel auf die Festplatte"
 msgid "Writing certificate to disk"
 msgstr "Schreibe Zertifikat auf die Festplatte"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -6180,7 +6204,7 @@ msgstr "Schreibe Zertifikat auf die Festplatte"
 msgid "Yes"
 msgstr "Ja"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6245,6 +6269,12 @@ msgstr "Ihre alten Codes funktionieren nicht mehr."
 msgid "Your passkeys"
 msgstr "Deine Passkeys"
 
+#~ msgid "Node Group"
+#~ msgstr "Node-Gruppe"
+
+#~ msgid "Node Groups"
+#~ msgstr "Knotengruppen"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "Überprüfen Sie, ob das conf.d-Verzeichnis existiert"
 
@@ -6305,9 +6335,6 @@ msgstr "Deine Passkeys"
 #~ msgid "Last Backup Error"
 #~ msgstr "Letzter Sicherungsfehler"
 
-#~ msgid "Apply"
-#~ msgstr "Anwenden"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "Massenaktion erfolgreich angewendet"
 

+ 159 - 138
app/src/language/en/app.po

@@ -83,6 +83,11 @@ msgstr ""
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr ""
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr ""
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr ""
@@ -113,7 +118,7 @@ msgid "Access Logs"
 msgstr ""
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr ""
 
@@ -125,10 +130,8 @@ msgstr ""
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -210,7 +213,7 @@ msgstr ""
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr ""
 
@@ -254,6 +257,10 @@ msgstr ""
 msgid "App"
 msgstr ""
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr ""
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr ""
@@ -292,7 +299,7 @@ msgstr ""
 msgid "Are you sure you want to delete?"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 
@@ -308,7 +315,7 @@ msgstr ""
 msgid "Are you sure you want to remove this location?"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr ""
 
@@ -379,16 +386,15 @@ msgstr ""
 msgid "Auto Backup Storage Failed"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr ""
 
@@ -534,7 +540,7 @@ msgstr ""
 msgid "Batch Modify"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr ""
 
@@ -777,8 +783,7 @@ msgstr[1] ""
 msgid "Changed Path"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr ""
 
@@ -958,6 +963,10 @@ msgstr ""
 msgid "Code Completion Model"
 msgstr ""
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr ""
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr ""
@@ -1049,6 +1058,10 @@ msgstr ""
 msgid "Configure SSL"
 msgstr ""
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr ""
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr ""
@@ -1061,7 +1074,7 @@ msgstr ""
 msgid "Connection error, trying to reconnect..."
 msgstr ""
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr ""
 
@@ -1140,7 +1153,7 @@ msgid ""
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1372,7 +1385,7 @@ msgstr ""
 msgid "Dev"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr ""
 
@@ -1472,8 +1485,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1576,16 +1588,15 @@ msgstr ""
 msgid "Downloading latest release"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr ""
 
@@ -1755,8 +1766,7 @@ msgid "Enable TOTP"
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1813,13 +1823,11 @@ msgstr ""
 msgid "Environment variables cleaned"
 msgstr ""
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr ""
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr ""
@@ -1968,6 +1976,11 @@ msgstr ""
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr ""
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr ""
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr ""
@@ -2410,8 +2423,7 @@ msgstr ""
 msgid "Get dns credential error: {0}"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr ""
 
@@ -2457,7 +2469,7 @@ msgstr ""
 msgid "History"
 msgstr ""
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr ""
 
@@ -2516,7 +2528,7 @@ msgid "Import"
 msgstr ""
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr ""
 
@@ -2538,7 +2550,7 @@ msgstr ""
 msgid "Indicator"
 msgstr ""
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr ""
 
@@ -2769,10 +2781,10 @@ msgstr ""
 msgid "Leave blank if you don't need this."
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr ""
 
@@ -2805,11 +2817,11 @@ msgstr ""
 msgid "Load Average:"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr ""
 
@@ -2839,7 +2851,7 @@ msgid "Loading data..."
 msgstr ""
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2859,7 +2871,7 @@ msgstr ""
 msgid "Locations"
 msgstr ""
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr ""
 
@@ -3056,7 +3068,7 @@ msgstr ""
 msgid "Minutes"
 msgstr ""
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr ""
 
@@ -3074,7 +3086,7 @@ msgid "Modify"
 msgstr ""
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr ""
 
@@ -3119,15 +3131,15 @@ msgstr ""
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3144,6 +3156,16 @@ msgstr ""
 msgid "Name or content"
 msgstr ""
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91 src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr ""
+
+#: src/routes/modules/namespaces.ts:11 src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr ""
@@ -3336,7 +3358,7 @@ msgstr ""
 msgid "Nginx reload failed: {0}"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr ""
 
@@ -3348,7 +3370,7 @@ msgstr ""
 msgid "Nginx Restart Command"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr ""
 
@@ -3400,8 +3422,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr ""
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3413,8 +3435,8 @@ msgstr ""
 msgid "No"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr ""
 
@@ -3422,7 +3444,7 @@ msgstr ""
 msgid "No data"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr ""
 
@@ -3448,17 +3470,6 @@ msgstr ""
 msgid "Node"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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 ""
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr ""
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr ""
@@ -3471,7 +3482,7 @@ msgstr ""
 msgid "Node Status"
 msgstr ""
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr ""
 
@@ -3508,6 +3519,11 @@ msgid ""
 "certificates, please synchronize them to the remote nodes in advance."
 msgstr ""
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr ""
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr ""
@@ -3571,12 +3587,11 @@ msgstr ""
 msgid "Official Document"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr ""
 
@@ -3605,13 +3620,12 @@ msgstr ""
 msgid "Once the verification is complete, the records will be removed."
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr ""
 
@@ -3755,7 +3769,7 @@ msgstr ""
 msgid "Pending"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr ""
 
@@ -3797,6 +3811,10 @@ msgid ""
 "count, etc."
 msgstr ""
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr ""
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -3930,17 +3948,15 @@ msgstr ""
 msgid "Please select at least one item"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr ""
 
@@ -3966,13 +3982,12 @@ msgstr ""
 msgid "Port Scanner"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr ""
@@ -4105,6 +4120,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr ""
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr ""
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr ""
@@ -4156,10 +4175,9 @@ msgstr ""
 msgid "Reload"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr ""
 
@@ -4183,7 +4201,7 @@ msgstr ""
 msgid "Reload Remote Nginx Success"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr ""
 
@@ -4195,7 +4213,7 @@ msgstr ""
 msgid "Reloading nginx"
 msgstr ""
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr ""
 
@@ -4344,9 +4362,8 @@ msgstr ""
 msgid "Restart"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr ""
 
@@ -4366,7 +4383,7 @@ msgstr ""
 msgid "Restart Remote Nginx Success"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr ""
 
@@ -4737,7 +4754,7 @@ msgstr ""
 msgid "Server"
 msgstr ""
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr ""
 
@@ -4887,7 +4904,8 @@ msgstr ""
 msgid "Sponsor"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr ""
 
@@ -4899,15 +4917,20 @@ msgstr ""
 msgid "SSL certificate file not found"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr ""
@@ -4936,8 +4959,7 @@ msgstr ""
 msgid "SSO Login"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr ""
@@ -4961,7 +4983,7 @@ msgstr ""
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5037,7 +5059,7 @@ msgstr ""
 msgid "Stub_status is not enabled"
 msgstr ""
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5123,10 +5145,9 @@ msgstr ""
 msgid "Sync Config Success"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr ""
 
@@ -5141,7 +5162,7 @@ msgstr ""
 msgid "Sync strategy"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr ""
 
@@ -5163,7 +5184,7 @@ msgstr ""
 msgid "System Check"
 msgstr ""
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr ""
 
@@ -5221,11 +5242,11 @@ msgid ""
 "dashes, colons, and dots."
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr ""
 
@@ -5256,11 +5277,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr ""
 
@@ -5324,9 +5345,9 @@ msgstr ""
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr ""
 
@@ -5415,7 +5436,7 @@ msgid ""
 "after the restoration is complete."
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid ""
 "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
@@ -5444,6 +5465,10 @@ msgstr ""
 msgid "Title"
 msgstr ""
 
+#: src/language/curd.ts:68 src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr ""
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr ""
@@ -5593,9 +5618,8 @@ msgstr ""
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5603,14 +5627,13 @@ msgstr ""
 msgid "Updated at"
 msgstr ""
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully "
 msgstr ""
 
@@ -5618,8 +5641,7 @@ msgstr ""
 msgid "Upgraded successfully"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr ""
 
@@ -5643,7 +5665,7 @@ msgstr ""
 msgid "Upstream Name"
 msgstr ""
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr ""
 
@@ -5651,7 +5673,7 @@ msgstr ""
 msgid "Uptime:"
 msgstr ""
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr ""
 
@@ -5719,7 +5741,7 @@ msgstr ""
 msgid "Verify system requirements"
 msgstr ""
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr ""
 
@@ -5732,8 +5754,7 @@ msgstr ""
 msgid "View all notifications"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr ""
 
@@ -5750,7 +5771,7 @@ msgstr ""
 msgid "Waiting processes"
 msgstr ""
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -5823,7 +5844,7 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
@@ -5855,7 +5876,7 @@ msgstr ""
 msgid "Workers"
 msgstr ""
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr ""
@@ -5881,8 +5902,8 @@ msgstr ""
 msgid "Writing certificate to disk"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -5890,7 +5911,7 @@ msgstr ""
 msgid "Yes"
 msgstr ""
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a non-"
 "localhost domain. This may expose sensitive information."

+ 170 - 143
app/src/language/es/app.po

@@ -106,6 +106,11 @@ msgstr "[Nginx UI] Escribiendo la clave privada del certificado en el disco"
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] Escribiendo certificado en el disco"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} copiado al portapapeles"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* Incluye nodos del grupo %{groupName} y nodos seleccionados manualmente"
@@ -136,7 +141,7 @@ msgid "Access Logs"
 msgstr "Logs de acceso"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "Usuario ACME"
 
@@ -148,10 +153,8 @@ msgstr "Acción"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -235,7 +238,7 @@ msgstr ""
 "Después, actualice esta página y haga clic en agregar clave de acceso "
 "nuevamente."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "Todos"
 
@@ -282,6 +285,10 @@ msgstr "Tipo de API"
 msgid "App"
 msgstr "Aplicación"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "Aplicar"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "Arquitectura"
@@ -320,7 +327,7 @@ msgstr "¿Estás seguro de que quieres eliminar permanentemente?"
 msgid "Are you sure you want to delete?"
 msgstr "¿Está seguro de que quiere borrar?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 "¿Estás seguro de que deseas recargar Nginx en los siguientes nodos de "
@@ -338,7 +345,7 @@ msgstr "¿Está seguro de que desea eliminar este elemento?"
 msgid "Are you sure you want to remove this location?"
 msgstr "¿Está seguro de que quiere borrar esta ubicación?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr ""
 "¿Estás seguro de que deseas reiniciar Nginx en los siguientes nodos de "
@@ -411,16 +418,15 @@ msgstr "Copia de seguridad automática fallida"
 msgid "Auto Backup Storage Failed"
 msgstr "Fallo en el almacenamiento de copia de seguridad automática"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "Actualización automática"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "Actualización automática desactivada"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "Actualización automática habilitada"
 
@@ -575,7 +581,7 @@ msgstr "Edición por lotes"
 msgid "Batch Modify"
 msgstr "Modificar por lotes"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "Actualización por lotes"
 
@@ -826,8 +832,7 @@ msgstr[1] "Cambiar Certificados"
 msgid "Changed Path"
 msgstr "Ruta cambiada"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "Canal"
 
@@ -1043,6 +1048,10 @@ msgstr "La finalización de código no está habilitada"
 msgid "Code Completion Model"
 msgstr "Modelo de finalización de código"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "Configuración de columnas"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "Comando"
@@ -1134,6 +1143,10 @@ msgstr "Configuraciones"
 msgid "Configure SSL"
 msgstr "Configurar SSL"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "Confirmar eliminación"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "Confirmar nueva contraseña"
@@ -1146,7 +1159,7 @@ msgstr "Conectado"
 msgid "Connection error, trying to reconnect..."
 msgstr "Error de conexión, intentando reconectar..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "Conexión perdida, por favor actualice la página."
 
@@ -1230,7 +1243,7 @@ msgstr ""
 "automáticamente en tu computadora."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1466,7 +1479,7 @@ msgstr "Detalles"
 msgid "Dev"
 msgstr "Dev"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "Desarrollo"
 
@@ -1566,8 +1579,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "Deshabilitar el flujo %{name} desde %{node} con éxito"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1671,16 +1683,15 @@ msgstr "Error al descargar la última versión"
 msgid "Downloading latest release"
 msgstr "Descargando la última versión"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "Suelta el archivo de certificado aquí"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "Suelta el archivo de clave privada aquí"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "Modo de ejecución de prueba habilitado"
 
@@ -1853,8 +1864,7 @@ msgid "Enable TOTP"
 msgstr "Habilitar TOTP"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1915,13 +1925,11 @@ msgstr "La configuración del entorno está vacía"
 msgid "Environment variables cleaned"
 msgstr "Variables de entorno limpiadas"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "Entornos"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "Error"
@@ -2076,6 +2084,11 @@ msgstr "Error al copiar el contenido del archivo: {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Error al copiar el directorio de configuración de Nginx: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "Error al copiar al portapapeles"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "No se pudo crear la copia de seguridad"
@@ -2525,8 +2538,7 @@ msgstr "Error al obtener los datos"
 msgid "Get dns credential error: {0}"
 msgstr "Error al obtener las credenciales DNS: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "Obtener error de información de versión"
 
@@ -2572,7 +2584,7 @@ msgstr "Un valor más alto significa una mejor reutilización de la conexión"
 msgid "History"
 msgstr "Historial"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "Inicio"
 
@@ -2636,7 +2648,7 @@ msgid "Import"
 msgstr "Importar"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "Importar Certificado"
 
@@ -2660,7 +2672,7 @@ msgstr "Indexando..."
 msgid "Indicator"
 msgstr "Indicador"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "Información"
 
@@ -2895,10 +2907,10 @@ msgstr "Dejar en blanco si no es requerido por su proveedor de ACME"
 msgid "Leave blank if you don't need this."
 msgstr "Déjelo en blanco si no lo necesita."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "Dejarlo en blanco no cambiará nada"
 
@@ -2931,11 +2943,11 @@ msgstr "Escuchando"
 msgid "Load Average:"
 msgstr "Promedios de carga:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "Cargar desde configuraciones"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "Cargado con éxito"
 
@@ -2965,7 +2977,7 @@ msgid "Loading data..."
 msgstr "Cargando datos..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2985,7 +2997,7 @@ msgstr "Ubicación"
 msgid "Locations"
 msgstr "Ubicaciones"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "Registro"
 
@@ -3195,7 +3207,7 @@ msgstr "Minuto"
 msgid "Minutes"
 msgstr "Minutos"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "Espejo"
 
@@ -3213,7 +3225,7 @@ msgid "Modify"
 msgstr "Modificar"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "Modificar Certificado"
 
@@ -3258,15 +3270,15 @@ msgstr "N/A"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3283,6 +3295,18 @@ msgstr "Nombre"
 msgid "Name or content"
 msgstr "Nombre o contenido"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "Espacio de nombres"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "Espacios de nombres"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "Es necesario habilitar el módulo stub_status"
@@ -3475,7 +3499,7 @@ msgstr "Comando de recarga de Nginx"
 msgid "Nginx reload failed: {0}"
 msgstr "Recarga de Nginx fallida: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Las operaciones de recarga de Nginx se han enviado a los nodos remotos"
 
@@ -3487,7 +3511,7 @@ msgstr "Nginx recargado con éxito"
 msgid "Nginx Restart Command"
 msgstr "Comando de reinicio de Nginx"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Las operaciones de reinicio de Nginx se han enviado a los nodos remotos"
 
@@ -3541,8 +3565,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf incluye el directorio streams-enabled"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3554,8 +3578,8 @@ msgstr "Nginx.conf incluye el directorio streams-enabled"
 msgid "No"
 msgstr "No"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "Sin acción"
 
@@ -3563,7 +3587,7 @@ msgstr "Sin acción"
 msgid "No data"
 msgstr "Sin datos"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "No se han seleccionado nodos"
 
@@ -3592,17 +3616,6 @@ msgstr "No hay upstreams configurados"
 msgid "Node"
 msgstr "Nodo"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "Grupos de nodos"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "Nombre del nodo"
@@ -3615,7 +3628,7 @@ msgstr "Secreto del nodo"
 msgid "Node Status"
 msgstr "Estado del nodo"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "Nodos"
 
@@ -3655,6 +3668,11 @@ msgstr ""
 "configuraciones o certificados, sincronícelos con anticipación a los nodos "
 "remotos."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "Nada que copiar"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "Notificación"
@@ -3722,12 +3740,11 @@ msgstr "Apagado"
 msgid "Official Document"
 msgstr "Documentación oficial"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "Desconectado"
 
@@ -3756,13 +3773,12 @@ msgstr "Encendido"
 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."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "En línea"
 
@@ -3910,7 +3926,7 @@ msgstr "El recurso de carga útil es nulo"
 msgid "Pending"
 msgstr "Pendiente"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "Realizar"
 
@@ -3954,6 +3970,10 @@ msgstr ""
 "Por favor, active el módulo stub_status para obtener estadísticas de "
 "solicitudes, recuento de conexiones, etc."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "Por favor ingrese"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -4105,17 +4125,15 @@ msgstr "Por favor, seleccione un archivo %{type} válido (%{extensions})"
 msgid "Please select at least one item"
 msgstr "Por favor seleccione al menos un elemento"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Por favor, seleccione al menos un nodo para recargar Nginx"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Por favor, seleccione al menos un nodo para reiniciar Nginx"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "Seleccione al menos un nodo para actualizar"
 
@@ -4141,13 +4159,12 @@ msgstr "El puerto 80 debe estar abierto para la validación del desafío HTTP-01
 msgid "Port Scanner"
 msgstr "Escáner de puertos"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Acción posterior a la sincronización"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "Prelanzamiento"
@@ -4287,6 +4304,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr "Servidores de nombres recursivos"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "Actualizar"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Regenerar respuesta"
@@ -4340,10 +4361,9 @@ msgstr "Nota de versión"
 msgid "Reload"
 msgstr "Recargar"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Recargar Nginx"
 
@@ -4367,7 +4387,7 @@ msgstr "Error al recargar Nginx remoto"
 msgid "Reload Remote Nginx Success"
 msgstr "Reinicio remoto de Nginx exitoso"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "La solicitud de recarga falló, por favor verifique su conexión de red"
 
@@ -4379,7 +4399,7 @@ msgstr "Recargando"
 msgid "Reloading nginx"
 msgstr "Recargando Nginx"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "Remoto"
 
@@ -4531,9 +4551,8 @@ msgstr "Respuestas"
 msgid "Restart"
 msgstr "Reiniciar"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Reiniciar Nginx"
 
@@ -4553,7 +4572,7 @@ msgstr "Error al reiniciar Nginx remoto"
 msgid "Restart Remote Nginx Success"
 msgstr "Reinicio remoto de Nginx exitoso"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "La solicitud de reinicio falló, por favor verifique su conexión de red"
 
@@ -4932,7 +4951,7 @@ msgstr "Enviar mensaje de prueba"
 msgid "Server"
 msgstr "Servidor"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "Error del servidor"
 
@@ -5090,7 +5109,8 @@ msgstr "Tiempo de espera entre iteraciones del administrador de caché"
 msgid "Sponsor"
 msgstr "Patrocinador"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "Contenido de certificado SSL"
 
@@ -5104,15 +5124,20 @@ msgstr ""
 msgid "SSL certificate file not found"
 msgstr "Archivo de certificado SSL no encontrado"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "Contenido de la llave del certificado SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "Ruta de la llave del certificado SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "Ruta del certificado SSL"
@@ -5143,8 +5168,7 @@ msgstr "Se requiere la ruta de la clave SSL cuando HTTPS está habilitado"
 msgid "SSO Login"
 msgstr "Acceso SSO"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "Estable"
@@ -5168,7 +5192,7 @@ msgstr "Estático"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5246,7 +5270,7 @@ msgstr "Puerto de estado stub"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status no está habilitado"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5336,10 +5360,9 @@ msgstr "Error de Configuración de Sincronización"
 msgid "Sync Config Success"
 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:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "Nodos de sincronización"
 
@@ -5354,7 +5377,7 @@ msgstr "Vista previa de sincronización"
 msgid "Sync strategy"
 msgstr "Estrategia de sincronización"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "Sincronizar con"
 
@@ -5376,7 +5399,7 @@ msgstr "Copia de seguridad del sistema"
 msgid "System Check"
 msgstr "Verificación del sistema"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "Usuario inicial del sistema"
 
@@ -5439,11 +5462,11 @@ msgstr ""
 "El número ICP solo debe contener letras, unicode, números, guiones, guiones "
 "bajos, dos puntos y puntos."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "La entrada no es un Certificado SSL"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "La entrada no es una clave de certificado SSL"
 
@@ -5482,11 +5505,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr "El parámetro de server_name es obligatorio"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "La ruta existe, pero el archivo no es un certificado"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "La ruta existe, pero el archivo no es una clave privada"
 
@@ -5562,9 +5585,9 @@ msgstr ""
 "Este directorio está protegido y no se puede eliminar por seguridad del "
 "sistema."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "Este campo es obligatorio"
 
@@ -5671,7 +5694,7 @@ msgstr ""
 "Esto restaurará los archivos de configuración y la base de datos. La "
 "interfaz de Nginx se reiniciará una vez completada la restauración."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Esto actualizará o reinstalará la interfaz de usuario de Nginx en "
@@ -5703,6 +5726,11 @@ msgstr ""
 msgid "Title"
 msgstr "Título"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "para confirmar la eliminación"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr ""
@@ -5868,9 +5896,8 @@ msgstr "Actualización exitosa"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5878,14 +5905,13 @@ msgstr "Actualización exitosa"
 msgid "Updated at"
 msgstr "Actualizado a"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Actualizar"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "Interfaz de usuario de Nginx actualizada en %{node} con éxito 🎉"
 
@@ -5893,8 +5919,7 @@ msgstr "Interfaz de usuario de Nginx actualizada en %{node} con éxito 🎉"
 msgid "Upgraded successfully"
 msgstr "Actualización exitosa"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Actualizando Nginx UI, por favor espere..."
 
@@ -5918,7 +5943,7 @@ msgstr "Aguas arriba"
 msgid "Upstream Name"
 msgstr "Nombre de la Transmisión"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "Tipo de prueba de upstream"
 
@@ -5926,7 +5951,7 @@ msgstr "Tipo de prueba de upstream"
 msgid "Uptime:"
 msgstr "Tiempo encendido:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5994,7 +6019,7 @@ msgstr "Verificar integridad del archivo de respaldo"
 msgid "Verify system requirements"
 msgstr "Verificar los requisitos del sistema"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "Versión"
 
@@ -6007,8 +6032,7 @@ msgstr "Ver"
 msgid "View all notifications"
 msgstr "Ver todas las notificaciones"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "Ver en GitHub"
 
@@ -6025,7 +6049,7 @@ msgstr "Visto"
 msgid "Waiting processes"
 msgstr "Procesos de espera"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -6112,11 +6136,11 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
 "Cuando habilites/deshabilites, elimines o guardes este sitio, los nodos "
-"establecidos en el Grupo de Nodos y los nodos seleccionados a continuación "
-"se sincronizarán."
+"establecidos en el espacio de nombres y los nodos seleccionados a "
+"continuación se sincronizarán."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -6149,7 +6173,7 @@ msgstr "Procesos de trabajo"
 msgid "Workers"
 msgstr "Trabajadores"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "Espacio de trabajo"
@@ -6175,8 +6199,8 @@ msgstr "Escribir la clave privada del certificado a disco"
 msgid "Writing certificate to disk"
 msgstr "Escribir certificado a disco"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -6184,7 +6208,7 @@ msgstr "Escribir certificado a disco"
 msgid "Yes"
 msgstr "Si"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6250,6 +6274,12 @@ msgstr "Tus códigos antiguos ya no funcionarán."
 msgid "Your passkeys"
 msgstr "Sus llaves de acceso"
 
+#~ msgid "Node Group"
+#~ msgstr "Grupo de nodos"
+
+#~ msgid "Node Groups"
+#~ msgstr "Grupos de nodos"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "Verifique si existe el directorio conf.d"
 
@@ -6310,9 +6340,6 @@ msgstr "Sus llaves de acceso"
 #~ msgid "Last Backup Error"
 #~ msgstr "Último error de copia de seguridad"
 
-#~ msgid "Apply"
-#~ msgstr "Aplicar"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "Acción masiva aplicada con éxito"
 

+ 169 - 142
app/src/language/fr_FR/app.po

@@ -104,6 +104,11 @@ msgstr "[Nginx UI] Écriture de la clé privée du certificat sur le disque"
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] Écriture du certificat sur le disque"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} copié dans le presse-papiers"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr ""
@@ -136,7 +141,7 @@ msgid "Access Logs"
 msgstr "Journaux d'accès"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "Utilisateur ACME"
 
@@ -148,10 +153,8 @@ msgstr "Action"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -235,7 +238,7 @@ msgstr ""
 "Ensuite, rafraîchissez cette page et cliquez à nouveau sur ajouter une clé "
 "d'accès."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "Tous"
 
@@ -282,6 +285,10 @@ msgstr "Type d'API"
 msgid "App"
 msgstr "Application"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "Appliquer"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "Arch"
@@ -320,7 +327,7 @@ msgstr "Êtes-vous sûr de vouloir supprimer définitivement ?"
 msgid "Are you sure you want to delete?"
 msgstr "Etes-vous sûr que vous voulez supprimer ?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 "Êtes-vous sûr de vouloir recharger Nginx sur les nœuds de synchronisation "
@@ -338,7 +345,7 @@ msgstr "Êtes-vous sûr de vouloir supprimer cet élément ?"
 msgid "Are you sure you want to remove this location?"
 msgstr "Voulez-vous vraiment supprimer cette localisation ?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr ""
 "Êtes-vous sûr de vouloir redémarrer Nginx sur les nœuds de synchronisation "
@@ -411,16 +418,15 @@ msgstr "Échec de la sauvegarde automatique"
 msgid "Auto Backup Storage Failed"
 msgstr "Échec du stockage de sauvegarde automatique"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "Actualisation automatique"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "Actualisation automatique désactivée"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "Actualisation automatique activée"
 
@@ -575,7 +581,7 @@ msgstr "Édition par lots"
 msgid "Batch Modify"
 msgstr "Modification par lot"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "Mise à jour par lot"
 
@@ -819,8 +825,7 @@ msgstr[0] "Certificat modifié"
 msgid "Changed Path"
 msgstr "Chemin modifié"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "Canal"
 
@@ -1039,6 +1044,10 @@ msgstr "La complétion de code n'est pas activée"
 msgid "Code Completion Model"
 msgstr "Modèle de complétion de code"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "Paramètres des colonnes"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "Commande"
@@ -1132,6 +1141,10 @@ msgstr "Configurations"
 msgid "Configure SSL"
 msgstr "Configurer SSL"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "Confirmer la suppression"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "Confirmer le nouveau mot de passe"
@@ -1144,7 +1157,7 @@ msgstr "Connecté"
 msgid "Connection error, trying to reconnect..."
 msgstr "Erreur de connexion, tentative de reconnexion..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "Connexion perdue, merci de recharger la page."
 
@@ -1228,7 +1241,7 @@ msgstr ""
 "téléchargés sur votre ordinateur."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1464,7 +1477,7 @@ msgstr "Détails"
 msgid "Dev"
 msgstr "Dev"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "Développement"
 
@@ -1564,8 +1577,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "Désactivation du flux %{name} depuis %{node} réussie"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1667,16 +1679,15 @@ msgstr "Erreur de téléchargement de la dernière version"
 msgid "Downloading latest release"
 msgstr "Téléchargement de la dernière version"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "Déposez le fichier de certificat ici"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "Déposer le fichier de clé privée ici"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "Mode de simulation activé"
 
@@ -1849,8 +1860,7 @@ msgid "Enable TOTP"
 msgstr "Activer TOTP"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1911,13 +1921,11 @@ msgstr "La configuration de l'environnement est vide"
 msgid "Environment variables cleaned"
 msgstr "Variables d'environnement nettoyées"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "Environnements"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "Erreur"
@@ -2070,6 +2078,11 @@ msgstr "Échec de la copie du contenu du fichier : {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Échec de la copie du répertoire de configuration Nginx : {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "Échec de la copie dans le presse-papiers"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "Échec de la création de la sauvegarde"
@@ -2521,8 +2534,7 @@ msgstr "Échec de la récupération des données"
 msgid "Get dns credential error: {0}"
 msgstr "Erreur lors de la récupération des informations d'identification DNS : {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "Erreur d'obtention des informations sur la version"
 
@@ -2568,7 +2580,7 @@ msgstr "Une valeur plus élevée signifie une meilleure réutilisation de la con
 msgid "History"
 msgstr "Historique"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "Menu principal"
 
@@ -2636,7 +2648,7 @@ msgid "Import"
 msgstr "Importer"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "Importer un certificat"
 
@@ -2660,7 +2672,7 @@ msgstr "Indexation en cours..."
 msgid "Indicator"
 msgstr "Indicateur"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "Info"
 
@@ -2895,10 +2907,10 @@ msgstr "Laissez vide si votre fournisseur ACME ne le requiert pas"
 msgid "Leave blank if you don't need this."
 msgstr "Laissez vide si vous n'en avez pas besoin."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "Laisser vide ne changera rien"
 
@@ -2931,11 +2943,11 @@ msgstr "En écoute"
 msgid "Load Average:"
 msgstr "Charge moyenne :"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "Charger à partir des options"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "Chargement réussi"
 
@@ -2965,7 +2977,7 @@ msgid "Loading data..."
 msgstr "Chargement des données..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2985,7 +2997,7 @@ msgstr "Emplacement"
 msgid "Locations"
 msgstr "Emplacements"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "Journal"
 
@@ -3195,7 +3207,7 @@ msgstr "Minute"
 msgid "Minutes"
 msgstr "Minutes"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "Miroir"
 
@@ -3213,7 +3225,7 @@ msgid "Modify"
 msgstr "Modifier"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "Modifier le certificat"
 
@@ -3258,15 +3270,15 @@ msgstr "N/D"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3283,6 +3295,18 @@ msgstr "Nom"
 msgid "Name or content"
 msgstr "Nom ou contenu"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "Espace de noms"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "Espaces de noms"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "Il faut activer le module stub_status"
@@ -3475,7 +3499,7 @@ msgstr "Commande de rechargement de Nginx"
 msgid "Nginx reload failed: {0}"
 msgstr "Échec du rechargement de Nginx : {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Les opérations de rechargement de Nginx ont été envoyées aux nœuds distants"
 
@@ -3487,7 +3511,7 @@ msgstr "Nginx a été rechargé avec succès"
 msgid "Nginx Restart Command"
 msgstr "Commande de redémarrage de Nginx"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Les opérations de redémarrage de Nginx ont été envoyées aux nœuds distants"
 
@@ -3541,8 +3565,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf inclut le répertoire streams-enabled"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3554,8 +3578,8 @@ msgstr "Nginx.conf inclut le répertoire streams-enabled"
 msgid "No"
 msgstr "Non"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "Aucune action"
 
@@ -3563,7 +3587,7 @@ msgstr "Aucune action"
 msgid "No data"
 msgstr "Aucune donnée"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "Aucun nœud sélectionné"
 
@@ -3591,17 +3615,6 @@ msgstr "Aucun amont configuré"
 msgid "Node"
 msgstr "Nœud"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "Groupes de nœuds"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "Nom du nœud"
@@ -3614,7 +3627,7 @@ msgstr "Secret du nœud"
 msgid "Node Status"
 msgstr "État du nœud"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "Nœuds"
 
@@ -3653,6 +3666,11 @@ msgstr ""
 "Notez que si le fichier de configuration inclut d'autres configurations ou "
 "certificats, veuillez les synchroniser avec les nœuds distants à l'avance."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "Rien à copier"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "Notification"
@@ -3720,12 +3738,11 @@ msgstr "Désactivé"
 msgid "Official Document"
 msgstr "Documentation officielle"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "Hors ligne"
 
@@ -3754,13 +3771,12 @@ msgstr "Activé"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Une fois la vérification terminée, les enregistrements seront supprimés."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "En ligne"
 
@@ -3910,7 +3926,7 @@ msgstr "La ressource de charge utile est nulle"
 msgid "Pending"
 msgstr "En attente"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "Exécuter"
 
@@ -3954,6 +3970,10 @@ msgstr ""
 "Veuillez activer le module stub_status pour obtenir des statistiques de "
 "requêtes, le nombre de connexions, etc."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "Veuillez saisir"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -4103,17 +4123,15 @@ msgstr "Veuillez sélectionner un fichier %{type} valide (%{extensions})"
 msgid "Please select at least one item"
 msgstr "Veuillez sélectionner au moins un élément"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Veuillez sélectionner au moins un nœud pour recharger Nginx"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Veuillez sélectionner au moins un nœud pour redémarrer Nginx"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "Veuillez sélectionner au moins un nœud à mettre à niveau"
 
@@ -4139,13 +4157,12 @@ msgstr "Le port 80 doit être ouvert pour la validation du défi HTTP-01"
 msgid "Port Scanner"
 msgstr "Scanner de ports"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Action post-synchronisation"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "Pré-version"
@@ -4285,6 +4302,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr "Serveurs de noms récursifs"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "Actualiser"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Régénérer la réponse"
@@ -4338,10 +4359,9 @@ msgstr "Note de version"
 msgid "Reload"
 msgstr "Recharger"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Recharger nginx"
 
@@ -4365,7 +4385,7 @@ msgstr "Erreur de rechargement de Nginx distant"
 msgid "Reload Remote Nginx Success"
 msgstr "Rechargement distant de Nginx réussi"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr ""
 "La demande de rechargement a échoué, veuillez vérifier votre connexion "
@@ -4379,7 +4399,7 @@ msgstr "Rechargement"
 msgid "Reloading nginx"
 msgstr "Rechargement de nginx"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "Distant"
 
@@ -4531,9 +4551,8 @@ msgstr "Réponses"
 msgid "Restart"
 msgstr "Redémarrer"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Redémarrer Nginx"
 
@@ -4553,7 +4572,7 @@ msgstr "Erreur de redémarrage de Nginx distant"
 msgid "Restart Remote Nginx Success"
 msgstr "Redémarrage distant de Nginx réussi"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "La demande de redémarrage a échoué, veuillez vérifier votre connexion réseau"
 
@@ -4932,7 +4951,7 @@ msgstr "Envoyer un message test"
 msgid "Server"
 msgstr "Serveur"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "Erreur du serveur"
 
@@ -5090,7 +5109,8 @@ msgstr "Temps d'attente entre les itérations du gestionnaire de cache"
 msgid "Sponsor"
 msgstr "Sponsor"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "Contenu du certificat SSL"
 
@@ -5104,15 +5124,20 @@ msgstr ""
 msgid "SSL certificate file not found"
 msgstr "Fichier de certificat SSL introuvable"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "Contenu de la clé du certificat SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "Chemin de la clé du certificat SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "Chemin du certificat SSL"
@@ -5143,8 +5168,7 @@ msgstr "Le chemin de la clé SSL est requis lorsque HTTPS est activé"
 msgid "SSO Login"
 msgstr "Connexion SSO"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "Stable"
@@ -5168,7 +5192,7 @@ msgstr "Statique"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5246,7 +5270,7 @@ msgstr "Port d'état stub"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status n'est pas activé"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5338,10 +5362,9 @@ msgstr "Erreur de synchronisation de la configuration"
 msgid "Sync Config Success"
 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:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "Nœuds de synchronisation"
 
@@ -5356,7 +5379,7 @@ msgstr "Aperçu de la synchronisation"
 msgid "Sync strategy"
 msgstr "Stratégie de synchronisation"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "Synchroniser vers"
 
@@ -5378,7 +5401,7 @@ msgstr "Sauvegarde du système"
 msgid "System Check"
 msgstr "Vérification du système"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "Utilisateur initial du système"
 
@@ -5441,11 +5464,11 @@ msgstr ""
 "Le numéro ICP ne doit contenir que des lettres, unicode, des chiffres, des "
 "traits d'union, des tirets, des deux-points et des points."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "L'entrée n'est pas un certificat SSL"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "L'entrée n'est pas une clé de certificat SSL"
 
@@ -5484,11 +5507,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr "Le paramètre server_name est requis"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "Le chemin existe, mais le fichier n'est pas un certificat"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "Le chemin existe, mais le fichier n'est pas une clé privée"
 
@@ -5565,9 +5588,9 @@ msgstr ""
 "Ce répertoire est protégé et ne peut pas être supprimé pour la sécurité du "
 "système."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "Ce champ est obligatoire"
 
@@ -5679,7 +5702,7 @@ msgstr ""
 "Cela restaurera les fichiers de configuration et la base de données. "
 "L'interface Nginx redémarrera une fois la restauration terminée."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Cela mettra à jour ou réinstallera l'interface Nginx sur %{nodeNames} vers "
@@ -5711,6 +5734,11 @@ msgstr ""
 msgid "Title"
 msgstr "Titre"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "pour confirmer la suppression"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr ""
@@ -5877,9 +5905,8 @@ msgstr "Mise à jour réussie"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5887,14 +5914,13 @@ msgstr "Mise à jour réussie"
 msgid "Updated at"
 msgstr "Mis à jour le"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Mettre à niveau"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "Nginx UI sur %{node} mis à jour avec succès 🎉"
 
@@ -5902,8 +5928,7 @@ msgstr "Nginx UI sur %{node} mis à jour avec succès 🎉"
 msgid "Upgraded successfully"
 msgstr "Mise à niveau réussie"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Mise à jour de Nginx UI, veuillez patienter..."
 
@@ -5927,7 +5952,7 @@ msgstr "Amont"
 msgid "Upstream Name"
 msgstr "Nom de l'amont"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "Type de test en amont"
 
@@ -5935,7 +5960,7 @@ msgstr "Type de test en amont"
 msgid "Uptime:"
 msgstr "Disponibilité :"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -6003,7 +6028,7 @@ msgstr "Vérifier l'intégrité du fichier de sauvegarde"
 msgid "Verify system requirements"
 msgstr "Vérifiez les exigences du système"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "Version"
 
@@ -6016,8 +6041,7 @@ msgstr "Voir"
 msgid "View all notifications"
 msgstr "Voir toutes les notifications"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "Voir sur GitHub"
 
@@ -6034,7 +6058,7 @@ msgstr "Vu"
 msgid "Waiting processes"
 msgstr "Processus d'attente"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -6122,10 +6146,10 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
 "Lorsque vous activez/désactivez, supprimez ou enregistrez ce site, les "
-"nœuds définis dans le Groupe de nœuds et les nœuds sélectionnés ci-dessous "
+"nœuds définis dans l'espace de noms et les nœuds sélectionnés ci-dessous "
 "seront synchronisés."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
@@ -6161,7 +6185,7 @@ msgstr "Processus de travail"
 msgid "Workers"
 msgstr "Workers"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "Espace de travail"
@@ -6187,8 +6211,8 @@ msgstr "Écriture de la clé privée du certificat sur le disque"
 msgid "Writing certificate to disk"
 msgstr "Écriture du certificat sur le disque"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -6196,7 +6220,7 @@ msgstr "Écriture du certificat sur le disque"
 msgid "Yes"
 msgstr "Oui"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6262,6 +6286,12 @@ msgstr "Vos anciens codes ne fonctionneront plus."
 msgid "Your passkeys"
 msgstr "Vos clés d'accès"
 
+#~ msgid "Node Group"
+#~ msgstr "Groupe de nœuds"
+
+#~ msgid "Node Groups"
+#~ msgstr "Groupes de nœuds"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "Vérifiez si le répertoire conf.d existe"
 
@@ -6322,9 +6352,6 @@ msgstr "Vos clés d'accès"
 #~ msgid "Last Backup Error"
 #~ msgstr "Dernière erreur de sauvegarde"
 
-#~ msgid "Apply"
-#~ msgstr "Appliquer"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "Action groupée appliquée avec succès"
 

+ 169 - 142
app/src/language/ja_JP/app.po

@@ -100,6 +100,11 @@ msgstr "[Nginx UI] 証明書の秘密鍵をディスクに書き込んでいま
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] 証明書をディスクに書き込み中"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} をクリップボードにコピーしました"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* グループ %{groupName} のノードと手動で選択したノードを含む"
@@ -130,7 +135,7 @@ msgid "Access Logs"
 msgstr "アクセスログ"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "ACMEユーザー"
 
@@ -142,10 +147,8 @@ msgstr "操作"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -227,7 +230,7 @@ msgstr "アドバンスモード"
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr "その後、このページを更新し、再度パスキーを追加をクリックしてください。"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "すべて"
 
@@ -270,6 +273,10 @@ msgstr "APIタイプ"
 msgid "App"
 msgstr "アプリ"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "適用"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "アーキテクチャ"
@@ -308,7 +315,7 @@ msgstr "完全に削除してもよろしいですか?"
 msgid "Are you sure you want to delete?"
 msgstr "削除してもよろしいですか?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr "以下の同期ノードでNginxを再読み込みしてもよろしいですか?"
 
@@ -324,7 +331,7 @@ msgstr "このアイテムを削除してもよろしいですか?"
 msgid "Are you sure you want to remove this location?"
 msgstr "このLocationを削除してもよろしいですか?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr "以下の同期ノードでNginxを再起動してもよろしいですか?"
 
@@ -395,16 +402,15 @@ msgstr "自動バックアップが失敗しました"
 msgid "Auto Backup Storage Failed"
 msgstr "自動バックアップの保存に失敗しました"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "自動更新"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "自動更新が無効になりました"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "自動更新が有効になりました"
 
@@ -549,7 +555,7 @@ msgstr "一括編集"
 msgid "Batch Modify"
 msgstr "一括変更"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "バッチアップグレード"
 
@@ -792,8 +798,7 @@ msgstr[0] "変更された証明書"
 msgid "Changed Path"
 msgstr "変更されたパス"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "チャンネル"
 
@@ -993,6 +998,10 @@ msgstr "コード補完が有効になっていません"
 msgid "Code Completion Model"
 msgstr "コード補完モデル"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "列の設定"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "コマンド"
@@ -1084,6 +1093,10 @@ msgstr "設定"
 msgid "Configure SSL"
 msgstr "SSLを設定する"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "削除の確認"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "新しいパスワードを確認"
@@ -1096,7 +1109,7 @@ msgstr "接続済み"
 msgid "Connection error, trying to reconnect..."
 msgstr "接続エラー、再接続を試みています..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "接続が失われました。ページを再読み込みしてください。"
 
@@ -1175,7 +1188,7 @@ msgid ""
 msgstr "Nginx 設定と Nginx UI 設定を含むシステムバックアップを作成します。バックアップファイルは自動的にコンピュータにダウンロードされます。"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1407,7 +1420,7 @@ msgstr "詳細"
 msgid "Dev"
 msgstr "Dev"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "開発"
 
@@ -1507,8 +1520,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "ストリーム %{name} を %{node} から無効化しました"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1610,16 +1622,15 @@ msgstr "最新リリースのダウンロードエラー"
 msgid "Downloading latest release"
 msgstr "最新リリースをダウンロード中"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "証明書ファイルをここにドロップ"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "秘密鍵ファイルをここにドロップ"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "ドライランモードが有効です"
 
@@ -1789,8 +1800,7 @@ msgid "Enable TOTP"
 msgstr "TOTP を有効にする"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1847,13 +1857,11 @@ msgstr "環境設定が空です"
 msgid "Environment variables cleaned"
 msgstr "環境変数をクリーンアップしました"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "環境"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "エラー"
@@ -2002,6 +2010,11 @@ msgstr "ファイルの内容のコピーに失敗しました: {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Nginx設定ディレクトリのコピーに失敗しました: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "クリップボードへのコピーに失敗しました"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "バックアップの作成に失敗しました"
@@ -2444,8 +2457,7 @@ msgstr "データの取得に失敗しました"
 msgid "Get dns credential error: {0}"
 msgstr "DNS認証情報の取得エラー: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "リリース情報の取得エラー"
 
@@ -2491,7 +2503,7 @@ msgstr "値が高いほど接続の再利用が効率的であることを意味
 msgid "History"
 msgstr "履歴"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "ホーム"
 
@@ -2550,7 +2562,7 @@ msgid "Import"
 msgstr "インポート"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "証明書をインポート"
 
@@ -2572,7 +2584,7 @@ msgstr "インデックス作成中..."
 msgid "Indicator"
 msgstr "指標"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "情報"
 
@@ -2803,10 +2815,10 @@ msgstr "ACMEプロバイダーが不要とする場合は空白のままにし
 msgid "Leave blank if you don't need this."
 msgstr "必要なければ空白のままにしてください。"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "空白のままにすると何も変更されません"
 
@@ -2839,11 +2851,11 @@ msgstr "リスニング"
 msgid "Load Average:"
 msgstr "平均負荷:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "設定から読み込む"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "読み込みに成功しました"
 
@@ -2873,7 +2885,7 @@ msgid "Loading data..."
 msgstr "データを読み込んでいます..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2893,7 +2905,7 @@ msgstr "ロケーション"
 msgid "Locations"
 msgstr "ロケーション"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "ログ"
 
@@ -3098,7 +3110,7 @@ msgstr "分"
 msgid "Minutes"
 msgstr "分"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "ミラー"
 
@@ -3116,7 +3128,7 @@ msgid "Modify"
 msgstr "変更"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "証明書を変更"
 
@@ -3161,15 +3173,15 @@ msgstr "該当なし"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3186,6 +3198,18 @@ msgstr "名前"
 msgid "Name or content"
 msgstr "名前または内容"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "名前空間"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "名前空間"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "stub_statusモジュールを有効にする必要があります"
@@ -3378,7 +3402,7 @@ msgstr "Nginx リロードコマンド"
 msgid "Nginx reload failed: {0}"
 msgstr "Nginx の再読み込みに失敗しました: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Nginxのリロード操作がリモートノードに送信されました"
 
@@ -3390,7 +3414,7 @@ msgstr "Nginxのリロードが成功しました"
 msgid "Nginx Restart Command"
 msgstr "Nginx 再起動コマンド"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Nginx の再起動操作がリモートノードに送信されました"
 
@@ -3442,8 +3466,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf には streams-enabled ディレクトリが含まれています"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3455,8 +3479,8 @@ msgstr "Nginx.conf には streams-enabled ディレクトリが含まれてい
 msgid "No"
 msgstr "いいえ"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "アクションなし"
 
@@ -3464,7 +3488,7 @@ msgstr "アクションなし"
 msgid "No data"
 msgstr "データなし"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "ノードが選択されていません"
 
@@ -3490,17 +3514,6 @@ msgstr "アップストリームが設定されていません"
 msgid "Node"
 msgstr "ノード"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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 "ノードグループ"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "ノードグループ"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "ノード名"
@@ -3513,7 +3526,7 @@ msgstr "ノードシークレット"
 msgid "Node Status"
 msgstr "ノードステータス"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "ノード"
 
@@ -3550,6 +3563,11 @@ msgid ""
 "certificates, please synchronize them to the remote nodes in advance."
 msgstr "設定ファイルに他の設定や証明書が含まれている場合は、事前にリモートノードに同期してください。"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "コピーするものはありません"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "通知"
@@ -3613,12 +3631,11 @@ msgstr "オフ"
 msgid "Official Document"
 msgstr "公式ドキュメント"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "オフライン"
 
@@ -3647,13 +3664,12 @@ msgstr "オン"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "検証が完了すると、レコードは削除されます。"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "オンライン"
 
@@ -3799,7 +3815,7 @@ msgstr "ペイロードリソースが nil です"
 msgid "Pending"
 msgstr "保留中"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "実行"
 
@@ -3841,6 +3857,10 @@ msgid ""
 "count, etc."
 msgstr "リクエスト統計や接続数などを取得するには、stub_statusモジュールを有効にしてください。"
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "入力してください"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -3975,17 +3995,15 @@ msgstr "有効な%{type}ファイルを選択してください(%{extensions}
 msgid "Please select at least one item"
 msgstr "少なくとも1つの項目を選択してください"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Nginxをリロードするには、少なくとも1つのノードを選択してください"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Nginx を再起動するには、少なくとも 1 つのノードを選択してください"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "少なくとも1つのノードを選択してアップグレードしてください"
 
@@ -4011,13 +4029,12 @@ msgstr "HTTP-01 チャレンジ検証のためにポート 80 を開放する必
 msgid "Port Scanner"
 msgstr "ポートスキャナー"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "同期後のアクション"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "プレリリース"
@@ -4151,6 +4168,10 @@ msgstr "リカバリーコードは、2FAデバイスへのアクセスを失っ
 msgid "Recursive Nameservers"
 msgstr "再帰的ネームサーバー"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "更新"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "応答を再生成"
@@ -4202,10 +4223,9 @@ msgstr "リリースノート"
 msgid "Reload"
 msgstr "再読み込み"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Nginx をリロード"
 
@@ -4229,7 +4249,7 @@ msgstr "リモートNginxの再読み込みエラー"
 msgid "Reload Remote Nginx Success"
 msgstr "リモートNginxのリロード成功"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "再読み込みリクエストが失敗しました。ネットワーク接続を確認してください"
 
@@ -4241,7 +4261,7 @@ msgstr "再読み込み中"
 msgid "Reloading nginx"
 msgstr "nginx をリロード中"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "リモート"
 
@@ -4390,9 +4410,8 @@ msgstr "レスポンス"
 msgid "Restart"
 msgstr "再起動"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Nginx を再起動"
 
@@ -4412,7 +4431,7 @@ msgstr "リモートNginxの再起動エラー"
 msgid "Restart Remote Nginx Success"
 msgstr "リモートNginxの再起動成功"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "再起動リクエストが失敗しました。ネットワーク接続を確認してください"
 
@@ -4783,7 +4802,7 @@ msgstr "テストメッセージを送信"
 msgid "Server"
 msgstr "サーバー"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "サーバーエラー"
 
@@ -4937,7 +4956,8 @@ msgstr "キャッシュマネージャーの反復処理間の待機時間"
 msgid "Sponsor"
 msgstr "スポンサー"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "SSL証明書の内容"
 
@@ -4949,15 +4969,20 @@ msgstr "SSL証明書ファイルはNginx設定ディレクトリの下にある
 msgid "SSL certificate file not found"
 msgstr "SSL証明書ファイルが見つかりません"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "SSL証明書キーの内容"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "SSL証明書キーパス"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "SSL証明書のパス"
@@ -4986,8 +5011,7 @@ msgstr "HTTPS を有効にするには SSL キーのパスが必要です"
 msgid "SSO Login"
 msgstr "SSOログイン"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "安定版"
@@ -5011,7 +5035,7 @@ msgstr "静的"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5087,7 +5111,7 @@ msgstr "スタブステータスポート"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status が有効になっていません"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5176,10 +5200,9 @@ msgstr "設定同期エラー"
 msgid "Sync Config Success"
 msgstr "設定の同期に成功しました"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "同期ノード"
 
@@ -5194,7 +5217,7 @@ msgstr "同期プレビュー"
 msgid "Sync strategy"
 msgstr "同期戦略"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "同期先"
 
@@ -5216,7 +5239,7 @@ msgstr "システムバックアップ"
 msgid "System Check"
 msgstr "システムチェック"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "システム初期ユーザー"
 
@@ -5274,11 +5297,11 @@ msgid ""
 "dashes, colons, and dots."
 msgstr "ICP番号には、文字、Unicode、数字、ハイフン、ダッシュ、コロン、およびドットのみを含める必要があります。"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "入力はSSL証明書ではありません"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "入力はSSL証明書キーではありません"
 
@@ -5309,11 +5332,11 @@ msgstr "ノード名には、文字、Unicode、数字、ハイフン、ダッ
 msgid "The parameter of server_name is required"
 msgstr "server_name のパラメーターが必要です"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "パスは存在しますが、ファイルは証明書ではありません"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "パスは存在しますが、ファイルは秘密鍵ではありません"
 
@@ -5381,9 +5404,9 @@ msgstr "この証明書はNginx UIによって管理されています"
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr "このディレクトリは保護されており、システムの安全のために削除できません。"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "このフィールドは必須です"
 
@@ -5476,7 +5499,7 @@ msgid ""
 "after the restoration is complete."
 msgstr "これにより設定ファイルとデータベースが復元されます。復元が完了すると、Nginx UI が再起動します。"
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "これにより、%{nodeNames} 上の Nginx UI が %{version} にアップグレードまたは再インストールされます。"
 
@@ -5504,6 +5527,11 @@ msgstr "ヒント: worker_processes または worker_connections を増やすこ
 msgid "Title"
 msgstr "タイトル"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "削除を確認する"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "失効を確認するには、下の欄に「失効」と入力してください:"
@@ -5661,9 +5689,8 @@ msgstr "更新に成功しました"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5671,14 +5698,13 @@ msgstr "更新に成功しました"
 msgid "Updated at"
 msgstr "更新日時"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "アップグレード"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "%{node} 上の Nginx UI のアップグレードに成功しました 🎉"
 
@@ -5686,8 +5712,7 @@ msgstr "%{node} 上の Nginx UI のアップグレードに成功しました 
 msgid "Upgraded successfully"
 msgstr "アップグレードに成功しました"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Nginx UI をアップグレード中です。しばらくお待ちください..."
 
@@ -5711,7 +5736,7 @@ msgstr "アップストリーム"
 msgid "Upstream Name"
 msgstr "アップストリーム名"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "アップストリームテストタイプ"
 
@@ -5719,7 +5744,7 @@ msgstr "アップストリームテストタイプ"
 msgid "Uptime:"
 msgstr "稼働時間:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5787,7 +5812,7 @@ msgstr "バックアップファイルの整合性を確認"
 msgid "Verify system requirements"
 msgstr "システム要件を確認する"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "バージョン"
 
@@ -5800,8 +5825,7 @@ msgstr "ビュー"
 msgid "View all notifications"
 msgstr "すべての通知を表示します"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "GitHubで見る"
 
@@ -5818,7 +5842,7 @@ msgstr "閲覧済み"
 msgid "Waiting processes"
 msgstr "待機プロセス"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -5896,8 +5920,8 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
-msgstr "このサイトを有効/無効にしたり、削除または保存すると、ノードグループで設定されたノードと以下で選択されたノードが同期されます。"
+"namespace and the nodes selected below will be synchronized."
+msgstr "このサイトを有効化/無効化、削除、または保存すると、名前空間に設定されたノードと以下で選択したノードが同期されます。"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5928,7 +5952,7 @@ msgstr "ワーカープロセス"
 msgid "Workers"
 msgstr "ワーカー"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "ワークスペース"
@@ -5954,8 +5978,8 @@ msgstr "証明書の秘密鍵をディスクに書き込んでいます"
 msgid "Writing certificate to disk"
 msgstr "証明書をディスクに書き込み中"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -5963,7 +5987,7 @@ msgstr "証明書をディスクに書き込み中"
 msgid "Yes"
 msgstr "はい"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6018,6 +6042,12 @@ msgstr "以前のコードはもう使えません。"
 msgid "Your passkeys"
 msgstr "あなたのパスキー"
 
+#~ msgid "Node Group"
+#~ msgstr "ノードグループ"
+
+#~ msgid "Node Groups"
+#~ msgstr "ノードグループ"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "conf.d ディレクトリが存在するか確認してください"
 
@@ -6076,9 +6106,6 @@ msgstr "あなたのパスキー"
 #~ msgid "Last Backup Error"
 #~ msgstr "最後のバックアップエラー"
 
-#~ msgid "Apply"
-#~ msgstr "適用"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "一括操作が正常に適用されました"
 

+ 169 - 142
app/src/language/ko_KR/app.po

@@ -98,6 +98,11 @@ msgstr "[Nginx UI] 인증서 개인 키를 디스크에 기록 중"
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] 인증서를 디스크에 작성 중"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label}이(가) 클립보드에 복사되었습니다"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* 그룹 %{groupName}의 노드와 수동으로 선택한 노드 포함"
@@ -128,7 +133,7 @@ msgid "Access Logs"
 msgstr "접근 로그"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "ACME 사용자"
 
@@ -140,10 +145,8 @@ msgstr "작업"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -225,7 +228,7 @@ msgstr "고급 모드"
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr "이후에 이 페이지를 새로 고치고 패스키 추가를 다시 클릭하세요."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "모두"
 
@@ -268,6 +271,10 @@ msgstr "API 유형"
 msgid "App"
 msgstr "앱"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "적용"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "아키텍처"
@@ -306,7 +313,7 @@ msgstr "정말 영구적으로 삭제하시겠습니까?"
 msgid "Are you sure you want to delete?"
 msgstr "정말 삭제하시겠습니까?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr "다음 동기화 노드에서 Nginx를 다시 로드하시겠습니까?"
 
@@ -322,7 +329,7 @@ msgstr "이 항목을 제거하시겠습니까?"
 msgid "Are you sure you want to remove this location?"
 msgstr "이 위치를 제거하시겠습니까?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr "다음 동기화 노드에서 Nginx를 다시 시작하시겠습니까?"
 
@@ -393,16 +400,15 @@ msgstr "자동 백업 실패"
 msgid "Auto Backup Storage Failed"
 msgstr "자동 백업 저장 실패"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "자동 새로고침"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "자동 새로고침이 비활성화되었습니다"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "자동 새로고침이 활성화되었습니다"
 
@@ -547,7 +553,7 @@ msgstr "일괄 편집"
 msgid "Batch Modify"
 msgstr "일괄 수정"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "배치 업그레이드"
 
@@ -791,8 +797,7 @@ msgstr[0] "변경된 인증서"
 msgid "Changed Path"
 msgstr "변경된 경로"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "채널"
 
@@ -990,6 +995,10 @@ msgstr "코드 완성이 활성화되지 않았습니다"
 msgid "Code Completion Model"
 msgstr "코드 완성 모델"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "열 설정"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "명령어"
@@ -1081,6 +1090,10 @@ msgstr "구성들"
 msgid "Configure SSL"
 msgstr "SSL 구성하기"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "삭제 확인"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "새 비밀번호 확인"
@@ -1093,7 +1106,7 @@ msgstr "연결됨"
 msgid "Connection error, trying to reconnect..."
 msgstr "연결 오류, 다시 연결 시도 중..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "연결이 끊어졌습니다. 페이지를 새로 고침하세요."
 
@@ -1172,7 +1185,7 @@ msgid ""
 msgstr "Nginx 구성 및 Nginx UI 설정을 포함한 시스템 백업을 생성합니다. 백업 파일은 자동으로 컴퓨터에 다운로드됩니다."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1404,7 +1417,7 @@ msgstr "세부 사항"
 msgid "Dev"
 msgstr "Dev"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "개발"
 
@@ -1504,8 +1517,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "스트림 %{name}을(를) %{node}에서 비활성화했습니다"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1607,16 +1619,15 @@ msgstr "최신 릴리스 다운로드 오류"
 msgid "Downloading latest release"
 msgstr "최신 릴리스 다운로드 중"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "인증서 파일을 여기에 놓으세요"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "개인 키 파일을 여기에 놓으세요"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "드라이런 모드 활성화됨"
 
@@ -1788,8 +1799,7 @@ msgid "Enable TOTP"
 msgstr "TOTP 활성화"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1846,13 +1856,11 @@ msgstr "환경 구성이 비어 있습니다"
 msgid "Environment variables cleaned"
 msgstr "환경 변수가 정리되었습니다"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "환경"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "오류"
@@ -2001,6 +2009,11 @@ msgstr "파일 내용 복사 실패: {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Nginx 설정 디렉토리 복사 실패: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "클립보드에 복사하지 못했습니다"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "백업 생성 실패"
@@ -2443,8 +2456,7 @@ msgstr "데이터 가져오기 실패"
 msgid "Get dns credential error: {0}"
 msgstr "DNS 자격 증명 가져오기 오류: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "릴리스 정보 가져오기 오류"
 
@@ -2490,7 +2502,7 @@ msgstr "값이 높을수록 연결 재사용이 더 좋다는 것을 의미합
 msgid "History"
 msgstr "기록"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "홈"
 
@@ -2549,7 +2561,7 @@ msgid "Import"
 msgstr "가져오기"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "인증서 가져오기"
 
@@ -2571,7 +2583,7 @@ msgstr "인덱싱 중..."
 msgid "Indicator"
 msgstr "지표"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "정보"
 
@@ -2802,10 +2814,10 @@ msgstr "ACME 공급자가 필요로 하지 않는 경우 비워 둡니다"
 msgid "Leave blank if you don't need this."
 msgstr "필요하지 않으면 비워 두세요."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "비워 두면 아무것도 변경되지 않습니다"
 
@@ -2838,11 +2850,11 @@ msgstr "수신 중"
 msgid "Load Average:"
 msgstr "평균 부하:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "설정에서 불러오기"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "성공적으로 로드되었습니다"
 
@@ -2872,7 +2884,7 @@ msgid "Loading data..."
 msgstr "데이터를 불러오는 중..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2892,7 +2904,7 @@ msgstr "위치"
 msgid "Locations"
 msgstr "위치들"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "로그"
 
@@ -3094,7 +3106,7 @@ msgstr "분"
 msgid "Minutes"
 msgstr "분"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "미러"
 
@@ -3112,7 +3124,7 @@ msgid "Modify"
 msgstr "수정"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "인증서 수정"
 
@@ -3157,15 +3169,15 @@ msgstr "해당 없음"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3182,6 +3194,18 @@ msgstr "이름"
 msgid "Name or content"
 msgstr "이름 또는 내용"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "네임스페이스"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "네임스페이스"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "stub_status 모듈을 활성화해야 합니다"
@@ -3374,7 +3398,7 @@ msgstr "Nginx 재로드 명령어"
 msgid "Nginx reload failed: {0}"
 msgstr "Nginx 다시 로드 실패: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Nginx 다시 로드 작업이 원격 노드로 전송되었습니다"
 
@@ -3386,7 +3410,7 @@ msgstr "Nginx 다시 로드 성공"
 msgid "Nginx Restart Command"
 msgstr "Nginx 재시작 명령어"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Nginx 재시작 작업이 원격 노드로 전송되었습니다"
 
@@ -3438,8 +3462,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf에는 streams-enabled 디렉토리가 포함됩니다"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3451,8 +3475,8 @@ msgstr "Nginx.conf에는 streams-enabled 디렉토리가 포함됩니다"
 msgid "No"
 msgstr "아니요"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "작업 없음"
 
@@ -3460,7 +3484,7 @@ msgstr "작업 없음"
 msgid "No data"
 msgstr "데이터 없음"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "선택된 노드 없음"
 
@@ -3486,17 +3510,6 @@ msgstr "업스트림이 구성되지 않았습니다"
 msgid "Node"
 msgstr "노드"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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 "노드 그룹"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "노드 그룹"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "노드 이름"
@@ -3509,7 +3522,7 @@ msgstr "노드 시크릿"
 msgid "Node Status"
 msgstr "노드 상태"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "노드"
 
@@ -3546,6 +3559,11 @@ msgid ""
 "certificates, please synchronize them to the remote nodes in advance."
 msgstr "구성 파일에 다른 구성이나 인증서가 포함되어 있는 경우, 미리 원격 노드에 동기화하십시오."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "복사할 내용이 없습니다"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "알림"
@@ -3609,12 +3627,11 @@ msgstr "끔"
 msgid "Official Document"
 msgstr "공식 문서"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "오프라인"
 
@@ -3643,13 +3660,12 @@ msgstr "켜짐"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "검증이 완료되면, 레코드는 제거됩니다."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "온라인"
 
@@ -3795,7 +3811,7 @@ msgstr "페이로드 리소스가 nil입니다"
 msgid "Pending"
 msgstr "대기 중"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "실행"
 
@@ -3837,6 +3853,10 @@ msgid ""
 "count, etc."
 msgstr "요청 통계, 연결 수 등을 얻으려면 stub_status 모듈을 활성화하세요."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "입력해 주세요"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -3969,17 +3989,15 @@ msgstr "유효한 %{type} 파일을 선택하세요 (%{extensions})"
 msgid "Please select at least one item"
 msgstr "최소한 하나의 항목을 선택해 주세요"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Nginx를 다시 로드하려면 최소한 하나의 노드를 선택하십시오"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Nginx를 다시 시작하려면 최소한 하나의 노드를 선택하세요"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "업그레이드할 노드를 최소한 하나 이상 선택해 주세요"
 
@@ -4005,13 +4023,12 @@ msgstr "HTTP-01 챌린지 검증을 위해 포트 80이 열려 있어야 합니
 msgid "Port Scanner"
 msgstr "포트 스캐너"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "동기화 후 작업"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "사전 출시"
@@ -4145,6 +4162,10 @@ msgstr "복구 코드는 2FA 장치에 대한 접근 권한을 잃었을 때 계
 msgid "Recursive Nameservers"
 msgstr "재귀적 네임서버"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "새로 고침"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "응답 재생성"
@@ -4196,10 +4217,9 @@ msgstr "릴리스 노트"
 msgid "Reload"
 msgstr "리로드"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Nginx 다시 로드"
 
@@ -4223,7 +4243,7 @@ msgstr "원격 Nginx 다시 로드 오류"
 msgid "Reload Remote Nginx Success"
 msgstr "원격 Nginx 다시 로드 성공"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "다시 로드 요청이 실패했습니다. 네트워크 연결을 확인하세요"
 
@@ -4235,7 +4255,7 @@ msgstr "리로딩 중"
 msgid "Reloading nginx"
 msgstr "Nginx 리로딩 중"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "원격"
 
@@ -4386,9 +4406,8 @@ msgstr "응답"
 msgid "Restart"
 msgstr "재시작"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Nginx 다시 시작"
 
@@ -4408,7 +4427,7 @@ msgstr "원격 Nginx 재시작 오류"
 msgid "Restart Remote Nginx Success"
 msgstr "원격 Nginx 재시작 성공"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "재시작 요청이 실패했습니다. 네트워크 연결을 확인해 주세요"
 
@@ -4779,7 +4798,7 @@ msgstr "테스트 메시지 전송"
 msgid "Server"
 msgstr "서버"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "서버 오류"
 
@@ -4933,7 +4952,8 @@ msgstr "캐시 관리자 반복 간 대기 시간"
 msgid "Sponsor"
 msgstr "스폰서"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "SSL 인증서 내용"
 
@@ -4945,15 +4965,20 @@ msgstr "SSL 인증서 파일은 Nginx 구성 디렉터리 아래에 있어야 
 msgid "SSL certificate file not found"
 msgstr "SSL 인증서 파일을 찾을 수 없음"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "SSL 인증서키 콘텐츠"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "SSL 인증서 키 경로"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "SSL 인증서 경로"
@@ -4982,8 +5007,7 @@ msgstr "HTTPS가 활성화된 경우 SSL 키 경로가 필요합니다"
 msgid "SSO Login"
 msgstr "SSO 로그인"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "안정적"
@@ -5007,7 +5031,7 @@ msgstr "정적"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5083,7 +5107,7 @@ msgstr "스텁 상태 포트"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status가 활성화되지 않았습니다"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5172,10 +5196,9 @@ msgstr "구성 동기화 오류"
 msgid "Sync Config Success"
 msgstr "구성 동기화 성공"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "동기화 노드"
 
@@ -5190,7 +5213,7 @@ msgstr "동기화 미리보기"
 msgid "Sync strategy"
 msgstr "동기화 전략"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "동기화 대상"
 
@@ -5212,7 +5235,7 @@ msgstr "시스템 백업"
 msgid "System Check"
 msgstr "시스템 점검"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "시스템 초기 사용자"
 
@@ -5270,11 +5293,11 @@ msgid ""
 "dashes, colons, and dots."
 msgstr "ICP 번호는 문자, 유니코드, 숫자, 하이픈, 대시, 콜론 및 점만 포함해야 합니다."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "입력이 SSL 인증서가 아닙니다"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "입력한 내용이 SSL 인증서 키가 아닙니다"
 
@@ -5305,11 +5328,11 @@ msgstr "노드 이름에는 문자, 유니코드, 숫자, 하이픈, 대시, 콜
 msgid "The parameter of server_name is required"
 msgstr "server_name 매개변수가 필요합니다"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "경로는 존재하지만, 파일이 인증서가 아닙니다"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "경로는 존재하지만 파일은 개인 키가 아닙니다"
 
@@ -5377,9 +5400,9 @@ msgstr "이 인증서는 Nginx UI에서 관리됩니다"
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr "이 디렉터리는 보호되어 있으며 시스템 안전을 위해 삭제할 수 없습니다."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "이 필드는 필수입니다"
 
@@ -5471,7 +5494,7 @@ msgid ""
 "after the restoration is complete."
 msgstr "이 작업은 구성 파일과 데이터베이스를 복원합니다. 복원이 완료되면 Nginx UI가 재시작됩니다."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "이 작업은 %{nodeNames}의 Nginx UI를 %{version}으로 업그레이드하거나 재설치합니다."
 
@@ -5499,6 +5522,11 @@ msgstr "팁: worker_processes 또는 worker_connections를 증가시켜 동시 
 msgid "Title"
 msgstr "제목"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "삭제 확인"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "취소를 확인하려면 아래 필드에 \"취소\"를 입력하세요:"
@@ -5654,9 +5682,8 @@ msgstr "성공적으로 업데이트되었습니다"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5664,14 +5691,13 @@ msgstr "성공적으로 업데이트되었습니다"
 msgid "Updated at"
 msgstr "업데이트됨"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "업그레이드"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "%{node}에서 Nginx UI 업그레이드 성공 🎉"
 
@@ -5679,8 +5705,7 @@ msgstr "%{node}에서 Nginx UI 업그레이드 성공 🎉"
 msgid "Upgraded successfully"
 msgstr "성공적으로 업그레이드됨"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Nginx UI를 업그레이드하는 중입니다. 잠시 기다려주세요..."
 
@@ -5704,7 +5729,7 @@ msgstr "업스트림"
 msgid "Upstream Name"
 msgstr "업스트림 이름"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "업스트림 테스트 유형"
 
@@ -5712,7 +5737,7 @@ msgstr "업스트림 테스트 유형"
 msgid "Uptime:"
 msgstr "가동 시간:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5780,7 +5805,7 @@ msgstr "백업 파일 무결성 확인"
 msgid "Verify system requirements"
 msgstr "시스템 요구 사항을 확인하십시오"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "버전"
 
@@ -5793,8 +5818,7 @@ msgstr "보기"
 msgid "View all notifications"
 msgstr "모든 알림 보기"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "GitHub에서 보기"
 
@@ -5811,7 +5835,7 @@ msgstr "확인됨"
 msgid "Waiting processes"
 msgstr "대기 과정"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -5888,8 +5912,8 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
-msgstr "이 사이트를 활성화/비활성화하거나 삭제 또는 저장할 때, 노드 그룹에 설정된 노드와 아래에서 선택한 노드가 동기화됩니다."
+"namespace and the nodes selected below will be synchronized."
+msgstr "이 사이트를 활성화/비활성화, 삭제 또는 저장할 때 네임스페이스에 설정된 노드와 아래에서 선택한 노드가 동기화됩니다."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5920,7 +5944,7 @@ msgstr "작업자 프로세스"
 msgid "Workers"
 msgstr "워커"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "작업 공간"
@@ -5946,8 +5970,8 @@ msgstr "인증서 개인 키를 디스크에 쓰기"
 msgid "Writing certificate to disk"
 msgstr "인증서를 디스크에 쓰기"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -5955,7 +5979,7 @@ msgstr "인증서를 디스크에 쓰기"
 msgid "Yes"
 msgstr "예"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6012,6 +6036,12 @@ msgstr "이전 코드는 더 이상 작동하지 않습니다."
 msgid "Your passkeys"
 msgstr "귀하의 패스키"
 
+#~ msgid "Node Group"
+#~ msgstr "노드 그룹"
+
+#~ msgid "Node Groups"
+#~ msgstr "노드 그룹"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "conf.d 디렉터리가 존재하는지 확인하세요"
 
@@ -6070,9 +6100,6 @@ msgstr "귀하의 패스키"
 #~ msgid "Last Backup Error"
 #~ msgstr "마지막 백업 오류"
 
-#~ msgid "Apply"
-#~ msgstr "적용"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "일괄 작업을 적용했습니다"
 

+ 174 - 127
app/src/language/messages.pot

@@ -86,6 +86,11 @@ msgstr ""
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr ""
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr ""
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr ""
@@ -117,7 +122,7 @@ msgstr ""
 
 #: src/routes/modules/certificates.ts:20
 #: src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr ""
 
@@ -130,9 +135,9 @@ msgstr ""
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
 #: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
+#: src/views/namespace/columns.ts:84
 #: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160
@@ -218,7 +223,7 @@ msgstr ""
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr ""
 
@@ -259,6 +264,10 @@ msgstr ""
 msgid "App"
 msgstr ""
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr ""
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr ""
@@ -298,7 +307,7 @@ msgstr ""
 msgid "Are you sure you want to delete?"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 
@@ -314,7 +323,7 @@ msgstr ""
 msgid "Are you sure you want to remove this location?"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr ""
 
@@ -385,16 +394,16 @@ msgstr ""
 msgid "Auto Backup Storage Failed"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:165
 #: src/views/nginx_log/NginxLog.vue:150
+#: src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr ""
 
@@ -541,7 +550,7 @@ msgstr ""
 msgid "Batch Modify"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr ""
 
@@ -783,7 +792,7 @@ msgstr[1] ""
 msgid "Changed Path"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:160
+#: src/views/node/BatchUpgrader.vue:160
 #: src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr ""
@@ -934,6 +943,10 @@ msgstr ""
 msgid "Code Completion Model"
 msgstr ""
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr ""
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr ""
@@ -1025,6 +1038,10 @@ msgstr ""
 msgid "Configure SSL"
 msgstr ""
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr ""
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr ""
@@ -1037,7 +1054,7 @@ msgstr ""
 msgid "Connection error, trying to reconnect..."
 msgstr ""
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr ""
 
@@ -1115,7 +1132,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:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1349,7 +1366,7 @@ msgstr ""
 msgid "Dev"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr ""
 
@@ -1449,8 +1466,8 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60
+#: src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1554,15 +1571,15 @@ msgstr ""
 msgid "Downloading latest release"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:192
+#: src/views/node/BatchUpgrader.vue:192
 #: src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr ""
@@ -1731,8 +1748,8 @@ msgid "Enable TOTP"
 msgstr ""
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69
+#: src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1790,13 +1807,11 @@ msgstr ""
 msgid "Environment variables cleaned"
 msgstr ""
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr ""
 
-#: src/constants/index.ts:22
+#: src/constants/index.ts:23
 #: src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
@@ -1942,6 +1957,11 @@ msgstr ""
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr ""
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr ""
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr ""
@@ -2379,7 +2399,7 @@ msgstr ""
 msgid "Get dns credential error: {0}"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:181
+#: src/views/node/BatchUpgrader.vue:181
 #: src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr ""
@@ -2426,7 +2446,7 @@ msgstr ""
 msgid "History"
 msgstr ""
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr ""
 
@@ -2479,7 +2499,7 @@ msgid "Import"
 msgstr ""
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr ""
 
@@ -2499,7 +2519,7 @@ msgstr ""
 msgid "Indicator"
 msgstr ""
 
-#: src/constants/index.ts:24
+#: src/constants/index.ts:25
 #: src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr ""
@@ -2728,10 +2748,10 @@ msgstr ""
 msgid "Leave blank if you don't need this."
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr ""
 
@@ -2764,11 +2784,11 @@ msgstr ""
 msgid "Load Average:"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr ""
 
@@ -2799,7 +2819,7 @@ msgstr ""
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
 #: src/components/NodeSelector/NodeSelector.vue:61
-#: src/constants/index.ts:41
+#: src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2819,7 +2839,7 @@ msgstr ""
 msgid "Locations"
 msgstr ""
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr ""
 
@@ -3010,7 +3030,7 @@ msgstr ""
 msgid "Minutes"
 msgstr ""
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr ""
 
@@ -3028,7 +3048,7 @@ msgid "Modify"
 msgstr ""
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr ""
 
@@ -3073,15 +3093,17 @@ msgstr ""
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
+#: src/views/namespace/columns.ts:9
 #: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3099,6 +3121,18 @@ msgstr ""
 msgid "Name or content"
 msgstr ""
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr ""
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr ""
@@ -3294,7 +3328,7 @@ msgstr ""
 msgid "Nginx reload failed: {0}"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr ""
 
@@ -3306,7 +3340,7 @@ msgstr ""
 msgid "Nginx Restart Command"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr ""
 
@@ -3357,8 +3391,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr ""
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108
@@ -3371,8 +3405,8 @@ msgstr ""
 msgid "No"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr ""
 
@@ -3380,7 +3414,7 @@ msgstr ""
 msgid "No data"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr ""
 
@@ -3404,18 +3438,6 @@ msgstr ""
 msgid "Node"
 msgstr ""
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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 ""
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr ""
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr ""
@@ -3428,7 +3450,8 @@ msgstr ""
 msgid "Node Status"
 msgstr ""
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11
+#: src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr ""
 
@@ -3463,6 +3486,11 @@ msgstr ""
 msgid "Note, if the configuration file include other configurations or certificates, please synchronize them to the remote nodes in advance."
 msgstr ""
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr ""
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr ""
@@ -3524,12 +3552,12 @@ msgstr ""
 msgid "Official Document"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106
+#: src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr ""
 
@@ -3559,13 +3587,13 @@ msgstr ""
 msgid "Once the verification is complete, the records will be removed."
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99
+#: src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr ""
 
@@ -3709,7 +3737,7 @@ msgstr ""
 msgid "Pending"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr ""
 
@@ -3749,6 +3777,10 @@ msgstr ""
 msgid "Please enable the stub_status module to get request statistics, connection count, etc."
 msgstr ""
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr ""
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid "Please enter a name for the passkey you wish to create and click the OK button below."
 msgstr ""
@@ -3871,17 +3903,17 @@ msgstr ""
 msgid "Please select at least one item"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201
+#: src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222
+#: src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr ""
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr ""
 
@@ -3907,13 +3939,13 @@ msgstr ""
 msgid "Port Scanner"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168
+#: src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213
 #: src/views/system/Upgrade.vue:267
 msgid "Pre-release"
@@ -4046,6 +4078,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr ""
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr ""
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr ""
@@ -4095,11 +4131,11 @@ msgstr ""
 msgid "Reload"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104
+#: src/constants/index.ts:38
+#: src/views/node/Node.vue:209
+#: src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr ""
 
@@ -4123,7 +4159,7 @@ msgstr ""
 msgid "Reload Remote Nginx Success"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr ""
 
@@ -4135,7 +4171,7 @@ msgstr ""
 msgid "Reloading nginx"
 msgstr ""
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr ""
 
@@ -4284,9 +4320,9 @@ msgstr ""
 msgid "Restart"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230
+#: src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr ""
 
@@ -4306,7 +4342,7 @@ msgstr ""
 msgid "Restart Remote Nginx Success"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr ""
 
@@ -4679,7 +4715,7 @@ msgstr ""
 msgid "Server"
 msgstr ""
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr ""
 
@@ -4823,7 +4859,8 @@ msgstr ""
 msgid "Sponsor"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr ""
 
@@ -4835,15 +4872,20 @@ msgstr ""
 msgid "SSL certificate file not found"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr ""
@@ -4872,8 +4914,8 @@ msgstr ""
 msgid "SSO Login"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165
+#: src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210
 #: src/views/system/Upgrade.vue:261
 msgid "Stable"
@@ -4898,7 +4940,7 @@ msgstr ""
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120
 #: src/views/stream/columns.tsx:87
@@ -4973,7 +5015,7 @@ msgstr ""
 msgid "Stub_status is not enabled"
 msgstr ""
 
-#: src/constants/index.ts:25
+#: src/constants/index.ts:26
 #: src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
@@ -5062,10 +5104,10 @@ msgstr ""
 msgid "Sync Config Success"
 msgstr ""
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17
+#: src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr ""
 
@@ -5080,7 +5122,7 @@ msgstr ""
 msgid "Sync strategy"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr ""
 
@@ -5102,7 +5144,7 @@ msgstr ""
 msgid "System Check"
 msgstr ""
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr ""
 
@@ -5156,11 +5198,11 @@ msgstr ""
 msgid "The ICP Number should only contain letters, unicode, numbers, hyphens, dashes, colons, and dots."
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr ""
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr ""
 
@@ -5185,11 +5227,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr ""
 
@@ -5243,9 +5285,9 @@ msgstr ""
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr ""
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr ""
 
@@ -5319,7 +5361,7 @@ msgstr ""
 msgid "This will restore configuration files and database. Nginx UI will restart after the restoration is complete."
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 
@@ -5345,6 +5387,11 @@ msgstr ""
 msgid "Title"
 msgstr ""
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr ""
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr ""
@@ -5481,8 +5528,8 @@ msgstr ""
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113
 #: src/views/stream/columns.tsx:80
@@ -5492,14 +5539,14 @@ msgid "Updated at"
 msgstr ""
 
 #: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
+#: src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196
 #: src/views/system/Upgrade.vue:154
 #: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr ""
 
@@ -5507,7 +5554,7 @@ msgstr ""
 msgid "Upgraded successfully"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:88
+#: src/views/node/BatchUpgrader.vue:88
 #: src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr ""
@@ -5532,7 +5579,7 @@ msgstr ""
 msgid "Upstream Name"
 msgstr ""
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr ""
 
@@ -5540,7 +5587,7 @@ msgstr ""
 msgid "Uptime:"
 msgstr ""
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr ""
 
@@ -5610,7 +5657,7 @@ msgstr ""
 msgid "Verify system requirements"
 msgstr ""
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr ""
 
@@ -5624,7 +5671,7 @@ msgstr ""
 msgid "View all notifications"
 msgstr ""
 
-#: src/views/environments/list/BatchUpgrader.vue:235
+#: src/views/node/BatchUpgrader.vue:235
 #: src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr ""
@@ -5642,7 +5689,7 @@ msgstr ""
 msgid "Waiting processes"
 msgstr ""
 
-#: src/constants/index.ts:23
+#: src/constants/index.ts:24
 #: src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
@@ -5701,7 +5748,7 @@ msgstr ""
 
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:62
 #: src/views/stream/components/RightPanel/Basic.vue:57
-msgid "When you enable/disable, delete, or save this site, the nodes set in the Node Group and the nodes selected below will be synchronized."
+msgid "When you enable/disable, delete, or save this site, the nodes set in the namespace and the nodes selected below will be synchronized."
 msgstr ""
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
@@ -5732,7 +5779,7 @@ msgid "Workers"
 msgstr ""
 
 #: src/layouts/HeaderLayout.vue:62
-#: src/routes/index.ts:57
+#: src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr ""
@@ -5758,8 +5805,8 @@ msgstr ""
 msgid "Writing certificate to disk"
 msgstr ""
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -5767,7 +5814,7 @@ msgstr ""
 msgid "Yes"
 msgstr ""
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid "You are accessing this terminal over an insecure HTTP connection on a non-localhost domain. This may expose sensitive information."
 msgstr ""
 

+ 169 - 142
app/src/language/pt_PT/app.po

@@ -100,6 +100,11 @@ msgstr "[Nginx UI] A gravar a chave privada do certificado no disco"
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] A escrever o certificado no disco"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} copiado para a área de transferência"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* Inclui nós do grupo %{groupName} e nós selecionados manualmente"
@@ -130,7 +135,7 @@ msgid "Access Logs"
 msgstr "Logs de Acesso"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "Utilizador ACME"
 
@@ -142,10 +147,8 @@ msgstr "Acção"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -229,7 +232,7 @@ msgstr ""
 "Depois, atualize esta página e clique em adicionar chave de acesso "
 "novamente."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "Todos"
 
@@ -276,6 +279,10 @@ msgstr "Tipo de API"
 msgid "App"
 msgstr "Aplicação"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "Aplicar"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "Arquitetura"
@@ -314,7 +321,7 @@ msgstr "Tem a certeza de que pretende eliminar permanentemente?"
 msgid "Are you sure you want to delete?"
 msgstr "Tem certeza que pretende eliminar?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 "Tem a certeza que pretende recarregar o Nginx nos seguintes nós de "
@@ -332,7 +339,7 @@ msgstr "Tem certeza que pretende eliminar este item?"
 msgid "Are you sure you want to remove this location?"
 msgstr "Tem certeza que pretende eliminar este local?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr ""
 "Tem a certeza de que pretende reiniciar o Nginx nos seguintes nós de "
@@ -405,16 +412,15 @@ msgstr "Backup automático falhou"
 msgid "Auto Backup Storage Failed"
 msgstr "Falha no armazenamento de backup automático"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "Actualizar Automaticamente"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "Atualização automática desativada"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "Atualização automática ativada"
 
@@ -565,7 +571,7 @@ msgstr "Edição em Lote"
 msgid "Batch Modify"
 msgstr "Modificar em Massa"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "Actualização em Massa"
 
@@ -812,8 +818,7 @@ msgstr[1] "Certificados Alterados"
 msgid "Changed Path"
 msgstr "Caminho Alterado"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "Canal"
 
@@ -1028,6 +1033,10 @@ msgstr "A conclusão de código não está ativada"
 msgid "Code Completion Model"
 msgstr "Modelo de conclusão de código"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "Configurações de coluna"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "Comando"
@@ -1119,6 +1128,10 @@ msgstr "Configurações"
 msgid "Configure SSL"
 msgstr "Configurar SSL"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "Confirmar eliminação"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "Confirmar nova palavra-passe"
@@ -1131,7 +1144,7 @@ msgstr "Conectado"
 msgid "Connection error, trying to reconnect..."
 msgstr "Erro de conexão, tentando reconectar..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "Ligação perdida, por favor actualize a página."
 
@@ -1215,7 +1228,7 @@ msgstr ""
 "automaticamente para o seu computador."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1449,7 +1462,7 @@ msgstr "Detalhes"
 msgid "Dev"
 msgstr "Dev"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "Desenvolvimento"
 
@@ -1549,8 +1562,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "Desativar o fluxo %{name} de %{node} com sucesso"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1652,16 +1664,15 @@ msgstr "Erro de download da versão mais recente"
 msgid "Downloading latest release"
 msgstr "Descarregar última versão"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "Solte o arquivo de certificado aqui"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "Solte o arquivo de chave privada aqui"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "Modo Dry Run activado"
 
@@ -1834,8 +1845,7 @@ msgid "Enable TOTP"
 msgstr "Ativar TOTP"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1892,13 +1902,11 @@ msgstr "A configuração do ambiente está vazia"
 msgid "Environment variables cleaned"
 msgstr "Variáveis de ambiente limpas"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "Ambientes"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "Erro"
@@ -2051,6 +2059,11 @@ msgstr "Falha ao copiar o conteúdo do ficheiro: {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Falha ao copiar o diretório de configuração do Nginx: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "Falha ao copiar para a área de transferência"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "Falha ao criar cópia de segurança"
@@ -2500,8 +2513,7 @@ msgstr "Falha ao obter os dados"
 msgid "Get dns credential error: {0}"
 msgstr "Erro ao obter credenciais DNS: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "Erro ao obter informações de release"
 
@@ -2547,7 +2559,7 @@ msgstr "Um valor mais alto significa uma melhor reutilização da conexão"
 msgid "History"
 msgstr "Histórico"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "Início"
 
@@ -2613,7 +2625,7 @@ msgid "Import"
 msgstr "Importar"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "Importar Certificados"
 
@@ -2637,7 +2649,7 @@ msgstr "A indexar..."
 msgid "Indicator"
 msgstr "Indicador"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "Informação"
 
@@ -2872,10 +2884,10 @@ msgstr "Deixe em branco se não for exigido pelo seu fornecedor ACME"
 msgid "Leave blank if you don't need this."
 msgstr "Deixe em branco se não precisar disto."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "Deixar em branco não vai mudar nada"
 
@@ -2908,11 +2920,11 @@ msgstr "A escutar"
 msgid "Load Average:"
 msgstr "Média de Carga:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "Carregar a partir das configurações"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "Carregado com sucesso"
 
@@ -2942,7 +2954,7 @@ msgid "Loading data..."
 msgstr "A carregar dados..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2962,7 +2974,7 @@ msgstr "Localização"
 msgid "Locations"
 msgstr "Localizações"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "Log"
 
@@ -3171,7 +3183,7 @@ msgstr "Minuto"
 msgid "Minutes"
 msgstr "Minutos"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "Espelho"
 
@@ -3189,7 +3201,7 @@ msgid "Modify"
 msgstr "Modificar"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "Modificar Certificado"
 
@@ -3234,15 +3246,15 @@ msgstr "N/D"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3259,6 +3271,18 @@ msgstr "Nome"
 msgid "Name or content"
 msgstr "Nome ou conteúdo"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "Espaço de nomes"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "Espaços de nomes"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "É necessário ativar o módulo stub_status"
@@ -3451,7 +3475,7 @@ msgstr "Comando de Recarregamento do Nginx"
 msgid "Nginx reload failed: {0}"
 msgstr "Recarga do Nginx falhou: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "As operações de recarregamento do Nginx foram enviadas para os nós remotos"
 
@@ -3463,7 +3487,7 @@ msgstr "Nginx recarregado com sucesso"
 msgid "Nginx Restart Command"
 msgstr "Comando de reinício do Nginx"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "As operações de reinício do Nginx foram enviadas para os nós remotos"
 
@@ -3517,8 +3541,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf inclui o diretório streams-enabled"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3530,8 +3554,8 @@ msgstr "Nginx.conf inclui o diretório streams-enabled"
 msgid "No"
 msgstr "Não"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "Sem ação"
 
@@ -3539,7 +3563,7 @@ msgstr "Sem ação"
 msgid "No data"
 msgstr "Sem dados"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "Nenhum nó selecionado"
 
@@ -3567,17 +3591,6 @@ msgstr "Nenhum upstream configurado"
 msgid "Node"
 msgstr "Nó"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "Grupos de nós"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "Nome do nó"
@@ -3590,7 +3603,7 @@ msgstr "Segredo do Nó"
 msgid "Node Status"
 msgstr "Estado do Nó"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "Nós"
 
@@ -3629,6 +3642,11 @@ msgstr ""
 "Nota, se o ficheiro de configuração incluir outras configurações ou "
 "certificados, por favor sincronize-os para os nós remotos antecipadamente."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "Nada para copiar"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "Notificação"
@@ -3696,12 +3714,11 @@ msgstr "Desligado"
 msgid "Official Document"
 msgstr "Documentação oficial"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "Off-line"
 
@@ -3730,13 +3747,12 @@ msgstr "Ligado"
 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."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "On-line"
 
@@ -3884,7 +3900,7 @@ msgstr "O recurso de carga útil é nulo"
 msgid "Pending"
 msgstr "Pendente"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "Realizar"
 
@@ -3928,6 +3944,10 @@ msgstr ""
 "Por favor, ative o módulo stub_status para obter estatísticas de pedidos, "
 "contagem de conexões, etc."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "Por favor, insira"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -4074,17 +4094,15 @@ msgstr "Por favor, selecione um ficheiro %{type} válido (%{extensions})"
 msgid "Please select at least one item"
 msgstr "Por favor, selecione pelo menos um item"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Por favor, selecione pelo menos um nó para recarregar o Nginx"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Por favor, selecione pelo menos um nó para reiniciar o Nginx"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "Por favor, selecione pelo menos um nó para atualizar"
 
@@ -4110,13 +4128,12 @@ msgstr "A porta 80 deve estar aberta para validação do desafio HTTP-01"
 msgid "Port Scanner"
 msgstr "Scanner de portas"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Ação pós-sincronização"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "Pre-lançamento"
@@ -4255,6 +4272,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr "Nameservers recursivos"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "Atualizar"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Regerar a resposta"
@@ -4308,10 +4329,9 @@ msgstr "Nota de Lançamento"
 msgid "Reload"
 msgstr "Recarregar"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Recarregar Nginx"
 
@@ -4335,7 +4355,7 @@ msgstr "Erro ao Recarregar Nginx Remoto"
 msgid "Reload Remote Nginx Success"
 msgstr "Recarregamento remoto do Nginx bem-sucedido"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "O pedido de recarregamento falhou, por favor verifique a sua ligação à rede"
 
@@ -4347,7 +4367,7 @@ msgstr "Recarregando"
 msgid "Reloading nginx"
 msgstr "Recarregando Nginx"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "Remoto"
 
@@ -4501,9 +4521,8 @@ msgstr "Respostas"
 msgid "Restart"
 msgstr "Reiniciar"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Reiniciar Nginx"
 
@@ -4523,7 +4542,7 @@ msgstr "Erro ao reiniciar Nginx remoto"
 msgid "Restart Remote Nginx Success"
 msgstr "Reinício remoto do Nginx bem-sucedido"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "Pedido de reinício falhou, por favor verifique a sua ligação à rede"
 
@@ -4902,7 +4921,7 @@ msgstr "Enviar mensagem de teste"
 msgid "Server"
 msgstr "Servidor"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "Erro do servidor"
 
@@ -5058,7 +5077,8 @@ msgstr "Tempo de espera entre iterações do gestor de cache"
 msgid "Sponsor"
 msgstr "Patrocinador"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "Conteúdo do Certificado SSL"
 
@@ -5072,15 +5092,20 @@ msgstr ""
 msgid "SSL certificate file not found"
 msgstr "Ficheiro de certificado SSL não encontrado"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "Conteúdo da Chave do Certificado SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "Caminho para a Chave do Certificado SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "Caminho para o Certificado SSL"
@@ -5111,8 +5136,7 @@ msgstr "O caminho da chave SSL é necessário quando o HTTPS está ativado"
 msgid "SSO Login"
 msgstr "Autenticação SSO"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "Estável"
@@ -5136,7 +5160,7 @@ msgstr "Estático"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5214,7 +5238,7 @@ msgstr "Porta de estado stub"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status não está ativado"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5304,10 +5328,9 @@ msgstr "Erro de Configuração de Sincronização"
 msgid "Sync Config Success"
 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:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "Nós de sincronização"
 
@@ -5322,7 +5345,7 @@ msgstr "Pré-visualização de sincronização"
 msgid "Sync strategy"
 msgstr "Estratégia de sincronização"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "Sincronizar para"
 
@@ -5344,7 +5367,7 @@ msgstr "Cópia de segurança do sistema"
 msgid "System Check"
 msgstr "Verificação do sistema"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "Utilizador Inicial do Sistema"
 
@@ -5407,11 +5430,11 @@ msgstr ""
 "O número ICP deve conter apenas letras, unicode, números, hífens, traços, "
 "dois pontos e pontos."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "A valor introduzido não é um certificado SSL"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "O valor introduzido não é uma Chave de Certificado SSL"
 
@@ -5450,11 +5473,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr "O parâmetro de server_name é obrigatório"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "O caminho existe, mas o ficheiro não é um certificado"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "O caminho existe, mas o ficheiro não é uma chave privada"
 
@@ -5530,9 +5553,9 @@ msgstr ""
 "Este diretório está protegido e não pode ser eliminado por segurança do "
 "sistema."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "Este campo é mantatório"
 
@@ -5640,7 +5663,7 @@ msgstr ""
 "Isto irá restaurar os ficheiros de configuração e a base de dados. O Nginx "
 "UI irá reiniciar após a conclusão da restauração."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Isto vai actualizar ou reinstalar o Nginx UI em %{nodeNames} para "
@@ -5672,6 +5695,11 @@ msgstr ""
 msgid "Title"
 msgstr "Título"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "para confirmar a eliminação"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "Para confirmar a revogação, digite \"Revogar\" no campo abaixo:"
@@ -5835,9 +5863,8 @@ msgstr "Atualização bem-sucedida"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5845,14 +5872,13 @@ msgstr "Atualização bem-sucedida"
 msgid "Updated at"
 msgstr "Actualizado em"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Actualizar"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "Nginx UI no %{node} actualizado com sucesso 🎉"
 
@@ -5860,8 +5886,7 @@ msgstr "Nginx UI no %{node} actualizado com sucesso 🎉"
 msgid "Upgraded successfully"
 msgstr "Actualizado com sucesso"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Actualizando Nginx UI, aguarde por favor..."
 
@@ -5885,7 +5910,7 @@ msgstr "A montante"
 msgid "Upstream Name"
 msgstr "Nome do Upstream"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "Tipo de teste de upstream"
 
@@ -5893,7 +5918,7 @@ msgstr "Tipo de teste de upstream"
 msgid "Uptime:"
 msgstr "Uptime:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5961,7 +5986,7 @@ msgstr "Verificar integridade do ficheiro de backup"
 msgid "Verify system requirements"
 msgstr "Verificar requisitos do sistema"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "Versão"
 
@@ -5974,8 +5999,7 @@ msgstr "Ver"
 msgid "View all notifications"
 msgstr "Ver todas notificações"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "Ver no GitHub"
 
@@ -5992,7 +6016,7 @@ msgstr "Visualizado"
 msgid "Waiting processes"
 msgstr "Processos em espera"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -6079,10 +6103,10 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
 "Quando ativar/desativar, eliminar ou guardar este site, os nós definidos no "
-"Grupo de Nós e os nós selecionados abaixo serão sincronizados."
+"espaço de nomes e os nós selecionados abaixo serão sincronizados."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -6115,7 +6139,7 @@ msgstr "Processos de trabalho"
 msgid "Workers"
 msgstr "Workers"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "Espaço de Trabalho"
@@ -6141,8 +6165,8 @@ msgstr "Escrever chave privada do certificado ao disco"
 msgid "Writing certificate to disk"
 msgstr "Escrevendo certificado no disco"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -6150,7 +6174,7 @@ msgstr "Escrevendo certificado no disco"
 msgid "Yes"
 msgstr "Sim"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6216,6 +6240,12 @@ msgstr "Os seus códigos antigos não funcionarão mais."
 msgid "Your passkeys"
 msgstr "As suas chaves de acesso"
 
+#~ msgid "Node Group"
+#~ msgstr "Grupo de nós"
+
+#~ msgid "Node Groups"
+#~ msgstr "Grupos de nós"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "Verifique se o diretório conf.d existe"
 
@@ -6275,9 +6305,6 @@ msgstr "As suas chaves de acesso"
 #~ msgid "Last Backup Error"
 #~ msgstr "Último erro de backup"
 
-#~ msgid "Apply"
-#~ msgstr "Aplicar"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "Ação em massa aplicada com sucesso"
 

+ 171 - 143
app/src/language/ru_RU/app.po

@@ -104,6 +104,11 @@ msgstr "[Nginx UI] Запись закрытого ключа сертифика
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] Запись сертификата на диск"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} скопировано в буфер обмена"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* Включает узлы из группы %{groupName} и узлы, выбранные вручную"
@@ -134,7 +139,7 @@ msgid "Access Logs"
 msgstr "Журналы доступа"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "Пользователь ACME"
 
@@ -146,10 +151,8 @@ msgstr "Действие"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -231,7 +234,7 @@ msgstr "Расширенный режим"
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr "После этого обновите эту страницу и снова нажмите «Добавить ключ доступа»."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "Все"
 
@@ -276,6 +279,10 @@ msgstr "Тип API"
 msgid "App"
 msgstr "Приложение"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "Применить"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "Архитектура"
@@ -314,7 +321,7 @@ msgstr "Вы уверены, что хотите удалить безвозвр
 msgid "Are you sure you want to delete?"
 msgstr "Вы уверены, что хотите удалить?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 "Вы уверены, что хотите перезагрузить Nginx на следующих синхронизированных "
@@ -332,7 +339,7 @@ msgstr "Вы уверены, что хотите удалить этот эле
 msgid "Are you sure you want to remove this location?"
 msgstr "Вы уверены, что хотите удалить location?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr ""
 "Вы уверены, что хотите перезапустить Nginx на следующих синхронизированных "
@@ -405,16 +412,15 @@ msgstr "Автоматическое резервное копирование 
 msgid "Auto Backup Storage Failed"
 msgstr "Сбой хранения автоматической резервной копии"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "Автообновление"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "Автоматическое обновление отключено"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "Автоматическое обновление включено"
 
@@ -569,7 +575,7 @@ msgstr "Пакетное редактирование"
 msgid "Batch Modify"
 msgstr "Массовое изменение"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "Пакетное обновление"
 
@@ -816,8 +822,7 @@ msgstr[1] "Сертификаты изменены"
 msgid "Changed Path"
 msgstr "Путь изменён"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "Канал"
 
@@ -1031,6 +1036,10 @@ msgstr "Автодополнение кода не включено"
 msgid "Code Completion Model"
 msgstr "Модель автодополнения кода"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "Настройки столбцов"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "Команда"
@@ -1122,6 +1131,10 @@ msgstr "Конфигурации"
 msgid "Configure SSL"
 msgstr "Настроить SSL"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "Подтвердить удаление"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "Подтвердите новый пароль"
@@ -1134,7 +1147,7 @@ msgstr "Подключено"
 msgid "Connection error, trying to reconnect..."
 msgstr "Ошибка соединения, попытка переподключения..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "Соединение потеряно, пожалуйста, обновите страницу."
 
@@ -1218,7 +1231,7 @@ msgstr ""
 "компьютер."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1450,7 +1463,7 @@ msgstr "Детали"
 msgid "Dev"
 msgstr "Dev"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "Разработка"
 
@@ -1550,8 +1563,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "Поток %{name} отключен от %{node} успешно"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1653,16 +1665,15 @@ msgstr "Ошибка загрузки последней версии"
 msgid "Downloading latest release"
 msgstr "Загрузка последней версии"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "Перетащите файл сертификата сюда"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "Перетащите файл закрытого ключа сюда"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "Включен пробный режим"
 
@@ -1835,8 +1846,7 @@ msgid "Enable TOTP"
 msgstr "Включить TOTP"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1897,13 +1907,11 @@ msgstr "Конфигурация среды пуста"
 msgid "Environment variables cleaned"
 msgstr "Переменные окружения очищены"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "Окружения"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "Ошибка"
@@ -2056,6 +2064,11 @@ msgstr "Не удалось скопировать содержимое файл
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Не удалось скопировать каталог конфигурации Nginx: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "Не удалось скопировать в буфер обмена"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "Не удалось создать резервную копию"
@@ -2505,8 +2518,7 @@ msgstr "Не удалось получить данные"
 msgid "Get dns credential error: {0}"
 msgstr "Ошибка получения учетных данных DNS: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "Ошибка получения информации о выпуске"
 
@@ -2552,7 +2564,7 @@ msgstr "Более высокое значение означает лучшее
 msgid "History"
 msgstr "История"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "Главная"
 
@@ -2616,7 +2628,7 @@ msgid "Import"
 msgstr "Импорт"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "Импортировать сертификат"
 
@@ -2640,7 +2652,7 @@ msgstr "Индексация..."
 msgid "Indicator"
 msgstr "Индикатор"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "Информация"
 
@@ -2875,10 +2887,10 @@ msgstr "Оставьте пустым, если ваш провайдер ACME 
 msgid "Leave blank if you don't need this."
 msgstr "Оставьте пустым без изменений."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "Если оставить пустым, ничего не изменится"
 
@@ -2911,11 +2923,11 @@ msgstr "Ожидает"
 msgid "Load Average:"
 msgstr "Средняя нагрузка:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "Загрузить из настроек"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "Загружено успешно"
 
@@ -2945,7 +2957,7 @@ msgid "Loading data..."
 msgstr "Загрузка данных..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2965,7 +2977,7 @@ msgstr "Локация"
 msgid "Locations"
 msgstr "Локации"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "Журнал"
 
@@ -3174,7 +3186,7 @@ msgstr "Минута"
 msgid "Minutes"
 msgstr "Минуты"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "Зеркало"
 
@@ -3192,7 +3204,7 @@ msgid "Modify"
 msgstr "Изменить"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "Изменить сертификат"
 
@@ -3237,15 +3249,15 @@ msgstr "Н/Д"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3262,6 +3274,18 @@ msgstr "Имя"
 msgid "Name or content"
 msgstr "Имя или содержание"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "Пространство имен"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "Пространства имен"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "Необходимо включить модуль stub_status"
@@ -3454,7 +3478,7 @@ msgstr "Команда перезагрузки Nginx"
 msgid "Nginx reload failed: {0}"
 msgstr "Перезагрузка Nginx не удалась: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Операции перезагрузки Nginx были отправлены на удаленные узлы"
 
@@ -3466,7 +3490,7 @@ msgstr "Nginx успешно перезагружен"
 msgid "Nginx Restart Command"
 msgstr "Команда перезапуска Nginx"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Операции перезапуска Nginx были отправлены на удаленные узлы"
 
@@ -3520,8 +3544,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf включает каталог streams-enabled"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3533,8 +3557,8 @@ msgstr "Nginx.conf включает каталог streams-enabled"
 msgid "No"
 msgstr "Нет"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "Нет действия"
 
@@ -3542,7 +3566,7 @@ msgstr "Нет действия"
 msgid "No data"
 msgstr "Нет данных"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "Нет выбранных узлов"
 
@@ -3570,17 +3594,6 @@ msgstr "Нет настроенных апстримов"
 msgid "Node"
 msgstr "Узел"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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 "Группа узлов"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "Группы узлов"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "Имя узла"
@@ -3593,7 +3606,7 @@ msgstr "Секрет узла"
 msgid "Node Status"
 msgstr "Статус узла"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "Узлы"
 
@@ -3632,6 +3645,11 @@ msgstr ""
 "Примечание: если файл конфигурации включает другие настройки или "
 "сертификаты, пожалуйста, заранее синхронизируйте их с удалёнными узлами."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "Нечего копировать"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "Уведомление"
@@ -3699,12 +3717,11 @@ msgstr "Выкл"
 msgid "Official Document"
 msgstr "Официальная документация"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "Оффлайн"
 
@@ -3733,13 +3750,12 @@ msgstr "Вкл"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "После завершения проверки записи будут удалены."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "Онлайн"
 
@@ -3887,7 +3903,7 @@ msgstr "Ресурс полезной нагрузки равен nil"
 msgid "Pending"
 msgstr "В ожидании"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "Выполнить"
 
@@ -3931,6 +3947,10 @@ msgstr ""
 "Пожалуйста, включите модуль stub_status, чтобы получать статистику "
 "запросов, количество соединений и т. д."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "Пожалуйста, введите"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -4082,17 +4102,15 @@ msgstr "Пожалуйста, выберите действительный фа
 msgid "Please select at least one item"
 msgstr "Пожалуйста, выберите хотя бы один элемент"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Пожалуйста, выберите хотя бы один узел для перезагрузки Nginx"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Пожалуйста, выберите хотя бы один узел для перезапуска Nginx"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "Пожалуйста, выберите хотя бы один узел"
 
@@ -4118,13 +4136,12 @@ msgstr "Порт 80 должен быть открыт для проверки H
 msgid "Port Scanner"
 msgstr "Сканер портов"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Действие после синхронизации"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "Предварительный выпуск"
@@ -4263,6 +4280,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr "Рекурсивные DNS"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "Обновить"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Восстановить ответ"
@@ -4316,10 +4337,9 @@ msgstr "Что нового"
 msgid "Reload"
 msgstr "Перегрузить"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Перезагрузить Nginx"
 
@@ -4343,7 +4363,7 @@ msgstr "Ошибка перезагрузки удаленного Nginx"
 msgid "Reload Remote Nginx Success"
 msgstr "Удаленная перезагрузка Nginx успешно выполнена"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "Не удалось выполнить запрос на перезагрузку, проверьте подключение к сети"
 
@@ -4355,7 +4375,7 @@ msgstr "Перезагружается"
 msgid "Reloading nginx"
 msgstr "Перезагружается nginx"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "Удаленный"
 
@@ -4507,9 +4527,8 @@ msgstr "Ответы"
 msgid "Restart"
 msgstr "Перезапуск"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Перезапустить Nginx"
 
@@ -4529,7 +4548,7 @@ msgstr "Ошибка перезапуска удаленного Nginx"
 msgid "Restart Remote Nginx Success"
 msgstr "Удалённая перезагрузка Nginx успешно выполнена"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "Запрос на перезапуск не выполнен, проверьте подключение к сети"
 
@@ -4906,7 +4925,7 @@ msgstr "Отправить тестовое сообщение"
 msgid "Server"
 msgstr "Сервер"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "Ошибка сервера"
 
@@ -5062,7 +5081,8 @@ msgstr "Время ожидания между итерациями менедж
 msgid "Sponsor"
 msgstr "Спонсор"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "Содержимое SSL-сертификата"
 
@@ -5074,15 +5094,20 @@ msgstr "Файл SSL-сертификата должен находиться в
 msgid "SSL certificate file not found"
 msgstr "Файл SSL-сертификата не найден"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "Содержимое ключа SSL-сертификата"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "Путь к ключу SSL-сертификата"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "Путь к SSL сертификату"
@@ -5111,8 +5136,7 @@ msgstr "Путь к SSL-ключу обязателен при включени
 msgid "SSO Login"
 msgstr "SSO Вход"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "Стабильный"
@@ -5136,7 +5160,7 @@ msgstr "Статический"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5214,7 +5238,7 @@ msgstr "Порт состояния заглушки"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status не включен"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5304,10 +5328,9 @@ msgstr "Ошибка синхронизации конфигурации"
 msgid "Sync Config Success"
 msgstr "Синхронизация конфигурации успешна"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "Синхронизированные узлы"
 
@@ -5322,7 +5345,7 @@ msgstr "Предпросмотр синхронизации"
 msgid "Sync strategy"
 msgstr "Стратегия синхронизации"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "Синхронизировать с"
 
@@ -5344,7 +5367,7 @@ msgstr "Резервное копирование системы"
 msgid "System Check"
 msgstr "Проверка системы"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "Первоначальный пользователь системы"
 
@@ -5407,11 +5430,11 @@ msgstr ""
 "Номер ICP должен содержать только буквы, юникод, цифры, дефисы, тире, "
 "двоеточия и точки."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "Входные данные не являются SSL-сертификатом"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "Введенные данные не являются ключом SSL сертификата"
 
@@ -5450,11 +5473,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr "Параметр server_name обязателен"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "Путь существует, но файл не является сертификатом"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "Путь существует, но файл не является приватным ключом"
 
@@ -5528,9 +5551,9 @@ msgstr "Этот сертификат под управлением Nginx UI"
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr "Этот каталог защищен и не может быть удален для безопасности системы."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "Это поле обязательно для заполнения"
 
@@ -5635,7 +5658,7 @@ msgstr ""
 "Это восстановит файлы конфигурации и базу данных. Nginx UI перезапустится "
 "после завершения восстановления."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Это обновит или переустановит интерфейс Nginx на %{nodeNames} до версии "
@@ -5667,6 +5690,11 @@ msgstr ""
 msgid "Title"
 msgstr "Заголовок"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "подтвердить удаление"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "Для подтверждения отзыва введите \"Отозвать\" в поле ниже:"
@@ -5830,9 +5858,8 @@ msgstr "Успешно обновлено"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5840,14 +5867,13 @@ msgstr "Успешно обновлено"
 msgid "Updated at"
 msgstr "Обновлено в"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Обновление"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "Интерфейс Nginx на %{node} успешно обновлен 🎉"
 
@@ -5855,8 +5881,7 @@ msgstr "Интерфейс Nginx на %{node} успешно обновлен 
 msgid "Upgraded successfully"
 msgstr "Обновлено успешно"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Обновление Nginx UI, подождите..."
 
@@ -5880,7 +5905,7 @@ msgstr "Восходящий поток"
 msgid "Upstream Name"
 msgstr "Имя Upstream"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "Тип теста апстрима"
 
@@ -5888,7 +5913,7 @@ msgstr "Тип теста апстрима"
 msgid "Uptime:"
 msgstr "Аптайм:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5956,7 +5981,7 @@ msgstr "Проверить целостность файла резервной
 msgid "Verify system requirements"
 msgstr "Проверьте системные требования"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "Версия"
 
@@ -5969,8 +5994,7 @@ msgstr "Просмотр"
 msgid "View all notifications"
 msgstr "Просмотреть все уведомления"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "Посмотреть на GitHub"
 
@@ -5987,7 +6011,7 @@ msgstr "Просмотрено"
 msgid "Waiting processes"
 msgstr "Процессы ожидания"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -6074,10 +6098,11 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
-"При включении/отключении, удалении или сохранении этого сайта узлы, "
-"заданные в Группе узлов, и узлы, выбранные ниже, будут синхронизированы."
+"При включении/отключении, удалении или сохранении этого сайта будут "
+"синхронизированы узлы, установленные в пространстве имен, и узлы, выбранные "
+"ниже."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -6110,7 +6135,7 @@ msgstr "Рабочие процессы"
 msgid "Workers"
 msgstr "Рабочие процессы"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "Рабочее пространство"
@@ -6136,8 +6161,8 @@ msgstr "Запись закрытого ключа сертификата на 
 msgid "Writing certificate to disk"
 msgstr "Запись сертификата на диск"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -6145,7 +6170,7 @@ msgstr "Запись сертификата на диск"
 msgid "Yes"
 msgstr "Да"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6208,6 +6233,12 @@ msgstr "Ваши старые коды больше не будут работа
 msgid "Your passkeys"
 msgstr "Ваши ключи доступа"
 
+#~ msgid "Node Group"
+#~ msgstr "Группа узлов"
+
+#~ msgid "Node Groups"
+#~ msgstr "Группы узлов"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "Проверьте, существует ли каталог conf.d"
 
@@ -6267,9 +6298,6 @@ msgstr "Ваши ключи доступа"
 #~ msgid "Last Backup Error"
 #~ msgstr "Ошибка последнего резервного копирования"
 
-#~ msgid "Apply"
-#~ msgstr "Применить"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "Массовое действие успешно применено"
 

+ 170 - 143
app/src/language/tr_TR/app.po

@@ -100,6 +100,11 @@ msgstr "[Nginx UI] Sertifika özel anahtarı diske yazılıyor"
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] Sertifika diske yazılıyor"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} panoya kopyalandı"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* %{groupName} grubundan düğümler ve manuel olarak seçilen düğümler içerir"
@@ -130,7 +135,7 @@ msgid "Access Logs"
 msgstr "Erişim Günlükleri"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "ACME Kullanıcısı"
 
@@ -142,10 +147,8 @@ msgstr "Eylem"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -227,7 +230,7 @@ msgstr "Gelişmiş Mod"
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr "Daha sonra bu sayfayı yenileyin ve tekrar parola anahtarı ekle'ye tıklayın."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "Tümü"
 
@@ -274,6 +277,10 @@ msgstr "API Türü"
 msgid "App"
 msgstr "Uygulama"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "Uygula"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "Mimari"
@@ -312,7 +319,7 @@ msgstr "Kalıcı olarak silmek istediğinizden emin misiniz?"
 msgid "Are you sure you want to delete?"
 msgstr "Silmek istediğine emin misin?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 "Aşağıdaki senkronizasyon düğümlerinde Nginx'i yeniden yüklemek "
@@ -330,7 +337,7 @@ msgstr "Bu öğeyi kaldırmak istediğinizden emin misiniz?"
 msgid "Are you sure you want to remove this location?"
 msgstr "Bu konumu kaldırmak istediğinizden emin misiniz?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr ""
 "Aşağıdaki senkronizasyon düğümlerinde Nginx'i yeniden başlatmak "
@@ -403,16 +410,15 @@ msgstr "Otomatik Yedekleme Başarısız"
 msgid "Auto Backup Storage Failed"
 msgstr "Otomatik Yedekleme Depolama Başarısız"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "Otomatik Yenileme"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "Otomatik yenileme devre dışı bırakıldı"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "Otomatik yenileme etkinleştirildi"
 
@@ -559,7 +565,7 @@ msgstr "Toplu Düzenleme"
 msgid "Batch Modify"
 msgstr "Toplu Değiştirme"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "Toplu Yükseltme"
 
@@ -804,8 +810,7 @@ msgstr[1] "Değişen Sertifikalar"
 msgid "Changed Path"
 msgstr "Değişen Dosya Yolu"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "Kanal"
 
@@ -1024,6 +1029,10 @@ msgstr "Kod tamamlama etkin değil"
 msgid "Code Completion Model"
 msgstr "Kod Tamamlama Modeli"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "Sütun Ayarları"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "Komut"
@@ -1115,6 +1124,10 @@ msgstr "Yapılandırmalar"
 msgid "Configure SSL"
 msgstr "SSL'yi Yapılandırma"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "Silme Onayı"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "Yeni Şifreyi Onayla"
@@ -1127,7 +1140,7 @@ msgstr "Bağlandı"
 msgid "Connection error, trying to reconnect..."
 msgstr "Bağlantı hatası, yeniden bağlanılmaya çalışılıyor..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "Bağlantı kesildi, lütfen sayfayı yenileyin."
 
@@ -1210,7 +1223,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:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1444,7 +1457,7 @@ msgstr "Detaylar"
 msgid "Dev"
 msgstr "Dev"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "Geliştirme"
 
@@ -1544,8 +1557,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "Akış %{name}, %{node} üzerinden başarıyla devre dışı bırakıldı"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1649,16 +1661,15 @@ msgstr "En son sürümü indirme hatası"
 msgid "Downloading latest release"
 msgstr "En son sürüm indiriliyor"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "Sertifika dosyasını buraya bırakın"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "Özel anahtar dosyasını buraya bırakın"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "Deneme modu etkinleştirildi(Dry-run)"
 
@@ -1831,8 +1842,7 @@ msgid "Enable TOTP"
 msgstr "TOTP'yi Etkinleştir"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1891,13 +1901,11 @@ msgstr "Ortam yapılandırması boş"
 msgid "Environment variables cleaned"
 msgstr "Ortam değişkenleri temizlendi"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "Ortamlar"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "Hata"
@@ -2050,6 +2058,11 @@ msgstr "Dosya içeriği kopyalanamadı: {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Nginx yapılandırma dizini kopyalanamadı: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "Panoya kopyalama başarısız oldu"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "Yedek oluşturma başarısız oldu"
@@ -2499,8 +2512,7 @@ msgstr "Veri alınamadı"
 msgid "Get dns credential error: {0}"
 msgstr "DNS kimlik bilgisi alınırken hata: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "Sürüm bilgilerini alma hatası"
 
@@ -2546,7 +2558,7 @@ msgstr "Daha yüksek bir değer, daha iyi bağlantı yeniden kullanımı anlamı
 msgid "History"
 msgstr "Geçmiş"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "Anasayfa"
 
@@ -2614,7 +2626,7 @@ msgid "Import"
 msgstr "İçe Aktar"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "Sertifika İçe Aktar"
 
@@ -2638,7 +2650,7 @@ msgstr "Dizinleniyor..."
 msgid "Indicator"
 msgstr "Gösterge"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "Bilgi"
 
@@ -2873,10 +2885,10 @@ msgstr "ACME sağlayıcınız tarafından gerekli değilse boş bırakın"
 msgid "Leave blank if you don't need this."
 msgstr "Buna ihtiyacınız yoksa boş bırakın."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "Boş bırakmak hiçbir şeyi değiştirmeyecektir"
 
@@ -2909,11 +2921,11 @@ msgstr "Dinliyor"
 msgid "Load Average:"
 msgstr "Yük Ortalaması:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "Ayarlar'dan yükle"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "Başarıyla yüklendi"
 
@@ -2943,7 +2955,7 @@ msgid "Loading data..."
 msgstr "Veriler yükleniyor..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2963,7 +2975,7 @@ msgstr "Konum"
 msgid "Locations"
 msgstr "Konumlar"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "Günlük"
 
@@ -3171,7 +3183,7 @@ msgstr "Dakika"
 msgid "Minutes"
 msgstr "Dakika"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "Ayna"
 
@@ -3189,7 +3201,7 @@ msgid "Modify"
 msgstr "Değiştir"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "Sertifikayı Düzenle"
 
@@ -3234,15 +3246,15 @@ msgstr "Yok"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3259,6 +3271,18 @@ msgstr "İsim"
 msgid "Name or content"
 msgstr "Ad veya içerik"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "İsim alanı"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "İsim Alanları"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "stub_status modülünün etkinleştirilmesi gerekiyor"
@@ -3451,7 +3475,7 @@ msgstr "Nginx Yeniden Yükleme Komutu"
 msgid "Nginx reload failed: {0}"
 msgstr "Nginx yeniden yükleme başarısız: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Nginx yeniden yükleme işlemleri uzak düğümlere gönderildi"
 
@@ -3463,7 +3487,7 @@ msgstr "Nginx başarıyla yeniden yüklendi"
 msgid "Nginx Restart Command"
 msgstr "Nginx Yeniden Başlatma Komutu"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Nginx yeniden başlatma işlemleri uzak düğümlere gönderildi"
 
@@ -3517,8 +3541,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf, streams-enabled dizinini içerir"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3530,8 +3554,8 @@ msgstr "Nginx.conf, streams-enabled dizinini içerir"
 msgid "No"
 msgstr "Hayır"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "Eylem Yok"
 
@@ -3539,7 +3563,7 @@ msgstr "Eylem Yok"
 msgid "No data"
 msgstr "Veri yok"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "Hiçbir düğüm seçilmedi"
 
@@ -3567,17 +3591,6 @@ msgstr "Yapılandırılmış yukarı akış yok"
 msgid "Node"
 msgstr "Düğüm"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "Düğüm Grupları"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "Düğüm adı"
@@ -3590,7 +3603,7 @@ msgstr "Düğüm Sırrı"
 msgid "Node Status"
 msgstr "Düğüm Durumu"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "Düğümler"
 
@@ -3629,6 +3642,11 @@ msgstr ""
 "Not: Eğer yapılandırma dosyası başka yapılandırmalar veya sertifikalar "
 "içeriyorsa, lütfen bunları uzak düğümlere önceden senkronize edin."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "Kopyalanacak bir şey yok"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "Bildirim"
@@ -3696,12 +3714,11 @@ msgstr "Kapalı"
 msgid "Official Document"
 msgstr "Resmi Belge"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "Çevrimdışı"
 
@@ -3730,13 +3747,12 @@ msgstr "Açık"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Doğrulama tamamlandığında, kayıtlar kaldırılacaktır."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "Çevrimiçi"
 
@@ -3883,7 +3899,7 @@ msgstr "Yük kaynağı nil"
 msgid "Pending"
 msgstr "Beklemede"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "Uygula"
 
@@ -3927,6 +3943,10 @@ msgstr ""
 "İstek istatistikleri, bağlantı sayısı vb. bilgileri almak için lütfen "
 "stub_status modülünü etkinleştirin."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "Lütfen girin"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -4074,17 +4094,15 @@ msgstr "Lütfen geçerli bir %{type} dosyası seçin (%{extensions})"
 msgid "Please select at least one item"
 msgstr "Lütfen en az bir öğe seçin"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Lütfen Nginx'i yeniden yüklemek için en az bir düğüm seçin"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Lütfen Nginx'i yeniden başlatmak için en az bir düğüm seçin"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "Lütfen yükseltmek için en az bir düğüm seçin"
 
@@ -4110,13 +4128,12 @@ msgstr "HTTP-01 challenge doğrulaması için 80 numaralı port açık olmalıd
 msgid "Port Scanner"
 msgstr "Port Tarayıcı"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Senkronizasyon Sonrası İşlem"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "Ön Sürüm"
@@ -4254,6 +4271,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr "Özyinelemeli İsim Sunucuları"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "Yenile"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Yanıtı yeniden oluştur"
@@ -4307,10 +4328,9 @@ msgstr "Sürüm Notları"
 msgid "Reload"
 msgstr "Yeniden Yükle"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Nginx'i Yeniden Yükle"
 
@@ -4334,7 +4354,7 @@ msgstr "Uzak Nginx Yeniden Yükleme Hatası"
 msgid "Reload Remote Nginx Success"
 msgstr "Uzak Nginx Yeniden Yükleme Başarılı"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "Yeniden yükleme isteği başarısız oldu, lütfen ağ bağlantınızı kontrol edin"
 
@@ -4346,7 +4366,7 @@ msgstr "Yeniden Yükleniyor"
 msgid "Reloading nginx"
 msgstr "nginx yeniden yükleniyor"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "Uzak"
 
@@ -4507,9 +4527,8 @@ msgstr "Yanıtlar"
 msgid "Restart"
 msgstr "Yeniden Başlat"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Nginx'i Yeniden Başlat"
 
@@ -4529,7 +4548,7 @@ msgstr "Uzak Nginx Yeniden Başlatma Hatası"
 msgid "Restart Remote Nginx Success"
 msgstr "Uzak Nginx Yeniden Başlatma Başarılı"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "Yeniden başlatma isteği başarısız oldu, lütfen ağ bağlantınızı kontrol edin"
 
@@ -4904,7 +4923,7 @@ msgstr "Test mesajı gönder"
 msgid "Server"
 msgstr "Sunucu"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "Sunucu hatası"
 
@@ -5062,7 +5081,8 @@ msgstr "Önbellek yöneticisi yinelemeleri arasındaki bekleme süresi"
 msgid "Sponsor"
 msgstr "Sponsor"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "SSL Sertifika İçeriği"
 
@@ -5074,15 +5094,20 @@ msgstr "SSL sertifika dosyası Nginx yapılandırma dizini altında olmalıdır:
 msgid "SSL certificate file not found"
 msgstr "SSL sertifika dosyası bulunamadı"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "SSL Sertifika Anahtarı İçeriği"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "SSL Sertifika Anahtar Yolu"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "SSL Sertifika Yolu"
@@ -5111,8 +5136,7 @@ msgstr "HTTPS etkinleştirildiğinde SSL anahtar yolu gereklidir"
 msgid "SSO Login"
 msgstr "SSO Girişi"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "Kararlı"
@@ -5136,7 +5160,7 @@ msgstr "Statik"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5214,7 +5238,7 @@ msgstr "Stub Durum Portu"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status etkin değil"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5306,10 +5330,9 @@ msgstr "Yapılandırma Senkronizasyon Hatası"
 msgid "Sync Config Success"
 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:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "Senkronizasyon Düğümleri"
 
@@ -5324,7 +5347,7 @@ msgstr "Senkronizasyon Önizleme"
 msgid "Sync strategy"
 msgstr "Senkronizasyon stratejisi"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "Senkronize Et"
 
@@ -5346,7 +5369,7 @@ msgstr "Sistem Yedekleme"
 msgid "System Check"
 msgstr "Sistem Kontrolü"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "Sistem Başlangıç Kullanıcısı"
 
@@ -5409,11 +5432,11 @@ msgstr ""
 "ICP Numarası yalnızca harfler, unicode, sayılar, kısa çizgiler, uzun "
 "çizgiler, iki nokta üst üste ve noktalar içermelidir."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "Girdi bir SSL Sertifikası değil"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "Girdi bir SSL Sertifika Anahtarı değil"
 
@@ -5452,11 +5475,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr "server_name parametresi gereklidir"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "Yol mevcut, ancak dosya bir sertifika değil"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "Yol mevcut, ancak dosya bir özel anahtar değil"
 
@@ -5530,9 +5553,9 @@ msgstr "Bu sertifika Nginx UI tarafından yönetilmektedir"
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr "Bu dizin korumalıdır ve sistem güvenliği için silinemez."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "Bu alan zorunludur"
 
@@ -5636,7 +5659,7 @@ msgstr ""
 "Bu işlem yapılandırma dosyalarını ve veritabanını geri yükleyecektir. Geri "
 "yükleme tamamlandıktan sonra Nginx UI yeniden başlatılacaktır."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Bu işlem, %{nodeNames} üzerindeki Nginx UI'yi %{version} sürümüne "
@@ -5668,6 +5691,11 @@ msgstr ""
 msgid "Title"
 msgstr "Başlık"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "silmeyi onaylamak için"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "İptali onaylamak için lütfen aşağıdaki alana \"İptal\" yazın:"
@@ -5831,9 +5859,8 @@ msgstr "Başarıyla güncellendi"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5841,14 +5868,13 @@ msgstr "Başarıyla güncellendi"
 msgid "Updated at"
 msgstr "Güncellenme Tarihi"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Yükselt"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "%{node} üzerindeki Nginx UI başarıyla güncellendi 🎉"
 
@@ -5856,8 +5882,7 @@ msgstr "%{node} üzerindeki Nginx UI başarıyla güncellendi 🎉"
 msgid "Upgraded successfully"
 msgstr "Başarıyla yükseltildi"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Nginx UI güncelleniyor, lütfen bekleyin..."
 
@@ -5881,7 +5906,7 @@ msgstr "Yukarı Akış"
 msgid "Upstream Name"
 msgstr "Yukarı Akış Adı"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "Yukarı Akış Test Türü"
 
@@ -5889,7 +5914,7 @@ msgstr "Yukarı Akış Test Türü"
 msgid "Uptime:"
 msgstr "Çalışma Süresi:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5957,7 +5982,7 @@ msgstr "Yedek Dosya Bütünlüğünü Doğrula"
 msgid "Verify system requirements"
 msgstr "Sistem Gereksinimlerini Doğrulun"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "Sürüm"
 
@@ -5970,8 +5995,7 @@ msgstr "Görüntüle"
 msgid "View all notifications"
 msgstr "Tüm bildirimleri görüntüle"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "GitHub'da Görüntüle"
 
@@ -5988,7 +6012,7 @@ msgstr "Görüntülendi"
 msgid "Waiting processes"
 msgstr "Bekleme süreçleri"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -6074,11 +6098,11 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
 "Bu siteyi etkinleştirdiğinizde/devre dışı bıraktığınızda, sildiğinizde veya "
-"kaydettiğinizde, Düğüm Grubunda ayarlanan düğümler ve aşağıda seçilen "
-"düğümler senkronize edilecektir."
+"kaydettiğinizde, ad alanında ayarlanan düğümler ve aşağıda seçilen düğümler "
+"senkronize edilecektir."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -6111,7 +6135,7 @@ msgstr "Çalışan Süreçler"
 msgid "Workers"
 msgstr "Çalışanlar"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "Çalışma alanı"
@@ -6137,8 +6161,8 @@ msgstr "Sertifika özel anahtarı diske yazılıyor"
 msgid "Writing certificate to disk"
 msgstr "Sertifika diske yazılıyor"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -6146,7 +6170,7 @@ msgstr "Sertifika diske yazılıyor"
 msgid "Yes"
 msgstr "Evet"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6210,6 +6234,12 @@ msgstr "Eski kodlarınız artık çalışmayacak."
 msgid "Your passkeys"
 msgstr "Geçiş Anahtarlarınız"
 
+#~ msgid "Node Group"
+#~ msgstr "Düğüm Grubu"
+
+#~ msgid "Node Groups"
+#~ msgstr "Düğüm Grupları"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "conf.d dizininin var olup olmadığını kontrol edin"
 
@@ -6269,9 +6299,6 @@ msgstr "Geçiş Anahtarlarınız"
 #~ msgid "Last Backup Error"
 #~ msgstr "Son Yedekleme Hatası"
 
-#~ msgid "Apply"
-#~ msgstr "Uygula"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "Toplu işlem başarıyla uygulandı"
 

+ 169 - 142
app/src/language/uk_UA/app.po

@@ -104,6 +104,11 @@ msgstr "[Nginx UI] Запис приватного ключа сертифіка
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] Запис сертифіката на диск"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} скопійовано в буфер обміну"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* Включає вузли з групи %{groupName} та вузли, вибрані вручну"
@@ -134,7 +139,7 @@ msgid "Access Logs"
 msgstr "Логи доступу"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "ACME Логін"
 
@@ -146,10 +151,8 @@ msgstr "Дія"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -231,7 +234,7 @@ msgstr "Розширений режим"
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr "Після цього оновіть цю сторінку та натисніть «Додати ключ доступу» знову."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "Усі"
 
@@ -278,6 +281,10 @@ msgstr "API Тип"
 msgid "App"
 msgstr "Додаток"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "Застосувати"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "Архітектура"
@@ -316,7 +323,7 @@ msgstr "Ви впевнені, що хочете видалити назавжд
 msgid "Are you sure you want to delete?"
 msgstr "Ви впевнені, що хочете видалити?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr ""
 "Ви впевнені, що бажаєте перезавантажити Nginx на наступних вузлах "
@@ -334,7 +341,7 @@ msgstr "Ви впевнені, що хочете видалити цей еле
 msgid "Are you sure you want to remove this location?"
 msgstr "Ви впевнені, що хочете видалити цю локацію?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr ""
 "Ви впевнені, що хочете перезавантажити Nginx на вказаних синхронізованих "
@@ -407,16 +414,15 @@ msgstr "Автоматичне резервне копіювання не вда
 msgid "Auto Backup Storage Failed"
 msgstr "Не вдалося зберегти автоматичну резервну копію"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "Автоматичне оновлення"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "Автоматичне оновлення вимкнено"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "Автоматичне оновлення увімкнено"
 
@@ -569,7 +575,7 @@ msgstr "Групове редагування"
 msgid "Batch Modify"
 msgstr "Масове редагування"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "Групове оновлення"
 
@@ -813,8 +819,7 @@ msgstr[0] "Змінено сертифікат"
 msgid "Changed Path"
 msgstr "Змінений шлях"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "Канал"
 
@@ -1027,6 +1032,10 @@ msgstr "Автозавершення коду не ввімкнено"
 msgid "Code Completion Model"
 msgstr "Модель автодоповнення коду"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "Налаштування стовпців"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "Команда"
@@ -1118,6 +1127,10 @@ msgstr "Конфігурації"
 msgid "Configure SSL"
 msgstr "Налаштувати SSL"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "Підтвердити видалення"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "Підтвердити новий пароль"
@@ -1130,7 +1143,7 @@ msgstr "Підключено"
 msgid "Connection error, trying to reconnect..."
 msgstr "Помилка з'єднання, спроба повторного підключення..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "З'єднання, будь ласка, оновіть сторінку."
 
@@ -1214,7 +1227,7 @@ msgstr ""
 "комп’ютер."
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1518,7 +1531,7 @@ msgstr "Деталі"
 msgid "Dev"
 msgstr "Розробка"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "Розробка"
 
@@ -1618,8 +1631,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "Потік %{name} успішно вимкнено з %{node}"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1721,16 +1733,15 @@ msgstr "Помилка завантаження останнього реліз
 msgid "Downloading latest release"
 msgstr "Завантаження останнього релізу"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "Перетягніть файл сертифіката сюди"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "Перетягніть файл приватного ключа сюди"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "Увімкнено тестовий режим"
 
@@ -1903,8 +1914,7 @@ msgid "Enable TOTP"
 msgstr "Увімкнути TOTP"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1965,13 +1975,11 @@ msgstr "Конфігурація середовища порожня"
 msgid "Environment variables cleaned"
 msgstr "Змінні середовища очищено"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "Середовища"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "Помилка"
@@ -2124,6 +2132,11 @@ msgstr "Не вдалося скопіювати вміст файлу: {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Не вдалося скопіювати каталог конфігурації Nginx: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "Не вдалося скопіювати в буфер обміну"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "Не вдалося створити резервну копію"
@@ -2573,8 +2586,7 @@ msgstr "Не вдалося отримати дані"
 msgid "Get dns credential error: {0}"
 msgstr "Помилка отримання облікових даних DNS: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "Помилка отримання інформації про реліз"
 
@@ -2620,7 +2632,7 @@ msgstr "Вище значення означає краще повторне в
 msgid "History"
 msgstr "Історія"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "Головна"
 
@@ -2684,7 +2696,7 @@ msgid "Import"
 msgstr "Імпорт"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "Імпортувати сертифікат"
 
@@ -2708,7 +2720,7 @@ msgstr "Індексація..."
 msgid "Indicator"
 msgstr "Індикатор"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "Інформація"
 
@@ -2943,10 +2955,10 @@ msgstr "Залиште порожнім, якщо ваш ACME-провайдер
 msgid "Leave blank if you don't need this."
 msgstr "Залиште порожнім, якщо вам це не потрібно."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "Залишити порожнім — нічого не зміниться"
 
@@ -2979,11 +2991,11 @@ msgstr "Прослуховує"
 msgid "Load Average:"
 msgstr "Середнє навантаження:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "Завантажити з налаштувань"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "Успішно завантажено"
 
@@ -3013,7 +3025,7 @@ msgid "Loading data..."
 msgstr "Завантаження даних..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -3033,7 +3045,7 @@ msgstr "Розташування"
 msgid "Locations"
 msgstr "Розташування"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "Журнал"
 
@@ -3242,7 +3254,7 @@ msgstr "Хвилина"
 msgid "Minutes"
 msgstr "Хвилини"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "Дзеркало"
 
@@ -3260,7 +3272,7 @@ msgid "Modify"
 msgstr "Змінити"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "Редагувати сертифікат"
 
@@ -3305,15 +3317,15 @@ msgstr "Н/Д"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3330,6 +3342,18 @@ msgstr "Ім'я"
 msgid "Name or content"
 msgstr "Ім’я або вміст"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "Простір імен"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "Простори імен"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "Потрібно активувати модуль stub_status"
@@ -3522,7 +3546,7 @@ msgstr "Команда перезавантаження Nginx"
 msgid "Nginx reload failed: {0}"
 msgstr "Не вдалося перезавантажити Nginx: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Операції перезавантаження Nginx були відправлені на віддалені вузли"
 
@@ -3534,7 +3558,7 @@ msgstr "Nginx успішно перезавантажено"
 msgid "Nginx Restart Command"
 msgstr "Команда перезавантаження Nginx"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Операції перезапуску Nginx були відправлені на віддалені вузли"
 
@@ -3588,8 +3612,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf включає каталог streams-enabled"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3601,8 +3625,8 @@ msgstr "Nginx.conf включає каталог streams-enabled"
 msgid "No"
 msgstr "Ні"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "Без дії"
 
@@ -3610,7 +3634,7 @@ msgstr "Без дії"
 msgid "No data"
 msgstr "Немає даних"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "Не вибрано жодного вузла"
 
@@ -3638,17 +3662,6 @@ msgstr "Не налаштовано жодного апстріму"
 msgid "Node"
 msgstr "Вузол"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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 "Група вузлів"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "Групи вузлів"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "Ім’я вузла"
@@ -3661,7 +3674,7 @@ msgstr "Секрет вузла"
 msgid "Node Status"
 msgstr "Стан вузла"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "Вузли"
 
@@ -3700,6 +3713,11 @@ msgstr ""
 "Примітка: якщо файл конфігурації містить інші налаштування або сертифікати, "
 "будь ласка, синхронізуйте їх з віддаленими вузлами заздалегідь."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "Немає чого копіювати"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "Сповіщення"
@@ -3767,12 +3785,11 @@ msgstr "Вимкнено"
 msgid "Official Document"
 msgstr "Офіційна документація"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "Офлайн"
 
@@ -3801,13 +3818,12 @@ msgstr "Увімкнено"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "Після завершення перевірки записи будуть видалені."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "Онлайн"
 
@@ -3955,7 +3971,7 @@ msgstr "Ресурс навантаження є nil"
 msgid "Pending"
 msgstr "Очікується"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "Виконати"
 
@@ -3999,6 +4015,10 @@ msgstr ""
 "Будь ласка, увімкніть модуль stub_status, щоб отримати статистику запитів, "
 "кількість з’єднань тощо."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "Будь ласка, введіть"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -4146,17 +4166,15 @@ msgstr "Будь ласка, виберіть дійсний файл %{type} (%
 msgid "Please select at least one item"
 msgstr "Будь ласка, виберіть хоча б один елемент"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Будь ласка, виберіть принаймні один вузол для перезавантаження Nginx"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Будь ласка, виберіть принаймні один вузол для перезапуску Nginx"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "Будь ласка, виберіть принаймні один вузол для оновлення"
 
@@ -4182,13 +4200,12 @@ msgstr "Порт 80 має бути відкритим для перевірки
 msgid "Port Scanner"
 msgstr "Сканер портів"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Дія після синхронізації"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "Попередній випуск"
@@ -4328,6 +4345,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr "Рекурсивні сервери імен"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "Оновити"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Повторити відповідь"
@@ -4381,10 +4402,9 @@ msgstr "Примітки до версії"
 msgid "Reload"
 msgstr "Перезавантажити"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Перезавантажити Nginx"
 
@@ -4408,7 +4428,7 @@ msgstr "Помилка перезавантаження віддаленого N
 msgid "Reload Remote Nginx Success"
 msgstr "Успішне перезавантаження віддаленого Nginx"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr ""
 "Не вдалося виконати запит на перезавантаження, будь ласка, перевірте "
@@ -4422,7 +4442,7 @@ msgstr "Перезавантаження"
 msgid "Reloading nginx"
 msgstr "Перезавантаження nginx"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "Віддалено"
 
@@ -4574,9 +4594,8 @@ msgstr "Відповіді"
 msgid "Restart"
 msgstr "Перезавантажити"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Перезапустити Nginx"
 
@@ -4596,7 +4615,7 @@ msgstr "Помилка перезапуску віддаленого Nginx"
 msgid "Restart Remote Nginx Success"
 msgstr "Віддалений перезапуск Nginx успішний"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr ""
 "Не вдалося виконати запит на перезавантаження, будь ласка, перевірте "
@@ -4975,7 +4994,7 @@ msgstr "Надіслати тестове повідомлення"
 msgid "Server"
 msgstr "Сервер"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "Помилка сервера"
 
@@ -5135,7 +5154,8 @@ msgstr "Час очікування між ітераціями менеджер
 msgid "Sponsor"
 msgstr "Спонсор"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "Вміст SSL-сертифіката"
 
@@ -5147,15 +5167,20 @@ msgstr "Файл SSL-сертифіката повинен знаходитис
 msgid "SSL certificate file not found"
 msgstr "Файл SSL-сертифіката не знайдено"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "Вміст ключа SSL-сертифіката"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "Шлях до ключа SSL-сертифіката"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "Шлях до SSL-сертифікату"
@@ -5184,8 +5209,7 @@ msgstr "Шлях до SSL-ключа обов’язковий при ввімк
 msgid "SSO Login"
 msgstr "Вхід через SSO"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "Стабільна"
@@ -5209,7 +5233,7 @@ msgstr "Статичний"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5287,7 +5311,7 @@ msgstr "Порт статусу Stub"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status не увімкнено"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5377,10 +5401,9 @@ msgstr "Помилка синхронізації конфігурації"
 msgid "Sync Config Success"
 msgstr "Успішна синхронізація конфігурації"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "Синхронізовані вузли"
 
@@ -5395,7 +5418,7 @@ msgstr "Попередній перегляд синхронізації"
 msgid "Sync strategy"
 msgstr "Стратегія синхронізації"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "Синхронізувати з"
 
@@ -5417,7 +5440,7 @@ msgstr "Резервне копіювання системи"
 msgid "System Check"
 msgstr "Перевірка системи"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "Початковий користувач системи"
 
@@ -5480,11 +5503,11 @@ msgstr ""
 "Номер ICP повинен містити лише літери, unicode, цифри, дефіси, тире, "
 "двокрапки та крапки."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "Введені дані не є SSL-сертифікатом"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "Введений текст не є ключем SSL-сертифіката"
 
@@ -5523,11 +5546,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr "Параметр server_name є обов'язковим"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "Шлях існує, але файл не є сертифікатом"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "Шлях існує, але файл не є приватним ключем"
 
@@ -5603,9 +5626,9 @@ msgstr "Цей сертифікат керується Nginx UI"
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr "Цей каталог захищений і не може бути видалений для безпеки системи."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "Це поле обов'язкове"
 
@@ -5709,7 +5732,7 @@ msgstr ""
 "Це відновить файли конфігурації та базу даних. Nginx UI перезапуститься "
 "після завершення відновлення."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "Це оновить або перевстановить Nginx UI на %{nodeNames} до версії %{version}."
 
@@ -5739,6 +5762,11 @@ msgstr ""
 msgid "Title"
 msgstr "Назва"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "підтвердити видалення"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "Щоб підтвердити анулювання, введіть \"Анулювати\" у поле нижче:"
@@ -5902,9 +5930,8 @@ msgstr "Успішно оновлено"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5912,14 +5939,13 @@ msgstr "Успішно оновлено"
 msgid "Updated at"
 msgstr "Оновлено"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Оновити"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "Nginx UI на %{node} успішно оновлено 🎉"
 
@@ -5927,8 +5953,7 @@ msgstr "Nginx UI на %{node} успішно оновлено 🎉"
 msgid "Upgraded successfully"
 msgstr "Успішно оновлено"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Оновлення Nginx UI, зачекайте..."
 
@@ -5952,7 +5977,7 @@ msgstr "Вгору за течією"
 msgid "Upstream Name"
 msgstr "Назва апстріму"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "Тип тестування апстриму"
 
@@ -5960,7 +5985,7 @@ msgstr "Тип тестування апстриму"
 msgid "Uptime:"
 msgstr "Час роботи:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -6028,7 +6053,7 @@ msgstr "Перевірити цілісність резервної копії"
 msgid "Verify system requirements"
 msgstr "Перевірте системні вимоги"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "Версія"
 
@@ -6041,8 +6066,7 @@ msgstr "Переглянути"
 msgid "View all notifications"
 msgstr "Переглянути всі сповіщення"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "Переглянути на GitHub"
 
@@ -6059,7 +6083,7 @@ msgstr "Переглянутий"
 msgid "Waiting processes"
 msgstr "Процеси очікування"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -6146,10 +6170,10 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
 "Коли ви вмикаєте/вимикаєте, видаляєте або зберігаєте цей сайт, вузли, "
-"встановлені в Групі вузлів, і вузли, вибрані нижче, будуть синхронізовані."
+"встановлені в просторі імен, і вузли, вибрані нижче, будуть синхронізовані."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -6182,7 +6206,7 @@ msgstr "Робочі процеси"
 msgid "Workers"
 msgstr "Робочі процеси"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "Робоча область"
@@ -6208,8 +6232,8 @@ msgstr "Запис приватного ключа сертифіката на 
 msgid "Writing certificate to disk"
 msgstr "Запис сертифіката на диск"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -6217,7 +6241,7 @@ msgstr "Запис сертифіката на диск"
 msgid "Yes"
 msgstr "Так"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6279,6 +6303,12 @@ msgstr "Ваші старі коди більше не працюватимут
 msgid "Your passkeys"
 msgstr "Ваші ключі доступу"
 
+#~ msgid "Node Group"
+#~ msgstr "Група вузлів"
+
+#~ msgid "Node Groups"
+#~ msgstr "Групи вузлів"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "Перевірте, чи існує каталог conf.d"
 
@@ -6338,9 +6368,6 @@ msgstr "Ваші ключі доступу"
 #~ msgid "Last Backup Error"
 #~ msgstr "Помилка останнього резервного копіювання"
 
-#~ msgid "Apply"
-#~ msgstr "Застосувати"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "Групову дію успішно застосовано"
 

+ 170 - 143
app/src/language/vi_VN/app.po

@@ -95,6 +95,11 @@ msgstr "[Nginx UI] Đang ghi khóa riêng của chứng chỉ vào ổ đĩa"
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] Đang ghi chứng chỉ vào ổ đĩa"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} đã được sao chép vào bảng nhớ tạm"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* Bao gồm các nút từ nhóm %{groupName} và các nút được chọn thủ công"
@@ -125,7 +130,7 @@ msgid "Access Logs"
 msgstr "Log truy cập"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "Người dùng ACME"
 
@@ -137,10 +142,8 @@ msgstr "Hành động"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -222,7 +225,7 @@ msgstr "Nâng cao"
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr "Sau đó, làm mới trang này và nhấp vào thêm khóa truy cập một lần nữa."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "Tất cả"
 
@@ -269,6 +272,10 @@ msgstr "Loại API"
 msgid "App"
 msgstr "Ứng dụng"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "Áp dụng"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "Kiến trúc"
@@ -307,7 +314,7 @@ msgstr "Bạn có chắc chắn muốn xóa vĩnh viễn không?"
 msgid "Are you sure you want to delete?"
 msgstr "Bạn có chắc chắn muốn xóa không?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr "Bạn có chắc chắn muốn tải lại Nginx trên các nút đồng bộ sau không?"
 
@@ -323,7 +330,7 @@ msgstr "Bạn có chắc chắn muốn xóa mục này không?"
 msgid "Are you sure you want to remove this location?"
 msgstr "Bạn có chắc chắn muốn xóa vị trí này không?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr "Bạn có chắc chắn muốn khởi động lại Nginx trên các nút đồng bộ sau không?"
 
@@ -394,16 +401,15 @@ msgstr "Sao lưu tự động thất bại"
 msgid "Auto Backup Storage Failed"
 msgstr "Lưu trữ sao lưu tự động thất bại"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "Tự động làm mới"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "Tự động làm mới đã bị vô hiệu hóa"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "Cập nhật tự động đã được bật"
 
@@ -550,7 +556,7 @@ msgstr "Chỉnh sửa hàng loạt"
 msgid "Batch Modify"
 msgstr "Chỉnh sửa hàng loạt"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "Nâng cấp hàng loạt"
 
@@ -793,8 +799,7 @@ msgstr[0] "Chứng chỉ đã thay đổi"
 msgid "Changed Path"
 msgstr "Đường dẫn đã thay đổi"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "Kênh"
 
@@ -1006,6 +1011,10 @@ msgstr "Hoàn thành mã không được bật"
 msgid "Code Completion Model"
 msgstr "Mô hình hoàn thành mã"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "Cài đặt cột"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "Lệnh"
@@ -1097,6 +1106,10 @@ msgstr "Cấu hình"
 msgid "Configure SSL"
 msgstr "Cấu hình SSL"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "Xác nhận xóa"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "Xác nhận mật khẩu mới"
@@ -1109,7 +1122,7 @@ msgstr "Đã kết nối"
 msgid "Connection error, trying to reconnect..."
 msgstr "Lỗi kết nối, đang thử kết nối lại..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "Kết nối bị mất, xin vui lòng làm mới trang."
 
@@ -1190,7 +1203,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:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1422,7 +1435,7 @@ msgstr "Chi tiết"
 msgid "Dev"
 msgstr "Dev"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "Phát triển"
 
@@ -1522,8 +1535,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "Đã vô hiệu hóa luồng %{name} từ %{node} thành công"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1627,16 +1639,15 @@ msgstr "Đã có lỗi xảy ra khi tải về phiên bản mới nhất"
 msgid "Downloading latest release"
 msgstr "Đang tải phiên bản mới nhất"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "Thả tệp chứng chỉ vào đây"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "Thả tệp khóa riêng tư vào đây"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "Đã bật chế độ Dry run"
 
@@ -1808,8 +1819,7 @@ msgid "Enable TOTP"
 msgstr "Bật TOTP"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1866,13 +1876,11 @@ msgstr "Cấu hình môi trường trống"
 msgid "Environment variables cleaned"
 msgstr "Đã dọn dẹp biến môi trường"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "Môi trường"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "Lỗi"
@@ -2025,6 +2033,11 @@ msgstr "Không thể sao chép nội dung tệp: {0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "Không thể sao chép thư mục cấu hình Nginx: {0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "Sao chép vào bộ nhớ tạm thất bại"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "Không thể tạo bản sao lưu"
@@ -2473,8 +2486,7 @@ msgstr "Không thể lấy dữ liệu"
 msgid "Get dns credential error: {0}"
 msgstr "Lỗi khi lấy thông tin xác thực DNS: {0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "Lỗi lấy thông tin phát hành"
 
@@ -2520,7 +2532,7 @@ msgstr "Giá trị cao hơn có nghĩa là tái sử dụng kết nối tốt h
 msgid "History"
 msgstr "Lịch sử"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "Trang chủ"
 
@@ -2583,7 +2595,7 @@ msgid "Import"
 msgstr "Nhập"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "Nhập chứng chỉ"
 
@@ -2607,7 +2619,7 @@ msgstr "Đang lập chỉ mục..."
 msgid "Indicator"
 msgstr "Chỉ số"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "Thông tin"
 
@@ -2842,10 +2854,10 @@ msgstr "Để trống nếu nhà cung cấp ACME của bạn không yêu cầu"
 msgid "Leave blank if you don't need this."
 msgstr "Để trống nếu bạn không cần cái này."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "Để trống sẽ không thay đổi bất cứ điều gì"
 
@@ -2878,11 +2890,11 @@ msgstr "Đang lắng nghe"
 msgid "Load Average:"
 msgstr "Tải trung bình:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "Tải từ cài đặt"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "Tải thành công"
 
@@ -2912,7 +2924,7 @@ msgid "Loading data..."
 msgstr "Đang tải dữ liệu..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2932,7 +2944,7 @@ msgstr "Location"
 msgid "Locations"
 msgstr "Locations"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "Nhật ký"
 
@@ -3141,7 +3153,7 @@ msgstr "Phút"
 msgid "Minutes"
 msgstr "Phút"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "Gương"
 
@@ -3159,7 +3171,7 @@ msgid "Modify"
 msgstr "Sửa đổi"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "Sửa đổi chứng chỉ"
 
@@ -3204,15 +3216,15 @@ msgstr "Không có"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3229,6 +3241,18 @@ msgstr "Tên"
 msgid "Name or content"
 msgstr "Tên hoặc nội dung"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "Không gian tên"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "Không gian tên"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "Cần bật module stub_status"
@@ -3421,7 +3445,7 @@ msgstr "Lệnh Tải lại Nginx"
 msgid "Nginx reload failed: {0}"
 msgstr "Tải lại Nginx thất bại: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Các thao tác tải lại Nginx đã được gửi đến các nút từ xa"
 
@@ -3433,7 +3457,7 @@ msgstr "Nginx đã tải lại thành công"
 msgid "Nginx Restart Command"
 msgstr "Lệnh khởi động lại Nginx"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Các thao tác khởi động lại Nginx đã được gửi đến các nút từ xa"
 
@@ -3487,8 +3511,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf bao gồm thư mục streams-enabled"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3500,8 +3524,8 @@ msgstr "Nginx.conf bao gồm thư mục streams-enabled"
 msgid "No"
 msgstr "Không"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "Không hành động"
 
@@ -3509,7 +3533,7 @@ msgstr "Không hành động"
 msgid "No data"
 msgstr "Không có dữ liệu"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "Không có nút nào được chọn"
 
@@ -3537,17 +3561,6 @@ msgstr "Không có upstream nào được cấu hình"
 msgid "Node"
 msgstr "Nút"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "Nhóm nút"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "Tên nút"
@@ -3560,7 +3573,7 @@ msgstr "Bí mật nút"
 msgid "Node Status"
 msgstr "Trạng thái nút"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "Nút"
 
@@ -3599,6 +3612,11 @@ msgstr ""
 "Lưu ý, nếu tệp cấu hình bao gồm các cấu hình hoặc chứng chỉ khác, vui lòng "
 "đồng bộ chúng với các nút từ xa trước."
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "Không có gì để sao chép"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "Thông báo"
@@ -3664,12 +3682,11 @@ msgstr "Tắt"
 msgid "Official Document"
 msgstr "Tài liệu chính thức"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "Ngoại tuyến"
 
@@ -3698,13 +3715,12 @@ msgstr "Bật"
 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."
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "Trực tuyến"
 
@@ -3852,7 +3868,7 @@ msgstr "Tài nguyên tải trọng là nil"
 msgid "Pending"
 msgstr "Đang chờ"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "Thực hiện"
 
@@ -3896,6 +3912,10 @@ msgstr ""
 "Vui lòng bật module stub_status để nhận thống kê yêu cầu, số lượng kết nối, "
 "v.v."
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "Vui lòng nhập"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -4034,17 +4054,15 @@ msgstr "Vui lòng chọn tệp %{type} hợp lệ (%{extensions})"
 msgid "Please select at least one item"
 msgstr "Vui lòng chọn ít nhất một mục"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "Vui lòng chọn ít nhất một nút để tải lại Nginx"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "Vui lòng chọn ít nhất một nút để khởi động lại Nginx"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "Vui lòng chọn ít nhất một nút để nâng cấp"
 
@@ -4070,13 +4088,12 @@ msgstr "Cổng 80 phải được mở để xác thực thử thách HTTP-01"
 msgid "Port Scanner"
 msgstr "Trình quét cổng"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "Hành động sau đồng bộ"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "Bản phát hành trước"
@@ -4214,6 +4231,10 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgstr "Máy chủ tên đệ quy"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "Làm mới"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "Tạo lại câu trả lời"
@@ -4267,10 +4288,9 @@ msgstr "Ghi chú phát hành"
 msgid "Reload"
 msgstr "Tải lại"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "Tải lại Nginx"
 
@@ -4294,7 +4314,7 @@ msgstr "Lỗi tải lại Nginx từ xa"
 msgid "Reload Remote Nginx Success"
 msgstr "Tải lại Nginx từ xa thành công"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "Yêu cầu tải lại thất bại, vui lòng kiểm tra kết nối mạng của bạn"
 
@@ -4306,7 +4326,7 @@ msgstr "Đang tải lại"
 msgid "Reloading nginx"
 msgstr "Tải lại nginx"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "Từ xa"
 
@@ -4458,9 +4478,8 @@ msgstr "Phản hồi"
 msgid "Restart"
 msgstr "Khởi động lại"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "Khởi động lại Nginx"
 
@@ -4480,7 +4499,7 @@ msgstr "Lỗi khởi động lại Nginx từ xa"
 msgid "Restart Remote Nginx Success"
 msgstr "Khởi động lại Nginx từ xa thành công"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "Yêu cầu khởi động lại thất bại, vui lòng kiểm tra kết nối mạng của bạn"
 
@@ -4855,7 +4874,7 @@ msgstr "Gửi tin nhắn kiểm tra"
 msgid "Server"
 msgstr "Máy chủ"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "Lỗi máy chủ"
 
@@ -5011,7 +5030,8 @@ msgstr "Thời gian chờ giữa các lần lặp của trình quản lý bộ n
 msgid "Sponsor"
 msgstr "Nhà tài trợ"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "Nội dung chứng chỉ SSL"
 
@@ -5023,15 +5043,20 @@ msgstr "Tệp chứng chỉ SSL phải nằm trong thư mục cấu hình Nginx:
 msgid "SSL certificate file not found"
 msgstr "Không tìm thấy tệp chứng chỉ SSL"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "Nội dung khóa chứng chỉ SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "Đường dẫn khóa chứng chỉ SSL"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "Đường dẫn chứng chỉ SSL"
@@ -5060,8 +5085,7 @@ msgstr "Đường dẫn khóa SSL là bắt buộc khi bật HTTPS"
 msgid "SSO Login"
 msgstr "Đăng nhập SSO"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "Ổn định"
@@ -5085,7 +5109,7 @@ msgstr "Tĩnh"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5163,7 +5187,7 @@ msgstr "Cổng trạng thái stub"
 msgid "Stub_status is not enabled"
 msgstr "Stub_status chưa được bật"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5253,10 +5277,9 @@ msgstr "Lỗi đồng bộ cấu hình"
 msgid "Sync Config Success"
 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:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "Nút đồng bộ"
 
@@ -5271,7 +5294,7 @@ msgstr "Xem trước đồng bộ"
 msgid "Sync strategy"
 msgstr "Chiến lược đồng bộ hóa"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "Đồng bộ tới"
 
@@ -5293,7 +5316,7 @@ msgstr "Sao lưu hệ thống"
 msgid "System Check"
 msgstr "Kiểm tra hệ thống"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "Người dùng ban đầu của hệ thống"
 
@@ -5356,11 +5379,11 @@ msgstr ""
 "Số ICP chỉ được chứa chữ cái, unicode, số, dấu gạch ngang, dấu gạch dài, "
 "dấu hai chấm và dấu chấm."
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "Đầu vào không phải là Chứng chỉ SSL"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "Đầu vào không phải là Khóa Chứng chỉ SSL"
 
@@ -5399,11 +5422,11 @@ msgstr ""
 msgid "The parameter of server_name is required"
 msgstr "Tham số của server_name là bắt buộc"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "Đường dẫn tồn tại, nhưng tệp không phải là chứng chỉ"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "Đường dẫn tồn tại, nhưng tệp không phải là khóa riêng tư"
 
@@ -5477,9 +5500,9 @@ msgstr "Chứng chỉ này được quản lý bởi Nginx UI"
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr "Thư mục này được bảo vệ và không thể xóa vì lý do an toàn hệ thống."
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "Trường này là bắt buộc"
 
@@ -5583,7 +5606,7 @@ msgstr ""
 "Thao tác này sẽ khôi phục các tệp cấu hình và cơ sở dữ liệu. Giao diện "
 "Nginx sẽ khởi động lại sau khi quá trình khôi phục hoàn tất."
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr ""
 "Thao tác này sẽ nâng cấp hoặc cài đặt lại Nginx UI trên %{nodeNames} lên "
@@ -5615,6 +5638,11 @@ msgstr ""
 msgid "Title"
 msgstr "Tiêu đề"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "để xác nhận xóa"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "Để xác nhận thu hồi, vui lòng nhập \"Thu hồi\" vào trường bên dưới:"
@@ -5778,9 +5806,8 @@ msgstr "Cập nhật thành công"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5788,14 +5815,13 @@ msgstr "Cập nhật thành công"
 msgid "Updated at"
 msgstr "Ngày cập nhật"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "Cập nhật"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "Nâng cấp Nginx UI trên %{node} thành công 🎉"
 
@@ -5803,8 +5829,7 @@ msgstr "Nâng cấp Nginx UI trên %{node} thành công 🎉"
 msgid "Upgraded successfully"
 msgstr "Nâng cấp thành công"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "Đang cập nhật Nginx UI, vui lòng đợi..."
 
@@ -5828,7 +5853,7 @@ msgstr "Ngược dòng"
 msgid "Upstream Name"
 msgstr "Tên Upstream"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "Loại kiểm tra upstream"
 
@@ -5836,7 +5861,7 @@ msgstr "Loại kiểm tra upstream"
 msgid "Uptime:"
 msgstr "Thời gian hoạt động:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5904,7 +5929,7 @@ msgstr "Xác minh tính toàn vẹn của tệp sao lưu"
 msgid "Verify system requirements"
 msgstr "Xác minh các yêu cầu hệ thống"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "Phiên bản"
 
@@ -5917,8 +5942,7 @@ msgstr "Xem"
 msgid "View all notifications"
 msgstr "Xem tất cả thông báo"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "Xem trên GitHub"
 
@@ -5935,7 +5959,7 @@ msgstr "Đã xem"
 msgid "Waiting processes"
 msgstr "Quá trình chờ đợi"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -6021,10 +6045,10 @@ msgstr ""
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
+"namespace and the nodes selected below will be synchronized."
 msgstr ""
-"Khi bạn bật/tắt, xóa hoặc lưu trang web này, các nút được đặt trong Nhóm "
-"Nút và các nút được chọn bên dưới sẽ được đồng bộ hóa."
+"Khi bạn bật/tắt, xóa hoặc lưu trang web này, các nút được đặt trong không "
+"gian tên và các nút được chọn bên dưới sẽ được đồng bộ hóa."
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -6055,7 +6079,7 @@ msgstr "Tiến trình công nhân"
 msgid "Workers"
 msgstr "Công nhân"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "Không gian làm việc"
@@ -6081,8 +6105,8 @@ msgstr "Ghi Private Key vào disk"
 msgid "Writing certificate to disk"
 msgstr "Ghi chứng chỉ vào disk"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -6090,7 +6114,7 @@ msgstr "Ghi chứng chỉ vào disk"
 msgid "Yes"
 msgstr "Có"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -6152,6 +6176,12 @@ 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 "Node Group"
+#~ msgstr "Nhóm nút"
+
+#~ msgid "Node Groups"
+#~ msgstr "Nhóm nút"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "Kiểm tra xem thư mục conf.d có tồn tại không"
 
@@ -6211,9 +6241,6 @@ msgstr "Khóa truy cập của bạn"
 #~ msgid "Last Backup Error"
 #~ msgstr "Lỗi sao lưu cuối cùng"
 
-#~ msgid "Apply"
-#~ msgstr "Áp dụng"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "Áp dụng hành động hàng loạt thành công"
 

+ 169 - 142
app/src/language/zh_CN/app.po

@@ -99,6 +99,11 @@ msgstr "[Nginx UI] 正在将证书私钥写入磁盘"
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] 正在将证书写入磁盘"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} 已复制到剪贴板"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* 包含来自组 %{groupName} 的节点和手动选择的节点"
@@ -129,7 +134,7 @@ msgid "Access Logs"
 msgstr "访问日志"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "ACME 用户"
 
@@ -141,10 +146,8 @@ msgstr "操作"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -226,7 +229,7 @@ msgstr "高级模式"
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr "之后,请刷新此页面并再次点击添加通行密钥。"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "全部"
 
@@ -269,6 +272,10 @@ msgstr "API 类型"
 msgid "App"
 msgstr "应用"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "应用"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "架构"
@@ -307,7 +314,7 @@ msgstr "确定要永久删除吗?"
 msgid "Are you sure you want to delete?"
 msgstr "您确定要删除吗?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr "你确定要在以下同步节点上重载 Nginx?"
 
@@ -323,7 +330,7 @@ msgstr "您确定要删除这个项目吗?"
 msgid "Are you sure you want to remove this location?"
 msgstr "您确定要删除这个 Location?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr "你确定要在以下同步节点上重启 Nginx 吗?"
 
@@ -394,16 +401,15 @@ msgstr "自动备份失败"
 msgid "Auto Backup Storage Failed"
 msgstr "自动备份存储失败"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "自动刷新"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "自动刷新已禁用"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "自动刷新已启用"
 
@@ -548,7 +554,7 @@ msgstr "批量编辑"
 msgid "Batch Modify"
 msgstr "批量修改"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "批量升级"
 
@@ -789,8 +795,7 @@ msgstr[0] "变更证书"
 msgid "Changed Path"
 msgstr "变更后的路径"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "通道"
 
@@ -984,6 +989,10 @@ msgstr "代码补全未启用"
 msgid "Code Completion Model"
 msgstr "代码补全模型"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "列设置"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "命令"
@@ -1075,6 +1084,10 @@ msgstr "配置"
 msgid "Configure SSL"
 msgstr "配置 SSL"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "确认删除"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "确认新密码"
@@ -1087,7 +1100,7 @@ msgstr "已连接"
 msgid "Connection error, trying to reconnect..."
 msgstr "连接错误,正在尝试重新连接..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "连接中断,请刷新页面。"
 
@@ -1166,7 +1179,7 @@ msgid ""
 msgstr "创建系统备份,包括 Nginx 配置和 Nginx UI 设置。备份文件将自动下载到你的电脑。"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1398,7 +1411,7 @@ msgstr "详情"
 msgid "Dev"
 msgstr "开发版"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "开发"
 
@@ -1498,8 +1511,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "在 %{node} 上禁用 %{name} 成功"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1601,16 +1613,15 @@ msgstr "下载最新版本错误"
 msgid "Downloading latest release"
 msgstr "下载最新版本"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "将证书文件拖放到此处"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "将私钥文件拖放到此处"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "试运行模式已启动"
 
@@ -1780,8 +1791,7 @@ msgid "Enable TOTP"
 msgstr "启用 TOTP"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1838,13 +1848,11 @@ msgstr "环境配置为空"
 msgid "Environment variables cleaned"
 msgstr "环境变量已清理"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "环境"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "错误"
@@ -1993,6 +2001,11 @@ msgstr "复制文件内容失败:{0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "复制 Nginx 配置目录失败:{0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "复制到剪贴板失败"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "创建备份失败"
@@ -2435,8 +2448,7 @@ msgstr "获取数据失败"
 msgid "Get dns credential error: {0}"
 msgstr "获取 DNS 凭证错误:{0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "获取发布信息错误"
 
@@ -2482,7 +2494,7 @@ msgstr "更高的值意味着更好的连接再利用"
 msgid "History"
 msgstr "历史"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "首页"
 
@@ -2541,7 +2553,7 @@ msgid "Import"
 msgstr "导入"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "导入证书"
 
@@ -2563,7 +2575,7 @@ msgstr "索引中..."
 msgid "Indicator"
 msgstr "指示器"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "信息"
 
@@ -2794,10 +2806,10 @@ msgstr "如果您的 ACME 提供商不需要,请留空"
 msgid "Leave blank if you don't need this."
 msgstr "如果不需要,请留空。"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "留空不做任何更改"
 
@@ -2830,11 +2842,11 @@ msgstr "监听中"
 msgid "Load Average:"
 msgstr "系统负载:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "从设置中加载"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "加载成功"
 
@@ -2864,7 +2876,7 @@ msgid "Loading data..."
 msgstr "正在加载数据..."
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2884,7 +2896,7 @@ msgstr "Location"
 msgid "Locations"
 msgstr "Locations"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "日志"
 
@@ -3086,7 +3098,7 @@ msgstr "分钟"
 msgid "Minutes"
 msgstr "分钟"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "镜像"
 
@@ -3104,7 +3116,7 @@ msgid "Modify"
 msgstr "修改"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "修改证书"
 
@@ -3149,15 +3161,15 @@ msgstr "不适用"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3174,6 +3186,18 @@ msgstr "名称"
 msgid "Name or content"
 msgstr "名称或内容"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "命名空间"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "命名空间"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "需要启用 stub_status 模块"
@@ -3366,7 +3390,7 @@ msgstr "Nginx 重载命令"
 msgid "Nginx reload failed: {0}"
 msgstr "Nginx 重载失败:{0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Nginx 重载操作已发送到远程节点"
 
@@ -3378,7 +3402,7 @@ msgstr "Nginx 重载成功"
 msgid "Nginx Restart Command"
 msgstr "Nginx 重启命令"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Nginx 重启操作已发送到远程节点"
 
@@ -3430,8 +3454,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "检查 nginx.conf 是否包含 streams-enabled 的目录"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3443,8 +3467,8 @@ msgstr "检查 nginx.conf 是否包含 streams-enabled 的目录"
 msgid "No"
 msgstr "取消"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "无操作"
 
@@ -3452,7 +3476,7 @@ msgstr "无操作"
 msgid "No data"
 msgstr "没有数据"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "未选择节点"
 
@@ -3478,17 +3502,6 @@ msgstr "未配置上游"
 msgid "Node"
 msgstr "节点"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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 "节点组"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "节点组"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "节点名称"
@@ -3501,7 +3514,7 @@ msgstr "节点密钥"
 msgid "Node Status"
 msgstr "节点状态"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "节点"
 
@@ -3538,6 +3551,11 @@ msgid ""
 "certificates, please synchronize them to the remote nodes in advance."
 msgstr "注意,如果配置文件中包含其他配置或证书,请提前将它们同步到远程节点。"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "无内容可复制"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "通知"
@@ -3601,12 +3619,11 @@ msgstr "关闭"
 msgid "Official Document"
 msgstr "官方文档"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "离线"
 
@@ -3635,13 +3652,12 @@ msgstr "开启"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "一旦验证完成,这些记录将被删除。"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "在线"
 
@@ -3785,7 +3801,7 @@ msgstr "有效载荷资源为空"
 msgid "Pending"
 msgstr "待处理"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "执行"
 
@@ -3827,6 +3843,10 @@ msgid ""
 "count, etc."
 msgstr "请启用 stub_status 模块,以获取请求统计信息、连接数等。"
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "请输入"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -3959,17 +3979,15 @@ msgstr "请选择有效的%{type}文件(%{extensions})"
 msgid "Please select at least one item"
 msgstr "请至少选择一项"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "请至少选择一个节点重载 Nginx"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "请至少选择一个节点重启 Nginx"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "请至少选择一个节点进行升级"
 
@@ -3995,13 +4013,12 @@ msgstr "必须开放 80 端口以进行 HTTP-01 挑战验证"
 msgid "Port Scanner"
 msgstr "端口检测"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "同步后操作"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "预发布"
@@ -4135,6 +4152,10 @@ msgstr "恢复代码用于在您无法访问双重身份验证设备时登录您
 msgid "Recursive Nameservers"
 msgstr "递归域名服务器"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "刷新"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "重新生成响应"
@@ -4186,10 +4207,9 @@ msgstr "发行日志"
 msgid "Reload"
 msgstr "重载"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "重载 Nginx"
 
@@ -4213,7 +4233,7 @@ msgstr "重载远程 Nginx 错误"
 msgid "Reload Remote Nginx Success"
 msgstr "重载远程 Nginx 成功"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "重载请求失败,请检查网络连接"
 
@@ -4225,7 +4245,7 @@ msgstr "重载中"
 msgid "Reloading nginx"
 msgstr "正在重载 Nginx"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "远程"
 
@@ -4374,9 +4394,8 @@ msgstr "响应"
 msgid "Restart"
 msgstr "重启"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "重启 Nginx"
 
@@ -4396,7 +4415,7 @@ msgstr "重启远程 Nginx 错误"
 msgid "Restart Remote Nginx Success"
 msgstr "重启远程 Nginx 成功"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "重启请求失败,请检查网络连接"
 
@@ -4767,7 +4786,7 @@ msgstr "发送测试消息"
 msgid "Server"
 msgstr "服务器"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "服务器错误"
 
@@ -4921,7 +4940,8 @@ msgstr "缓存管理器迭代之间的休眠时间"
 msgid "Sponsor"
 msgstr "赞助"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "SSL 证书内容"
 
@@ -4933,15 +4953,20 @@ msgstr "SSL 证书文件必须位于 Nginx 配置目录下:{0}"
 msgid "SSL certificate file not found"
 msgstr "未找到 SSL 证书文件"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "SSL 证书密钥内容"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "SSL证书密钥路径"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "SSL证书路径"
@@ -4970,8 +4995,7 @@ msgstr "启用 HTTPS 时需要 SSL 密钥路径"
 msgid "SSO Login"
 msgstr "SSO 登录"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "稳定"
@@ -4995,7 +5019,7 @@ msgstr "静态"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5071,7 +5095,7 @@ msgstr "Stub 状态端口"
 msgid "Stub_status is not enabled"
 msgstr "未启用 stub_status"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5159,10 +5183,9 @@ msgstr "同步配置错误"
 msgid "Sync Config Success"
 msgstr "同步配置成功"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "同步节点"
 
@@ -5177,7 +5200,7 @@ msgstr "同步预览"
 msgid "Sync strategy"
 msgstr "同步策略"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "同步到"
 
@@ -5199,7 +5222,7 @@ msgstr "系统备份"
 msgid "System Check"
 msgstr "系统检查"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "系统初始用户"
 
@@ -5257,11 +5280,11 @@ msgid ""
 "dashes, colons, and dots."
 msgstr "ICP 备案号只能包含字母、单码、数字、连字符、破折号、冒号和点。"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "输入的内容不是 SSL 证书"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "输入的内容不是 SSL 证书密钥"
 
@@ -5292,11 +5315,11 @@ msgstr "节点名称只能包含字母、统一码、数字、连字符、破折
 msgid "The parameter of server_name is required"
 msgstr "必须为 server_name 指令指明参数"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "路径存在,但文件不是证书"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "路径存在,但文件不是私钥"
 
@@ -5360,9 +5383,9 @@ msgstr "该证书由 Nginx UI 托管"
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr "此目录受保护,为确保系统安全无法删除。"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "此字段必填"
 
@@ -5452,7 +5475,7 @@ msgid ""
 "after the restoration is complete."
 msgstr "这将恢复配置文件和数据库。恢复完成后,Nginx UI 将重新启动。"
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "将 %{nodeNames} 上的 Nginx UI 升级或重新安装到 %{version} 版本。"
 
@@ -5480,6 +5503,11 @@ msgstr "提示您可以通过增加 worker_processes 或 worker_connections 来
 msgid "Title"
 msgstr "标题"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "确认删除"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "要确认撤销,请在下面的字段中输入 \"撤销\":"
@@ -5633,9 +5661,8 @@ msgstr "更新成功"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5643,14 +5670,13 @@ msgstr "更新成功"
 msgid "Updated at"
 msgstr "修改时间"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "升级"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "成功升级 %{node} 上的 Nginx UI 🎉"
 
@@ -5658,8 +5684,7 @@ msgstr "成功升级 %{node} 上的 Nginx UI 🎉"
 msgid "Upgraded successfully"
 msgstr "升级成功"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "正在升级 Nginx UI,请等待..."
 
@@ -5683,7 +5708,7 @@ msgstr "上游"
 msgid "Upstream Name"
 msgstr "Upstream 名称"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "上游测试类型"
 
@@ -5691,7 +5716,7 @@ msgstr "上游测试类型"
 msgid "Uptime:"
 msgstr "运行时间:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5759,7 +5784,7 @@ msgstr "验证备份文件的完整性"
 msgid "Verify system requirements"
 msgstr "验证系统要求"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "版本"
 
@@ -5772,8 +5797,7 @@ msgstr "查看"
 msgid "View all notifications"
 msgstr "查看全部通知"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "在 GitHub 上查看"
 
@@ -5790,7 +5814,7 @@ msgstr "已查看"
 msgid "Waiting processes"
 msgstr "等待处理"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -5865,8 +5889,8 @@ msgstr "启用后,Nginx UI 将在启动时自动重新注册用户。一般情
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
-msgstr "启用/禁用、删除或保存此站点时,环境组中设置的节点和下面选择的节点将同步执行操作。"
+"namespace and the nodes selected below will be synchronized."
+msgstr "当您启用/禁用、删除或保存此站点时,命名空间中设置的节点和下方选择的节点将被同步。"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5897,7 +5921,7 @@ msgstr "工作进程"
 msgid "Workers"
 msgstr "Workers"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "工作区"
@@ -5923,8 +5947,8 @@ msgstr "正在将证书私钥写入磁盘"
 msgid "Writing certificate to disk"
 msgstr "正在将证书写入磁盘"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -5932,7 +5956,7 @@ msgstr "正在将证书写入磁盘"
 msgid "Yes"
 msgstr "是的"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -5987,6 +6011,12 @@ msgstr "您的旧代码将不再有效。"
 msgid "Your passkeys"
 msgstr "你的 Passkeys"
 
+#~ msgid "Node Group"
+#~ msgstr "节点组"
+
+#~ msgid "Node Groups"
+#~ msgstr "节点组"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "检查 conf.d 目录是否存在"
 
@@ -6044,9 +6074,6 @@ msgstr "你的 Passkeys"
 #~ msgid "Last Backup Error"
 #~ msgstr "最后一次备份错误"
 
-#~ msgid "Apply"
-#~ msgstr "应用"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "批量操作应用成功"
 

+ 169 - 142
app/src/language/zh_TW/app.po

@@ -103,6 +103,11 @@ msgstr "[Nginx UI] 正在將證書私鑰寫入磁碟"
 msgid "[Nginx UI] Writing certificate to disk"
 msgstr "[Nginx UI] 正在將憑證寫入磁碟"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:28
+#: src/views/certificate/components/CertificateContentEditor.vue:29
+msgid "{label} copied to clipboard"
+msgstr "{label} 已複製到剪貼簿"
+
 #: src/components/SyncNodesPreview/SyncNodesPreview.vue:59
 msgid "* Includes nodes from group %{groupName} and manually selected nodes"
 msgstr "* 包含來自群組 %{groupName} 的節點和手動選擇的節點"
@@ -133,7 +138,7 @@ msgid "Access Logs"
 msgstr "存取日誌"
 
 #: src/routes/modules/certificates.ts:20 src/views/certificate/ACMEUser.vue:147
-#: src/views/certificate/components/ACMEUserSelector.vue:52
+#: src/views/certificate/components/ACMEUserSelector.vue:64
 msgid "ACME User"
 msgstr "ACME 使用者"
 
@@ -145,10 +150,8 @@ msgstr "操作"
 #: src/views/certificate/ACMEUser.vue:129
 #: src/views/certificate/CertificateList/certColumns.tsx:92
 #: src/views/certificate/DNSCredential.vue:71
-#: src/views/config/configColumns.tsx:50
-#: src/views/environments/group/columns.ts:84
-#: src/views/environments/list/envColumns.tsx:96
-#: src/views/nginx_log/NginxLogList.vue:68
+#: src/views/config/configColumns.tsx:50 src/views/namespace/columns.ts:84
+#: src/views/nginx_log/NginxLogList.vue:68 src/views/node/nodeColumns.tsx:96
 #: src/views/notification/notificationColumns.tsx:72
 #: src/views/preference/components/ExternalNotify/columns.tsx:85
 #: src/views/site/site_list/columns.tsx:160 src/views/stream/columns.tsx:123
@@ -230,7 +233,7 @@ msgstr "進階模式"
 msgid "Afterwards, refresh this page and click add passkey again."
 msgstr "之後,請重新整理此頁面並再次點擊新增通行金鑰。"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:83
+#: src/components/NamespaceTabs/NamespaceTabs.vue:83
 msgid "All"
 msgstr "全部"
 
@@ -273,6 +276,10 @@ msgstr "API 類型"
 msgid "App"
 msgstr "應用"
 
+#: src/language/curd.ts:65
+msgid "Apply"
+msgstr "應用"
+
 #: src/views/system/Upgrade.vue:195
 msgid "Arch"
 msgstr "架構"
@@ -311,7 +318,7 @@ msgstr "確定要永久刪除嗎?"
 msgid "Are you sure you want to delete?"
 msgstr "您確定要刪除嗎?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:97
+#: src/components/NamespaceTabs/NamespaceTabs.vue:97
 msgid "Are you sure you want to reload Nginx on the following sync nodes?"
 msgstr "您確定要在以下同步節點上重新載入 Nginx 嗎?"
 
@@ -327,7 +334,7 @@ msgstr "您確定要刪除此項目嗎?"
 msgid "Are you sure you want to remove this location?"
 msgstr "您確定要刪除此 Location 嗎?"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:109
+#: src/components/NamespaceTabs/NamespaceTabs.vue:109
 msgid "Are you sure you want to restart Nginx on the following sync nodes?"
 msgstr "您確定要在以下同步節點上重新啟動 Nginx 嗎?"
 
@@ -398,16 +405,15 @@ msgstr "自動備份失敗"
 msgid "Auto Backup Storage Failed"
 msgstr "自動備份儲存失敗"
 
-#: src/views/environments/list/Environment.vue:165
-#: src/views/nginx_log/NginxLog.vue:150
+#: src/views/nginx_log/NginxLog.vue:150 src/views/node/Node.vue:165
 msgid "Auto Refresh"
 msgstr "自動重新整理"
 
-#: src/views/environments/list/Environment.vue:48
+#: src/views/node/Node.vue:48
 msgid "Auto refresh disabled"
 msgstr "自動刷新已停用"
 
-#: src/views/environments/list/Environment.vue:44
+#: src/views/node/Node.vue:44
 msgid "Auto refresh enabled"
 msgstr "自動刷新已啟用"
 
@@ -552,7 +558,7 @@ msgstr "批次編輯"
 msgid "Batch Modify"
 msgstr "批次修改"
 
-#: src/views/environments/list/BatchUpgrader.vue:153
+#: src/views/node/BatchUpgrader.vue:153
 msgid "Batch Upgrade"
 msgstr "批次升級"
 
@@ -793,8 +799,7 @@ msgstr[0] "變更後憑證"
 msgid "Changed Path"
 msgstr "變更後路徑"
 
-#: src/views/environments/list/BatchUpgrader.vue:160
-#: src/views/system/Upgrade.vue:207
+#: src/views/node/BatchUpgrader.vue:160 src/views/system/Upgrade.vue:207
 msgid "Channel"
 msgstr "通道"
 
@@ -988,6 +993,10 @@ msgstr "程式碼補全未啟用"
 msgid "Code Completion Model"
 msgstr "程式碼補全模型"
 
+#: src/language/curd.ts:64
+msgid "Column Settings"
+msgstr "列設置"
+
 #: src/views/preference/tabs/LogrotateSettings.vue:23
 msgid "Command"
 msgstr "命令"
@@ -1079,6 +1088,10 @@ msgstr "設定"
 msgid "Configure SSL"
 msgstr "設定 SSL"
 
+#: src/language/curd.ts:66
+msgid "Confirm Delete"
+msgstr "確認刪除"
+
 #: src/views/user/UserProfile.vue:204
 msgid "Confirm New Password"
 msgstr "確認新密碼"
@@ -1091,7 +1104,7 @@ msgstr "已連線"
 msgid "Connection error, trying to reconnect..."
 msgstr "連線錯誤,正在嘗試重新連線..."
 
-#: src/views/terminal/Terminal.vue:139
+#: src/views/terminal/Terminal.vue:149
 msgid "Connection lost, please refresh the page."
 msgstr "連線中斷,請重新整理此頁面。"
 
@@ -1170,7 +1183,7 @@ msgid ""
 msgstr "建立系統備份,包括 Nginx 設定與 Nginx UI 設定。備份檔案將自動下載至您的電腦。"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:229
-#: src/views/environments/group/columns.ts:72
+#: src/views/namespace/columns.ts:72
 #: src/views/notification/notificationColumns.tsx:51
 #: src/views/preference/components/AuthSettings/Passkey.vue:95
 #: src/views/preference/components/ExternalNotify/columns.tsx:80
@@ -1402,7 +1415,7 @@ msgstr "細節"
 msgid "Dev"
 msgstr "Dev"
 
-#: src/views/environments/list/BatchUpgrader.vue:171
+#: src/views/node/BatchUpgrader.vue:171
 msgid "Development"
 msgstr "開發"
 
@@ -1502,8 +1515,7 @@ msgid "Disable stream %{name} from %{node} successfully"
 msgstr "已成功從 %{node} 停用串流 %{name}"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:175
-#: src/views/environments/list/envColumns.tsx:60
-#: src/views/environments/list/envColumns.tsx:78
+#: src/views/node/nodeColumns.tsx:60 src/views/node/nodeColumns.tsx:78
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/NodeSettings.vue:25
 #: src/views/preference/tabs/NodeSettings.vue:30
@@ -1605,16 +1617,15 @@ msgstr "下載最新版本錯誤"
 msgid "Downloading latest release"
 msgstr "正在下載最新版本"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:126
+#: src/views/certificate/components/CertificateContentEditor.vue:157
 msgid "Drop certificate file here"
 msgstr "將證書文件拖放到此處"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:175
+#: src/views/certificate/components/CertificateContentEditor.vue:218
 msgid "Drop private key file here"
 msgstr "將私鑰檔案拖放到此處"
 
-#: src/views/environments/list/BatchUpgrader.vue:192
-#: src/views/system/Upgrade.vue:237
+#: src/views/node/BatchUpgrader.vue:192 src/views/system/Upgrade.vue:237
 msgid "Dry run mode enabled"
 msgstr "試運轉模式已啟用"
 
@@ -1784,8 +1795,7 @@ msgid "Enable TOTP"
 msgstr "啟用 TOTP"
 
 #: src/views/backup/AutoBackup/AutoBackup.vue:174
-#: src/views/environments/list/envColumns.tsx:69
-#: src/views/environments/list/envColumns.tsx:75
+#: src/views/node/nodeColumns.tsx:69 src/views/node/nodeColumns.tsx:75
 #: src/views/preference/components/ExternalNotify/columns.tsx:47
 #: src/views/preference/tabs/HTTPSettings.vue:24
 #: src/views/preference/tabs/LogrotateSettings.vue:20
@@ -1842,13 +1852,11 @@ msgstr "環境配置為空"
 msgid "Environment variables cleaned"
 msgstr "環境變數已清理"
 
-#: src/routes/modules/environments.ts:11
-#: src/views/dashboard/Environments.vue:80
-#: src/views/environments/list/Environment.vue:131
+#: src/views/node/Node.vue:131
 msgid "Environments"
 msgstr "環境"
 
-#: src/constants/index.ts:22 src/views/config/InspectConfig.vue:63
+#: src/constants/index.ts:23 src/views/config/InspectConfig.vue:63
 #: src/views/notification/notificationColumns.tsx:14
 msgid "Error"
 msgstr "錯誤"
@@ -1997,6 +2005,11 @@ msgstr "複製檔案內容失敗:{0}"
 msgid "Failed to copy Nginx config directory: {0}"
 msgstr "複製 Nginx 設定目錄失敗:{0}"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:32
+#: src/views/certificate/components/CertificateContentEditor.vue:33
+msgid "Failed to copy to clipboard"
+msgstr "複製到剪貼簿失敗"
+
 #: src/constants/errors/self_check.ts:10
 msgid "Failed to create backup"
 msgstr "建立備份失敗"
@@ -2439,8 +2452,7 @@ msgstr "取得資料失敗"
 msgid "Get dns credential error: {0}"
 msgstr "獲取 DNS 憑證錯誤:{0}"
 
-#: src/views/environments/list/BatchUpgrader.vue:181
-#: src/views/system/Upgrade.vue:188
+#: src/views/node/BatchUpgrader.vue:181 src/views/system/Upgrade.vue:188
 msgid "Get release information error"
 msgstr "取得發佈資訊錯誤"
 
@@ -2486,7 +2498,7 @@ msgstr "數值越高表示連線重複使用率越好"
 msgid "History"
 msgstr "歷史"
 
-#: src/routes/index.ts:48
+#: src/routes/index.ts:50
 msgid "Home"
 msgstr "首頁"
 
@@ -2545,7 +2557,7 @@ msgid "Import"
 msgstr "匯入"
 
 #: src/routes/modules/certificates.ts:54
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Import Certificate"
 msgstr "匯入憑證"
 
@@ -2567,7 +2579,7 @@ msgstr "建立索引中..."
 msgid "Indicator"
 msgstr "指標"
 
-#: src/constants/index.ts:24 src/views/notification/notificationColumns.tsx:28
+#: src/constants/index.ts:25 src/views/notification/notificationColumns.tsx:28
 msgid "Info"
 msgstr "資訊"
 
@@ -2798,10 +2810,10 @@ msgstr "如果您的 ACME 提供商不需要,請留空"
 msgid "Leave blank if you don't need this."
 msgstr "留空表示不需要此項目。"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:118
-#: src/views/certificate/components/CertificateContentEditor.vue:136
+#: src/views/certificate/components/CertificateContentEditor.vue:149
 #: src/views/certificate/components/CertificateContentEditor.vue:167
-#: src/views/certificate/components/CertificateContentEditor.vue:185
+#: src/views/certificate/components/CertificateContentEditor.vue:210
+#: src/views/certificate/components/CertificateContentEditor.vue:228
 msgid "Leave blank will not change anything"
 msgstr "留空將不會改變任何內容"
 
@@ -2834,11 +2846,11 @@ msgstr "監聽中"
 msgid "Load Average:"
 msgstr "負載平均值:"
 
-#: src/views/environments/list/Environment.vue:138
+#: src/views/node/Node.vue:138
 msgid "Load from settings"
 msgstr "從設定載入"
 
-#: src/views/environments/list/Environment.vue:68
+#: src/views/node/Node.vue:68
 msgid "Load successfully"
 msgstr "載入成功"
 
@@ -2868,7 +2880,7 @@ msgid "Loading data..."
 msgstr "資料載入中…"
 
 #: src/components/EnvIndicator/EnvIndicator.vue:39
-#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:41
+#: src/components/NodeSelector/NodeSelector.vue:61 src/constants/index.ts:42
 #: src/views/backup/AutoBackup/AutoBackup.vue:74
 #: src/views/backup/AutoBackup/AutoBackup.vue:83
 #: src/views/backup/AutoBackup/components/StorageConfigEditor.vue:48
@@ -2888,7 +2900,7 @@ msgstr "Location"
 msgid "Locations"
 msgstr "Locations"
 
-#: src/views/certificate/CertificateEditor.vue:126
+#: src/views/certificate/CertificateEditor.vue:122
 msgid "Log"
 msgstr "日誌"
 
@@ -3090,7 +3102,7 @@ msgstr "分鐘"
 msgid "Minutes"
 msgstr "分鐘"
 
-#: src/constants/index.ts:43
+#: src/constants/index.ts:44
 msgid "Mirror"
 msgstr "鏡像"
 
@@ -3108,7 +3120,7 @@ msgid "Modify"
 msgstr "修改"
 
 #: src/routes/modules/certificates.ts:44
-#: src/views/certificate/CertificateEditor.vue:86
+#: src/views/certificate/CertificateEditor.vue:82
 msgid "Modify Certificate"
 msgstr "修改憑證"
 
@@ -3153,15 +3165,15 @@ msgstr "不適用"
 #: 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/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:69
 #: 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:9
-#: src/views/environments/list/envColumns.tsx:8
-#: src/views/nginx_log/NginxLogList.vue:52
+#: src/views/config/configColumns.tsx:17 src/views/namespace/columns.ts:9
+#: src/views/nginx_log/NginxLogList.vue:52 src/views/node/nodeColumns.tsx:8
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:80
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:36
 #: src/views/site/site_list/columns.tsx:30
@@ -3178,6 +3190,18 @@ msgstr "名稱"
 msgid "Name or content"
 msgstr "名稱或內容"
 
+#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
+#: src/views/site/site_list/columns.tsx:91
+#: src/views/stream/columns.tsx:58
+#: src/views/stream/components/RightPanel/Basic.vue:39
+msgid "Namespace"
+msgstr "命名空間"
+
+#: src/routes/modules/namespaces.ts:11
+#: src/views/namespace/Namespace.vue:19
+msgid "Namespaces"
+msgstr "命名空間"
+
 #: src/views/dashboard/NginxDashBoard.vue:195
 msgid "Need to enable the stub_status module"
 msgstr "需要啟用 stub_status 模組"
@@ -3370,7 +3394,7 @@ msgstr "Nginx 重新載入指令"
 msgid "Nginx reload failed: {0}"
 msgstr "Nginx 重新載入失敗: {0}"
 
-#: src/views/environments/list/Environment.vue:89
+#: src/views/node/Node.vue:89
 msgid "Nginx reload operations have been dispatched to remote nodes"
 msgstr "Nginx 重新載入操作已分發至遠端節點"
 
@@ -3382,7 +3406,7 @@ msgstr "Nginx 重新載入成功"
 msgid "Nginx Restart Command"
 msgstr "Nginx 重啟指令"
 
-#: src/views/environments/list/Environment.vue:103
+#: src/views/node/Node.vue:103
 msgid "Nginx restart operations have been dispatched to remote nodes"
 msgstr "Nginx 重啟操作已分發至遠端節點"
 
@@ -3434,8 +3458,8 @@ msgid "Nginx.conf includes streams-enabled directory"
 msgstr "Nginx.conf 包含 streams-enabled 目錄"
 
 #: src/components/ChatGPT/ChatMessageInput.vue:17
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:111
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:99
+#: src/components/NamespaceTabs/NamespaceTabs.vue:111
+#: src/components/NamespaceTabs/NamespaceTabs.vue:99
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:102
 #: src/components/NgxConfigEditor/LocationEditor.vue:89
 #: src/components/Notification/Notification.vue:108 src/language/curd.ts:40
@@ -3447,8 +3471,8 @@ msgstr "Nginx.conf 包含 streams-enabled 目錄"
 msgid "No"
 msgstr "取消"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:41
-#: src/constants/index.ts:36
+#: src/components/NamespaceRender/NamespaceRender.vue:41
+#: src/constants/index.ts:37
 msgid "No Action"
 msgstr "無行動"
 
@@ -3456,7 +3480,7 @@ msgstr "無行動"
 msgid "No data"
 msgstr "無數據"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:55
+#: src/components/NamespaceRender/NamespaceRender.vue:55
 msgid "No nodes selected"
 msgstr "未選擇節點"
 
@@ -3482,17 +3506,6 @@ msgstr "未配置上游"
 msgid "Node"
 msgstr "節點"
 
-#: src/views/site/site_edit/components/RightPanel/Basic.vue:42
-#: 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 "節點群組"
-
-#: src/routes/modules/environments.ts:33
-#: src/views/environments/group/EnvGroup.vue:19
-msgid "Node Groups"
-msgstr "節點群組"
-
 #: src/views/preference/tabs/NodeSettings.vue:15
 msgid "Node name"
 msgstr "節點名稱"
@@ -3505,7 +3518,7 @@ msgstr "節點金鑰"
 msgid "Node Status"
 msgstr "節點狀態"
 
-#: src/routes/modules/environments.ts:25
+#: src/routes/modules/nodes.ts:11 src/views/dashboard/Nodes.vue:80
 msgid "Nodes"
 msgstr "節點"
 
@@ -3542,6 +3555,11 @@ msgid ""
 "certificates, please synchronize them to the remote nodes in advance."
 msgstr "請注意,如果設定檔包含其他設定或憑證,請提前將它們同步到遠端節點。"
 
+#: src/views/certificate/components/CertificateBasicInfo.vue:23
+#: src/views/certificate/components/CertificateContentEditor.vue:24
+msgid "Nothing to copy"
+msgstr "無內容可複製"
+
 #: src/views/notification/Notification.vue:28
 msgid "Notification"
 msgstr "通知"
@@ -3605,12 +3623,11 @@ msgstr "關"
 msgid "Official Document"
 msgstr "官方文件"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:84
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:106
-#: src/views/environments/list/envColumns.tsx:55
+#: src/views/dashboard/Nodes.vue:106 src/views/node/nodeColumns.tsx:55
 msgid "Offline"
 msgstr "離線"
 
@@ -3639,13 +3656,12 @@ msgstr "開啟"
 msgid "Once the verification is complete, the records will be removed."
 msgstr "驗證完成後,記錄將被刪除。"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:127
+#: src/components/NamespaceTabs/NamespaceTabs.vue:127
 #: src/components/NodeCard/NodeCard.vue:51
 #: src/components/NodeSelector/NodeSelector.vue:64
 #: src/components/NodeSelector/NodeSelector.vue:78
 #: src/components/UpstreamDetailModal/UpstreamDetailModal.vue:48
-#: src/views/dashboard/Environments.vue:99
-#: src/views/environments/list/envColumns.tsx:51
+#: src/views/dashboard/Nodes.vue:99 src/views/node/nodeColumns.tsx:51
 msgid "Online"
 msgstr "線上"
 
@@ -3791,7 +3807,7 @@ msgstr "有效載荷資源為空"
 msgid "Pending"
 msgstr "待處理"
 
-#: src/views/environments/list/BatchUpgrader.vue:245
+#: src/views/node/BatchUpgrader.vue:245
 msgid "Perform"
 msgstr "執行"
 
@@ -3833,6 +3849,10 @@ msgid ""
 "count, etc."
 msgstr "請啟用 stub_status 模組以取得請求統計、連線數量等資訊"
 
+#: src/language/curd.ts:67
+msgid "Please enter"
+msgstr "請輸入"
+
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:74
 msgid ""
 "Please enter a name for the passkey you wish to create and click the OK "
@@ -3965,17 +3985,15 @@ msgstr "請選擇有效的%{type}檔案(%{extensions})"
 msgid "Please select at least one item"
 msgstr "請至少選擇一項"
 
-#: src/views/environments/list/Environment.vue:201
-#: src/views/environments/list/Environment.vue:83
+#: src/views/node/Node.vue:201 src/views/node/Node.vue:83
 msgid "Please select at least one node to reload Nginx"
 msgstr "請至少選擇一個節點以重新載入 Nginx"
 
-#: src/views/environments/list/Environment.vue:222
-#: src/views/environments/list/Environment.vue:97
+#: src/views/node/Node.vue:222 src/views/node/Node.vue:97
 msgid "Please select at least one node to restart Nginx"
 msgstr "請至少選擇一個節點以重啟 Nginx"
 
-#: src/views/environments/list/Environment.vue:180
+#: src/views/node/Node.vue:180
 msgid "Please select at least one node to upgrade"
 msgstr "請至少選擇一個節點進行升級"
 
@@ -4001,13 +4019,12 @@ msgstr "必須開放 80 端口以進行 HTTP-01 挑戰驗證"
 msgid "Port Scanner"
 msgstr "端口掃描器"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:38
-#: src/views/environments/group/columns.ts:46
+#: src/components/NamespaceRender/NamespaceRender.vue:38
+#: src/views/namespace/columns.ts:46
 msgid "Post-sync Action"
 msgstr "同步後動作"
 
-#: src/views/environments/list/BatchUpgrader.vue:168
-#: src/views/environments/list/BatchUpgrader.vue:224
+#: src/views/node/BatchUpgrader.vue:168 src/views/node/BatchUpgrader.vue:224
 #: src/views/system/Upgrade.vue:213 src/views/system/Upgrade.vue:267
 msgid "Pre-release"
 msgstr "預先發布"
@@ -4141,6 +4158,10 @@ msgstr "復原代碼在您無法使用 2FA 裝置時,用於存取您的帳戶
 msgid "Recursive Nameservers"
 msgstr "遞迴名稱伺服器"
 
+#: src/language/curd.ts:70
+msgid "Refresh"
+msgstr "重新整理"
+
 #: src/components/ChatGPT/ChatMessageInput.vue:30
 msgid "Regenerate response"
 msgstr "重新產生回應"
@@ -4192,10 +4213,9 @@ msgstr "發行公告"
 msgid "Reload"
 msgstr "重新載入"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:44
-#: 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
+#: src/components/NamespaceRender/NamespaceRender.vue:44
+#: src/components/NamespaceTabs/NamespaceTabs.vue:104 src/constants/index.ts:38
+#: src/views/node/Node.vue:209 src/views/node/Node.vue:217
 msgid "Reload Nginx"
 msgstr "重新載入 Nginx"
 
@@ -4219,7 +4239,7 @@ msgstr "重新載入遠端 Nginx 錯誤"
 msgid "Reload Remote Nginx Success"
 msgstr "遠端 Nginx 重新載入成功"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:52
+#: src/components/NamespaceTabs/NamespaceTabs.vue:52
 msgid "Reload request failed, please check your network connection"
 msgstr "重新載入請求失敗,請檢查您的網路連線"
 
@@ -4231,7 +4251,7 @@ msgstr "重新載入中"
 msgid "Reloading nginx"
 msgstr "正在重新載入 Nginx"
 
-#: src/constants/index.ts:42
+#: src/constants/index.ts:43
 msgid "Remote"
 msgstr "遠端"
 
@@ -4380,9 +4400,8 @@ msgstr "回應"
 msgid "Restart"
 msgstr "重新啟動"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:116
-#: src/views/environments/list/Environment.vue:230
-#: src/views/environments/list/Environment.vue:238
+#: src/components/NamespaceTabs/NamespaceTabs.vue:116
+#: src/views/node/Node.vue:230 src/views/node/Node.vue:238
 msgid "Restart Nginx"
 msgstr "重新啟動 Nginx"
 
@@ -4402,7 +4421,7 @@ msgstr "遠端 Nginx 重啟錯誤"
 msgid "Restart Remote Nginx Success"
 msgstr "遠端 Nginx 重啟成功"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:72
+#: src/components/NamespaceTabs/NamespaceTabs.vue:72
 msgid "Restart request failed, please check your network connection"
 msgstr "重新啟動請求失敗,請檢查您的網路連線"
 
@@ -4773,7 +4792,7 @@ msgstr "發送測試訊息"
 msgid "Server"
 msgstr "伺服器"
 
-#: src/views/certificate/CertificateEditor.vue:58
+#: src/views/certificate/CertificateEditor.vue:54
 msgid "Server error"
 msgstr "伺服器錯誤"
 
@@ -4927,7 +4946,8 @@ msgstr "快取管理器迭代間的休眠時間"
 msgid "Sponsor"
 msgstr "贊助"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:93
+#: src/views/certificate/components/CertificateContentEditor.vue:118
+#: src/views/certificate/components/CertificateContentEditor.vue:123
 msgid "SSL Certificate Content"
 msgstr "SSL 憑證內容"
 
@@ -4939,15 +4959,20 @@ msgstr "SSL 憑證檔案必須位於 Nginx 設定目錄下:{0}"
 msgid "SSL certificate file not found"
 msgstr "SSL 憑證檔案未找到"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:142
+#: src/views/certificate/components/CertificateContentEditor.vue:179
+#: src/views/certificate/components/CertificateContentEditor.vue:184
 msgid "SSL Certificate Key Content"
 msgstr "SSL 憑證金鑰內容"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:55
+#: src/views/certificate/components/CertificateBasicInfo.vue:111
+#: src/views/certificate/components/CertificateBasicInfo.vue:125
+#: src/views/certificate/components/CertificateBasicInfo.vue:137
 msgid "SSL Certificate Key Path"
 msgstr "SSL 憑證金鑰路徑"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:39
+#: src/views/certificate/components/CertificateBasicInfo.vue:103
+#: src/views/certificate/components/CertificateBasicInfo.vue:77
+#: src/views/certificate/components/CertificateBasicInfo.vue:91
 #: src/views/preference/tabs/ServerSettings.vue:37
 msgid "SSL Certificate Path"
 msgstr "SSL 憑證路徑"
@@ -4976,8 +5001,7 @@ msgstr "啟用 HTTPS 時必須提供 SSL 金鑰路徑"
 msgid "SSO Login"
 msgstr "SSO 登入"
 
-#: src/views/environments/list/BatchUpgrader.vue:165
-#: src/views/environments/list/BatchUpgrader.vue:218
+#: src/views/node/BatchUpgrader.vue:165 src/views/node/BatchUpgrader.vue:218
 #: src/views/system/Upgrade.vue:210 src/views/system/Upgrade.vue:261
 msgid "Stable"
 msgstr "穩定"
@@ -5001,7 +5025,7 @@ msgstr "靜態"
 #: src/views/certificate/ACMEUser.vue:73
 #: src/views/certificate/CertificateList/certColumns.tsx:63
 #: src/views/dashboard/components/ModulesTable.vue:96
-#: src/views/environments/list/envColumns.tsx:43
+#: src/views/node/nodeColumns.tsx:43
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:29
 #: src/views/site/site_list/columns.tsx:120 src/views/stream/columns.tsx:87
 msgid "Status"
@@ -5077,7 +5101,7 @@ msgstr "存根狀態端口"
 msgid "Stub_status is not enabled"
 msgstr "未啟用 stub_status"
 
-#: src/constants/index.ts:25 src/views/backup/AutoBackup/AutoBackup.vue:195
+#: src/constants/index.ts:26 src/views/backup/AutoBackup/AutoBackup.vue:195
 #: src/views/backup/AutoBackup/AutoBackup.vue:220
 #: src/views/notification/notificationColumns.tsx:35
 msgid "Success"
@@ -5165,10 +5189,9 @@ msgstr "同步設定錯誤"
 msgid "Sync Config Success"
 msgstr "同步設定成功"
 
-#: src/components/EnvGroupRender/EnvGroupRender.vue:53
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:90
-#: src/views/environments/group/columns.ts:17
-#: src/views/environments/group/EnvGroup.vue:31
+#: src/components/NamespaceRender/NamespaceRender.vue:53
+#: src/components/NamespaceTabs/NamespaceTabs.vue:90
+#: src/views/namespace/columns.ts:17 src/views/namespace/Namespace.vue:31
 msgid "Sync Nodes"
 msgstr "同步節點"
 
@@ -5183,7 +5206,7 @@ msgstr "同步預覽"
 msgid "Sync strategy"
 msgstr "同步策略"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:70
+#: src/views/certificate/components/CertificateBasicInfo.vue:144
 msgid "Sync to"
 msgstr "同步到"
 
@@ -5205,7 +5228,7 @@ msgstr "系統備份"
 msgid "System Check"
 msgstr "系統檢查"
 
-#: src/views/certificate/components/ACMEUserSelector.vue:55
+#: src/views/certificate/components/ACMEUserSelector.vue:67
 msgid "System Initial User"
 msgstr "系統初始使用者"
 
@@ -5263,11 +5286,11 @@ msgid ""
 "dashes, colons, and dots."
 msgstr "ICP 編號僅能包含字母、Unicode 字元、數字、連字號、破折號、冒號和句點。"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:96
+#: src/views/certificate/components/CertificateContentEditor.vue:114
 msgid "The input is not a SSL Certificate"
 msgstr "輸入的不是 SSL 憑證"
 
-#: src/views/certificate/components/CertificateContentEditor.vue:145
+#: src/views/certificate/components/CertificateContentEditor.vue:175
 msgid "The input is not a SSL Certificate Key"
 msgstr "輸入的不是 SSL 憑證金鑰"
 
@@ -5298,11 +5321,11 @@ msgstr "節點名稱僅能包含字母、Unicode 字元、數字、連字號、
 msgid "The parameter of server_name is required"
 msgstr "必須提供 server_name 參數"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:43
+#: src/views/certificate/components/CertificateBasicInfo.vue:81
 msgid "The path exists, but the file is not a certificate"
 msgstr "路徑存在,但檔案不是憑證"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:59
+#: src/views/certificate/components/CertificateBasicInfo.vue:115
 msgid "The path exists, but the file is not a private key"
 msgstr "路徑存在,但檔案不是金鑰"
 
@@ -5366,9 +5389,9 @@ msgstr "此憑證由 Nginx UI 管理"
 msgid "This directory is protected and cannot be deleted for system safety."
 msgstr "此目錄受保護,為確保系統安全無法刪除。"
 
-#: src/views/certificate/components/CertificateBasicInfo.vue:26
-#: src/views/certificate/components/CertificateBasicInfo.vue:41
-#: src/views/certificate/components/CertificateBasicInfo.vue:57
+#: src/views/certificate/components/CertificateBasicInfo.vue:113
+#: src/views/certificate/components/CertificateBasicInfo.vue:46
+#: src/views/certificate/components/CertificateBasicInfo.vue:79
 msgid "This field is required"
 msgstr "此欄位為必填項"
 
@@ -5458,7 +5481,7 @@ msgid ""
 "after the restoration is complete."
 msgstr "這將恢復設定檔案和資料庫。恢復完成後,Nginx UI 將重新啟動。"
 
-#: src/views/environments/list/BatchUpgrader.vue:186
+#: src/views/node/BatchUpgrader.vue:186
 msgid "This will upgrade or reinstall the Nginx UI on %{nodeNames} to %{version}."
 msgstr "這將在 %{nodeNames} 上升級或重新安裝 Nginx UI 到 %{version}。"
 
@@ -5486,6 +5509,11 @@ msgstr "提示:您可以通過增加 worker_processes 或 worker_connections 
 msgid "Title"
 msgstr "標題"
 
+#: src/language/curd.ts:68
+#: src/language/curd.ts:69
+msgid "to confirm deletion"
+msgstr "確認刪除"
+
 #: src/views/certificate/components/RemoveCert.vue:124
 msgid "To confirm revocation, please type \"Revoke\" in the field below:"
 msgstr "若要確認撤銷,請在下方欄位中輸入「撤銷」:"
@@ -5639,9 +5667,8 @@ msgstr "更新成功"
 #: src/views/certificate/ACMEUser.vue:122
 #: 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:78
-#: src/views/environments/list/envColumns.tsx:89
+#: src/views/config/configColumns.tsx:43 src/views/namespace/columns.ts:78
+#: src/views/node/nodeColumns.tsx:89
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:39
 #: src/views/site/site_list/columns.tsx:113 src/views/stream/columns.tsx:80
 #: src/views/stream/components/RightPanel/Basic.vue:35
@@ -5649,14 +5676,13 @@ msgstr "更新成功"
 msgid "Updated at"
 msgstr "更新時間"
 
-#: src/routes/modules/system.ts:26
-#: src/views/environments/list/Environment.vue:188
-#: src/views/environments/list/Environment.vue:196
-#: src/views/system/Upgrade.vue:154 src/views/system/Upgrade.vue:159
+#: src/routes/modules/system.ts:26 src/views/node/Node.vue:188
+#: src/views/node/Node.vue:196 src/views/system/Upgrade.vue:154
+#: src/views/system/Upgrade.vue:159
 msgid "Upgrade"
 msgstr "升級"
 
-#: src/views/environments/list/BatchUpgrader.vue:137
+#: src/views/node/BatchUpgrader.vue:137
 msgid "Upgraded Nginx UI on %{node} successfully 🎉"
 msgstr "成功升級 %{node} 上的 Nginx UI 🎉"
 
@@ -5664,8 +5690,7 @@ msgstr "成功升級 %{node} 上的 Nginx UI 🎉"
 msgid "Upgraded successfully"
 msgstr "升級成功"
 
-#: src/views/environments/list/BatchUpgrader.vue:88
-#: src/views/system/Upgrade.vue:81
+#: src/views/node/BatchUpgrader.vue:88 src/views/system/Upgrade.vue:81
 msgid "Upgrading Nginx UI, please wait..."
 msgstr "正在升級 Nginx UI,請稍候..."
 
@@ -5689,7 +5714,7 @@ msgstr "上游"
 msgid "Upstream Name"
 msgstr "Upstream 名稱"
 
-#: src/views/environments/group/columns.ts:59
+#: src/views/namespace/columns.ts:59
 msgid "Upstream Test Type"
 msgstr "上游測試類型"
 
@@ -5697,7 +5722,7 @@ msgstr "上游測試類型"
 msgid "Uptime:"
 msgstr "運作時間:"
 
-#: src/views/environments/list/envColumns.tsx:18
+#: src/views/node/nodeColumns.tsx:18
 msgid "URL"
 msgstr "URL"
 
@@ -5765,7 +5790,7 @@ msgstr "驗證備份檔案完整性"
 msgid "Verify system requirements"
 msgstr "驗證系統要求"
 
-#: src/views/environments/list/envColumns.tsx:30
+#: src/views/node/nodeColumns.tsx:30
 msgid "Version"
 msgstr "版本"
 
@@ -5778,8 +5803,7 @@ msgstr "檢視"
 msgid "View all notifications"
 msgstr "檢視所有通知"
 
-#: src/views/environments/list/BatchUpgrader.vue:235
-#: src/views/system/Upgrade.vue:279
+#: src/views/node/BatchUpgrader.vue:235 src/views/system/Upgrade.vue:279
 msgid "View on GitHub"
 msgstr "在 GitHub 上查看"
 
@@ -5796,7 +5820,7 @@ msgstr "已檢視"
 msgid "Waiting processes"
 msgstr "等待過程"
 
-#: src/constants/index.ts:23 src/views/backup/components/BackupCreator.vue:138
+#: src/constants/index.ts:24 src/views/backup/components/BackupCreator.vue:138
 #: src/views/config/InspectConfig.vue:51
 #: src/views/notification/notificationColumns.tsx:21
 #: src/views/preference/components/AuthSettings/AddPasskey.vue:87
@@ -5869,8 +5893,8 @@ msgstr "啟用後,Nginx UI 將在啟動時自動重新註冊使用者。通常
 #: src/views/stream/components/RightPanel/Basic.vue:57
 msgid ""
 "When you enable/disable, delete, or save this site, the nodes set in the "
-"Node Group and the nodes selected below will be synchronized."
-msgstr "當您啟用/停用、刪除或儲存此網站時,在節點群組中設定的節點以及下方選擇的節點將會同步更新。"
+"namespace and the nodes selected below will be synchronized."
+msgstr "當您啟用/停用、刪除或儲存此站點時,命名空間中設定的節點和下方選擇的節點將被同步。"
 
 #: src/views/preference/components/AuthSettings/RecoveryCodes.vue:140
 msgid ""
@@ -5901,7 +5925,7 @@ msgstr "worker 行程"
 msgid "Workers"
 msgstr "worker"
 
-#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:57
+#: src/layouts/HeaderLayout.vue:62 src/routes/index.ts:59
 #: src/views/workspace/WorkSpace.vue:52
 msgid "Workspace"
 msgstr "工作區"
@@ -5927,8 +5951,8 @@ msgstr "將憑證私鑰寫入磁碟"
 msgid "Writing certificate to disk"
 msgstr "將憑證寫入磁碟"
 
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:110
-#: src/components/EnvGroupTabs/EnvGroupTabs.vue:98
+#: src/components/NamespaceTabs/NamespaceTabs.vue:110
+#: src/components/NamespaceTabs/NamespaceTabs.vue:98
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:101
 #: src/components/NgxConfigEditor/LocationEditor.vue:88
 #: src/views/preference/tabs/AuthSettings.vue:131
@@ -5936,7 +5960,7 @@ msgstr "將憑證寫入磁碟"
 msgid "Yes"
 msgstr "是的"
 
-#: src/views/terminal/Terminal.vue:132
+#: src/views/terminal/Terminal.vue:142
 msgid ""
 "You are accessing this terminal over an insecure HTTP connection on a "
 "non-localhost domain. This may expose sensitive information."
@@ -5991,6 +6015,12 @@ msgstr "您的舊代碼將不再有效。"
 msgid "Your passkeys"
 msgstr "您的通行金鑰"
 
+#~ msgid "Node Group"
+#~ msgstr "節點群組"
+
+#~ msgid "Node Groups"
+#~ msgstr "節點群組"
+
 #~ msgid "Check if the conf.d directory exists"
 #~ msgstr "檢查 conf.d 目錄是否存在"
 
@@ -6048,9 +6078,6 @@ msgstr "您的通行金鑰"
 #~ msgid "Last Backup Error"
 #~ msgstr "最後一次備份錯誤"
 
-#~ msgid "Apply"
-#~ msgstr "應用"
-
 #~ msgid "Apply bulk action successfully"
 #~ msgstr "批次操作成功應用"
 

+ 2 - 2
app/src/layouts/SideBar.vue

@@ -4,8 +4,8 @@ import type { AntdIconType } from '@ant-design/icons-vue/lib/components/AntdIcon
 import type { Key } from 'ant-design-vue/es/_util/type'
 import type { NgxModule } from '@/api/ngx'
 import ngx from '@/api/ngx'
-import EnvIndicator from '@/components/EnvIndicator'
 import Logo from '@/components/Logo'
+import NodeIndicator from '@/components/NodeIndicator'
 import { useGlobalStore } from '@/pinia/moudule/global'
 import { routes } from '@/routes'
 
@@ -112,7 +112,7 @@ const visible: ComputedRef<Sidebar[]> = computed(() => {
       v-model:selected-keys="selectedKey"
       mode="inline"
     >
-      <EnvIndicator />
+      <NodeIndicator />
 
       <template v-for="s in visible">
         <AMenuItem

+ 2 - 2
app/src/lib/http/interceptors.ts

@@ -84,8 +84,8 @@ export function setupRequestInterceptor() {
         config.headers.Authorization = token.value
       }
 
-      if (settings.environment.id) {
-        config.headers['X-Node-ID'] = settings.environment.id
+      if (settings.node.id) {
+        config.headers['X-Node-ID'] = settings.node.id
       }
 
       if (secureSessionId.value) {

+ 1 - 1
app/src/lib/websocket/index.ts

@@ -29,7 +29,7 @@ function ws(url: string, reconnect: boolean = true): ReconnectingWebSocket | Web
   const settings = useSettingsStore()
   const { token, shortToken } = storeToRefs(user)
 
-  const _url = buildWebSocketUrl(url, token.value, shortToken.value, settings.environment.id)
+  const _url = buildWebSocketUrl(url, token.value, shortToken.value, settings.node.id)
 
   if (reconnect)
     return new ReconnectingWebSocket(_url, undefined, { maxRetries: 10 })

+ 61 - 26
app/src/pinia/moudule/nodeAvailability.ts

@@ -1,6 +1,7 @@
 import type ReconnectingWebSocket from 'reconnecting-websocket'
-import type { Environment } from '@/api/environment'
+import type { Node } from '@/api/node'
 import { defineStore } from 'pinia'
+import nodeApi from '@/api/node'
 import ws from '@/lib/websocket'
 
 export interface NodeStatus {
@@ -19,14 +20,40 @@ export const useNodeAvailabilityStore = defineStore('nodeAvailability', () => {
   const isInitialized = ref(false)
   const lastUpdateTime = ref<string>('')
 
-  // Initialize node data from WebSocket
-  function initialize() {
+  // Initialize node data from API and WebSocket
+  async function initialize() {
     if (isInitialized.value) {
       return
     }
 
-    connectWebSocket()
-    isInitialized.value = true
+    try {
+      // First, load the initial node data from API
+      const response = await nodeApi.getList({ enabled: true })
+      const nodeMap: Record<number, NodeStatus> = {}
+
+      response.data.forEach((node: Node) => {
+        nodeMap[node.id] = {
+          id: node.id,
+          name: node.name,
+          status: node.status ?? false,
+          url: node.url,
+          token: node.token,
+          enabled: true,
+        }
+      })
+
+      nodes.value = nodeMap
+
+      // Then connect WebSocket for real-time updates
+      connectWebSocket()
+      isInitialized.value = true
+    }
+    catch (error) {
+      console.error('Failed to initialize node data:', error)
+      // Still try to connect WebSocket even if API call fails
+      connectWebSocket()
+      isInitialized.value = true
+    }
   }
 
   // Connect to WebSocket for real-time updates
@@ -42,7 +69,7 @@ export const useNodeAvailabilityStore = defineStore('nodeAvailability', () => {
 
     try {
       // Create new WebSocket connection
-      const socket = ws('/api/environments/enabled', true)
+      const socket = ws('/api/analytic/nodes', true)
       websocket.value = socket
 
       socket.onopen = () => {
@@ -51,26 +78,34 @@ export const useNodeAvailabilityStore = defineStore('nodeAvailability', () => {
 
       socket.onmessage = event => {
         try {
-          const message = JSON.parse(event.data)
-
-          if (message.event === 'message') {
-            const environments: Environment[] = message.data
-            const nodeMap: Record<number, NodeStatus> = {}
-
-            environments.forEach(env => {
-              nodeMap[env.id] = {
-                id: env.id,
-                name: env.name,
-                status: env.status ?? false,
-                url: env.url,
-                token: env.token,
+          const nodesData = JSON.parse(event.data)
+
+          // The /api/analytic/nodes endpoint returns an object with node IDs as keys
+          // Update existing nodes' status or create new ones if not exist
+          Object.keys(nodesData).forEach((nodeIdStr: string) => {
+            const nodeId = Number.parseInt(nodeIdStr)
+            const nodeData = nodesData[nodeIdStr]
+
+            // Update existing node or create new one
+            const existingNode = nodes.value[nodeId]
+            if (existingNode) {
+              // Update status for existing node
+              existingNode.status = nodeData.status ?? false
+            }
+            else {
+              // Create new node entry (this should be initialized from API call)
+              nodes.value[nodeId] = {
+                id: nodeId,
+                name: nodeData.name || `Node ${nodeId}`,
+                status: nodeData.status ?? false,
+                url: nodeData.url,
+                token: nodeData.token,
                 enabled: true,
               }
-            })
+            }
+          })
 
-            nodes.value = nodeMap
-            lastUpdateTime.value = new Date().toISOString()
-          }
+          lastUpdateTime.value = new Date().toISOString()
         }
         catch (error) {
           console.error('Error parsing WebSocket message:', error)
@@ -82,7 +117,7 @@ export const useNodeAvailabilityStore = defineStore('nodeAvailability', () => {
       }
 
       socket.onerror = error => {
-        console.warn('Failed to connect to environments WebSocket endpoint', error)
+        console.warn('Failed to connect to nodes WebSocket endpoint', error)
         isConnected.value = false
       }
     }
@@ -92,8 +127,8 @@ export const useNodeAvailabilityStore = defineStore('nodeAvailability', () => {
   }
 
   // Start monitoring (initialize + WebSocket)
-  function startMonitoring() {
-    initialize()
+  async function startMonitoring() {
+    await initialize()
   }
 
   // Stop monitoring and cleanup

+ 12 - 12
app/src/pinia/moudule/nodeGroupStore.ts

@@ -1,10 +1,10 @@
-import type { EnvGroup } from '@/api/env_group'
+import type { Namespace } from '@/api/namespace'
 import { defineStore } from 'pinia'
-import env_group from '@/api/env_group'
+import namespace from '@/api/namespace'
 
 export const useNodeGroupStore = defineStore('nodeGroup', () => {
-  const envGroups = ref<EnvGroup[]>([])
-  const envGroupMap = ref<Record<number, EnvGroup>>({})
+  const namespaces = ref<Namespace[]>([])
+  const namespaceMap = ref<Record<number, Namespace>>({})
   const isLoading = ref(false)
   const isInitialized = ref(false)
   const lastUpdateTime = ref<string>('')
@@ -28,12 +28,12 @@ export const useNodeGroupStore = defineStore('nodeGroup', () => {
     isLoading.value = true
 
     try {
-      const allGroups: EnvGroup[] = []
+      const allGroups: Namespace[] = []
       let currentPage = 1
       let hasMorePages = true
 
       while (hasMorePages) {
-        const response = await env_group.getList({
+        const response = await namespace.getList({
           page: currentPage,
           page_size: 100, // Use a reasonable page size
         })
@@ -53,12 +53,12 @@ export const useNodeGroupStore = defineStore('nodeGroup', () => {
         currentPage++
       }
 
-      envGroups.value = allGroups
+      namespaces.value = allGroups
       lastUpdateTime.value = new Date().toISOString()
-      envGroupMap.value = allGroups.reduce((acc, group) => {
+      namespaceMap.value = allGroups.reduce((acc, group) => {
         acc[group.id] = group
         return acc
-      }, {} as Record<number, EnvGroup>)
+      }, {} as Record<number, Namespace>)
     }
     catch (error) {
       console.error('Failed to load environment groups:', error)
@@ -69,8 +69,8 @@ export const useNodeGroupStore = defineStore('nodeGroup', () => {
   }
 
   // Get environment group by ID
-  function getGroupById(id: number): EnvGroup | undefined {
-    return envGroupMap.value[id]
+  function getGroupById(id: number): Namespace | undefined {
+    return namespaceMap.value[id]
   }
 
   // Refresh all data
@@ -79,7 +79,7 @@ export const useNodeGroupStore = defineStore('nodeGroup', () => {
   }
 
   return {
-    envGroups: readonly(envGroups),
+    namespaces: readonly(namespaces),
     isLoading: readonly(isLoading),
     isInitialized: readonly(isInitialized),
     lastUpdateTime: readonly(lastUpdateTime),

+ 5 - 5
app/src/pinia/moudule/settings.ts

@@ -6,7 +6,7 @@ export const useSettingsStore = defineStore('settings', {
     language: '',
     theme: 'light',
     preference_theme: 'auto',
-    environment: {
+    node: {
       id: 0,
       name: 'Local',
     },
@@ -15,7 +15,7 @@ export const useSettingsStore = defineStore('settings', {
   }),
   getters: {
     is_remote(): boolean {
-      return this.environment.id !== 0
+      return this.node.id !== 0
     },
   },
   actions: {
@@ -30,9 +30,9 @@ export const useSettingsStore = defineStore('settings', {
     set_preference_theme(t: string) {
       this.preference_theme = t
     },
-    clear_environment() {
-      this.environment.id = 0
-      this.environment.name = 'Local'
+    clear_node() {
+      this.node.id = 0
+      this.node.name = 'Local'
     },
   },
   persist: [

+ 4 - 2
app/src/routes/index.ts

@@ -8,9 +8,10 @@ import { backupRoutes } from './modules/backup'
 import { certificatesRoutes } from './modules/certificates'
 import { configRoutes } from './modules/config'
 import { dashboardRoutes } from './modules/dashboard'
-import { environmentsRoutes } from './modules/environments'
 import { errorRoutes } from './modules/error'
+import { namespacesRoutes } from './modules/namespaces'
 import { nginxLogRoutes } from './modules/nginx_log'
+import { nodesRoutes } from './modules/nodes'
 import { notificationsRoutes } from './modules/notifications'
 import { preferenceRoutes } from './modules/preference'
 import { sitesRoutes } from './modules/sites'
@@ -29,7 +30,8 @@ const mainLayoutChildren: RouteRecordRaw[] = [
   ...certificatesRoutes,
   ...terminalRoutes,
   ...nginxLogRoutes,
-  ...environmentsRoutes,
+  ...namespacesRoutes,
+  ...nodesRoutes,
   ...notificationsRoutes,
   ...userRoutes,
   ...preferenceRoutes,

+ 0 - 38
app/src/routes/modules/environments.ts

@@ -1,38 +0,0 @@
-import type { RouteRecordRaw } from 'vue-router'
-import { DatabaseOutlined } from '@ant-design/icons-vue'
-import { useSettingsStore } from '@/pinia'
-
-export const environmentsRoutes: RouteRecordRaw[] = [
-  {
-    path: 'environments',
-    name: 'Environments',
-    component: () => import('@/layouts/BaseRouterView.vue'),
-    meta: {
-      name: () => $gettext('Environments'),
-      icon: DatabaseOutlined,
-      hiddenInSidebar: (): boolean => {
-        const settings = useSettingsStore()
-
-        return settings.is_remote
-      },
-    },
-    children: [
-      {
-        path: 'list',
-        name: 'env.list',
-        component: () => import('@/views/environments/list/Environment.vue'),
-        meta: {
-          name: () => $gettext('Nodes'),
-        },
-      },
-      {
-        path: 'groups',
-        name: 'env.groups',
-        component: () => import('@/views/environments/group/EnvGroup.vue'),
-        meta: {
-          name: () => $gettext('Node Groups'),
-        },
-      },
-    ],
-  },
-]

+ 14 - 0
app/src/routes/modules/namespaces.ts

@@ -0,0 +1,14 @@
+import type { RouteRecordRaw } from 'vue-router'
+import { StarOutlined } from '@ant-design/icons-vue'
+
+export const namespacesRoutes: RouteRecordRaw[] = [
+  {
+    path: 'namespaces',
+    name: 'Namespaces',
+    component: () => import('@/views/namespace/Namespace.vue'),
+    meta: {
+      name: () => $gettext('Namespaces'),
+      icon: StarOutlined,
+    },
+  },
+]

+ 20 - 0
app/src/routes/modules/nodes.ts

@@ -0,0 +1,20 @@
+import type { RouteRecordRaw } from 'vue-router'
+import { DatabaseOutlined } from '@ant-design/icons-vue'
+import { useSettingsStore } from '@/pinia'
+
+export const nodesRoutes: RouteRecordRaw[] = [
+  {
+    path: 'nodes',
+    name: 'Nodes',
+    component: () => import('@/views/node/Node.vue'),
+    meta: {
+      name: () => $gettext('Nodes'),
+      icon: DatabaseOutlined,
+      hiddenInSidebar: (): boolean => {
+        const settings = useSettingsStore()
+
+        return settings.is_remote
+      },
+    },
+  },
+]

+ 1 - 1
app/src/version.json

@@ -1 +1 @@
-{"version":"2.1.17","build_id":9,"total_build":476}
+{"version":"2.1.17","build_id":11,"total_build":478}

+ 5 - 5
app/src/views/dashboard/Environments.vue → app/src/views/dashboard/Nodes.vue

@@ -1,9 +1,9 @@
 <script setup lang="ts">
 import type { Ref } from 'vue'
-import type { Node } from '@/api/environment'
+import type { Node } from '@/api/node'
 import Icon, { LinkOutlined, ThunderboltOutlined } from '@ant-design/icons-vue'
 import analytic from '@/api/analytic'
-import environment from '@/api/environment'
+import nodeApi from '@/api/node'
 import logo from '@/assets/img/logo.png'
 import pulse from '@/assets/svg/pulse.svg?component'
 import { formatDateTime } from '@/lib/helper'
@@ -26,7 +26,7 @@ const nodeMap = computed(() => {
 })
 
 onMounted(() => {
-  environment.getList({ enabled: true }).then(r => {
+  nodeApi.getList({ enabled: true }).then(r => {
     data.value.push(...r.data)
   })
 })
@@ -58,7 +58,7 @@ onMounted(() => {
   })
 })
 
-const { environment: env } = useSettingsStore()
+const { node: env } = useSettingsStore()
 
 function linkStart(node: Node) {
   env.id = node.id
@@ -77,7 +77,7 @@ const visible = computed(() => {
   <ACard
     v-if="visible"
     class="env-list-card w-full max-w-none"
-    :title="$gettext('Environments')"
+    :title="$gettext('Nodes')"
     :bordered="false"
   >
     <AList

+ 2 - 2
app/src/views/dashboard/ServerDashBoard.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import Environments from '@/views/dashboard/Environments.vue'
+import Nodes from '@/views/dashboard/Nodes.vue'
 import ServerAnalytic from '@/views/dashboard/ServerAnalytic.vue'
 
 const key = ref(0)
@@ -12,7 +12,7 @@ setInterval(() => {
 <template>
   <div>
     <ServerAnalytic :key />
-    <Environments />
+    <Nodes />
   </div>
 </template>
 

+ 1 - 3
app/src/views/dashboard/components/NodeAnalyticItem.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import type { Node } from '@/api/environment'
+import type { Node } from '@/api/node'
 import Icon, { ArrowDownOutlined, ArrowUpOutlined, DatabaseOutlined, LineChartOutlined, SendOutlined } from '@ant-design/icons-vue'
 import cpu from '@/assets/svg/cpu.svg?component'
 import memory from '@/assets/svg/memory.svg?component'
@@ -8,8 +8,6 @@ import { bytesToSize } from '@/lib/helper'
 
 interface ExtendedNode extends Node {
   version?: string
-  status?: boolean
-  url?: string
   avg_load?: {
     load1: number
     load5: number

+ 5 - 5
app/src/views/environments/group/EnvGroup.vue → app/src/views/namespace/Namespace.vue

@@ -1,14 +1,14 @@
 <script setup lang="ts">
 import type { UpdateOrderRequest } from '@/api/curd'
 import { StdCurd } from '@uozi-admin/curd'
-import env_group from '@/api/env_group'
+import namespace from '@/api/namespace'
 import NodeSelector from '@/components/NodeSelector'
-import columns from '@/views/environments/group/columns'
+import columns from './columns'
 
 const table = useTemplateRef('table')
 
 async function handleDragEnd(data: UpdateOrderRequest) {
-  await env_group.updateOrder(data)
+  await namespace.updateOrder(data)
   table.value?.refresh()
 }
 </script>
@@ -16,8 +16,8 @@ async function handleDragEnd(data: UpdateOrderRequest) {
 <template>
   <StdCurd
     ref="table"
-    :title="$gettext('Node Groups')"
-    :api="env_group"
+    :title="$gettext('Namespaces')"
+    :api="namespace"
     :columns="columns"
     :scroll-x="600"
     disable-export

+ 1 - 1
app/src/views/environments/group/columns.ts → app/src/views/namespace/columns.ts

@@ -1,6 +1,6 @@
 import type { StdTableColumn } from '@uozi-admin/curd'
 import { datetimeRender, maskRender } from '@uozi-admin/curd'
-import { PostSyncAction, UpstreamTestType } from '@/api/env_group'
+import { PostSyncAction, UpstreamTestType } from '@/api/namespace'
 import { PostSyncActionMask, UpstreamTestTypeMask } from '@/constants'
 import { useNodeAvailabilityStore } from '@/pinia/moudule/nodeAvailability'
 

+ 3 - 3
app/src/views/environments/list/BatchUpgrader.vue → app/src/views/node/BatchUpgrader.vue

@@ -1,5 +1,5 @@
 <script setup lang="ts">
-import type { Environment } from '@/api/environment'
+import type { Node } from '@/api/node'
 import type { ReleaseInfo } from '@/api/upgrade'
 import { cloneDeep } from 'lodash'
 import { marked } from 'marked'
@@ -11,7 +11,7 @@ const emit = defineEmits(['success'])
 const route = useRoute()
 const visible = ref(false)
 const nodeIds = ref<number[]>([])
-const nodes = ref<Environment[]>([])
+const nodes = ref<Node[]>([])
 const channel = ref('stable')
 const nodeNames = computed(() => nodes.value.map(v => v.name).join(', '))
 const loading = ref(false)
@@ -59,7 +59,7 @@ function getLatestRelease() {
   })
 }
 
-function open(selectedNodeIds: Ref<number[]>, selectedNodes: Ref<Environment[]>) {
+function open(selectedNodeIds: Ref<number[]>, selectedNodes: Ref<Node[]>) {
   showLogContainer.value = false
   visible.value = true
   nodeIds.value = selectedNodeIds.value

+ 7 - 8
app/src/views/environments/list/Environment.vue → app/src/views/node/Node.vue

@@ -1,11 +1,10 @@
 <script setup lang="tsx">
 import { StdCurd } from '@uozi-admin/curd'
 import { message } from 'ant-design-vue'
-import environment from '@/api/environment'
-import node from '@/api/node'
+import nodeApi from '@/api/node'
 import FooterToolBar from '@/components/FooterToolbar'
 import BatchUpgrader from './BatchUpgrader.vue'
-import envColumns from './envColumns'
+import envColumns from './nodeColumns'
 
 const route = useRoute()
 const curd = ref()
@@ -63,7 +62,7 @@ onBeforeUnmount(() => {
 
 function loadFromSettings() {
   loadingFromSettings.value = true
-  environment.load_from_settings().then(() => {
+  nodeApi.load_from_settings().then(() => {
     curd.value.getList()
     message.success($gettext('Load successfully'))
   }).finally(() => {
@@ -85,7 +84,7 @@ function reloadNginx() {
   }
 
   loadingReload.value = true
-  node.reloadNginx(selectedNodeIds.value).then(() => {
+  nodeApi.reloadNginx(selectedNodeIds.value).then(() => {
     message.success($gettext('Nginx reload operations have been dispatched to remote nodes'))
   }).finally(() => {
     loadingReload.value = false
@@ -99,7 +98,7 @@ function restartNginx() {
   }
 
   loadingRestart.value = true
-  node.restartNginx(selectedNodeIds.value).then(() => {
+  nodeApi.restartNginx(selectedNodeIds.value).then(() => {
     message.success($gettext('Nginx restart operations have been dispatched to remote nodes'))
   }).finally(() => {
     loadingRestart.value = false
@@ -128,8 +127,8 @@ const inTrash = computed(() => {
         },
         pagination: false,
       }"
-      :title="$gettext('Environments')"
-      :api="environment"
+      :title="$gettext('Nodes')"
+      :api="nodeApi"
       :columns="envColumns"
       disable-export
     >

+ 0 - 0
app/src/views/environments/list/envColumns.tsx → app/src/views/node/nodeColumns.tsx


+ 4 - 0
app/src/views/preference/Preference.vue

@@ -126,5 +126,9 @@ onMounted(() => {
   max-width: 850px;
   margin: 0 auto;
   padding: 0 10px;
+
+  :deep(label) {
+    font-weight: 500;
+  }
 }
 </style>

+ 84 - 87
app/src/views/preference/tabs/AuthSettings.vue

@@ -50,97 +50,94 @@ function removeBannedIP(ip: string) {
 </script>
 
 <template>
-  <div class="flex justify-center">
-    <div>
-      <h2>
-        {{ $gettext('Authentication Settings') }}
-      </h2>
-      <div
-        v-if="data.webauthn.rpid
-          && data.webauthn.rp_display_name
-          && data.webauthn.rp_origins?.length > 0"
-        class="mb-4"
-      >
-        <h3>
-          {{ $gettext('Webauthn') }}
-        </h3>
-        <div class="mb-4">
-          <h4>
-            {{ $gettext('RPID') }}
-          </h4>
-          <p>{{ data.webauthn.rpid }}</p>
-        </div>
-        <div class="mb-4">
-          <h4>
-            {{ $gettext('RP Display Name') }}
-          </h4>
-          <p>{{ data.webauthn.rp_display_name }}</p>
-        </div>
-        <div>
-          <h4>
-            {{ $gettext('RP Origins') }}
-          </h4>
-          <div
-            v-for="origin in data.webauthn.rp_origins"
-            :key="origin"
-            class="mb-4"
-          >
-            {{ origin }}
-          </div>
+  <div>
+    <h2>
+      {{ $gettext('Authentication Settings') }}
+    </h2>
+    <div
+      v-if="data.webauthn.rpid
+        && data.webauthn.rp_display_name
+        && data.webauthn.rp_origins?.length > 0"
+      class="mb-4"
+    >
+      <h3>
+        {{ $gettext('Webauthn') }}
+      </h3>
+      <div class="mb-4">
+        <h4>
+          {{ $gettext('RPID') }}
+        </h4>
+        <p>{{ data.webauthn.rpid }}</p>
+      </div>
+      <div class="mb-4">
+        <h4>
+          {{ $gettext('RP Display Name') }}
+        </h4>
+        <p>{{ data.webauthn.rp_display_name }}</p>
+      </div>
+      <div>
+        <h4>
+          {{ $gettext('RP Origins') }}
+        </h4>
+        <div
+          v-for="origin in data.webauthn.rp_origins"
+          :key="origin"
+          class="mb-4"
+        >
+          {{ origin }}
         </div>
       </div>
-      <h3>{{ $gettext('Throttle') }}</h3>
-      <AForm
-        layout="horizontal"
-        style="width:90%;max-width: 500px"
+    </div>
+    <h3>{{ $gettext('Throttle') }}</h3>
+    <AForm
+      layout="horizontal"
+    >
+      <AFormItem :label="$gettext('Ban Threshold Minutes')">
+        <AInputNumber
+          v-model:value="data.auth.ban_threshold_minutes"
+          min="1"
+        />
+      </AFormItem>
+      <AFormItem :label="$gettext('Max Attempts')">
+        <AInputNumber
+          v-model:value="data.auth.max_attempts"
+          min="1"
+        />
+      </AFormItem>
+    </AForm>
+    <AAlert
+      class="mb-6"
+      show-icon
+      :message="$gettext('If the number of login failed attempts from a ip reach the max attempts in ban threshold minutes,'
+        + ' the ip will be banned for a period of time.')"
+      type="info"
+    />
+    <h3 class="mb-4">
+      {{ $gettext('Banned IPs') }}
+    </h3>
+    <div class="mb-6">
+      <ATable
+        :columns="bannedIPColumns"
+        row-key="ip"
+        :data-source="bannedIPs"
+        size="small"
       >
-        <AFormItem :label="$gettext('Ban Threshold Minutes')">
-          <AInputNumber
-            v-model:value="data.auth.ban_threshold_minutes"
-            min="1"
-          />
-        </AFormItem>
-        <AFormItem :label="$gettext('Max Attempts')">
-          <AInputNumber
-            v-model:value="data.auth.max_attempts"
-            min="1"
-          />
-        </AFormItem>
-      </AForm>
-      <AAlert
-        class="mb-6"
-        :message="$gettext('Tips')"
-        :description="$gettext('If the number of login failed attempts from a ip reach the max attempts in ban threshold minutes,'
-          + ' the ip will be banned for a period of time.')"
-        type="info"
-      />
-      <h3 class="mb-4">
-        {{ $gettext('Banned IPs') }}
-      </h3>
-      <div class="mb-6">
-        <ATable
-          :columns="bannedIPColumns"
-          row-key="ip"
-          :data-source="bannedIPs"
-          size="small"
-        >
-          <template #bodyCell="{ column, record }">
-            <template v-if="column.dataIndex === 'action'">
-              <APopconfirm
-                :title="$gettext('Are you sure to delete this banned IP immediately?')"
-                :ok-text="$gettext('Yes')"
-                :cancel-text="$gettext('No')"
-                placement="bottom"
-                @confirm="() => removeBannedIP(record.ip)"
-              >
-                <a>
-                  {{ $gettext('Remove') }}
-                </a>
-              </APopconfirm>
-            </template>
+        <template #bodyCell="{ column, record }">
+          <template v-if="column.dataIndex === 'action'">
+            <APopconfirm
+              :title="$gettext('Are you sure to delete this banned IP immediately?')"
+              :ok-text="$gettext('Yes')"
+              :cancel-text="$gettext('No')"
+              placement="bottom"
+              @confirm="() => removeBannedIP(record.ip)"
+            >
+              <a>
+                {{ $gettext('Remove') }}
+              </a>
+            </APopconfirm>
           </template>
-        </ATable>
-      </div>
+        </template>
+      </ATable>
     </div>
   </div>
 </template>

+ 8 - 8
app/src/views/site/site_edit/components/RightPanel/Basic.vue

@@ -2,12 +2,12 @@
 import type { SiteStatus } from '@/api/site'
 import { InfoCircleOutlined } from '@ant-design/icons-vue'
 import { StdSelector } from '@uozi-admin/curd'
-import envGroup from '@/api/env_group'
+import namespace from '@/api/namespace'
 import NodeSelector from '@/components/NodeSelector'
 import SyncNodesPreview from '@/components/SyncNodesPreview'
 import { formatDateTime } from '@/lib/helper'
 import { useSettingsStore } from '@/pinia'
-import envGroupColumns from '@/views/environments/group/columns'
+import namespaceColumns from '@/views/namespace/columns'
 import SiteStatusSelect from '@/views/site/components/SiteStatusSelect.vue'
 import ConfigName from '@/views/site/site_edit/components/ConfigName/ConfigName.vue'
 import { useSiteEditorStore } from '../SiteEditor/store'
@@ -39,11 +39,11 @@ function handleStatusChanged(event: { status: SiteStatus }) {
         <AFormItem :label="$gettext('Updated at')">
           {{ formatDateTime(data.modified_at) }}
         </AFormItem>
-        <AFormItem :label="$gettext('Node Group')">
+        <AFormItem :label="$gettext('Namespace')">
           <StdSelector
-            v-model:value="data.env_group_id"
-            :get-list-api="envGroup.getList"
-            :columns="envGroupColumns"
+            v-model:value="data.namespace_id"
+            :get-list-api="namespace.getList"
+            :columns="namespaceColumns"
             display-key="name"
             selection-type="radio"
           />
@@ -60,7 +60,7 @@ function handleStatusChanged(event: { status: SiteStatus }) {
           <template #content>
             <div class="max-w-200px mb-2">
               {{ $gettext('When you enable/disable, delete, or save this site, '
-                + 'the nodes set in the Node Group and the nodes selected below will be synchronized.') }}
+                + 'the nodes set in the namespace and the nodes selected below will be synchronized.') }}
             </div>
             <div class="max-w-200px">
               {{ $gettext('Note, if the configuration file include other configurations or certificates, '
@@ -81,7 +81,7 @@ function handleStatusChanged(event: { status: SiteStatus }) {
 
       <!-- Sync nodes preview -->
       <SyncNodesPreview
-        :env-group-id="data.env_group_id"
+        :namespace-id="data.namespace_id"
         :sync-node-ids="data.sync_node_ids"
       />
     </div>

+ 1 - 1
app/src/views/site/site_edit/components/SiteEditor/SiteEditor.vue

@@ -142,7 +142,7 @@ async function save() {
           <!-- Upstream Cards Display -->
           <UpstreamCards
             :targets="upstreamTargets"
-            :env-group-id="data.env_group_id"
+            :namespace-id="data.namespace_id"
           />
 
           <NgxConfigEditor

+ 1 - 1
app/src/views/site/site_edit/components/SiteEditor/store.ts

@@ -71,7 +71,7 @@ export const useSiteEditorStore = defineStore('siteEditor', () => {
       const response = await site.updateItem(encodeURIComponent(name.value), {
         content: configText.value,
         overwrite: true,
-        env_group_id: data.value.env_group_id,
+        namespace_id: data.value.namespace_id,
         sync_node_ids: data.value.sync_node_ids,
         post_action: 'reload_nginx',
       })

+ 9 - 9
app/src/views/site/site_list/SiteList.vue

@@ -1,10 +1,10 @@
 <script setup lang="tsx">
-import type { EnvGroup } from '@/api/env_group'
+import type { Namespace } from '@/api/namespace'
 import { StdCurd } from '@uozi-admin/curd'
 import { message } from 'ant-design-vue'
-import env_group from '@/api/env_group'
+import namespace from '@/api/namespace'
 import site from '@/api/site'
-import EnvGroupTabs from '@/components/EnvGroupTabs'
+import NamespaceTabs from '@/components/NamespaceTabs'
 import { ConfigStatus } from '@/constants'
 import InspectConfig from '@/views/config/InspectConfig.vue'
 import columns from '@/views/site/site_list/columns'
@@ -16,8 +16,8 @@ const router = useRouter()
 const curd = ref()
 const inspectConfig = ref()
 
-const envGroupId = ref(Number.parseInt(route.query.env_group_id as string) || 0)
-const envGroups = ref<EnvGroup[]>([])
+const namespaceId = ref(Number.parseInt(route.query.namespace_id as string) || 0)
+const namespaces = ref<Namespace[]>([])
 
 watch(route, () => {
   inspectConfig.value?.test()
@@ -27,10 +27,10 @@ onMounted(async () => {
   let page = 1
   while (true) {
     try {
-      const { data, pagination } = await env_group.getList({ page })
+      const { data, pagination } = await namespace.getList({ page })
       if (!data || !pagination)
         return
-      envGroups.value.push(...data)
+      namespaces.value.push(...data)
       if (data.length < pagination?.per_page) {
         return
       }
@@ -77,7 +77,7 @@ function handle_click_duplicate(name: string) {
       disable-export
       row-selection-type="checkbox"
       :custom-query-params="{
-        env_group_id: envGroupId,
+        namespace_id: namespaceId,
       }"
       :scroll-x="1600"
       @edit-item="record => router.push({
@@ -97,7 +97,7 @@ function handle_click_duplicate(name: string) {
       </template>
       <template #beforeCardBody>
         <InspectConfig ref="inspectConfig" />
-        <EnvGroupTabs v-model:active-key="envGroupId" :env-groups="envGroups" />
+        <NamespaceTabs v-model:active-key="namespaceId" :namespaces="namespaces" />
       </template>
       <template #afterActions="{ record }">
         <AButton

+ 10 - 10
app/src/views/site/site_list/columns.tsx

@@ -6,11 +6,11 @@ import type { Site, SiteStatus } from '@/api/site'
 import type { JSXElements } from '@/types'
 import { datetimeRender } from '@uozi-admin/curd'
 import { Tag } from 'ant-design-vue'
-import env_group from '@/api/env_group'
-import EnvGroupRender from '@/components/EnvGroupRender'
+import namespace from '@/api/namespace'
+import NamespaceRender from '@/components/NamespaceRender'
 import ProxyTargets from '@/components/ProxyTargets'
 import { ConfigStatus } from '@/constants'
-import envGroupColumns from '@/views/environments/group/columns'
+import namespaceColumns from '@/views/namespace/columns'
 import SiteStatusSelect from '@/views/site/components/SiteStatusSelect.vue'
 
 const columns: StdTableColumn[] = [{
@@ -81,25 +81,25 @@ const columns: StdTableColumn[] = [{
   customRender: ({ record }: CustomRenderArgs) => {
     if (record.proxy_targets && record.proxy_targets.length > 0) {
       return h(ProxyTargets, {
-        envGroupId: record.env_group_id,
+        namespaceId: record.namespace_id,
         targets: record.proxy_targets,
       })
     }
     return h('span', '-')
   },
 }, {
-  title: () => $gettext('Node Group'),
-  dataIndex: 'env_group_id',
+  title: () => $gettext('Namespace'),
+  dataIndex: 'namespace_id',
   customRender: ({ record }: CustomRenderArgs<Site>) => {
-    return h(EnvGroupRender, {
-      envGroup: record.env_group || null,
+    return h(NamespaceRender, {
+      namespace: record.namespace || null,
     })
   },
   edit: {
     type: 'selector',
     selector: {
-      getListApi: env_group.getList,
-      columns: envGroupColumns,
+      getListApi: namespace.getList,
+      columns: namespaceColumns,
       valueKey: 'id',
       displayKey: 'name',
       selectionType: 'radio',

+ 9 - 9
app/src/views/stream/StreamList.vue

@@ -1,10 +1,10 @@
 <script setup lang="tsx">
-import type { EnvGroup } from '@/api/env_group'
+import type { Namespace } from '@/api/namespace'
 import { StdCurd } from '@uozi-admin/curd'
 import { message } from 'ant-design-vue'
-import env_group from '@/api/env_group'
+import namespace from '@/api/namespace'
 import stream from '@/api/stream'
-import EnvGroupTabs from '@/components/EnvGroupTabs'
+import NamespaceTabs from '@/components/NamespaceTabs'
 import InspectConfig from '@/views/config/InspectConfig.vue'
 import columns from '@/views/stream/columns'
 import StreamDuplicate from '@/views/stream/components/StreamDuplicate.vue'
@@ -15,17 +15,17 @@ const router = useRouter()
 const curd = ref()
 const inspect_config = ref()
 
-const envGroupId = ref(Number.parseInt(route.query.env_group_id as string) || 0)
-const envGroups = ref<EnvGroup[]>([])
+const namespaceId = ref(Number.parseInt(route.query.namespace_id as string) || 0)
+const namespaces = ref<Namespace[]>([])
 
 onMounted(async () => {
   let page = 1
   while (true) {
     try {
-      const { data, pagination } = await env_group.getList({ page })
+      const { data, pagination } = await namespace.getList({ page })
       if (!data || !pagination)
         return
-      envGroups.value.push(...data)
+      namespaces.value.push(...data)
       if (data.length < pagination?.per_page) {
         return
       }
@@ -91,7 +91,7 @@ function handleAddStream() {
       disable-export
       row-selection-type="checkbox"
       :custom-query-params="{
-        env_group_id: envGroupId,
+        namespace_id: namespaceId,
       }"
       :scroll-x="800"
       @edit-item="record => router.push({
@@ -106,7 +106,7 @@ function handleAddStream() {
 
       <template #beforeCardBody>
         <InspectConfig ref="inspect_config" />
-        <EnvGroupTabs v-model:active-key="envGroupId" :env-groups="envGroups" />
+        <NamespaceTabs v-model:active-key="namespaceId" :namespaces="namespaces" />
       </template>
 
       <template #afterActions="{ record }">

+ 9 - 9
app/src/views/stream/columns.tsx

@@ -3,10 +3,10 @@ import type { SiteStatus } from '@/api/site'
 import type { Stream } from '@/api/stream'
 import type { JSXElements } from '@/types'
 import { datetimeRender } from '@uozi-admin/curd'
-import env_group from '@/api/env_group'
-import EnvGroupRender from '@/components/EnvGroupRender'
+import namespace from '@/api/namespace'
+import NamespaceRender from '@/components/NamespaceRender'
 import ProxyTargets from '@/components/ProxyTargets'
-import envGroupColumns from '@/views/environments/group/columns'
+import namespaceColumns from '@/views/namespace/columns'
 import StreamStatusSelect from '@/views/stream/components/StreamStatusSelect.vue'
 
 const columns: StdTableColumn[] = [{
@@ -55,18 +55,18 @@ const columns: StdTableColumn[] = [{
     return h('span', '-')
   },
 }, {
-  title: () => $gettext('Node Group'),
-  dataIndex: 'env_group_id',
+  title: () => $gettext('Namespace'),
+  dataIndex: 'namespace_id',
   customRender: ({ record }: CustomRenderArgs<Stream>) => {
-    return h(EnvGroupRender, {
-      envGroup: record.env_group || null,
+    return h(NamespaceRender, {
+      namespace: record.namespace || null,
     })
   },
   edit: {
     type: 'selector',
     selector: {
-      getListApi: env_group.getList,
-      columns: envGroupColumns,
+      getListApi: namespace.getList,
+      columns: namespaceColumns,
       valueKey: 'id',
       displayKey: 'name',
       selectionType: 'radio',

+ 8 - 8
app/src/views/stream/components/RightPanel/Basic.vue

@@ -2,12 +2,12 @@
 import { InfoCircleOutlined } from '@ant-design/icons-vue'
 import { StdSelector } from '@uozi-admin/curd'
 import { storeToRefs } from 'pinia'
-import envGroup from '@/api/env_group'
+import namespace from '@/api/namespace'
 import NodeSelector from '@/components/NodeSelector'
 import SyncNodesPreview from '@/components/SyncNodesPreview'
 import { formatDateTime } from '@/lib/helper'
 import { useSettingsStore } from '@/pinia'
-import envGroupColumns from '@/views/environments/group/columns'
+import namespaceColumns from '@/views/namespace/columns'
 import { useStreamEditorStore } from '../../store'
 import ConfigName from '../ConfigName.vue'
 import StreamStatusSelect from '../StreamStatusSelect.vue'
@@ -36,11 +36,11 @@ const showSync = computed(() => !settings.is_remote)
       {{ formatDateTime(data.modified_at) }}
     </AFormItem>
 
-    <AFormItem :label="$gettext('Node Group')">
+    <AFormItem :label="$gettext('Namespace')">
       <StdSelector
-        v-model:value="data.env_group_id"
-        :get-list-api="envGroup.getList"
-        :columns="envGroupColumns"
+        v-model:value="data.namespace_id"
+        :get-list-api="namespace.getList"
+        :columns="namespaceColumns"
         display-key="name"
         selection-type="radio"
       />
@@ -55,7 +55,7 @@ const showSync = computed(() => !settings.is_remote)
           <template #content>
             <div class="max-w-200px mb-2">
               {{ $gettext('When you enable/disable, delete, or save this site, '
-                + 'the nodes set in the Node Group and the nodes selected below will be synchronized.') }}
+                + 'the nodes set in the namespace and the nodes selected below will be synchronized.') }}
             </div>
             <div class="max-w-200px">
               {{ $gettext('Note, if the configuration file include other configurations or certificates, '
@@ -76,7 +76,7 @@ const showSync = computed(() => !settings.is_remote)
 
       <!-- Sync nodes preview -->
       <SyncNodesPreview
-        :env-group-id="data.env_group_id"
+        :namespace-id="data.namespace_id"
         :sync-node-ids="data.sync_node_ids"
       />
     </div>

+ 1 - 1
app/src/views/stream/components/StreamEditor.vue

@@ -100,7 +100,7 @@ const upstreamTargets = computed(() => {
             <!-- Upstream Cards Display -->
             <UpstreamCards
               :targets="upstreamTargets"
-              :env-group-id="data.env_group_id"
+              :namespace-id="data.namespace_id"
             />
 
             <NgxConfigEditor

+ 1 - 1
app/src/views/stream/store.ts

@@ -60,7 +60,7 @@ export const useStreamEditorStore = defineStore('streamEditor', () => {
       const response = await stream.updateItem(encodeURIComponent(name.value), {
         content: configText.value,
         overwrite: true,
-        env_group_id: data.value.env_group_id,
+        namespace_id: data.value.namespace_id,
         sync_node_ids: data.value.sync_node_ids,
         post_action: 'reload_nginx',
       })

+ 13 - 13
internal/analytic/node.go

@@ -38,8 +38,8 @@ type NodeStat struct {
 }
 
 type Node struct {
-	EnvironmentID int `json:"environment_id,omitempty"`
-	*model.Environment
+	NodeID int `json:"node_id,omitempty"`
+	*model.Node
 	NodeStat
 	NodeInfo
 }
@@ -54,31 +54,31 @@ func init() {
 	NodeMap = make(TNodeMap)
 }
 
-func GetNode(env *model.Environment) (n *Node) {
-	if env == nil {
+func GetNode(node *model.Node) (n *Node) {
+	if node == nil {
 		// this should never happen
-		logger.Error("env is nil")
+		logger.Error("node is nil")
 		return
 	}
-	if !env.Enabled {
+	if !node.Enabled {
 		return &Node{
-			Environment: env,
+			Node: node,
 		}
 	}
-	n, ok := NodeMap[env.ID]
+	n, ok := NodeMap[node.ID]
 	if !ok {
 		n = &Node{}
 	}
-	n.Environment = env
+	n.Node = node
 	return n
 }
 
-func InitNode(env *model.Environment) (n *Node, err error) {
+func InitNode(node *model.Node) (n *Node, err error) {
 	n = &Node{
-		Environment: env,
+		Node: node,
 	}
 
-	u, err := url.JoinPath(env.URL, "/api/node")
+	u, err := url.JoinPath(node.URL, "/api/node")
 	if err != nil {
 		return
 	}
@@ -96,7 +96,7 @@ func InitNode(env *model.Environment) (n *Node, err error) {
 		return
 	}
 
-	req.Header.Set("X-Node-Secret", env.Token)
+	req.Header.Set("X-Node-Secret", node.Token)
 
 	resp, err := client.Do(req)
 	if err != nil {

+ 71 - 71
internal/analytic/node_record.go

@@ -37,9 +37,9 @@ var defaultRetryConfig = RetryConfig{
 }
 
 type NodeRetryState struct {
-	FailureCount  int
-	LastSuccess   time.Time
-	NextRetry     time.Time
+	FailureCount int
+	LastSuccess  time.Time
+	NextRetry    time.Time
 }
 
 var (
@@ -47,30 +47,30 @@ var (
 	retryMutex  sync.Mutex
 )
 
-func getRetryState(envID uint64) *NodeRetryState {
+func getRetryState(nodeID uint64) *NodeRetryState {
 	retryMutex.Lock()
 	defer retryMutex.Unlock()
 
-	if state, exists := retryStates[envID]; exists {
+	if state, exists := retryStates[nodeID]; exists {
 		return state
 	}
 
 	state := &NodeRetryState{LastSuccess: time.Now(), NextRetry: time.Now()}
-	retryStates[envID] = state
+	retryStates[nodeID] = state
 	return state
 }
 
 // updateNodeStatus directly updates node status without condition checks
-func updateNodeStatus(envID uint64, status bool, reason string) {
+func updateNodeStatus(nodeID uint64, status bool, reason string) {
 	mutex.Lock()
 	defer mutex.Unlock()
 
 	now := time.Now()
-	if NodeMap[envID] == nil {
-		NodeMap[envID] = &Node{NodeStat: NodeStat{}}
+	if NodeMap[nodeID] == nil {
+		NodeMap[nodeID] = &Node{NodeStat: NodeStat{}}
 	}
-	NodeMap[envID].Status = status
-	NodeMap[envID].ResponseAt = now
+	NodeMap[nodeID].Status = status
+	NodeMap[nodeID].ResponseAt = now
 }
 
 func calculateNextRetryInterval(failureCount int) time.Duration {
@@ -87,8 +87,8 @@ func calculateNextRetryInterval(failureCount int) time.Duration {
 	return interval
 }
 
-func shouldRetry(envID uint64) bool {
-	state := getRetryState(envID)
+func shouldRetry(nodeID uint64) bool {
+	state := getRetryState(nodeID)
 	now := time.Now()
 
 	if state.FailureCount >= defaultRetryConfig.MaxRetries {
@@ -108,19 +108,19 @@ func shouldRetry(envID uint64) bool {
 	return !now.Before(state.NextRetry)
 }
 
-func markConnectionFailure(envID uint64, err error) {
-	state := getRetryState(envID)
+func markConnectionFailure(nodeID uint64, err error) {
+	state := getRetryState(nodeID)
 	state.FailureCount++
 	state.NextRetry = time.Now().Add(calculateNextRetryInterval(state.FailureCount))
-	updateNodeStatus(envID, false, "connection_failed")
+	updateNodeStatus(nodeID, false, "connection_failed")
 }
 
-func markConnectionSuccess(envID uint64) {
-	state := getRetryState(envID)
+func markConnectionSuccess(nodeID uint64) {
+	state := getRetryState(nodeID)
 	state.FailureCount = 0
 	state.LastSuccess = time.Now()
 	state.NextRetry = time.Now()
-	updateNodeStatus(envID, true, "connection_success")
+	updateNodeStatus(nodeID, true, "connection_success")
 }
 
 func logCurrentNodeStatus(prefix string) {
@@ -221,10 +221,10 @@ func cleanupDisabledNodes(enabledEnvIDs []uint64) {
 	mutex.Unlock()
 }
 
-func checkEnvironmentStillEnabled(envID uint64) bool {
-	env := query.Environment
-	environment, err := env.Where(env.ID.Eq(envID), env.Enabled.Is(true)).First()
-	return err == nil && environment != nil
+func checkNodeStillEnabled(nodeID uint64) bool {
+	nodeQuery := query.Node
+	node, err := nodeQuery.Where(nodeQuery.ID.Eq(nodeID), nodeQuery.Enabled.Is(true)).First()
+	return err == nil && node != nil
 }
 
 func RetrieveNodesStatus(ctx context.Context) {
@@ -242,25 +242,25 @@ func RetrieveNodesStatus(ctx context.Context) {
 	timeoutCheckTicker := time.NewTicker(10 * time.Second)
 	defer timeoutCheckTicker.Stop()
 
-	env := query.Environment
-	envs, err := env.Where(env.Enabled.Is(true)).Find()
+	nodeQuery := query.Node
+	nodes, err := nodeQuery.Where(nodeQuery.Enabled.Is(true)).Find()
 	if err != nil {
 		logger.Error(err)
 		return
 	}
 
-	var enabledEnvIDs []uint64
-	for _, e := range envs {
-		enabledEnvIDs = append(enabledEnvIDs, e.ID)
+	var enabledNodeIDs []uint64
+	for _, n := range nodes {
+		enabledNodeIDs = append(enabledNodeIDs, n.ID)
 	}
 
-	cleanupDisabledNodes(enabledEnvIDs)
+	cleanupDisabledNodes(enabledNodeIDs)
 
 	var wg sync.WaitGroup
 	defer wg.Wait()
 
-	// Channel to signal when environment list changes
-	envUpdateChan := make(chan []uint64, 1)
+	// Channel to signal when nodes list changes
+	nodeUpdateChan := make(chan []uint64, 1)
 
 	wg.Add(1)
 	go func() {
@@ -272,20 +272,20 @@ func RetrieveNodesStatus(ctx context.Context) {
 			case <-timeoutCheckTicker.C:
 				checkNodeTimeouts(2 * time.Minute)
 			case <-envCheckTicker.C:
-				currentEnvs, err := env.Where(env.Enabled.Is(true)).Find()
+				currentNodes, err := nodeQuery.Where(nodeQuery.Enabled.Is(true)).Find()
 				if err != nil {
-					logger.Error("Failed to re-query environments:", err)
+					logger.Error("Failed to re-query nodes:", err)
 					continue
 				}
 				var currentEnabledIDs []uint64
-				for _, e := range currentEnvs {
-					currentEnabledIDs = append(currentEnabledIDs, e.ID)
+				for _, n := range currentNodes {
+					currentEnabledIDs = append(currentEnabledIDs, n.ID)
 				}
-				if !equalUint64Slices(enabledEnvIDs, currentEnabledIDs) {
+				if !equalUint64Slices(enabledNodeIDs, currentEnabledIDs) {
 					cleanupDisabledNodes(currentEnabledIDs)
-					enabledEnvIDs = currentEnabledIDs
+					enabledNodeIDs = currentEnabledIDs
 					select {
-					case envUpdateChan <- currentEnabledIDs:
+					case nodeUpdateChan <- currentEnabledIDs:
 					default:
 					}
 				}
@@ -293,9 +293,9 @@ func RetrieveNodesStatus(ctx context.Context) {
 		}
 	}()
 
-	for _, env := range envs {
+	for _, node := range nodes {
 		wg.Add(1)
-		go func(e *model.Environment) {
+		go func(n *model.Node) {
 			defer wg.Done()
 			retryTicker := time.NewTicker(1 * time.Second)
 			defer retryTicker.Stop()
@@ -304,10 +304,10 @@ func RetrieveNodesStatus(ctx context.Context) {
 				select {
 				case <-ctx.Done():
 					return
-				case newEnabledIDs := <-envUpdateChan:
+				case newEnabledIDs := <-nodeUpdateChan:
 					found := false
 					for _, id := range newEnabledIDs {
-						if id == e.ID {
+						if id == n.ID {
 							found = true
 							break
 						}
@@ -316,24 +316,24 @@ func RetrieveNodesStatus(ctx context.Context) {
 						return
 					}
 				case <-retryTicker.C:
-					if !checkEnvironmentStillEnabled(e.ID) {
+					if !checkNodeStillEnabled(n.ID) {
 						retryMutex.Lock()
-						delete(retryStates, e.ID)
+						delete(retryStates, n.ID)
 						retryMutex.Unlock()
 						return
 					}
-					if !shouldRetry(e.ID) {
+					if !shouldRetry(n.ID) {
 						continue
 					}
-					if err := nodeAnalyticRecord(e, ctx); err != nil {
+					if err := nodeAnalyticRecord(n, ctx); err != nil {
 						logger.Error(err)
-						markConnectionFailure(e.ID, err)
+						markConnectionFailure(n.ID, err)
 					} else {
-						markConnectionSuccess(e.ID)
+						markConnectionSuccess(n.ID)
 					}
 				}
 			}
-		}(env)
+		}(node)
 	}
 
 }
@@ -382,37 +382,37 @@ func equalUint64Slices(a, b []uint64) bool {
 	return true
 }
 
-func nodeAnalyticRecord(env *model.Environment, ctx context.Context) error {
+func nodeAnalyticRecord(nodeModel *model.Node, ctx context.Context) error {
 	scopeCtx, cancel := context.WithCancel(ctx)
 	defer cancel()
 
-	node, err := InitNode(env)
+	node, err := InitNode(nodeModel)
 	if err != nil {
 		mutex.Lock()
-		if NodeMap[env.ID] == nil {
-			NodeMap[env.ID] = &Node{
-				Environment: env,
+		if NodeMap[nodeModel.ID] == nil {
+			NodeMap[nodeModel.ID] = &Node{
+				Node:     nodeModel,
 				NodeStat: NodeStat{Status: false, ResponseAt: time.Now()},
 			}
 		} else {
-			NodeMap[env.ID].Status = false
-			NodeMap[env.ID].ResponseAt = time.Now()
+			NodeMap[nodeModel.ID].Status = false
+			NodeMap[nodeModel.ID].ResponseAt = time.Now()
 		}
 		mutex.Unlock()
 		return err
 	}
 
 	mutex.Lock()
-	NodeMap[env.ID] = node
+	NodeMap[nodeModel.ID] = node
 	mutex.Unlock()
 
-	u, err := env.GetWebSocketURL("/api/analytic/intro")
+	u, err := nodeModel.GetWebSocketURL("/api/analytic/intro")
 	if err != nil {
 		return err
 	}
 
 	header := http.Header{}
-	header.Set("X-Node-Secret", env.Token)
+	header.Set("X-Node-Secret", nodeModel.Token)
 
 	dial := &websocket.Dialer{
 		Proxy:            http.ProxyFromEnvironment,
@@ -421,13 +421,13 @@ func nodeAnalyticRecord(env *model.Environment, ctx context.Context) error {
 
 	c, _, err := dial.Dial(u, header)
 	if err != nil {
-		updateNodeStatus(env.ID, false, "websocket_dial_failed")
+		updateNodeStatus(nodeModel.ID, false, "websocket_dial_failed")
 		return err
 	}
 
 	defer func() {
 		c.Close()
-		updateNodeStatus(env.ID, false, "websocket_connection_closed")
+		updateNodeStatus(nodeModel.ID, false, "websocket_connection_closed")
 	}()
 
 	go func() {
@@ -452,31 +452,31 @@ func nodeAnalyticRecord(env *model.Environment, ctx context.Context) error {
 		err = c.ReadJSON(&rawMsg)
 		if err != nil {
 			if helper.IsUnexpectedWebsocketError(err) {
-				updateNodeStatus(env.ID, false, "websocket_error")
+				updateNodeStatus(nodeModel.ID, false, "websocket_error")
 				return err
 			}
 			return nil
 		}
 
 		mutex.Lock()
-		if NodeMap[env.ID] == nil {
-			NodeMap[env.ID] = &Node{
-				Environment: env,
-				NodeStat:    NodeStat{Status: true, ResponseAt: time.Now()},
+		if NodeMap[nodeModel.ID] == nil {
+			NodeMap[nodeModel.ID] = &Node{
+				Node:     nodeModel,
+				NodeStat: NodeStat{Status: true, ResponseAt: time.Now()},
 			}
 		} else {
 			var fullNode Node
 			if err := json.Unmarshal(rawMsg, &fullNode); err == nil && fullNode.Version != "" {
-				NodeMap[env.ID].NodeInfo = fullNode.NodeInfo
-				NodeMap[env.ID].NodeStat = fullNode.NodeStat
+				NodeMap[nodeModel.ID].NodeInfo = fullNode.NodeInfo
+				NodeMap[nodeModel.ID].NodeStat = fullNode.NodeStat
 			} else {
 				var nodeStat NodeStat
 				if err := json.Unmarshal(rawMsg, &nodeStat); err == nil {
-					NodeMap[env.ID].NodeStat = nodeStat
+					NodeMap[nodeModel.ID].NodeStat = nodeStat
 				}
 			}
-			NodeMap[env.ID].Status = true
-			NodeMap[env.ID].ResponseAt = time.Now()
+			NodeMap[nodeModel.ID].Status = true
+			NodeMap[nodeModel.ID].ResponseAt = time.Now()
 		}
 		mutex.Unlock()
 	}

+ 11 - 11
internal/cert/sync.go

@@ -63,11 +63,11 @@ func SyncToRemoteServer(c *model.Cert) (err error) {
 		return
 	}
 
-	q := query.Environment
-	envs, _ := q.Where(q.ID.In(c.SyncNodeIds...)).Find()
-	for _, env := range envs {
+	q := query.Node
+	nodes, _ := q.Where(q.ID.In(c.SyncNodeIds...)).Find()
+	for _, node := range nodes {
 		go func() {
-			err := deploy(env, c, payloadBytes)
+			err := deploy(node, c, payloadBytes)
 			if err != nil {
 				logger.Error(err)
 			}
@@ -80,11 +80,11 @@ func SyncToRemoteServer(c *model.Cert) (err error) {
 type SyncNotificationPayload struct {
 	StatusCode int    `json:"status_code"`
 	CertName   string `json:"cert_name"`
-	EnvName    string `json:"env_name"`
+	NodeName    string `json:"node_name"`
 	Response   string `json:"response"`
 }
 
-func deploy(env *model.Environment, c *model.Cert, payloadBytes []byte) (err error) {
+func deploy(node *model.Node, c *model.Cert, payloadBytes []byte) (err error) {
 	t, err := transport.NewTransport()
 	if err != nil {
 		return
@@ -92,7 +92,7 @@ func deploy(env *model.Environment, c *model.Cert, payloadBytes []byte) (err err
 	client := http.Client{
 		Transport: t,
 	}
-	url, err := env.GetUrl("/api/cert_sync")
+	url, err := node.GetUrl("/api/cert_sync")
 	if err != nil {
 		return
 	}
@@ -100,7 +100,7 @@ func deploy(env *model.Environment, c *model.Cert, payloadBytes []byte) (err err
 	if err != nil {
 		return
 	}
-	req.Header.Set("X-Node-Secret", env.Token)
+	req.Header.Set("X-Node-Secret", node.Token)
 	resp, err := client.Do(req)
 	if err != nil {
 		return
@@ -115,18 +115,18 @@ func deploy(env *model.Environment, c *model.Cert, payloadBytes []byte) (err err
 	notificationPayload := &SyncNotificationPayload{
 		StatusCode: resp.StatusCode,
 		CertName:   c.Name,
-		EnvName:    env.Name,
+		NodeName:    node.Name,
 		Response:   string(respBody),
 	}
 
 	if resp.StatusCode != http.StatusOK {
 		notification.Error("Sync Certificate Error",
-			"Sync Certificate %{cert_name} to %{env_name} failed", notificationPayload)
+			"Sync Certificate %{cert_name} to %{node_name} failed", notificationPayload)
 		return
 	}
 
 	notification.Success("Sync Certificate Success",
-		"Sync Certificate %{cert_name} to %{env_name} successfully", notificationPayload)
+		"Sync Certificate %{cert_name} to %{node_name} successfully", notificationPayload)
 
 	return
 }

+ 0 - 0
internal/cluster/.db


+ 3 - 3
internal/cluster/cluster.go

@@ -18,7 +18,7 @@ func RegisterPredefinedNodes(ctx context.Context) {
 		return
 	}
 
-	q := query.Environment
+	q := query.Node
 	for _, nodeUrl := range settings.ClusterSettings.Node {
 		func() {
 			node, err := parseNodeUrl(nodeUrl)
@@ -52,7 +52,7 @@ func RegisterPredefinedNodes(ctx context.Context) {
 	}
 }
 
-func parseNodeUrl(nodeUrl string) (env *model.Environment, err error) {
+func parseNodeUrl(nodeUrl string) (node *model.Node, err error) {
 	u, err := url.Parse(nodeUrl)
 	if err != nil {
 		return
@@ -63,7 +63,7 @@ func parseNodeUrl(nodeUrl string) (env *model.Environment, err error) {
 	sb.WriteString(u.Host)
 	sb.WriteString(u.Path)
 
-	env = &model.Environment{
+	node = &model.Node{
 		Name:    u.Query().Get("name"),
 		URL:     sb.String(),
 		Token:   u.Query().Get("node_secret"),

+ 2 - 2
internal/config/config.go

@@ -25,8 +25,8 @@ type Config struct {
 	ModifiedAt    time.Time       `json:"modified_at"`
 	Size          int64           `json:"size,omitempty"`
 	IsDir         bool            `json:"is_dir"`
-	EnvGroupID    uint64          `json:"env_group_id"`
-	EnvGroup      *model.EnvGroup `json:"env_group,omitempty"`
+	NamespaceID   uint64          `json:"namespace_id"`
+	Namespace     *model.Namespace `json:"namespace,omitempty"`
 	Status        ConfigStatus    `json:"status"`
 	Dir           string          `json:"dir"`
 	Urls          []string        `json:"urls,omitempty"`

+ 2 - 2
internal/config/config_list.go

@@ -37,8 +37,8 @@ func (c ConfigsSort) Less(i, j int) bool {
 		flag = boolToInt(c.ConfigList[i].IsDir) > boolToInt(c.ConfigList[j].IsDir)
 	case "status":
 		flag = c.ConfigList[i].Status > c.ConfigList[j].Status
-	case "env_group_id":
-		flag = c.ConfigList[i].EnvGroupID > c.ConfigList[j].EnvGroupID
+	case "namespace_id":
+		flag = c.ConfigList[i].NamespaceID > c.ConfigList[j].NamespaceID
 	}
 
 	if c.Order == "asc" {

+ 18 - 18
internal/config/generic_list.go

@@ -20,15 +20,15 @@ type GenericListOptions struct {
 	Status      string
 	OrderBy     string
 	Sort        string
-	EnvGroupID  uint64
+	NamespaceID uint64
 	IncludeDirs bool // Whether to include directories in the results, default is false (filter out directories)
 }
 
 // ConfigEntity represents a generic configuration entity interface
 type ConfigEntity interface {
 	GetPath() string
-	GetEnvGroupID() uint64
-	GetEnvGroup() *model.EnvGroup
+	GetNamespaceID() uint64
+	GetNamespace() *model.Namespace
 }
 
 // ConfigPaths holds the directory paths for available and enabled configurations
@@ -41,10 +41,10 @@ type ConfigPaths struct {
 type StatusMapBuilder func(configFiles, enabledConfig []os.DirEntry) map[string]ConfigStatus
 
 // ConfigBuilder is a function type for building Config objects with custom logic
-type ConfigBuilder func(fileName string, fileInfo os.FileInfo, status ConfigStatus, envGroupID uint64, envGroup *model.EnvGroup) Config
+type ConfigBuilder func(fileName string, fileInfo os.FileInfo, status ConfigStatus, namespaceID uint64, namespace *model.Namespace) Config
 
 // FilterMatcher is a function type for custom filtering logic
-type FilterMatcher func(fileName string, status ConfigStatus, envGroupID uint64, options *GenericListOptions) bool
+type FilterMatcher func(fileName string, status ConfigStatus, namespaceID uint64, options *GenericListOptions) bool
 
 // GenericConfigProcessor holds all the custom functions for processing configurations
 type GenericConfigProcessor struct {
@@ -113,15 +113,15 @@ func GetGenericConfigs[T ConfigEntity](
 		status := statusMap[fileName]
 
 		// Get environment group info from database
-		var envGroupID uint64
-		var envGroup *model.EnvGroup
+		var namespaceID uint64
+		var namespace *model.Namespace
 		if entity, ok := entitiesMap[fileName]; ok {
-			envGroupID = entity.GetEnvGroupID()
-			envGroup = entity.GetEnvGroup()
+			namespaceID = entity.GetNamespaceID()
+			namespace = entity.GetNamespace()
 		}
 
 		// Apply filters using custom logic
-		if !processor.FilterMatcher(fileName, status, envGroupID, options) {
+		if !processor.FilterMatcher(fileName, status, namespaceID, options) {
 			continue
 		}
 
@@ -154,7 +154,7 @@ func GetGenericConfigs[T ConfigEntity](
 		}
 
 		// Build configuration using custom logic
-		configs = append(configs, processor.ConfigBuilder(fileName, fileInfo, status, envGroupID, envGroup))
+		configs = append(configs, processor.ConfigBuilder(fileName, fileInfo, status, namespaceID, namespace))
 	}
 
 	// Sort and return
@@ -270,7 +270,7 @@ func SiteStatusMapBuilder(maintenanceSuffix string) StatusMapBuilder {
 }
 
 // DefaultFilterMatcher provides the standard filtering logic with name search
-func DefaultFilterMatcher(fileName string, status ConfigStatus, envGroupID uint64, options *GenericListOptions) bool {
+func DefaultFilterMatcher(fileName string, status ConfigStatus, namespaceID uint64, options *GenericListOptions) bool {
 	// Exact name matching
 	if options.Name != "" && fileName != options.Name {
 		return false
@@ -278,14 +278,14 @@ func DefaultFilterMatcher(fileName string, status ConfigStatus, envGroupID uint6
 	if options.Status != "" && status != ConfigStatus(options.Status) {
 		return false
 	}
-	if options.EnvGroupID != 0 && envGroupID != options.EnvGroupID {
+	if options.NamespaceID != 0 && namespaceID != options.NamespaceID {
 		return false
 	}
 	return true
 }
 
 // FuzzyFilterMatcher provides filtering logic with fuzzy search support
-func FuzzyFilterMatcher(fileName string, status ConfigStatus, envGroupID uint64, options *GenericListOptions) bool {
+func FuzzyFilterMatcher(fileName string, status ConfigStatus, namespaceID uint64, options *GenericListOptions) bool {
 	// Exact name matching takes precedence over fuzzy search
 	if options.Name != "" && fileName != options.Name {
 		return false
@@ -293,21 +293,21 @@ func FuzzyFilterMatcher(fileName string, status ConfigStatus, envGroupID uint64,
 	if options.Status != "" && status != ConfigStatus(options.Status) {
 		return false
 	}
-	if options.EnvGroupID != 0 && envGroupID != options.EnvGroupID {
+	if options.NamespaceID != 0 && namespaceID != options.NamespaceID {
 		return false
 	}
 	return true
 }
 
 // DefaultConfigBuilder provides basic config building logic
-func DefaultConfigBuilder(fileName string, fileInfo os.FileInfo, status ConfigStatus, envGroupID uint64, envGroup *model.EnvGroup) Config {
+func DefaultConfigBuilder(fileName string, fileInfo os.FileInfo, status ConfigStatus, namespaceID uint64, namespace *model.Namespace) Config {
 	return Config{
 		Name:       fileName,
 		ModifiedAt: fileInfo.ModTime(),
 		Size:       fileInfo.Size(),
 		IsDir:      fileInfo.IsDir(),
 		Status:     status,
-		EnvGroupID: envGroupID,
-		EnvGroup:   envGroup,
+		NamespaceID: namespaceID,
+		Namespace:   namespace,
 	}
 }

+ 33 - 33
internal/config/sync.go

@@ -54,11 +54,11 @@ func SyncToRemoteServer(c *model.Config) (err error) {
 		return
 	}
 
-	q := query.Environment
-	envs, _ := q.Where(q.ID.In(c.SyncNodeIds...), q.Enabled.Is(true)).Find()
-	for _, env := range envs {
+	q := query.Node
+	nodes, _ := q.Where(q.ID.In(c.SyncNodeIds...), q.Enabled.Is(true)).Find()
+	for _, node := range nodes {
 		go func() {
-			err := payload.deploy(env, c, payloadBytes)
+			err := payload.deploy(node, c, payloadBytes)
 			if err != nil {
 				logger.Error(err)
 			}
@@ -87,11 +87,11 @@ func SyncRenameOnRemoteServer(origPath, newPath string, syncNodeIds []uint64) (e
 		NewFilepath: newPath,
 	}
 
-	q := query.Environment
-	envs, _ := q.Where(q.ID.In(syncNodeIds...)).Find()
-	for _, env := range envs {
+	q := query.Node
+	nodes, _ := q.Where(q.ID.In(syncNodeIds...)).Find()
+	for _, node := range nodes {
 		go func() {
-			err := payload.rename(env)
+			err := payload.rename(node)
 			if err != nil {
 				logger.Error(err)
 			}
@@ -104,11 +104,11 @@ func SyncRenameOnRemoteServer(origPath, newPath string, syncNodeIds []uint64) (e
 type SyncNotificationPayload struct {
 	StatusCode int    `json:"status_code"`
 	ConfigName string `json:"config_name"`
-	EnvName    string `json:"env_name"`
+	NodeName    string `json:"node_name"`
 	Response   string `json:"response"`
 }
 
-func (p *SyncConfigPayload) deploy(env *model.Environment, c *model.Config, payloadBytes []byte) (err error) {
+func (p *SyncConfigPayload) deploy(node *model.Node, c *model.Config, payloadBytes []byte) (err error) {
 	t, err := transport.NewTransport()
 	if err != nil {
 		return
@@ -116,7 +116,7 @@ func (p *SyncConfigPayload) deploy(env *model.Environment, c *model.Config, payl
 	client := http.Client{
 		Transport: t,
 	}
-	url, err := env.GetUrl("/api/configs")
+	url, err := node.GetUrl("/api/configs")
 	if err != nil {
 		return
 	}
@@ -124,7 +124,7 @@ func (p *SyncConfigPayload) deploy(env *model.Environment, c *model.Config, payl
 	if err != nil {
 		return
 	}
-	req.Header.Set("X-Node-Secret", env.Token)
+	req.Header.Set("X-Node-Secret", node.Token)
 	resp, err := client.Do(req)
 	if err != nil {
 		return
@@ -139,16 +139,16 @@ func (p *SyncConfigPayload) deploy(env *model.Environment, c *model.Config, payl
 	notificationPayload := &SyncNotificationPayload{
 		StatusCode: resp.StatusCode,
 		ConfigName: c.Name,
-		EnvName:    env.Name,
+		NodeName:    node.Name,
 		Response:   string(respBody),
 	}
 
 	if resp.StatusCode != http.StatusOK {
-		notification.Error("Sync Config Error", "Sync config %{config_name} to %{env_name} failed", notificationPayload)
+		notification.Error("Sync Config Error", "Sync config %{config_name} to %{node_name} failed", notificationPayload)
 		return
 	}
 
-	notification.Success("Sync Config Success", "Sync config %{config_name} to %{env_name} successfully", notificationPayload)
+	notification.Success("Sync Config Success", "Sync config %{config_name} to %{node_name} successfully", notificationPayload)
 
 	return
 }
@@ -162,11 +162,11 @@ type SyncRenameNotificationPayload struct {
 	StatusCode int    `json:"status_code"`
 	OrigPath   string `json:"orig_path"`
 	NewPath    string `json:"new_path"`
-	EnvName    string `json:"env_name"`
+	NodeName    string `json:"node_name"`
 	Response   string `json:"response"`
 }
 
-func (p *RenameConfigPayload) rename(env *model.Environment) (err error) {
+func (p *RenameConfigPayload) rename(node *model.Node) (err error) {
 	// handle rename
 	if p.NewFilepath == "" || p.Filepath == p.NewFilepath {
 		return
@@ -186,7 +186,7 @@ func (p *RenameConfigPayload) rename(env *model.Environment) (err error) {
 	if err != nil {
 		return
 	}
-	url, err := env.GetUrl("/api/config_rename")
+	url, err := node.GetUrl("/api/config_rename")
 	if err != nil {
 		return
 	}
@@ -194,7 +194,7 @@ func (p *RenameConfigPayload) rename(env *model.Environment) (err error) {
 	if err != nil {
 		return
 	}
-	req.Header.Set("X-Node-Secret", env.Token)
+	req.Header.Set("X-Node-Secret", node.Token)
 	resp, err := client.Do(req)
 	if err != nil {
 		return
@@ -210,16 +210,16 @@ func (p *RenameConfigPayload) rename(env *model.Environment) (err error) {
 		StatusCode: resp.StatusCode,
 		OrigPath:   p.Filepath,
 		NewPath:    p.NewFilepath,
-		EnvName:    env.Name,
+		NodeName:    node.Name,
 		Response:   string(respBody),
 	}
 
 	if resp.StatusCode != http.StatusOK {
-		notification.Error("Rename Remote Config Error", "Rename %{orig_path} to %{new_path} on %{env_name} failed", notificationPayload)
+		notification.Error("Rename Remote Config Error", "Rename %{orig_path} to %{new_path} on %{node_name} failed", notificationPayload)
 		return
 	}
 
-	notification.Success("Rename Remote Config Success", "Rename %{orig_path} to %{new_path} on %{env_name} successfully", notificationPayload)
+	notification.Success("Rename Remote Config Success", "Rename %{orig_path} to %{new_path} on %{node_name} successfully", notificationPayload)
 
 	return
 }
@@ -238,11 +238,11 @@ func SyncDeleteOnRemoteServer(deletePath string, syncNodeIds []uint64) (err erro
 		Filepath: deletePath,
 	}
 
-	q := query.Environment
-	envs, _ := q.Where(q.ID.In(syncNodeIds...)).Find()
-	for _, env := range envs {
+	q := query.Node
+	nodes, _ := q.Where(q.ID.In(syncNodeIds...)).Find()
+	for _, node := range nodes {
 		go func() {
-			err := payload.delete(env)
+			err := payload.delete(node)
 			if err != nil {
 				logger.Error(err)
 			}
@@ -259,11 +259,11 @@ type DeleteConfigPayload struct {
 type SyncDeleteNotificationPayload struct {
 	StatusCode int    `json:"status_code"`
 	Path       string `json:"path"`
-	EnvName    string `json:"env_name"`
+	NodeName    string `json:"node_name"`
 	Response   string `json:"response"`
 }
 
-func (p *DeleteConfigPayload) delete(env *model.Environment) (err error) {
+func (p *DeleteConfigPayload) delete(node *model.Node) (err error) {
 	client := http.Client{
 		Transport: &http.Transport{
 			TLSClientConfig: &tls.Config{InsecureSkipVerify: settings.HTTPSettings.InsecureSkipVerify},
@@ -278,7 +278,7 @@ func (p *DeleteConfigPayload) delete(env *model.Environment) (err error) {
 		return
 	}
 
-	url, err := env.GetUrl("/api/config_delete")
+	url, err := node.GetUrl("/api/config_delete")
 	if err != nil {
 		return
 	}
@@ -287,7 +287,7 @@ func (p *DeleteConfigPayload) delete(env *model.Environment) (err error) {
 	if err != nil {
 		return
 	}
-	req.Header.Set("X-Node-Secret", env.Token)
+	req.Header.Set("X-Node-Secret", node.Token)
 	resp, err := client.Do(req)
 	if err != nil {
 		return
@@ -302,16 +302,16 @@ func (p *DeleteConfigPayload) delete(env *model.Environment) (err error) {
 	notificationPayload := &SyncDeleteNotificationPayload{
 		StatusCode: resp.StatusCode,
 		Path:       p.Filepath,
-		EnvName:    env.Name,
+		NodeName:    node.Name,
 		Response:   string(respBody),
 	}
 
 	if resp.StatusCode != http.StatusOK {
-		notification.Error("Delete Remote Config Error", "Delete %{path} on %{env_name} failed", notificationPayload)
+		notification.Error("Delete Remote Config Error", "Delete %{path} on %{node_name} failed", notificationPayload)
 		return
 	}
 
-	notification.Success("Delete Remote Config Success", "Delete %{path} on %{env_name} successfully", notificationPayload)
+	notification.Success("Delete Remote Config Success", "Delete %{path} on %{node_name} successfully", notificationPayload)
 
 	return
 }

+ 4 - 4
internal/middleware/proxy.go

@@ -28,9 +28,9 @@ func Proxy() gin.HandlerFunc {
 
 		defer c.Abort()
 
-		env := query.Environment
+		nodeQuery := query.Node
 
-		environment, err := env.Where(env.ID.Eq(id)).First()
+		node, err := nodeQuery.Where(nodeQuery.ID.Eq(id)).First()
 		if err != nil {
 			logger.Error(err)
 			c.AbortWithStatusJSON(http.StatusServiceUnavailable, gin.H{
@@ -39,7 +39,7 @@ func Proxy() gin.HandlerFunc {
 			return
 		}
 
-		baseUrl, err := url.Parse(environment.URL)
+		baseUrl, err := url.Parse(node.URL)
 		if err != nil {
 			logger.Error(err)
 			c.AbortWithStatusJSON(http.StatusInternalServerError, gin.H{
@@ -65,7 +65,7 @@ func Proxy() gin.HandlerFunc {
 		proxy.Director = func(req *http.Request) {
 			defaultDirector(req)
 			req.Header.Del("X-Node-ID")
-			req.Header.Set("X-Node-Secret", environment.Token)
+			req.Header.Set("X-Node-Secret", node.Token)
 		}
 
 		// resolve https://github.com/0xJacky/nginx-ui/issues/342

+ 4 - 4
internal/middleware/proxy_ws.go

@@ -25,14 +25,14 @@ func ProxyWs() gin.HandlerFunc {
 
 		defer c.Abort()
 
-		env := query.Environment
-		environment, err := env.Where(env.ID.Eq(id)).First()
+		nodeQuery := query.Node
+		node, err := nodeQuery.Where(nodeQuery.ID.Eq(id)).First()
 		if err != nil {
 			logger.Error(err)
 			return
 		}
 
-		decodedUri, err := environment.GetWebSocketURL(c.Request.RequestURI)
+		decodedUri, err := node.GetWebSocketURL(c.Request.RequestURI)
 
 		if err != nil {
 			logger.Error(err)
@@ -42,7 +42,7 @@ func ProxyWs() gin.HandlerFunc {
 		logger.Debug("Proxy request", decodedUri)
 
 		wp, err := websocketproxy.NewProxy(decodedUri, func(r *http.Request) error {
-			r.Header.Set("X-Node-Secret", environment.Token)
+			r.Header.Set("X-Node-Secret", node.Token)
 			r.Header.Del("X-Node-ID")
 			queryValues := r.URL.Query()
 			queryValues.Del("x_node_id")

+ 6 - 6
internal/migrate/1.site_category_to_env_group.go

@@ -6,11 +6,11 @@ import (
 	"gorm.io/gorm"
 )
 
-var SiteCategoryToEnvGroup = &gormigrate.Migration{
+var SiteCategoryToNamespace = &gormigrate.Migration{
 	ID: "20250405000001",
 	Migrate: func(tx *gorm.DB) error {
 		// Step 1: Create new env_groups table
-		if err := tx.Migrator().AutoMigrate(&model.EnvGroup{}); err != nil {
+		if err := tx.Migrator().AutoMigrate(&model.Namespace{}); err != nil {
 			return err
 		}
 
@@ -22,7 +22,7 @@ var SiteCategoryToEnvGroup = &gormigrate.Migration{
 			}
 
 			for _, sc := range siteCategories {
-				if err := tx.Table("env_groups").Create(sc).Error; err != nil {
+				if err := tx.Table("namespaces").Create(sc).Error; err != nil {
 					return err
 				}
 			}
@@ -30,14 +30,14 @@ var SiteCategoryToEnvGroup = &gormigrate.Migration{
 			// Step 3: Update sites table to use env_group_id instead of site_category_id
 			if tx.Migrator().HasColumn("sites", "site_category_id") {
 				// First add the new column if it doesn't exist
-				if !tx.Migrator().HasColumn("sites", "env_group_id") {
-					if err := tx.Exec("ALTER TABLE sites ADD COLUMN env_group_id bigint").Error; err != nil {
+				if !tx.Migrator().HasColumn("sites", "namespace_id") {
+					if err := tx.Exec("ALTER TABLE sites ADD COLUMN namespace_id bigint").Error; err != nil {
 						return err
 					}
 				}
 
 				// Copy the values from site_category_id to env_group_id
-				if err := tx.Exec("UPDATE sites SET env_group_id = site_category_id").Error; err != nil {
+				if err := tx.Exec("UPDATE sites SET namespace_id = site_category_id").Error; err != nil {
 					return err
 				}
 			}

+ 91 - 0
internal/migrate/5.rename_env_groups_to_namespaces.go

@@ -0,0 +1,91 @@
+package migrate
+
+import (
+	"github.com/go-gormigrate/gormigrate/v2"
+	"gorm.io/gorm"
+)
+
+var RenameEnvGroupsToNamespaces = &gormigrate.Migration{
+	ID: "20250812000001",
+	Migrate: func(tx *gorm.DB) error {
+		// 检查 env_groups 表是否存在
+		if !tx.Migrator().HasTable("env_groups") {
+			// 如果 env_groups 表不存在,说明已经迁移过了或者是新安装
+			return nil
+		}
+
+		// 检查 namespaces 表是否存在
+		if !tx.Migrator().HasTable("namespaces") {
+			// namespaces 表不存在,直接重命名
+			if err := tx.Exec("ALTER TABLE env_groups RENAME TO namespaces").Error; err != nil {
+				return err
+			}
+		} else {
+			// namespaces 表已存在,迁移数据后删除旧表
+			if err := tx.Exec(`
+				INSERT OR IGNORE INTO namespaces (id, created_at, updated_at, deleted_at, name, sync_node_ids, order_id, post_sync_action, upstream_test_type)
+				SELECT id, created_at, updated_at, deleted_at, 
+					   COALESCE(name, 'Default') as name,
+					   COALESCE(sync_node_ids, '[]') as sync_node_ids,
+					   COALESCE(order_id, 0) as order_id,
+					   COALESCE(post_sync_action, 'reload_nginx') as post_sync_action,
+					   COALESCE(upstream_test_type, 'local') as upstream_test_type
+				FROM env_groups
+			`).Error; err != nil {
+				return err
+			}
+
+			// 删除旧表
+			if err := tx.Migrator().DropTable("env_groups"); err != nil {
+				return err
+			}
+		}
+
+		// 更新 sites 表中的外键字段
+		if tx.Migrator().HasColumn("sites", "env_group_id") {
+			// 添加新列(如果不存在)
+			if !tx.Migrator().HasColumn("sites", "namespace_id") {
+				if err := tx.Exec("ALTER TABLE sites ADD COLUMN namespace_id BIGINT").Error; err != nil {
+					return err
+				}
+			}
+
+			// 复制数据
+			if err := tx.Exec("UPDATE sites SET namespace_id = env_group_id WHERE namespace_id IS NULL OR namespace_id = 0").Error; err != nil {
+				return err
+			}
+		}
+
+		// 更新 streams 表中的外键字段
+		if tx.Migrator().HasColumn("streams", "env_group_id") {
+			// 添加新列(如果不存在)
+			if !tx.Migrator().HasColumn("streams", "namespace_id") {
+				if err := tx.Exec("ALTER TABLE streams ADD COLUMN namespace_id BIGINT").Error; err != nil {
+					return err
+				}
+			}
+
+			// 复制数据
+			if err := tx.Exec("UPDATE streams SET namespace_id = env_group_id WHERE namespace_id IS NULL OR namespace_id = 0").Error; err != nil {
+				return err
+			}
+		}
+
+		// 更新 configs 表中的外键字段(如果存在)
+		if tx.Migrator().HasColumn("configs", "env_group_id") {
+			// 添加新列(如果不存在)
+			if !tx.Migrator().HasColumn("configs", "namespace_id") {
+				if err := tx.Exec("ALTER TABLE configs ADD COLUMN namespace_id BIGINT").Error; err != nil {
+					return err
+				}
+			}
+
+			// 复制数据
+			if err := tx.Exec("UPDATE configs SET namespace_id = env_group_id WHERE namespace_id IS NULL OR namespace_id = 0").Error; err != nil {
+				return err
+			}
+		}
+
+		return nil
+	},
+}

+ 109 - 0
internal/migrate/6.rename_environments_to_nodes.go

@@ -0,0 +1,109 @@
+package migrate
+
+import (
+	"github.com/go-gormigrate/gormigrate/v2"
+	"gorm.io/gorm"
+)
+
+var RenameEnvironmentsToNodes = &gormigrate.Migration{
+	ID: "20250812000002",
+	Migrate: func(tx *gorm.DB) error {
+		// 检查 environments 表是否存在
+		if !tx.Migrator().HasTable("environments") {
+			// 如果 environments 表不存在,说明已经迁移过了或者是新安装
+			return nil
+		}
+
+		// 检查 nodes 表是否存在
+		if !tx.Migrator().HasTable("nodes") {
+			// nodes 表不存在,直接重命名
+			if err := tx.Exec("ALTER TABLE environments RENAME TO nodes").Error; err != nil {
+				return err
+			}
+		} else {
+			// nodes 表已存在,迁移数据后删除旧表
+			if err := tx.Exec(`
+				INSERT OR IGNORE INTO nodes (id, created_at, updated_at, deleted_at, name, url, token, enabled)
+				SELECT id, created_at, updated_at, deleted_at, 
+					   COALESCE(name, 'Unknown Node') as name,
+					   COALESCE(url, '') as url,
+					   COALESCE(token, '') as token,
+					   COALESCE(enabled, false) as enabled
+				FROM environments
+			`).Error; err != nil {
+				return err
+			}
+
+			// 删除旧表
+			if err := tx.Migrator().DropTable("environments"); err != nil {
+				return err
+			}
+		}
+
+		// 更新 sites 表中的外键字段
+		if tx.Migrator().HasColumn("sites", "environment_id") {
+			// 添加新列(如果不存在)
+			if !tx.Migrator().HasColumn("sites", "node_id") {
+				if err := tx.Exec("ALTER TABLE sites ADD COLUMN node_id BIGINT").Error; err != nil {
+					return err
+				}
+			}
+
+			// 复制数据
+			if err := tx.Exec("UPDATE sites SET node_id = environment_id WHERE node_id IS NULL OR node_id = 0").Error; err != nil {
+				return err
+			}
+		}
+
+		// 更新 streams 表中的外键字段
+		if tx.Migrator().HasColumn("streams", "environment_id") {
+			// 添加新列(如果不存在)
+			if !tx.Migrator().HasColumn("streams", "node_id") {
+				if err := tx.Exec("ALTER TABLE streams ADD COLUMN node_id BIGINT").Error; err != nil {
+					return err
+				}
+			}
+
+			// 复制数据
+			if err := tx.Exec("UPDATE streams SET node_id = environment_id WHERE node_id IS NULL OR node_id = 0").Error; err != nil {
+				return err
+			}
+		}
+
+		// 更新 configs 表中的外键字段(如果存在)
+		if tx.Migrator().HasColumn("configs", "environment_id") {
+			// 添加新列(如果不存在)
+			if !tx.Migrator().HasColumn("configs", "node_id") {
+				if err := tx.Exec("ALTER TABLE configs ADD COLUMN node_id BIGINT").Error; err != nil {
+					return err
+				}
+			}
+
+			// 复制数据
+			if err := tx.Exec("UPDATE configs SET node_id = environment_id WHERE node_id IS NULL OR node_id = 0").Error; err != nil {
+				return err
+			}
+		}
+
+		// 更新 certs 表中的外键字段(如果存在)
+		if tx.Migrator().HasColumn("certs", "environment_id") {
+			// 添加新列(如果不存在)
+			if !tx.Migrator().HasColumn("certs", "node_id") {
+				if err := tx.Exec("ALTER TABLE certs ADD COLUMN node_id BIGINT").Error; err != nil {
+					return err
+				}
+			}
+
+			// 复制数据
+			if err := tx.Exec("UPDATE certs SET node_id = environment_id WHERE node_id IS NULL OR node_id = 0").Error; err != nil {
+				return err
+			}
+		}
+
+		// 更新 namespaces 表中的 sync_node_ids 字段内容(JSON 格式的环境 ID 需要保持数据一致性)
+		// 由于 sync_node_ids 存储的是 JSON 数组,我们只需要确保引用的 ID 仍然有效
+		// 这里不需要特殊处理,因为 ID 值在重命名表后保持不变
+
+		return nil
+	},
+}

+ 3 - 1
internal/migrate/migrate.go

@@ -5,9 +5,11 @@ import (
 )
 
 var Migrations = []*gormigrate.Migration{
-	SiteCategoryToEnvGroup,
+	SiteCategoryToNamespace,
 	RenameAuthsToUsers,
 	UpdateCertDomains,
+	RenameEnvGroupsToNamespaces,
+	RenameEnvironmentsToNodes,
 }
 
 var BeforeAutoMigrate = []*gormigrate.Migration{

+ 3 - 1
internal/self_check/test_cases/no-http-sites-enabled-fixed.conf

@@ -12,7 +12,9 @@ stream {
 http {
     include /etc/nginx/mime.types;
     default_type application/octet-stream;
-    log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
+    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
+        '$status $body_bytes_sent "$http_referer" '
+        '"$http_user_agent" "$http_x_forwarded_for"';
     access_log /var/log/nginx/access.log main;
     sendfile on;
     #tcp_nopush     on;

+ 5 - 5
internal/site/list.go

@@ -16,7 +16,7 @@ type ListOptions struct {
 	Status     string
 	OrderBy    string
 	Sort       string
-	EnvGroupID uint64
+	NamespaceID uint64
 }
 
 // GetSiteConfigs retrieves and processes site configurations with database integration
@@ -28,7 +28,7 @@ func GetSiteConfigs(ctx context.Context, options *ListOptions, sites []*model.Si
 		Status:      options.Status,
 		OrderBy:     options.OrderBy,
 		Sort:        options.Sort,
-		EnvGroupID:  options.EnvGroupID,
+		NamespaceID:  options.NamespaceID,
 		IncludeDirs: false, // Filter out directories for site configurations
 	}
 
@@ -47,7 +47,7 @@ func GetSiteConfigs(ctx context.Context, options *ListOptions, sites []*model.Si
 }
 
 // buildConfig creates a config.Config from file information with site-specific data
-func buildConfig(fileName string, fileInfo os.FileInfo, status config.ConfigStatus, envGroupID uint64, envGroup *model.EnvGroup) config.Config {
+func buildConfig(fileName string, fileInfo os.FileInfo, status config.ConfigStatus, namespaceID uint64, namespace *model.Namespace) config.Config {
 	indexedSite := GetIndexedSite(fileName)
 
 	// Convert proxy targets, expanding upstream references
@@ -81,8 +81,8 @@ func buildConfig(fileName string, fileInfo os.FileInfo, status config.ConfigStat
 		Size:         fileInfo.Size(),
 		IsDir:        fileInfo.IsDir(),
 		Status:       status,
-		EnvGroupID:   envGroupID,
-		EnvGroup:     envGroup,
+		NamespaceID:   namespaceID,
+		Namespace:     namespace,
 		Urls:         indexedSite.Urls,
 		ProxyTargets: proxyTargets,
 	}

+ 2 - 2
internal/site/maintenance.go

@@ -318,7 +318,7 @@ func syncEnableMaintenance(name string) {
 	wg.Add(len(nodes))
 
 	for _, node := range nodes {
-		go func(node *model.Environment) {
+		go func(node *model.Node) {
 			defer func() {
 				if err := recover(); err != nil {
 					buf := make([]byte, 1024)
@@ -356,7 +356,7 @@ func syncDisableMaintenance(name string) {
 	wg.Add(len(nodes))
 
 	for _, node := range nodes {
-		go func(node *model.Environment) {
+		go func(node *model.Node) {
 			defer func() {
 				if err := recover(); err != nil {
 					buf := make([]byte, 1024)

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff