Browse Source

Merge pull request #376 from 0xJacky/docker/s6-overlay

Enhance nginx ui docker image
Jacky 1 year ago
parent
commit
1ac1d150c0
86 changed files with 2812 additions and 1622 deletions
  1. 1 0
      .gitignore
  2. 21 10
      Dockerfile
  3. 1 1
      README-es.md
  4. 1 1
      README-vi_VN.md
  5. 1 1
      README-zh_CN.md
  6. 1 1
      README-zh_TW.md
  7. 1 1
      README.md
  8. 37 85
      api/cluster/environment.go
  9. 1 0
      api/cluster/router.go
  10. 19 3
      api/nginx/control.go
  11. 43 57
      api/nginx/nginx.go
  12. 2 2
      api/system/install.go
  13. 1 0
      api/system/router.go
  14. 10 20
      api/system/settings.go
  15. 30 22
      app.example.ini
  16. 13 13
      app/package.json
  17. 612 281
      app/pnpm-lock.yaml
  18. 3 0
      app/src/App.vue
  19. 13 1
      app/src/api/environment.ts
  20. 1 1
      app/src/api/ngx.ts
  21. 4 0
      app/src/api/settings.ts
  22. 19 0
      app/src/api/translations.ts
  23. 13 8
      app/src/components/ChatGPT/ChatGPT.vue
  24. 3 1
      app/src/components/EnvIndicator/EnvIndicator.vue
  25. 13 10
      app/src/components/NginxControl/NginxControl.vue
  26. 27 7
      app/src/components/NodeSelector/NodeSelector.vue
  27. 11 17
      app/src/components/SetLanguage/SetLanguage.vue
  28. 1 1
      app/src/language/LINGUAS
  29. 107 85
      app/src/language/en/app.po
  30. 112 85
      app/src/language/es/app.po
  31. 107 85
      app/src/language/fr_FR/app.po
  32. 112 85
      app/src/language/ko_KR/app.po
  33. 103 79
      app/src/language/messages.pot
  34. 112 85
      app/src/language/ru_RU/app.po
  35. 107 85
      app/src/language/vi_VN/app.po
  36. BIN
      app/src/language/zh_CN/app.mo
  37. 111 85
      app/src/language/zh_CN/app.po
  38. 112 85
      app/src/language/zh_TW/app.po
  39. 9 4
      app/src/layouts/BaseLayout.vue
  40. 2 2
      app/src/layouts/SideBar.vue
  41. 1 0
      app/src/pinia/moudule/settings.ts
  42. 1 1
      app/src/version.json
  43. 10 5
      app/src/views/certificate/ACMEUserSelector.vue
  44. 7 1
      app/src/views/dashboard/DashBoard.vue
  45. 14 3
      app/src/views/dashboard/Environments.vue
  46. 49 8
      app/src/views/environment/Environment.vue
  47. 0 2
      app/src/views/other/Error.vue
  48. 11 2
      app/src/views/preference/BasicSettings.vue
  49. 9 3
      app/src/views/preference/OpenAISettings.vue
  50. 7 0
      app/src/views/preference/Preference.vue
  51. 1 0
      app/src/views/preference/typedef.ts
  52. 1 1
      app/version.json
  53. 12 6
      demo.Dockerfile
  54. 2 1
      docs/.vitepress/config/en.ts
  55. 2 1
      docs/.vitepress/config/zh_CN.ts
  56. 2 1
      docs/.vitepress/config/zh_TW.ts
  57. 24 0
      docs/guide/config-cluster.md
  58. 0 30
      docs/guide/config-nginx.md
  59. 25 0
      docs/guide/config-server.md
  60. 1 1
      docs/zh_CN/guide/build.md
  61. 24 0
      docs/zh_CN/guide/config-cluster.md
  62. 0 33
      docs/zh_CN/guide/config-nginx.md
  63. 24 0
      docs/zh_CN/guide/config-server.md
  64. 1 1
      docs/zh_TW/guide/build.md
  65. 26 0
      docs/zh_TW/guide/config-cluster.md
  66. 0 33
      docs/zh_TW/guide/config-nginx.md
  67. 24 0
      docs/zh_TW/guide/config-server.md
  68. 31 30
      go.mod
  69. 62 0
      go.sum
  70. 78 70
      internal/analytic/node.go
  71. 71 0
      internal/cluster/cluster.go
  72. 47 0
      internal/cluster/cluster_test.go
  73. 0 23
      internal/environment/environment.go
  74. 8 1
      internal/kernal/boot.go
  75. 74 0
      internal/kernal/skip_install.go
  76. 45 22
      internal/nginx/nginx.go
  77. 1 0
      model/environment.go
  78. 4 4
      resources/demo/app.ini
  79. 3 0
      resources/docker/nginx-ui.run
  80. 3 2
      resources/docker/nginx.conf
  81. 0 10
      resources/docker/start.sh
  82. 19 0
      settings/cluster.go
  83. 15 0
      settings/cluster_test.go
  84. 2 0
      settings/server.go
  85. 71 18
      settings/settings.go
  86. 103 0
      settings/settings_test.go

+ 1 - 0
.gitignore

@@ -2,6 +2,7 @@
 database.db
 database.db
 tmp
 tmp
 node_modules
 node_modules
+.pnpm-store
 app.ini
 app.ini
 dist
 dist
 *.exe
 *.exe

+ 21 - 10
Dockerfile

@@ -2,17 +2,28 @@ FROM --platform=$TARGETPLATFORM uozi/nginx-ui-base:latest
 ARG TARGETOS
 ARG TARGETOS
 ARG TARGETARCH
 ARG TARGETARCH
 ARG TARGETVARIANT
 ARG TARGETVARIANT
-WORKDIR /app
 EXPOSE 80 443
 EXPOSE 80 443
 
 
-COPY resources/docker/start.sh /app/start.sh
-COPY resources/docker/nginx.conf /usr/etc/nginx/nginx.conf
-COPY resources/docker/nginx-ui.conf /usr/etc/nginx/conf.d/nginx-ui.conf
-COPY resources/docker/nginx-ui.conf /etc/nginx/conf.d/nginx-ui.conf
-COPY nginx-ui-$TARGETOS-$TARGETARCH$TARGETVARIANT/nginx-ui /app/nginx-ui
+ENV NGINX_UI_OFFICIAL_DOCKER=true
 
 
-RUN cd /app && chmod a+x /app/start.sh  \
-    && rm -f /etc/nginx/conf.d/default.conf  \
-    && rm -f /usr/etc/nginx/conf.d/default.conf
+# register nginx-ui service
+COPY resources/docker/nginx-ui.run /etc/s6-overlay/s6-rc.d/nginx-ui/run
+RUN echo 'longrun' > /etc/s6-overlay/s6-rc.d/nginx-ui/type && \
+    touch /etc/s6-overlay/s6-rc.d/user/contents.d/nginx-ui
 
 
-ENTRYPOINT ["./start.sh"]
+# copy nginx config
+COPY resources/docker/nginx.conf /usr/local/etc/nginx/nginx.conf
+COPY resources/docker/nginx-ui.conf /usr/local/etc/nginx/conf.d/nginx-ui.conf
+
+# copy nginx-ui executable binary
+COPY nginx-ui-$TARGETOS-$TARGETARCH$TARGETVARIANT/nginx-ui /usr/local/bin/nginx-ui
+
+# remove default nginx config
+RUN rm -f /etc/nginx/conf.d/default.conf  \
+    && rm -f /usr/local/etc/nginx/conf.d/default.conf
+
+# recreate access.log and error.log
+RUN rm -f /var/log/nginx/access.log && \
+    touch /var/log/nginx/access.log && \
+    rm -f /var/log/nginx/error.log && \
+    touch /var/log/nginx/error.log

+ 1 - 1
README-es.md

@@ -235,7 +235,7 @@ pnpm build
 Primero compile la interfaz y luego ejecute el siguiente comando en el directorio raíz del proyecto.
 Primero compile la interfaz y luego ejecute el siguiente comando en el directorio raíz del proyecto.
 
 
 ```shell
 ```shell
-go build -o nginx-ui -v main.go
+go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'" -o nginx-ui -v main.go
 ```
 ```
 
 
 ## Script para Linux
 ## Script para Linux

+ 1 - 1
README-vi_VN.md

@@ -298,7 +298,7 @@ pnpm build
 Vui lòng build Frontend trước, sau đó thực hiện lệnh sau trong thư mục gốc của dự án.
 Vui lòng build Frontend trước, sau đó thực hiện lệnh sau trong thư mục gốc của dự án.
 
 
 ```shell
 ```shell
-go build -o nginx-ui -v main.go
+go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'" -o nginx-ui -v main.go
 ```
 ```
 
 
 ## Tập lệnh cho Linux
 ## Tập lệnh cho Linux

+ 1 - 1
README-zh_CN.md

@@ -229,7 +229,7 @@ pnpm build
 请先完成前端编译,再回到项目的根目录执行以下命令。
 请先完成前端编译,再回到项目的根目录执行以下命令。
 
 
 ```shell
 ```shell
-go build -o nginx-ui -v main.go
+go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'" -o nginx-ui -v main.go
 ```
 ```
 
 
 ## Linux 安装脚本
 ## Linux 安装脚本

+ 1 - 1
README-zh_TW.md

@@ -234,7 +234,7 @@ pnpm build
 請先完成前端編譯,再回到專案的根目錄執行以下命令。
 請先完成前端編譯,再回到專案的根目錄執行以下命令。
 
 
 ```shell
 ```shell
-go build -o nginx-ui -v main.go
+go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'" -o nginx-ui -v main.go
 ```
 ```
 
 
 ## Linux 安裝指令
 ## Linux 安裝指令

+ 1 - 1
README.md

@@ -295,7 +295,7 @@ pnpm build
 Please build the app first, and then execute the following command in the project root directory.
 Please build the app first, and then execute the following command in the project root directory.
 
 
 ```shell
 ```shell
-go build -o nginx-ui -v main.go
+go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'" -o nginx-ui -v main.go
 ```
 ```
 
 
 ## Script for Linux
 ## Script for Linux

+ 37 - 85
api/cluster/environment.go

@@ -3,13 +3,14 @@ package cluster
 import (
 import (
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
-	"github.com/0xJacky/Nginx-UI/internal/environment"
+	"github.com/0xJacky/Nginx-UI/internal/cluster"
+	"github.com/0xJacky/Nginx-UI/internal/cosy"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/model"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/0xJacky/Nginx-UI/query"
+	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 	"github.com/spf13/cast"
 	"github.com/spf13/cast"
 	"net/http"
 	"net/http"
-	"regexp"
 )
 )
 
 
 func GetEnvironment(c *gin.Context) {
 func GetEnvironment(c *gin.Context) {
@@ -27,75 +28,38 @@ func GetEnvironment(c *gin.Context) {
 }
 }
 
 
 func GetEnvironmentList(c *gin.Context) {
 func GetEnvironmentList(c *gin.Context) {
-	data, err := environment.RetrieveEnvironmentList()
-	if err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-	c.JSON(http.StatusOK, gin.H{
-		"data": data,
-	})
-}
-
-type EnvironmentManageJson struct {
-	Name          string `json:"name" binding:"required"`
-	URL           string `json:"url" binding:"required"`
-	Token         string `json:"token"  binding:"required"`
-	OperationSync bool   `json:"operation_sync"`
-	SyncApiRegex  string `json:"sync_api_regex"`
-}
-
-func validateRegex(data EnvironmentManageJson) error {
-	if data.OperationSync {
-		_, err := regexp.Compile(data.SyncApiRegex)
-		return err
-	}
-	return nil
+	cosy.Core[model.Environment](c).
+		SetFussy("name").
+		SetEqual("enabled").
+		SetTransformer(func(m *model.Environment) any {
+			return analytic.GetNode(m)
+		}).PagingList()
 }
 }
 
 
 func AddEnvironment(c *gin.Context) {
 func AddEnvironment(c *gin.Context) {
-	var json EnvironmentManageJson
-	if !api.BindAndValid(c, &json) {
-		return
-	}
-	if err := validateRegex(json); err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-
-	env := model.Environment{
-		Name:          json.Name,
-		URL:           json.URL,
-		Token:         json.Token,
-		OperationSync: json.OperationSync,
-		SyncApiRegex:  json.SyncApiRegex,
-	}
-
-	envQuery := query.Environment
-
-	err := envQuery.Create(&env)
-	if err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-
-	go analytic.RestartRetrieveNodesStatus()
-
-	c.JSON(http.StatusOK, env)
+	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) {
 func EditEnvironment(c *gin.Context) {
-	id := cast.ToInt(c.Param("id"))
-
-	var json EnvironmentManageJson
-	if !api.BindAndValid(c, &json) {
-		return
-	}
-	if err := validateRegex(json); err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
+	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) {
+	id := cast.ToInt(c.Param("id"))
 	envQuery := query.Environment
 	envQuery := query.Environment
 
 
 	env, err := envQuery.FirstByID(id)
 	env, err := envQuery.FirstByID(id)
@@ -103,15 +67,7 @@ func EditEnvironment(c *gin.Context) {
 		api.ErrHandler(c, err)
 		api.ErrHandler(c, err)
 		return
 		return
 	}
 	}
-
-	_, err = envQuery.Where(envQuery.ID.Eq(env.ID)).Updates(&model.Environment{
-		Name:          json.Name,
-		URL:           json.URL,
-		Token:         json.Token,
-		OperationSync: json.OperationSync,
-		SyncApiRegex:  json.SyncApiRegex,
-	})
-
+	err = envQuery.DeleteByID(env.ID)
 	if err != nil {
 	if err != nil {
 		api.ErrHandler(c, err)
 		api.ErrHandler(c, err)
 		return
 		return
@@ -119,25 +75,21 @@ func EditEnvironment(c *gin.Context) {
 
 
 	go analytic.RestartRetrieveNodesStatus()
 	go analytic.RestartRetrieveNodesStatus()
 
 
-	GetEnvironment(c)
+	c.JSON(http.StatusNoContent, nil)
 }
 }
 
 
-func DeleteEnvironment(c *gin.Context) {
-	id := cast.ToInt(c.Param("id"))
-	envQuery := query.Environment
-
-	env, err := envQuery.FirstByID(id)
-	if err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-	err = envQuery.DeleteByID(env.ID)
+func LoadEnvironmentFromSettings(c *gin.Context) {
+	err := settings.ReloadCluster()
 	if err != nil {
 	if err != nil {
 		api.ErrHandler(c, err)
 		api.ErrHandler(c, err)
 		return
 		return
 	}
 	}
 
 
+	cluster.RegisterPredefinedNodes()
+
 	go analytic.RestartRetrieveNodesStatus()
 	go analytic.RestartRetrieveNodesStatus()
 
 
-	c.JSON(http.StatusNoContent, nil)
+	c.JSON(http.StatusOK, gin.H{
+		"message": "ok",
+	})
 }
 }

+ 1 - 0
api/cluster/router.go

@@ -5,6 +5,7 @@ import "github.com/gin-gonic/gin"
 func InitRouter(r *gin.RouterGroup) {
 func InitRouter(r *gin.RouterGroup) {
 	// Environment
 	// Environment
 	r.GET("environments", GetEnvironmentList)
 	r.GET("environments", GetEnvironmentList)
+	r.POST("environments/load_from_settings", LoadEnvironmentFromSettings)
 	envGroup := r.Group("environment")
 	envGroup := r.Group("environment")
 	{
 	{
 		envGroup.GET("/:id", GetEnvironment)
 		envGroup.GET("/:id", GetEnvironment)

+ 19 - 3
api/nginx/control.go

@@ -4,6 +4,7 @@ import (
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 	"net/http"
 	"net/http"
+	"os"
 )
 )
 
 
 func Reload(c *gin.Context) {
 func Reload(c *gin.Context) {
@@ -23,9 +24,24 @@ func Test(c *gin.Context) {
 }
 }
 
 
 func Restart(c *gin.Context) {
 func Restart(c *gin.Context) {
-	output := nginx.Restart()
 	c.JSON(http.StatusOK, gin.H{
 	c.JSON(http.StatusOK, gin.H{
-		"message": output,
-		"level":   nginx.GetLogLevel(output),
+		"message": "ok",
+	})
+	go nginx.Restart()
+}
+
+func Status(c *gin.Context) {
+	pidPath := nginx.GetPIDPath()
+	lastOutput := nginx.GetLastOutput()
+
+	running := true
+	if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 { // fileInfo.Size() == 0 no process id
+		running = false
+	}
+
+	c.JSON(http.StatusOK, gin.H{
+		"running": running,
+		"message": lastOutput,
+		"level":   nginx.GetLogLevel(lastOutput),
 	})
 	})
 }
 }

+ 43 - 57
api/nginx/nginx.go

@@ -1,73 +1,59 @@
 package nginx
 package nginx
 
 
 import (
 import (
-	"github.com/0xJacky/Nginx-UI/api"
-	"github.com/0xJacky/Nginx-UI/internal/nginx"
-	"github.com/gin-gonic/gin"
-	"net/http"
-	"os"
+    "github.com/0xJacky/Nginx-UI/api"
+    "github.com/0xJacky/Nginx-UI/internal/nginx"
+    "github.com/gin-gonic/gin"
+    "net/http"
 )
 )
 
 
 func BuildNginxConfig(c *gin.Context) {
 func BuildNginxConfig(c *gin.Context) {
-	var ngxConf nginx.NgxConfig
-	if !api.BindAndValid(c, &ngxConf) {
-		return
-	}
-	content, err := ngxConf.BuildConfig()
-	if err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-	c.JSON(http.StatusOK, gin.H{
-		"content": content,
-	})
+    var ngxConf nginx.NgxConfig
+    if !api.BindAndValid(c, &ngxConf) {
+        return
+    }
+    content, err := ngxConf.BuildConfig()
+    if err != nil {
+        api.ErrHandler(c, err)
+        return
+    }
+    c.JSON(http.StatusOK, gin.H{
+        "content": content,
+    })
 }
 }
 
 
 func TokenizeNginxConfig(c *gin.Context) {
 func TokenizeNginxConfig(c *gin.Context) {
-	var json struct {
-		Content string `json:"content" binding:"required"`
-	}
+    var json struct {
+        Content string `json:"content" binding:"required"`
+    }
 
 
-	if !api.BindAndValid(c, &json) {
-		return
-	}
+    if !api.BindAndValid(c, &json) {
+        return
+    }
 
 
-	ngxConfig, err := nginx.ParseNgxConfigByContent(json.Content)
-	if err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-	c.JSON(http.StatusOK, ngxConfig)
+    ngxConfig, err := nginx.ParseNgxConfigByContent(json.Content)
+    if err != nil {
+        api.ErrHandler(c, err)
+        return
+    }
+    c.JSON(http.StatusOK, ngxConfig)
 
 
 }
 }
 
 
 func FormatNginxConfig(c *gin.Context) {
 func FormatNginxConfig(c *gin.Context) {
-	var json struct {
-		Content string `json:"content" binding:"required"`
-	}
-
-	if !api.BindAndValid(c, &json) {
-		return
-	}
-	content, err := nginx.FmtCode(json.Content)
-	if err != nil {
-		api.ErrHandler(c, err)
-		return
-	}
-	c.JSON(http.StatusOK, gin.H{
-		"content": content,
-	})
-}
-
-func Status(c *gin.Context) {
-	pidPath := nginx.GetPIDPath()
-
-	running := true
-	if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 { // fileInfo.Size() == 0 no process id
-		running = false
-	}
-
-	c.JSON(http.StatusOK, gin.H{
-		"running": running,
-	})
+    var json struct {
+        Content string `json:"content" binding:"required"`
+    }
+
+    if !api.BindAndValid(c, &json) {
+        return
+    }
+    content, err := nginx.FmtCode(json.Content)
+    if err != nil {
+        api.ErrHandler(c, err)
+        return
+    }
+    c.JSON(http.StatusOK, gin.H{
+        "content": content,
+    })
 }
 }

+ 2 - 2
api/system/install.go

@@ -13,7 +13,7 @@ import (
 )
 )
 
 
 func installLockStatus() bool {
 func installLockStatus() bool {
-	return "" != settings.ServerSettings.JwtSecret
+	return settings.ServerSettings.SkipInstallation || "" != settings.ServerSettings.JwtSecret
 }
 }
 
 
 func InstallLockCheck(c *gin.Context) {
 func InstallLockCheck(c *gin.Context) {
@@ -49,7 +49,6 @@ func InstallNginxUI(c *gin.Context) {
 	if "" != json.Database {
 	if "" != json.Database {
 		settings.ServerSettings.Database = json.Database
 		settings.ServerSettings.Database = json.Database
 	}
 	}
-	settings.ReflectFrom()
 
 
 	err := settings.Save()
 	err := settings.Save()
 	if err != nil {
 	if err != nil {
@@ -72,6 +71,7 @@ func InstallNginxUI(c *gin.Context) {
 		api.ErrHandler(c, err)
 		api.ErrHandler(c, err)
 		return
 		return
 	}
 	}
+
 	c.JSON(http.StatusOK, gin.H{
 	c.JSON(http.StatusOK, gin.H{
 		"message": "ok",
 		"message": "ok",
 	})
 	})

+ 1 - 0
api/system/router.go

@@ -11,6 +11,7 @@ func InitPublicRouter(r *gin.RouterGroup) {
 }
 }
 
 
 func InitPrivateRouter(r *gin.RouterGroup) {
 func InitPrivateRouter(r *gin.RouterGroup) {
+    r.GET("settings/server/name", GetServerName)
     r.GET("settings", GetSettings)
     r.GET("settings", GetSettings)
     r.POST("settings", SaveSettings)
     r.POST("settings", SaveSettings)
 
 

+ 10 - 20
api/system/settings.go

@@ -6,9 +6,14 @@ import (
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 	"net/http"
 	"net/http"
-	"reflect"
 )
 )
 
 
+func GetServerName(c *gin.Context) {
+	c.JSON(http.StatusOK, gin.H{
+		"name": settings.ServerSettings.Name,
+	})
+}
+
 func GetSettings(c *gin.Context) {
 func GetSettings(c *gin.Context) {
 	c.JSON(http.StatusOK, gin.H{
 	c.JSON(http.StatusOK, gin.H{
 		"server":    settings.ServerSettings,
 		"server":    settings.ServerSettings,
@@ -35,12 +40,10 @@ func SaveSettings(c *gin.Context) {
 		go cron.RestartLogrotate()
 		go cron.RestartLogrotate()
 	}
 	}
 
 
-	fillSettings(&settings.ServerSettings, &json.Server)
-	fillSettings(&settings.NginxSettings, &json.Nginx)
-	fillSettings(&settings.OpenAISettings, &json.Openai)
-	fillSettings(&settings.LogrotateSettings, &json.Logrotate)
-
-	settings.ReflectFrom()
+	settings.ProtectedFill(&settings.ServerSettings, &json.Server)
+	settings.ProtectedFill(&settings.NginxSettings, &json.Nginx)
+	settings.ProtectedFill(&settings.OpenAISettings, &json.Openai)
+	settings.ProtectedFill(&settings.LogrotateSettings, &json.Logrotate)
 
 
 	err := settings.Save()
 	err := settings.Save()
 	if err != nil {
 	if err != nil {
@@ -50,16 +53,3 @@ func SaveSettings(c *gin.Context) {
 
 
 	GetSettings(c)
 	GetSettings(c)
 }
 }
-
-func fillSettings(targetSettings interface{}, newSettings interface{}) {
-	s := reflect.TypeOf(targetSettings).Elem()
-	vt := reflect.ValueOf(targetSettings).Elem()
-	vn := reflect.ValueOf(newSettings).Elem()
-
-	// copy the values from new to target settings if it is not protected
-	for i := 0; i < s.NumField(); i++ {
-		if s.Field(i).Tag.Get("protected") != "true" {
-			vt.Field(i).Set(vn.Field(i))
-		}
-	}
-}

+ 30 - 22
app.example.ini

@@ -1,45 +1,53 @@
+; suppress inspection "DuplicateKeyInSection" for whole file
 [server]
 [server]
 HttpPort             = 9000
 HttpPort             = 9000
 RunMode              = debug
 RunMode              = debug
-JwtSecret            =
-Email                =
+JwtSecret            = 
+Email                = 
 HTTPChallengePort    = 9180
 HTTPChallengePort    = 9180
 StartCmd             = bash
 StartCmd             = bash
 Database             = database
 Database             = database
-CADir                =
-GithubProxy          =
-NodeSecret           =
+CADir                = 
+GithubProxy          = 
+NodeSecret           = 
 Demo                 = false
 Demo                 = false
 PageSize             = 10
 PageSize             = 10
 HttpHost             = 0.0.0.0
 HttpHost             = 0.0.0.0
 CertRenewalInterval  = 7
 CertRenewalInterval  = 7
-RecursiveNameservers =
+RecursiveNameservers = 
+SkipInstallation     = false
+Name                 = 
 
 
 [nginx]
 [nginx]
 AccessLogPath = /var/log/nginx/access.log
 AccessLogPath = /var/log/nginx/access.log
 ErrorLogPath  = /var/log/nginx/error.log
 ErrorLogPath  = /var/log/nginx/error.log
-ConfigDir    =
-PIDPath       =
-TestConfigCmd =
-ReloadCmd     =
-RestartCmd    =
+ConfigDir     = 
+PIDPath       = 
+TestConfigCmd = 
+ReloadCmd     = 
+RestartCmd    = 
 
 
 [openai]
 [openai]
-Model =
-BaseUrl =
-Proxy =
-Token =
+Model   = 
+BaseUrl = 
+Proxy   = 
+Token   = 
 
 
 [casdoor]
 [casdoor]
-Endpoint =
-ClientId =
-ClientSecret =
-Certificate =
-Organization =
-Application =
-RedirectUri =
+Endpoint     = 
+ClientId     = 
+ClientSecret = 
+Certificate  = 
+Organization = 
+Application  = 
+RedirectUri  = 
 
 
 [logrotate]
 [logrotate]
 Enabled  = false
 Enabled  = false
 CMD      = logrotate /etc/logrotate.d/nginx
 CMD      = logrotate /etc/logrotate.d/nginx
 Interval = 1440
 Interval = 1440
+
+[cluster]
+Node = http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true
+Node = http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=true
+Node = http://10.0.0.3?name=node3&node_secret=my-node-secret&enabled=true

+ 13 - 13
app/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "nginx-ui-app-next",
   "name": "nginx-ui-app-next",
-  "version": "2.0.0-beta.22",
+  "version": "2.0.0-beta.23",
   "type": "module",
   "type": "module",
   "scripts": {
   "scripts": {
     "dev": "vite",
     "dev": "vite",
@@ -13,13 +13,16 @@
   "dependencies": {
   "dependencies": {
     "@ant-design/icons-vue": "^7.0.1",
     "@ant-design/icons-vue": "^7.0.1",
     "@formkit/auto-animate": "^0.8.2",
     "@formkit/auto-animate": "^0.8.2",
-    "@vue/reactivity": "^3.4.25",
-    "@vue/shared": "^3.4.25",
+    "@vue/reactivity": "^3.4.27",
+    "@vue/shared": "^3.4.27",
     "@vueuse/core": "^10.9.0",
     "@vueuse/core": "^10.9.0",
+    "@xterm/addon-attach": "^0.11.0",
+    "@xterm/addon-fit": "^0.10.0",
+    "@xterm/xterm": "^5.5.0",
     "ant-design-vue": "^4.2.1",
     "ant-design-vue": "^4.2.1",
     "apexcharts": "^3.49.0",
     "apexcharts": "^3.49.0",
     "axios": "^1.6.8",
     "axios": "^1.6.8",
-    "dayjs": "^1.11.10",
+    "dayjs": "^1.11.11",
     "highlight.js": "^11.9.0",
     "highlight.js": "^11.9.0",
     "lodash": "^4.17.21",
     "lodash": "^4.17.21",
     "marked": "^10.0.0",
     "marked": "^10.0.0",
@@ -29,27 +32,24 @@
     "reconnecting-websocket": "^4.4.0",
     "reconnecting-websocket": "^4.4.0",
     "sortablejs": "^1.15.2",
     "sortablejs": "^1.15.2",
     "vite-plugin-build-id": "^0.2.8",
     "vite-plugin-build-id": "^0.2.8",
-    "vue": "^3.4.26",
+    "vue": "^3.4.27",
     "vue-github-button": "github:0xJacky/vue-github-button",
     "vue-github-button": "github:0xJacky/vue-github-button",
     "vue-router": "^4.3.2",
     "vue-router": "^4.3.2",
     "vue3-ace-editor": "2.2.4",
     "vue3-ace-editor": "2.2.4",
     "vue3-apexcharts": "1.4.4",
     "vue3-apexcharts": "1.4.4",
     "vue3-gettext": "3.0.0-beta.4",
     "vue3-gettext": "3.0.0-beta.4",
-    "vuedraggable": "^4.1.0",
-    "@xterm/xterm": "^5.5.0",
-    "@xterm/addon-attach": "^0.11.0",
-    "@xterm/addon-fit": "^0.10.0"
+    "vuedraggable": "^4.1.0"
   },
   },
   "devDependencies": {
   "devDependencies": {
     "@antfu/eslint-config-vue": "^0.43.1",
     "@antfu/eslint-config-vue": "^0.43.1",
-    "@types/lodash": "^4.17.0",
+    "@types/lodash": "^4.17.1",
     "@types/nprogress": "^0.2.3",
     "@types/nprogress": "^0.2.3",
     "@types/sortablejs": "^1.15.8",
     "@types/sortablejs": "^1.15.8",
     "@typescript-eslint/eslint-plugin": "^6.21.0",
     "@typescript-eslint/eslint-plugin": "^6.21.0",
     "@typescript-eslint/parser": "^6.21.0",
     "@typescript-eslint/parser": "^6.21.0",
     "@vitejs/plugin-vue": "^5.0.4",
     "@vitejs/plugin-vue": "^5.0.4",
     "@vitejs/plugin-vue-jsx": "^3.1.0",
     "@vitejs/plugin-vue-jsx": "^3.1.0",
-    "@vue/compiler-sfc": "^3.4.25",
+    "@vue/compiler-sfc": "^3.4.27",
     "@vue/tsconfig": "^0.5.1",
     "@vue/tsconfig": "^0.5.1",
     "ace-builds": "^1.33.1",
     "ace-builds": "^1.33.1",
     "autoprefixer": "^10.4.19",
     "autoprefixer": "^10.4.19",
@@ -66,8 +66,8 @@
     "typescript": "5.3.3",
     "typescript": "5.3.3",
     "unplugin-auto-import": "^0.17.5",
     "unplugin-auto-import": "^0.17.5",
     "unplugin-vue-components": "^0.26.0",
     "unplugin-vue-components": "^0.26.0",
-    "unplugin-vue-define-options": "^1.4.3",
-    "vite": "^5.2.10",
+    "unplugin-vue-define-options": "^1.4.4",
+    "vite": "^5.2.11",
     "vite-svg-loader": "^5.1.0",
     "vite-svg-loader": "^5.1.0",
     "vue-tsc": "^1.8.27"
     "vue-tsc": "^1.8.27"
   },
   },

File diff suppressed because it is too large
+ 612 - 281
app/pnpm-lock.yaml


+ 3 - 0
app/src/App.vue

@@ -10,6 +10,7 @@ import en_US from 'ant-design-vue/es/locale/en_US'
 
 
 import { useSettingsStore } from '@/pinia'
 import { useSettingsStore } from '@/pinia'
 import gettext from '@/gettext'
 import gettext from '@/gettext'
+import loadTranslations from '@/api/translations'
 
 
 const media = window.matchMedia('(prefers-color-scheme: dark)')
 const media = window.matchMedia('(prefers-color-scheme: dark)')
 
 
@@ -49,6 +50,8 @@ const lang = computed(() => {
 
 
 const settings = useSettingsStore()
 const settings = useSettingsStore()
 const is_theme_dark = computed(() => settings.theme === 'dark')
 const is_theme_dark = computed(() => settings.theme === 'dark')
+
+loadTranslations()
 </script>
 </script>
 
 
 <template>
 <template>

+ 13 - 1
app/src/api/environment.ts

@@ -1,3 +1,4 @@
+import http from '@/lib/http'
 import type { ModelBase } from '@/api/curd'
 import type { ModelBase } from '@/api/curd'
 import Curd from '@/api/curd'
 import Curd from '@/api/curd'
 
 
@@ -14,6 +15,17 @@ export interface Node {
   token: string
   token: string
   response_at?: Date
   response_at?: Date
 }
 }
-const environment: Curd<Environment> = new Curd('/environment')
+
+class EnvironmentCurd extends Curd<Environment> {
+  constructor() {
+    super('/environment')
+  }
+
+  load_from_settings() {
+    return http.post(`${this.plural}/load_from_settings`)
+  }
+}
+
+const environment: EnvironmentCurd = new EnvironmentCurd()
 
 
 export default environment
 export default environment

+ 1 - 1
app/src/api/ngx.ts

@@ -46,7 +46,7 @@ const ngx = {
     return http.post('/ngx/format_code', { content })
     return http.post('/ngx/format_code', { content })
   },
   },
 
 
-  status(): Promise<{ running: boolean }> {
+  status(): Promise<{ running: boolean; message: string; level: number }> {
     return http.get('/nginx/status')
     return http.get('/nginx/status')
   },
   },
 
 

+ 4 - 0
app/src/api/settings.ts

@@ -8,6 +8,10 @@ const settings = {
   save(data: any) {
   save(data: any) {
     return http.post('/settings', data)
     return http.post('/settings', data)
   },
   },
+
+  get_server_name() {
+    return http.get('/settings/server/name')
+  },
 }
 }
 
 
 export default settings
 export default settings

+ 19 - 0
app/src/api/translations.ts

@@ -0,0 +1,19 @@
+import gettext from '@/gettext'
+
+export default async function loadTranslations() {
+  const route = useRoute()
+
+  if (gettext.current !== 'en') {
+    await fetch(`${import.meta.env.VITE_API_ROOT}/translation/${gettext.current}`).then(async r => {
+      gettext.translations[gettext.current] = await r.json()
+    })
+
+    if (route?.meta?.name)
+      document.title = `${route.meta.name?.()} | Nginx UI`
+  }
+
+  watch(route, () => {
+    if (route?.meta?.name)
+      document.title = `${route.meta.name?.()} | Nginx UI`
+  })
+}

+ 13 - 8
app/src/components/ChatGPT/ChatGPT.vue

@@ -66,16 +66,21 @@ async function request() {
   let hasCodeBlockIndicator = false
   let hasCodeBlockIndicator = false
 
 
   while (true) {
   while (true) {
-    const { done, value } = await reader.read()
-    if (done) {
-      setTimeout(() => {
-        scrollToBottom()
-      }, 500)
-      loading.value = false
-      store_record()
+    try {
+      const { done, value } = await reader.read()
+      if (done) {
+        setTimeout(() => {
+          scrollToBottom()
+        }, 500)
+        loading.value = false
+        store_record()
+        break
+      }
+      apply(value!)
+    }
+    catch (e) {
       break
       break
     }
     }
-    apply(value!)
   }
   }
 
 
   function apply(input: Uint8Array) {
   function apply(input: Uint8Array) {

+ 3 - 1
app/src/components/EnvIndicator/EnvIndicator.vue

@@ -25,6 +25,8 @@ watch(node_id, async () => {
   await router.push('/dashboard')
   await router.push('/dashboard')
   location.reload()
   location.reload()
 })
 })
+
+const { server_name } = storeToRefs(useSettingsStore())
 </script>
 </script>
 
 
 <template>
 <template>
@@ -35,7 +37,7 @@ watch(node_id, async () => {
         v-if="is_local"
         v-if="is_local"
         class="env-name"
         class="env-name"
       >
       >
-        {{ $gettext('Local') }}
+        {{ server_name || $gettext('Local') }}
       </span>
       </span>
       <span
       <span
         v-else
         v-else

+ 13 - 10
app/src/components/NginxControl/NginxControl.vue

@@ -6,13 +6,14 @@ import { logLevel } from '@/views/config/constants'
 import { NginxStatus } from '@/constants'
 import { NginxStatus } from '@/constants'
 
 
 const status = ref(0)
 const status = ref(0)
-function get_status() {
-  ngx.status().then(r => {
-    if (r?.running === true)
-      status.value = NginxStatus.Running
-    else
-      status.value = NginxStatus.Stopped
-  })
+async function get_status() {
+  const r = await ngx.status()
+  if (r?.running === true)
+    status.value = NginxStatus.Running
+  else
+    status.value = NginxStatus.Stopped
+
+  return r
 }
 }
 
 
 function reload_nginx() {
 function reload_nginx() {
@@ -29,9 +30,11 @@ function reload_nginx() {
   }).finally(() => get_status())
   }).finally(() => get_status())
 }
 }
 
 
-function restart_nginx() {
+async function restart_nginx() {
   status.value = NginxStatus.Restarting
   status.value = NginxStatus.Restarting
-  ngx.restart().then(r => {
+  await ngx.restart()
+
+  get_status().then(r => {
     if (r.level < logLevel.Warn)
     if (r.level < logLevel.Warn)
       message.success($gettext('Nginx restarted successfully'))
       message.success($gettext('Nginx restarted successfully'))
     else if (r.level === logLevel.Warn)
     else if (r.level === logLevel.Warn)
@@ -40,7 +43,7 @@ function restart_nginx() {
       message.error(r.message)
       message.error(r.message)
   }).catch(e => {
   }).catch(e => {
     message.error(`${$gettext('Server error')} ${e?.message}`)
     message.error(`${$gettext('Server error')} ${e?.message}`)
-  }).finally(() => get_status())
+  })
 }
 }
 
 
 const visible = ref(false)
 const visible = ref(false)

+ 27 - 7
app/src/components/NodeSelector/NodeSelector.vue

@@ -14,11 +14,21 @@ const emit = defineEmits(['update:target', 'update:map'])
 const data = ref([]) as Ref<Environment[]>
 const data = ref([]) as Ref<Environment[]>
 const data_map = ref({}) as Ref<Record<number, Environment>>
 const data_map = ref({}) as Ref<Record<number, Environment>>
 
 
-environment.get_list().then(r => {
-  data.value = r.data
-  r.data?.forEach(node => {
-    data_map.value[node.id] = node
-  })
+onMounted(async () => {
+  let hasMore = true
+  let page = 1
+  while (hasMore) {
+    await environment.get_list({ page, enabled: true }).then(r => {
+      data.value.push(...r.data)
+      r.data?.forEach(node => {
+        data_map.value[node.id] = node
+      })
+      hasMore = r.data.length === r.pagination.per_page
+      page++
+    }).catch(() => {
+      hasMore = false
+    })
+  }
 })
 })
 
 
 const value = computed({
 const value = computed({
@@ -35,14 +45,24 @@ const value = computed({
     emit('update:target', v)
     emit('update:target', v)
   },
   },
 })
 })
+
+const noData = computed(() => {
+  return props.hiddenLocal && !data?.value?.length
+})
 </script>
 </script>
 
 
 <template>
 <template>
   <ACheckboxGroup
   <ACheckboxGroup
     v-model:value="value"
     v-model:value="value"
     style="width: 100%"
     style="width: 100%"
+    :class="{
+      'justify-center': noData,
+    }"
   >
   >
-    <ARow :gutter="[16, 16]">
+    <ARow
+      v-if="!noData"
+      :gutter="[16, 16]"
+    >
       <ACol
       <ACol
         v-if="!hiddenLocal"
         v-if="!hiddenLocal"
         :span="8"
         :span="8"
@@ -76,7 +96,7 @@ const value = computed({
         </ATag>
         </ATag>
       </ACol>
       </ACol>
     </ARow>
     </ARow>
-    <AEmpty v-if="hiddenLocal && data?.length === 0" />
+    <AEmpty v-else />
   </ACheckboxGroup>
   </ACheckboxGroup>
 </template>
 </template>
 
 

+ 11 - 17
app/src/components/SetLanguage/SetLanguage.vue

@@ -1,32 +1,27 @@
 <script setup lang="ts">
 <script setup lang="ts">
-import { ref, watch } from 'vue'
+import { watch } from 'vue'
 
 
 import { useSettingsStore } from '@/pinia'
 import { useSettingsStore } from '@/pinia'
-import http from '@/lib/http'
 import gettext from '@/gettext'
 import gettext from '@/gettext'
+import loadTranslations from '@/api/translations'
 
 
 const settings = useSettingsStore()
 const settings = useSettingsStore()
 
 
 const route = useRoute()
 const route = useRoute()
 
 
-const current = ref(gettext.current)
+const current = computed({
+  get() {
+    return gettext.current
+  },
+  set(v) {
+    gettext.current = v
+  },
+})
 
 
 const languageAvailable = gettext.available
 const languageAvailable = gettext.available
 
 
-async function init() {
-  if (current.value !== 'en') {
-    await http.get(`/translation/${current.value}`).then(r => {
-      gettext.translations[current.value] = r
-    })
-
-    document.title = `${route.meta.name?.()} | Nginx UI`
-  }
-}
-
-init()
-
 watch(current, v => {
 watch(current, v => {
-  init()
+  loadTranslations()
   settings.set_language(v)
   settings.set_language(v)
   gettext.current = v
   gettext.current = v
 
 
@@ -34,7 +29,6 @@ watch(current, v => {
 
 
   document.title = `${name()} | Nginx UI`
   document.title = `${name()} | Nginx UI`
 })
 })
-
 </script>
 </script>
 
 
 <template>
 <template>

+ 1 - 1
app/src/language/LINGUAS

@@ -1 +1 @@
-es fr_FR ko_KR ru_RU vi_VN zh_CN zh_TW
+en zh_CN zh_TW fr_FR es ru_RU vi_VN ko_KR

+ 107 - 85
app/src/language/en/app.po

@@ -18,7 +18,7 @@ msgid "Access Logs"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
-#: src/views/certificate/ACMEUserSelector.vue:79
+#: src/views/certificate/ACMEUserSelector.vue:84
 #, fuzzy
 #, fuzzy
 msgid "ACME User"
 msgid "ACME User"
 msgstr "Username"
 msgstr "Username"
@@ -26,7 +26,7 @@ msgstr "Username"
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
-#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:102
+#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:35
 #: src/views/notification/Notification.vue:35
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
@@ -74,7 +74,7 @@ msgstr "Add Location"
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Advance Mode"
 msgstr "Advance Mode"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:39
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr ""
 msgstr ""
 
 
@@ -82,11 +82,11 @@ msgstr ""
 msgid "API Document"
 msgid "API Document"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:45
+#: src/views/preference/OpenAISettings.vue:51
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:63
 msgid "API Token"
 msgid "API Token"
 msgstr ""
 msgstr ""
 
 
@@ -100,7 +100,7 @@ msgstr ""
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Are you sure you want to remove this directive?"
 msgstr "Are you sure you want to remove this directive?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:267
+#: src/components/ChatGPT/ChatGPT.vue:272
 #, fuzzy
 #, fuzzy
 msgid "Are you sure you want to clear the record of chat?"
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Are you sure you want to remove this directive?"
 msgstr "Are you sure you want to remove this directive?"
@@ -134,11 +134,11 @@ msgstr "Are you sure you want to remove this directive?"
 msgid "Are you sure you want to remove this location?"
 msgid "Are you sure you want to remove this location?"
 msgstr "Are you sure you want to remove this directive?"
 msgstr "Are you sure you want to remove this directive?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:211
+#: src/components/ChatGPT/ChatGPT.vue:216
 msgid "Ask ChatGPT for Help"
 msgid "Ask ChatGPT for Help"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "Assistant"
 msgid "Assistant"
 msgstr ""
 msgstr ""
 
 
@@ -147,7 +147,7 @@ msgstr ""
 msgid "Author"
 msgid "Author"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/cert/ChangeCert.vue:34
+#: src/views/domain/cert/ChangeCert.vue:33
 msgid "Auto Cert"
 msgid "Auto Cert"
 msgstr ""
 msgstr ""
 
 
@@ -181,7 +181,7 @@ msgstr "Base information"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:94
+#: src/views/preference/Preference.vue:101
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Basic"
 msgid "Basic"
@@ -209,10 +209,10 @@ msgstr ""
 msgid "CADir"
 msgid "CADir"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:248
+#: src/components/ChatGPT/ChatGPT.vue:253
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:102
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:153
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/RightSettings.vue:51
 #: src/views/domain/components/RightSettings.vue:51
@@ -256,8 +256,8 @@ msgstr "Certificate is valid"
 msgid "Challenge Method"
 msgid "Challenge Method"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/cert/ChangeCert.vue:88
-#: src/views/domain/cert/ChangeCert.vue:92
+#: src/views/domain/cert/ChangeCert.vue:95
+#: src/views/domain/cert/ChangeCert.vue:99
 #, fuzzy
 #, fuzzy
 msgid "Change Certificate"
 msgid "Change Certificate"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
@@ -274,7 +274,7 @@ msgstr ""
 msgid "Cleaning environment variables"
 msgid "Cleaning environment variables"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:271
+#: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/Notification/Notification.vue:89
 #: src/components/Notification/Notification.vue:89
 #: src/views/notification/Notification.vue:75
 #: src/views/notification/Notification.vue:75
 msgid "Clear"
 msgid "Clear"
@@ -319,7 +319,7 @@ msgstr "Configurations"
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Configure SSL"
 msgstr "Configure SSL"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Connected"
 msgid "Connected"
 msgstr ""
 msgstr ""
 
 
@@ -333,7 +333,7 @@ msgstr "Content"
 msgid "Core Upgrade"
 msgid "Core Upgrade"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:293
+#: src/views/dashboard/ServerAnalytic.vue:296
 msgid "CPU Status"
 msgid "CPU Status"
 msgstr "CPU Status"
 msgstr "CPU Status"
 
 
@@ -375,6 +375,12 @@ msgstr ""
 msgid "Custom"
 msgid "Custom"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/BasicSettings.vue:121
+msgid ""
+"Customize the name of local server to be displayed in the environment "
+"indicator."
+msgstr ""
+
 #: src/routes/index.ts:39
 #: src/routes/index.ts:39
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Dashboard"
 msgstr "Dashboard"
@@ -466,9 +472,9 @@ msgstr "Disabled"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "Disable auto-renewal failed for %{name}"
 msgstr "Disable auto-renewal failed for %{name}"
 
 
-#: src/views/domain/cert/ChangeCert.vue:45 src/views/domain/DomainEdit.vue:185
-#: src/views/domain/DomainList.vue:33 src/views/stream/StreamEdit.vue:177
-#: src/views/stream/StreamList.vue:33
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
+#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Disabled"
 msgstr "Disabled"
 
 
@@ -479,7 +485,7 @@ msgstr "Disabled"
 msgid "Disabled successfully"
 msgid "Disabled successfully"
 msgstr "Disabled successfully"
 msgstr "Disabled successfully"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:358
+#: src/views/dashboard/ServerAnalytic.vue:361
 msgid "Disk IO"
 msgid "Disk IO"
 msgstr "Disk IO"
 msgstr "Disk IO"
 
 
@@ -660,9 +666,10 @@ msgstr "Enabled successfully"
 msgid "Enable TLS"
 msgid "Enable TLS"
 msgstr "Enable TLS"
 msgstr "Enable TLS"
 
 
-#: src/views/domain/cert/ChangeCert.vue:41
+#: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
@@ -682,11 +689,11 @@ msgstr "Enabled successfully"
 msgid "Encrypt website with Let's Encrypt"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Encrypt website with Let's Encrypt"
 msgstr "Encrypt website with Let's Encrypt"
 
 
-#: src/routes/index.ts:212 src/views/environment/Environment.vue:110
+#: src/routes/index.ts:212 src/views/environment/Environment.vue:137
 msgid "Environment"
 msgid "Environment"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/Environments.vue:71
+#: src/views/dashboard/Environments.vue:82
 #, fuzzy
 #, fuzzy
 msgid "Environments"
 msgid "Environments"
 msgstr "Comments"
 msgstr "Comments"
@@ -913,7 +920,7 @@ msgstr ""
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Leave blank for no change"
 msgstr "Leave blank for no change"
 
 
-#: src/views/preference/OpenAISettings.vue:41
+#: src/views/preference/OpenAISettings.vue:47
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr ""
 msgstr ""
 
 
@@ -928,7 +935,7 @@ msgstr "Leave blank for no change"
 msgid "License"
 msgid "License"
 msgstr "License"
 msgstr "License"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Link Start"
 msgid "Link Start"
 msgstr ""
 msgstr ""
 
 
@@ -942,8 +949,8 @@ msgstr ""
 msgid "Load Average:"
 msgid "Load Average:"
 msgstr "Load Averages:"
 msgstr "Load Averages:"
 
 
-#: src/components/EnvIndicator/EnvIndicator.vue:38
-#: src/components/NodeSelector/NodeSelector.vue:51
+#: src/components/EnvIndicator/EnvIndicator.vue:40
+#: src/components/NodeSelector/NodeSelector.vue:71
 #, fuzzy
 #, fuzzy
 msgid "Local"
 msgid "Local"
 msgstr "Location"
 msgstr "Location"
@@ -973,7 +980,7 @@ msgstr "Login successful"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Logout successful"
 msgstr "Logout successful"
 
 
-#: src/views/preference/Preference.vue:112
+#: src/views/preference/Preference.vue:119
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1019,6 +1026,7 @@ msgid "Managed Certificate"
 msgstr "Certificate is valid"
 msgstr "Certificate is valid"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
+#: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
 msgstr "Memory"
 msgstr "Memory"
 
 
@@ -1030,12 +1038,12 @@ msgstr "Memory and Storage"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:26
+#: src/views/preference/OpenAISettings.vue:27
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Advance Mode"
 msgstr "Advance Mode"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:244
+#: src/components/ChatGPT/ChatGPT.vue:249
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #, fuzzy
 #, fuzzy
@@ -1065,7 +1073,7 @@ msgstr "Single Directive"
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
-#: src/views/domain/cert/ChangeCert.vue:18
+#: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
@@ -1077,19 +1085,19 @@ msgstr "Single Directive"
 msgid "Name"
 msgid "Name"
 msgstr "Name"
 msgstr "Name"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:319
+#: src/views/dashboard/ServerAnalytic.vue:322
 msgid "Network"
 msgid "Network"
 msgstr "Network"
 msgstr "Network"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:261
+#: src/views/dashboard/ServerAnalytic.vue:264
 msgid "Network Statistics"
 msgid "Network Statistics"
 msgstr "Network Statistics"
 msgstr "Network Statistics"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:268
+#: src/views/dashboard/ServerAnalytic.vue:271
 msgid "Network Total Receive"
 msgid "Network Total Receive"
 msgstr "Network Total Receive"
 msgstr "Network Total Receive"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:274
+#: src/views/dashboard/ServerAnalytic.vue:277
 msgid "Network Total Send"
 msgid "Network Total Send"
 msgstr "Network Total Send"
 msgstr "Network Total Send"
 
 
@@ -1103,7 +1111,7 @@ msgstr ""
 msgid "Next"
 msgid "Next"
 msgstr "Next"
 msgstr "Next"
 
 
-#: src/views/preference/Preference.vue:100
+#: src/views/preference/Preference.vue:107
 msgid "Nginx"
 msgid "Nginx"
 msgstr ""
 msgstr ""
 
 
@@ -1116,7 +1124,7 @@ msgstr ""
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Configuration Name"
 msgstr "Configuration Name"
 
 
-#: src/components/NginxControl/NginxControl.vue:62
+#: src/components/NginxControl/NginxControl.vue:65
 msgid "Nginx Control"
 msgid "Nginx Control"
 msgstr ""
 msgstr ""
 
 
@@ -1128,17 +1136,17 @@ msgstr ""
 msgid "Nginx Log"
 msgid "Nginx Log"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:22
+#: src/components/NginxControl/NginxControl.vue:23
 #, fuzzy
 #, fuzzy
 msgid "Nginx reloaded successfully"
 msgid "Nginx reloaded successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
 
 
-#: src/components/NginxControl/NginxControl.vue:36
+#: src/components/NginxControl/NginxControl.vue:39
 #, fuzzy
 #, fuzzy
 msgid "Nginx restarted successfully"
 msgid "Nginx restarted successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:265
+#: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/Notification/Notification.vue:82
 #: src/components/Notification/Notification.vue:82
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
@@ -1191,22 +1199,22 @@ msgstr "Certificate is valid"
 msgid "Obtaining certificate"
 msgid "Obtaining certificate"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NodeSelector/NodeSelector.vue:75
-#: src/views/dashboard/Environments.vue:95
-#: src/views/environment/Environment.vue:86
+#: src/components/NodeSelector/NodeSelector.vue:95
+#: src/views/dashboard/Environments.vue:106
+#: src/views/environment/Environment.vue:88
 msgid "Offline"
 msgid "Offline"
 msgstr ""
 msgstr ""
 
 
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:154
 msgid "Ok"
 msgid "Ok"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:266
+#: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/Notification/Notification.vue:83
 #: src/components/Notification/Notification.vue:83
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:103
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/RightSettings.vue:50
 #: src/views/domain/components/RightSettings.vue:50
@@ -1225,14 +1233,14 @@ msgstr ""
 msgid "Once the verification is complete, the records will be removed."
 msgid "Once the verification is complete, the records will be removed."
 msgstr ""
 msgstr ""
 
 
-#: src/components/NodeSelector/NodeSelector.vue:54
-#: src/components/NodeSelector/NodeSelector.vue:69
-#: src/views/dashboard/Environments.vue:88
-#: src/views/environment/Environment.vue:82
+#: src/components/NodeSelector/NodeSelector.vue:74
+#: src/components/NodeSelector/NodeSelector.vue:89
+#: src/views/dashboard/Environments.vue:99
+#: src/views/environment/Environment.vue:84
 msgid "Online"
 msgid "Online"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:106
+#: src/views/preference/Preference.vue:113
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr ""
 msgstr ""
 
 
@@ -1326,7 +1334,7 @@ msgstr ""
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:89
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
 msgid "Preference"
 msgid "Preference"
 msgstr ""
 msgstr ""
 
 
@@ -1352,12 +1360,12 @@ msgid "Provider"
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:28
 #: src/views/dashboard/ServerAnalytic.vue:28
-#: src/views/dashboard/ServerAnalytic.vue:375
+#: src/views/dashboard/ServerAnalytic.vue:378
 msgid "Reads"
 msgid "Reads"
 msgstr "Reads"
 msgstr "Reads"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:24
 #: src/views/dashboard/ServerAnalytic.vue:24
-#: src/views/dashboard/ServerAnalytic.vue:326
+#: src/views/dashboard/ServerAnalytic.vue:329
 msgid "Receive"
 msgid "Receive"
 msgstr "Receive"
 msgstr "Receive"
 
 
@@ -1374,7 +1382,7 @@ msgstr "Saved successfully"
 msgid "Recursive Nameservers"
 msgid "Recursive Nameservers"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:278
+#: src/components/ChatGPT/ChatGPT.vue:283
 msgid "Regenerate response"
 msgid "Regenerate response"
 msgstr ""
 msgstr ""
 
 
@@ -1409,12 +1417,12 @@ msgstr "Install"
 msgid "Release Note"
 msgid "Release Note"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:254
-#: src/components/NginxControl/NginxControl.vue:97
+#: src/components/ChatGPT/ChatGPT.vue:259
+#: src/components/NginxControl/NginxControl.vue:100
 msgid "Reload"
 msgid "Reload"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:71
+#: src/components/NginxControl/NginxControl.vue:74
 msgid "Reloading"
 msgid "Reloading"
 msgstr ""
 msgstr ""
 
 
@@ -1462,11 +1470,11 @@ msgstr ""
 msgid "Reset"
 msgid "Reset"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:90
+#: src/components/NginxControl/NginxControl.vue:93
 msgid "Restart"
 msgid "Restart"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:76
+#: src/components/NginxControl/NginxControl.vue:79
 msgid "Restarting"
 msgid "Restarting"
 msgstr ""
 msgstr ""
 
 
@@ -1475,15 +1483,15 @@ msgstr ""
 msgid "Run Mode"
 msgid "Run Mode"
 msgstr "Advance Mode"
 msgstr "Advance Mode"
 
 
-#: src/components/NginxControl/NginxControl.vue:66
+#: src/components/NginxControl/NginxControl.vue:69
 msgid "Running"
 msgid "Running"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:247
+#: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:123 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
 msgid "Save"
 msgid "Save"
 msgstr "Save"
 msgstr "Save"
 
 
@@ -1499,7 +1507,7 @@ msgstr "Save error %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:45
 #: src/views/certificate/CertificateEditor.vue:45
-#: src/views/preference/Preference.vue:59
+#: src/views/preference/Preference.vue:66
 #, fuzzy
 #, fuzzy
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Saved successfully"
 msgstr "Saved successfully"
@@ -1515,24 +1523,24 @@ msgstr "Saved successfully"
 msgid "SDK"
 msgid "SDK"
 msgstr ""
 msgstr ""
 
 
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:104
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:155
 msgid "Selector"
 msgid "Selector"
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:25
 #: src/views/dashboard/ServerAnalytic.vue:25
-#: src/views/dashboard/ServerAnalytic.vue:336
+#: src/views/dashboard/ServerAnalytic.vue:339
 msgid "Send"
 msgid "Send"
 msgstr "Send"
 msgstr "Send"
 
 
-#: src/components/NginxControl/NginxControl.vue:28
-#: src/components/NginxControl/NginxControl.vue:42
+#: src/components/NginxControl/NginxControl.vue:29
+#: src/components/NginxControl/NginxControl.vue:45
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:63
+#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:70
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
@@ -1542,6 +1550,11 @@ msgstr "Server error"
 msgid "Server Info"
 msgid "Server Info"
 msgstr "Server Info"
 msgstr "Server Info"
 
 
+#: src/views/preference/BasicSettings.vue:117
+#, fuzzy
+msgid "Server Name"
+msgstr "Server Info"
+
 #: src/views/domain/cert/components/ObtainCert.vue:102
 #: src/views/domain/cert/components/ObtainCert.vue:102
 msgid "server_name not found in directives"
 msgid "server_name not found in directives"
 msgstr "server_name not found in directives"
 msgstr "server_name not found in directives"
@@ -1616,15 +1629,16 @@ msgstr "Enabled"
 
 
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
-#: src/views/environment/Environment.vue:75 src/views/stream/StreamList.vue:22
+#: src/views/environment/Environment.vue:76 src/views/stream/StreamList.vue:22
 msgid "Status"
 msgid "Status"
 msgstr "Status"
 msgstr "Status"
 
 
-#: src/components/NginxControl/NginxControl.vue:81
+#: src/components/NginxControl/NginxControl.vue:84
 msgid "Stopped"
 msgid "Stopped"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:243
+#: src/views/dashboard/ServerAnalytic.vue:245
+#: src/views/dashboard/ServerAnalytic.vue:246
 msgid "Storage"
 msgid "Storage"
 msgstr "Storage"
 msgstr "Storage"
 
 
@@ -1637,7 +1651,8 @@ msgstr "Subject Name: %{name}"
 msgid "Success"
 msgid "Success"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:230
+#: src/views/dashboard/ServerAnalytic.vue:231
+#: src/views/dashboard/ServerAnalytic.vue:232
 msgid "Swap"
 msgid "Swap"
 msgstr "Swap"
 msgstr "Swap"
 
 
@@ -1688,6 +1703,10 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "Certificate Status"
 msgstr "Certificate Status"
 
 
+#: src/views/preference/OpenAISettings.vue:30
+msgid "The model name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/certificate/CertificateEditor.vue:165
 #: src/views/certificate/CertificateEditor.vue:165
 #, fuzzy
 #, fuzzy
 msgid "The path exists, but the file is not a certificate"
 msgid "The path exists, but the file is not a certificate"
@@ -1697,6 +1716,10 @@ msgstr "Certificate Status"
 msgid "The path exists, but the file is not a private key"
 msgid "The path exists, but the file is not a private key"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/BasicSettings.vue:120
+msgid "The server name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #, fuzzy
 #, fuzzy
 msgid ""
 msgid ""
@@ -1708,9 +1731,12 @@ msgstr ""
 
 
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:50
 #: src/views/preference/BasicSettings.vue:50
-#: src/views/preference/OpenAISettings.vue:36
-#: src/views/preference/OpenAISettings.vue:48
-msgid "The url is not valid"
+msgid "The url is invalid"
+msgstr ""
+
+#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:54
+msgid "The url is invalid."
 msgstr ""
 msgstr ""
 
 
 #: src/language/constants.ts:2
 #: src/language/constants.ts:2
@@ -1751,7 +1777,7 @@ msgid ""
 "continue?"
 "continue?"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:66
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
@@ -1768,7 +1794,7 @@ msgstr ""
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/components/RightSettings.vue:86
-#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:95
+#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:122
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 msgid "Updated at"
 msgid "Updated at"
@@ -1801,11 +1827,11 @@ msgstr ""
 msgid "Uptime:"
 msgid "Uptime:"
 msgstr "Uptime:"
 msgstr "Uptime:"
 
 
-#: src/views/environment/Environment.vue:21
+#: src/views/environment/Environment.vue:22
 msgid "URL"
 msgid "URL"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 #, fuzzy
 #, fuzzy
 msgid "User"
 msgid "User"
 msgstr "Username"
 msgstr "Username"
@@ -1861,7 +1887,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:27
 #: src/views/dashboard/ServerAnalytic.vue:27
-#: src/views/dashboard/ServerAnalytic.vue:365
+#: src/views/dashboard/ServerAnalytic.vue:368
 msgid "Writes"
 msgid "Writes"
 msgstr "Writes"
 msgstr "Writes"
 
 
@@ -1895,10 +1921,6 @@ msgstr ""
 #~ msgid "Table"
 #~ msgid "Table"
 #~ msgstr "Enabled"
 #~ msgstr "Enabled"
 
 
-#, fuzzy
-#~ msgid "Server"
-#~ msgstr "Server Info"
-
 #, fuzzy
 #, fuzzy
 #~ msgid "Leave blank will not change anything."
 #~ msgid "Leave blank will not change anything."
 #~ msgstr "Leave blank for no change"
 #~ msgstr "Leave blank for no change"

+ 112 - 85
app/src/language/es/app.po

@@ -23,7 +23,7 @@ msgid "Access Logs"
 msgstr "Registros de acceso"
 msgstr "Registros de acceso"
 
 
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
-#: src/views/certificate/ACMEUserSelector.vue:79
+#: src/views/certificate/ACMEUserSelector.vue:84
 #, fuzzy
 #, fuzzy
 msgid "ACME User"
 msgid "ACME User"
 msgstr "Usuario"
 msgstr "Usuario"
@@ -31,7 +31,7 @@ msgstr "Usuario"
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
-#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:102
+#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:35
 #: src/views/notification/Notification.vue:35
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
@@ -76,7 +76,7 @@ msgstr "Adicional"
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Modo avanzado"
 msgstr "Modo avanzado"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:39
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "URL Base de la API"
 msgstr "URL Base de la API"
 
 
@@ -85,11 +85,11 @@ msgstr "URL Base de la API"
 msgid "API Document"
 msgid "API Document"
 msgstr "Token de la API"
 msgstr "Token de la API"
 
 
-#: src/views/preference/OpenAISettings.vue:45
+#: src/views/preference/OpenAISettings.vue:51
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "Proxy de la API"
 msgstr "Proxy de la API"
 
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:63
 msgid "API Token"
 msgid "API Token"
 msgstr "Token de la API"
 msgstr "Token de la API"
 
 
@@ -102,7 +102,7 @@ msgstr "Arquitectura"
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "¿Está seguro de que desea borrar todas las notificaciones?"
 msgstr "¿Está seguro de que desea borrar todas las notificaciones?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:267
+#: src/components/ChatGPT/ChatGPT.vue:272
 msgid "Are you sure you want to clear the record of chat?"
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "¿Está seguro de que desea borrar el registro del chat?"
 msgstr "¿Está seguro de que desea borrar el registro del chat?"
 
 
@@ -133,11 +133,11 @@ msgstr "¿Está seguro de que quiere borrar esta directiva?"
 msgid "Are you sure you want to remove this location?"
 msgid "Are you sure you want to remove this location?"
 msgstr "¿Está seguro de que quiere borrar esta ubicación?"
 msgstr "¿Está seguro de que quiere borrar esta ubicación?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:211
+#: src/components/ChatGPT/ChatGPT.vue:216
 msgid "Ask ChatGPT for Help"
 msgid "Ask ChatGPT for Help"
 msgstr "Preguntar por ayuda a ChatGPT"
 msgstr "Preguntar por ayuda a ChatGPT"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "Assistant"
 msgid "Assistant"
 msgstr "Asistente"
 msgstr "Asistente"
 
 
@@ -146,7 +146,7 @@ msgstr "Asistente"
 msgid "Author"
 msgid "Author"
 msgstr "Autor"
 msgstr "Autor"
 
 
-#: src/views/domain/cert/ChangeCert.vue:34
+#: src/views/domain/cert/ChangeCert.vue:33
 msgid "Auto Cert"
 msgid "Auto Cert"
 msgstr "Certificado automático"
 msgstr "Certificado automático"
 
 
@@ -179,7 +179,7 @@ msgstr "Información general"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:94
+#: src/views/preference/Preference.vue:101
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "Básico"
 msgstr "Básico"
@@ -205,10 +205,10 @@ msgstr ""
 msgid "CADir"
 msgid "CADir"
 msgstr "Directorio CA"
 msgstr "Directorio CA"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:248
+#: src/components/ChatGPT/ChatGPT.vue:253
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:102
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:153
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/RightSettings.vue:51
 #: src/views/domain/components/RightSettings.vue:51
@@ -250,8 +250,8 @@ msgstr "Lista de Certificados"
 msgid "Challenge Method"
 msgid "Challenge Method"
 msgstr "Método de desafío"
 msgstr "Método de desafío"
 
 
-#: src/views/domain/cert/ChangeCert.vue:88
-#: src/views/domain/cert/ChangeCert.vue:92
+#: src/views/domain/cert/ChangeCert.vue:95
+#: src/views/domain/cert/ChangeCert.vue:99
 msgid "Change Certificate"
 msgid "Change Certificate"
 msgstr "Cambiar Certificado"
 msgstr "Cambiar Certificado"
 
 
@@ -267,7 +267,7 @@ msgstr "Intentar nuevamente"
 msgid "Cleaning environment variables"
 msgid "Cleaning environment variables"
 msgstr "Borrar las variables de entorno"
 msgstr "Borrar las variables de entorno"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:271
+#: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/Notification/Notification.vue:89
 #: src/components/Notification/Notification.vue:89
 #: src/views/notification/Notification.vue:75
 #: src/views/notification/Notification.vue:75
 msgid "Clear"
 msgid "Clear"
@@ -310,7 +310,7 @@ msgstr "Configuraciones"
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Configurar SSL"
 msgstr "Configurar SSL"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Connected"
 msgid "Connected"
 msgstr "Conectado"
 msgstr "Conectado"
 
 
@@ -324,7 +324,7 @@ msgstr "Contenido"
 msgid "Core Upgrade"
 msgid "Core Upgrade"
 msgstr "Actualización del kernel"
 msgstr "Actualización del kernel"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:293
+#: src/views/dashboard/ServerAnalytic.vue:296
 msgid "CPU Status"
 msgid "CPU Status"
 msgstr "Estado del CPU"
 msgstr "Estado del CPU"
 
 
@@ -365,6 +365,12 @@ msgstr "Versión actual"
 msgid "Custom"
 msgid "Custom"
 msgstr "Personalizado"
 msgstr "Personalizado"
 
 
+#: src/views/preference/BasicSettings.vue:121
+msgid ""
+"Customize the name of local server to be displayed in the environment "
+"indicator."
+msgstr ""
+
 #: src/routes/index.ts:39
 #: src/routes/index.ts:39
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Panel"
 msgstr "Panel"
@@ -452,9 +458,9 @@ msgstr "Desactivar"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "No se pudo desactivar la renovación automática por %{name}"
 msgstr "No se pudo desactivar la renovación automática por %{name}"
 
 
-#: src/views/domain/cert/ChangeCert.vue:45 src/views/domain/DomainEdit.vue:185
-#: src/views/domain/DomainList.vue:33 src/views/stream/StreamEdit.vue:177
-#: src/views/stream/StreamList.vue:33
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
+#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Desactivado"
 msgstr "Desactivado"
 
 
@@ -465,7 +471,7 @@ msgstr "Desactivado"
 msgid "Disabled successfully"
 msgid "Disabled successfully"
 msgstr "Desactivado con éxito"
 msgstr "Desactivado con éxito"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:358
+#: src/views/dashboard/ServerAnalytic.vue:361
 msgid "Disk IO"
 msgid "Disk IO"
 msgstr "I/O del disco"
 msgstr "I/O del disco"
 
 
@@ -633,9 +639,10 @@ msgstr "Habilitado con Éxito"
 msgid "Enable TLS"
 msgid "Enable TLS"
 msgstr "Habilitar TLS"
 msgstr "Habilitar TLS"
 
 
-#: src/views/domain/cert/ChangeCert.vue:41
+#: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
@@ -655,11 +662,11 @@ msgstr "Habilitado con éxito"
 msgid "Encrypt website with Let's Encrypt"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Encriptar sitio web con Let's Encrypt"
 msgstr "Encriptar sitio web con Let's Encrypt"
 
 
-#: src/routes/index.ts:212 src/views/environment/Environment.vue:110
+#: src/routes/index.ts:212 src/views/environment/Environment.vue:137
 msgid "Environment"
 msgid "Environment"
 msgstr "Entorno"
 msgstr "Entorno"
 
 
-#: src/views/dashboard/Environments.vue:71
+#: src/views/dashboard/Environments.vue:82
 msgid "Environments"
 msgid "Environments"
 msgstr "Entornos"
 msgstr "Entornos"
 
 
@@ -876,7 +883,7 @@ msgstr "Comprobado por última vez el"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Para no modificar dejar en blanco"
 msgstr "Para no modificar dejar en blanco"
 
 
-#: src/views/preference/OpenAISettings.vue:41
+#: src/views/preference/OpenAISettings.vue:47
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Dejar en blanco para el valor predeterminado: https://api.openai.com/"
 msgstr "Dejar en blanco para el valor predeterminado: https://api.openai.com/"
 
 
@@ -889,7 +896,7 @@ msgstr "Dejarlo en blanco no cambiará nada"
 msgid "License"
 msgid "License"
 msgstr "Licencia"
 msgstr "Licencia"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Link Start"
 msgid "Link Start"
 msgstr "Iniciar conexión"
 msgstr "Iniciar conexión"
 
 
@@ -902,8 +909,8 @@ msgstr ""
 msgid "Load Average:"
 msgid "Load Average:"
 msgstr "Promedios de carga:"
 msgstr "Promedios de carga:"
 
 
-#: src/components/EnvIndicator/EnvIndicator.vue:38
-#: src/components/NodeSelector/NodeSelector.vue:51
+#: src/components/EnvIndicator/EnvIndicator.vue:40
+#: src/components/NodeSelector/NodeSelector.vue:71
 msgid "Local"
 msgid "Local"
 msgstr "Local"
 msgstr "Local"
 
 
@@ -931,7 +938,7 @@ msgstr "Acceso exitoso"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Cierre de sesión exitoso"
 msgstr "Cierre de sesión exitoso"
 
 
-#: src/views/preference/Preference.vue:112
+#: src/views/preference/Preference.vue:119
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -974,6 +981,7 @@ msgid "Managed Certificate"
 msgstr "Certificado Administrado"
 msgstr "Certificado Administrado"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
+#: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
 msgstr "Memoria"
 msgstr "Memoria"
 
 
@@ -985,12 +993,12 @@ msgstr "Memoria y almacenamiento"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:26
+#: src/views/preference/OpenAISettings.vue:27
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Modo de ejecución"
 msgstr "Modo de ejecución"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:244
+#: src/components/ChatGPT/ChatGPT.vue:249
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 msgid "Modify"
 msgid "Modify"
@@ -1017,7 +1025,7 @@ msgstr "Directiva multilínea"
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
-#: src/views/domain/cert/ChangeCert.vue:18
+#: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
@@ -1029,19 +1037,19 @@ msgstr "Directiva multilínea"
 msgid "Name"
 msgid "Name"
 msgstr "Nombre"
 msgstr "Nombre"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:319
+#: src/views/dashboard/ServerAnalytic.vue:322
 msgid "Network"
 msgid "Network"
 msgstr "Red"
 msgstr "Red"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:261
+#: src/views/dashboard/ServerAnalytic.vue:264
 msgid "Network Statistics"
 msgid "Network Statistics"
 msgstr "Estadísticas de red"
 msgstr "Estadísticas de red"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:268
+#: src/views/dashboard/ServerAnalytic.vue:271
 msgid "Network Total Receive"
 msgid "Network Total Receive"
 msgstr "Total recibido por la red"
 msgstr "Total recibido por la red"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:274
+#: src/views/dashboard/ServerAnalytic.vue:277
 msgid "Network Total Send"
 msgid "Network Total Send"
 msgstr "Total enviado por la red"
 msgstr "Total enviado por la red"
 
 
@@ -1055,7 +1063,7 @@ msgstr "Se liberó una nueva versión"
 msgid "Next"
 msgid "Next"
 msgstr "Siguiente"
 msgstr "Siguiente"
 
 
-#: src/views/preference/Preference.vue:100
+#: src/views/preference/Preference.vue:107
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Nginx"
 msgstr "Nginx"
 
 
@@ -1067,7 +1075,7 @@ msgstr "Ruta de registro de acceso de Nginx"
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Error de análisis de configuración de Nginx"
 msgstr "Error de análisis de configuración de Nginx"
 
 
-#: src/components/NginxControl/NginxControl.vue:62
+#: src/components/NginxControl/NginxControl.vue:65
 msgid "Nginx Control"
 msgid "Nginx Control"
 msgstr "Control de Nginx"
 msgstr "Control de Nginx"
 
 
@@ -1079,15 +1087,15 @@ msgstr "Ruta de registro de errores de Nginx"
 msgid "Nginx Log"
 msgid "Nginx Log"
 msgstr "Registro Nginx"
 msgstr "Registro Nginx"
 
 
-#: src/components/NginxControl/NginxControl.vue:22
+#: src/components/NginxControl/NginxControl.vue:23
 msgid "Nginx reloaded successfully"
 msgid "Nginx reloaded successfully"
 msgstr "Nginx recargado con éxito"
 msgstr "Nginx recargado con éxito"
 
 
-#: src/components/NginxControl/NginxControl.vue:36
+#: src/components/NginxControl/NginxControl.vue:39
 msgid "Nginx restarted successfully"
 msgid "Nginx restarted successfully"
 msgstr "Nginx reiniciado con éxito"
 msgstr "Nginx reiniciado con éxito"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:265
+#: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/Notification/Notification.vue:82
 #: src/components/Notification/Notification.vue:82
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
@@ -1137,22 +1145,22 @@ msgstr "Obtener certificado"
 msgid "Obtaining certificate"
 msgid "Obtaining certificate"
 msgstr "Obteniendo certificado"
 msgstr "Obteniendo certificado"
 
 
-#: src/components/NodeSelector/NodeSelector.vue:75
-#: src/views/dashboard/Environments.vue:95
-#: src/views/environment/Environment.vue:86
+#: src/components/NodeSelector/NodeSelector.vue:95
+#: src/views/dashboard/Environments.vue:106
+#: src/views/environment/Environment.vue:88
 msgid "Offline"
 msgid "Offline"
 msgstr "Desconectado"
 msgstr "Desconectado"
 
 
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:154
 msgid "Ok"
 msgid "Ok"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:266
+#: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/Notification/Notification.vue:83
 #: src/components/Notification/Notification.vue:83
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:103
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/RightSettings.vue:50
 #: src/views/domain/components/RightSettings.vue:50
@@ -1171,14 +1179,14 @@ msgstr "OK"
 msgid "Once the verification is complete, the records will be removed."
 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."
 msgstr "Una vez que se complete la verificación, los registros se eliminarán."
 
 
-#: src/components/NodeSelector/NodeSelector.vue:54
-#: src/components/NodeSelector/NodeSelector.vue:69
-#: src/views/dashboard/Environments.vue:88
-#: src/views/environment/Environment.vue:82
+#: src/components/NodeSelector/NodeSelector.vue:74
+#: src/components/NodeSelector/NodeSelector.vue:89
+#: src/views/dashboard/Environments.vue:99
+#: src/views/environment/Environment.vue:84
 msgid "Online"
 msgid "Online"
 msgstr "En línea"
 msgstr "En línea"
 
 
-#: src/views/preference/Preference.vue:106
+#: src/views/preference/Preference.vue:113
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "OpenAI"
 msgstr "OpenAI"
 
 
@@ -1280,7 +1288,7 @@ msgstr "¡Seleccione al menos un nodo!"
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr "Prelanzamiento"
 msgstr "Prelanzamiento"
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:89
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
 msgid "Preference"
 msgid "Preference"
 msgstr "Configuración"
 msgstr "Configuración"
 
 
@@ -1305,12 +1313,12 @@ msgid "Provider"
 msgstr "Proveedor"
 msgstr "Proveedor"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:28
 #: src/views/dashboard/ServerAnalytic.vue:28
-#: src/views/dashboard/ServerAnalytic.vue:375
+#: src/views/dashboard/ServerAnalytic.vue:378
 msgid "Reads"
 msgid "Reads"
 msgstr "Lecturas"
 msgstr "Lecturas"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:24
 #: src/views/dashboard/ServerAnalytic.vue:24
-#: src/views/dashboard/ServerAnalytic.vue:326
+#: src/views/dashboard/ServerAnalytic.vue:329
 msgid "Receive"
 msgid "Receive"
 msgstr "Recibido"
 msgstr "Recibido"
 
 
@@ -1327,7 +1335,7 @@ msgstr "Eliminado con éxito"
 msgid "Recursive Nameservers"
 msgid "Recursive Nameservers"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:278
+#: src/components/ChatGPT/ChatGPT.vue:283
 msgid "Regenerate response"
 msgid "Regenerate response"
 msgstr "Regenerar respuesta"
 msgstr "Regenerar respuesta"
 
 
@@ -1363,12 +1371,12 @@ msgstr "Reinstalar"
 msgid "Release Note"
 msgid "Release Note"
 msgstr "Nota de versión"
 msgstr "Nota de versión"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:254
-#: src/components/NginxControl/NginxControl.vue:97
+#: src/components/ChatGPT/ChatGPT.vue:259
+#: src/components/NginxControl/NginxControl.vue:100
 msgid "Reload"
 msgid "Reload"
 msgstr "Recargar"
 msgstr "Recargar"
 
 
-#: src/components/NginxControl/NginxControl.vue:71
+#: src/components/NginxControl/NginxControl.vue:74
 msgid "Reloading"
 msgid "Reloading"
 msgstr "Recargando"
 msgstr "Recargando"
 
 
@@ -1410,11 +1418,11 @@ msgstr "Pedido con parámetros incorrectos"
 msgid "Reset"
 msgid "Reset"
 msgstr "Limpiar"
 msgstr "Limpiar"
 
 
-#: src/components/NginxControl/NginxControl.vue:90
+#: src/components/NginxControl/NginxControl.vue:93
 msgid "Restart"
 msgid "Restart"
 msgstr "Reiniciar"
 msgstr "Reiniciar"
 
 
-#: src/components/NginxControl/NginxControl.vue:76
+#: src/components/NginxControl/NginxControl.vue:79
 msgid "Restarting"
 msgid "Restarting"
 msgstr "Reiniciando"
 msgstr "Reiniciando"
 
 
@@ -1422,15 +1430,15 @@ msgstr "Reiniciando"
 msgid "Run Mode"
 msgid "Run Mode"
 msgstr "Modo de ejecución"
 msgstr "Modo de ejecución"
 
 
-#: src/components/NginxControl/NginxControl.vue:66
+#: src/components/NginxControl/NginxControl.vue:69
 msgid "Running"
 msgid "Running"
 msgstr "Corriendo"
 msgstr "Corriendo"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:247
+#: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:123 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
 msgid "Save"
 msgid "Save"
 msgstr "Guardar"
 msgstr "Guardar"
 
 
@@ -1446,7 +1454,7 @@ msgstr "Error al guardar %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:45
 #: src/views/certificate/CertificateEditor.vue:45
-#: src/views/preference/Preference.vue:59
+#: src/views/preference/Preference.vue:66
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Guardado con éxito"
 msgstr "Guardado con éxito"
 
 
@@ -1461,24 +1469,24 @@ msgstr "Guardado con éxito"
 msgid "SDK"
 msgid "SDK"
 msgstr ""
 msgstr ""
 
 
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:104
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:155
 msgid "Selector"
 msgid "Selector"
 msgstr "Selector"
 msgstr "Selector"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:25
 #: src/views/dashboard/ServerAnalytic.vue:25
-#: src/views/dashboard/ServerAnalytic.vue:336
+#: src/views/dashboard/ServerAnalytic.vue:339
 msgid "Send"
 msgid "Send"
 msgstr "Enviado"
 msgstr "Enviado"
 
 
-#: src/components/NginxControl/NginxControl.vue:28
-#: src/components/NginxControl/NginxControl.vue:42
+#: src/components/NginxControl/NginxControl.vue:29
+#: src/components/NginxControl/NginxControl.vue:45
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:63
+#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:70
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
@@ -1488,6 +1496,11 @@ msgstr "Error del servidor"
 msgid "Server Info"
 msgid "Server Info"
 msgstr "Información del servidor"
 msgstr "Información del servidor"
 
 
+#: src/views/preference/BasicSettings.vue:117
+#, fuzzy
+msgid "Server Name"
+msgstr "Información del servidor"
+
 #: src/views/domain/cert/components/ObtainCert.vue:102
 #: src/views/domain/cert/components/ObtainCert.vue:102
 msgid "server_name not found in directives"
 msgid "server_name not found in directives"
 msgstr "No se encuentra server_name en las directivas"
 msgstr "No se encuentra server_name en las directivas"
@@ -1555,15 +1568,16 @@ msgstr "Estable"
 
 
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
-#: src/views/environment/Environment.vue:75 src/views/stream/StreamList.vue:22
+#: src/views/environment/Environment.vue:76 src/views/stream/StreamList.vue:22
 msgid "Status"
 msgid "Status"
 msgstr "Estado"
 msgstr "Estado"
 
 
-#: src/components/NginxControl/NginxControl.vue:81
+#: src/components/NginxControl/NginxControl.vue:84
 msgid "Stopped"
 msgid "Stopped"
 msgstr "Detenido"
 msgstr "Detenido"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:243
+#: src/views/dashboard/ServerAnalytic.vue:245
+#: src/views/dashboard/ServerAnalytic.vue:246
 msgid "Storage"
 msgid "Storage"
 msgstr "Almacenamiento"
 msgstr "Almacenamiento"
 
 
@@ -1575,7 +1589,8 @@ msgstr "Nombre del asunto: %{subject}"
 msgid "Success"
 msgid "Success"
 msgstr "Éxito"
 msgstr "Éxito"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:230
+#: src/views/dashboard/ServerAnalytic.vue:231
+#: src/views/dashboard/ServerAnalytic.vue:232
 msgid "Swap"
 msgid "Swap"
 msgstr "Swap"
 msgstr "Swap"
 
 
@@ -1625,6 +1640,10 @@ msgstr "La entrada no es un Certificado SSL"
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "La entrada no es una clave de certificado SSL"
 msgstr "La entrada no es una clave de certificado SSL"
 
 
+#: src/views/preference/OpenAISettings.vue:30
+msgid "The model name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/certificate/CertificateEditor.vue:165
 #: src/views/certificate/CertificateEditor.vue:165
 #, fuzzy
 #, fuzzy
 msgid "The path exists, but the file is not a certificate"
 msgid "The path exists, but the file is not a certificate"
@@ -1634,6 +1653,10 @@ msgstr "La ruta existe, pero el archivo no es una clave privada"
 msgid "The path exists, but the file is not a private key"
 msgid "The path exists, but the file is not a private key"
 msgstr "La ruta existe, pero el archivo no es una clave privada"
 msgstr "La ruta existe, pero el archivo no es una clave privada"
 
 
+#: src/views/preference/BasicSettings.vue:120
+msgid "The server name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 msgid ""
 msgid ""
 "The server_name in the current configuration must be the domain name you "
 "The server_name in the current configuration must be the domain name you "
@@ -1644,9 +1667,14 @@ msgstr ""
 
 
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:50
 #: src/views/preference/BasicSettings.vue:50
-#: src/views/preference/OpenAISettings.vue:36
-#: src/views/preference/OpenAISettings.vue:48
-msgid "The url is not valid"
+#, fuzzy
+msgid "The url is invalid"
+msgstr "La URL no es válida"
+
+#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:54
+#, fuzzy
+msgid "The url is invalid."
 msgstr "La URL no es válida"
 msgstr "La URL no es válida"
 
 
 #: src/language/constants.ts:2
 #: src/language/constants.ts:2
@@ -1691,7 +1719,7 @@ msgstr ""
 "de la autoridad al backend, y debemos guardar este archivo y volver a cargar "
 "de la autoridad al backend, y debemos guardar este archivo y volver a cargar "
 "Nginx. ¿Estás seguro de que quieres continuar?"
 "Nginx. ¿Estás seguro de que quieres continuar?"
 
 
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:66
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr "El token no es válido"
 msgstr "El token no es válido"
 
 
@@ -1708,7 +1736,7 @@ msgstr "Tipo"
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/components/RightSettings.vue:86
-#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:95
+#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:122
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 msgid "Updated at"
 msgid "Updated at"
@@ -1739,11 +1767,11 @@ msgstr "Nombre de la Transmisión"
 msgid "Uptime:"
 msgid "Uptime:"
 msgstr "Tiempo encendido:"
 msgstr "Tiempo encendido:"
 
 
-#: src/views/environment/Environment.vue:21
+#: src/views/environment/Environment.vue:22
 msgid "URL"
 msgid "URL"
 msgstr "URL"
 msgstr "URL"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "User"
 msgid "User"
 msgstr "Usuario"
 msgstr "Usuario"
 
 
@@ -1802,7 +1830,7 @@ msgstr ""
 "recargaremos Nginx. ¿Estás seguro de que quieres continuar?"
 "recargaremos Nginx. ¿Estás seguro de que quieres continuar?"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:27
 #: src/views/dashboard/ServerAnalytic.vue:27
-#: src/views/dashboard/ServerAnalytic.vue:365
+#: src/views/dashboard/ServerAnalytic.vue:368
 msgid "Writes"
 msgid "Writes"
 msgstr "Escrituras"
 msgstr "Escrituras"
 
 
@@ -1828,6 +1856,9 @@ msgstr "Estás usando la última versión"
 msgid "You can check Nginx UI upgrade at this page."
 msgid "You can check Nginx UI upgrade at this page."
 msgstr "Puede consultar la actualización de Nginx UI en esta página."
 msgstr "Puede consultar la actualización de Nginx UI en esta página."
 
 
+#~ msgid "The url is not valid"
+#~ msgstr "La URL no es válida"
+
 #~ msgid "ChatGPT Model"
 #~ msgid "ChatGPT Model"
 #~ msgstr "Modelo de ChatGPT"
 #~ msgstr "Modelo de ChatGPT"
 
 
@@ -1852,10 +1883,6 @@ msgstr "Puede consultar la actualización de Nginx UI en esta página."
 #~ msgid "The path exists, but the file is not a public key"
 #~ msgid "The path exists, but the file is not a public key"
 #~ msgstr "La ruta existe, pero el archivo no es una clave pública"
 #~ msgstr "La ruta existe, pero el archivo no es una clave pública"
 
 
-#, fuzzy
-#~ msgid "Server"
-#~ msgstr "Información del servidor"
-
 #, fuzzy
 #, fuzzy
 #~ msgid "Leave blank will not change anything."
 #~ msgid "Leave blank will not change anything."
 #~ msgstr "Para no modificar dejar en blanco"
 #~ msgstr "Para no modificar dejar en blanco"

+ 107 - 85
app/src/language/fr_FR/app.po

@@ -20,7 +20,7 @@ msgid "Access Logs"
 msgstr "Journaux d'accès"
 msgstr "Journaux d'accès"
 
 
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
-#: src/views/certificate/ACMEUserSelector.vue:79
+#: src/views/certificate/ACMEUserSelector.vue:84
 #, fuzzy
 #, fuzzy
 msgid "ACME User"
 msgid "ACME User"
 msgstr "Nom d'utilisateur"
 msgstr "Nom d'utilisateur"
@@ -28,7 +28,7 @@ msgstr "Nom d'utilisateur"
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
-#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:102
+#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:35
 #: src/views/notification/Notification.vue:35
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
@@ -76,7 +76,7 @@ msgstr "Supplémentaire"
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Mode avancé"
 msgstr "Mode avancé"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:39
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "URL de base de l'API"
 msgstr "URL de base de l'API"
 
 
@@ -85,11 +85,11 @@ msgstr "URL de base de l'API"
 msgid "API Document"
 msgid "API Document"
 msgstr "Jeton d'API"
 msgstr "Jeton d'API"
 
 
-#: src/views/preference/OpenAISettings.vue:45
+#: src/views/preference/OpenAISettings.vue:51
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "Proxy d'API"
 msgstr "Proxy d'API"
 
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:63
 msgid "API Token"
 msgid "API Token"
 msgstr "Jeton d'API"
 msgstr "Jeton d'API"
 
 
@@ -104,7 +104,7 @@ msgstr "Arch"
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Voulez-vous vraiment effacer l'historique du chat ?"
 msgstr "Voulez-vous vraiment effacer l'historique du chat ?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:267
+#: src/components/ChatGPT/ChatGPT.vue:272
 msgid "Are you sure you want to clear the record of chat?"
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Voulez-vous vraiment effacer l'historique du chat ?"
 msgstr "Voulez-vous vraiment effacer l'historique du chat ?"
 
 
@@ -135,12 +135,12 @@ msgstr "Voulez-vous vraiment supprimer cette directive ?"
 msgid "Are you sure you want to remove this location?"
 msgid "Are you sure you want to remove this location?"
 msgstr "Voulez-vous vraiment supprimer cette localisation ?"
 msgstr "Voulez-vous vraiment supprimer cette localisation ?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:211
+#: src/components/ChatGPT/ChatGPT.vue:216
 #, fuzzy
 #, fuzzy
 msgid "Ask ChatGPT for Help"
 msgid "Ask ChatGPT for Help"
 msgstr "Modèle ChatGPT"
 msgstr "Modèle ChatGPT"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "Assistant"
 msgid "Assistant"
 msgstr ""
 msgstr ""
 
 
@@ -149,7 +149,7 @@ msgstr ""
 msgid "Author"
 msgid "Author"
 msgstr "Autheur"
 msgstr "Autheur"
 
 
-#: src/views/domain/cert/ChangeCert.vue:34
+#: src/views/domain/cert/ChangeCert.vue:33
 msgid "Auto Cert"
 msgid "Auto Cert"
 msgstr "Auto Cert"
 msgstr "Auto Cert"
 
 
@@ -182,7 +182,7 @@ msgstr "Information générale"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:94
+#: src/views/preference/Preference.vue:101
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "Basique"
 msgstr "Basique"
@@ -209,10 +209,10 @@ msgstr ""
 msgid "CADir"
 msgid "CADir"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:248
+#: src/components/ChatGPT/ChatGPT.vue:253
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:102
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:153
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/RightSettings.vue:51
 #: src/views/domain/components/RightSettings.vue:51
@@ -256,8 +256,8 @@ msgstr "Liste des certifications"
 msgid "Challenge Method"
 msgid "Challenge Method"
 msgstr "Méthode de challenge"
 msgstr "Méthode de challenge"
 
 
-#: src/views/domain/cert/ChangeCert.vue:88
-#: src/views/domain/cert/ChangeCert.vue:92
+#: src/views/domain/cert/ChangeCert.vue:95
+#: src/views/domain/cert/ChangeCert.vue:99
 msgid "Change Certificate"
 msgid "Change Certificate"
 msgstr "Changer de certificat"
 msgstr "Changer de certificat"
 
 
@@ -273,7 +273,7 @@ msgstr "Revérifier"
 msgid "Cleaning environment variables"
 msgid "Cleaning environment variables"
 msgstr "Nettoyage des variables d'environnement"
 msgstr "Nettoyage des variables d'environnement"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:271
+#: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/Notification/Notification.vue:89
 #: src/components/Notification/Notification.vue:89
 #: src/views/notification/Notification.vue:75
 #: src/views/notification/Notification.vue:75
 msgid "Clear"
 msgid "Clear"
@@ -317,7 +317,7 @@ msgstr "Configurations"
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Configurer SSL"
 msgstr "Configurer SSL"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Connected"
 msgid "Connected"
 msgstr ""
 msgstr ""
 
 
@@ -331,7 +331,7 @@ msgstr "Contenu"
 msgid "Core Upgrade"
 msgid "Core Upgrade"
 msgstr "Mise à jour du core"
 msgstr "Mise à jour du core"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:293
+#: src/views/dashboard/ServerAnalytic.vue:296
 msgid "CPU Status"
 msgid "CPU Status"
 msgstr "État du processeur"
 msgstr "État du processeur"
 
 
@@ -373,6 +373,12 @@ msgstr "Version actuelle"
 msgid "Custom"
 msgid "Custom"
 msgstr "Custom"
 msgstr "Custom"
 
 
+#: src/views/preference/BasicSettings.vue:121
+msgid ""
+"Customize the name of local server to be displayed in the environment "
+"indicator."
+msgstr ""
+
 #: src/routes/index.ts:39
 #: src/routes/index.ts:39
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Dashboard"
 msgstr "Dashboard"
@@ -465,9 +471,9 @@ msgstr "Désactivé"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "La désactivation du renouvellement automatique a échoué pour %{name}"
 msgstr "La désactivation du renouvellement automatique a échoué pour %{name}"
 
 
-#: src/views/domain/cert/ChangeCert.vue:45 src/views/domain/DomainEdit.vue:185
-#: src/views/domain/DomainList.vue:33 src/views/stream/StreamEdit.vue:177
-#: src/views/stream/StreamList.vue:33
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
+#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Désactivé"
 msgstr "Désactivé"
 
 
@@ -478,7 +484,7 @@ msgstr "Désactivé"
 msgid "Disabled successfully"
 msgid "Disabled successfully"
 msgstr "Désactivé avec succès"
 msgstr "Désactivé avec succès"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:358
+#: src/views/dashboard/ServerAnalytic.vue:361
 msgid "Disk IO"
 msgid "Disk IO"
 msgstr "E/S disque"
 msgstr "E/S disque"
 
 
@@ -658,9 +664,10 @@ msgstr "Activé avec succès"
 msgid "Enable TLS"
 msgid "Enable TLS"
 msgstr "Activer TLS"
 msgstr "Activer TLS"
 
 
-#: src/views/domain/cert/ChangeCert.vue:41
+#: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
@@ -680,11 +687,11 @@ msgstr "Activé avec succès"
 msgid "Encrypt website with Let's Encrypt"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Crypter le site Web avec Let's Encrypt"
 msgstr "Crypter le site Web avec Let's Encrypt"
 
 
-#: src/routes/index.ts:212 src/views/environment/Environment.vue:110
+#: src/routes/index.ts:212 src/views/environment/Environment.vue:137
 msgid "Environment"
 msgid "Environment"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/Environments.vue:71
+#: src/views/dashboard/Environments.vue:82
 #, fuzzy
 #, fuzzy
 msgid "Environments"
 msgid "Environments"
 msgstr "Commentaires"
 msgstr "Commentaires"
@@ -910,7 +917,7 @@ msgstr "Dernière vérification le"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Laisser vide pour aucun changement"
 msgstr "Laisser vide pour aucun changement"
 
 
-#: src/views/preference/OpenAISettings.vue:41
+#: src/views/preference/OpenAISettings.vue:47
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Laissez vide pour la valeur par défaut : https://api.openai.com/"
 msgstr "Laissez vide pour la valeur par défaut : https://api.openai.com/"
 
 
@@ -925,7 +932,7 @@ msgstr "Laisser vide pour aucun changement"
 msgid "License"
 msgid "License"
 msgstr "Licence"
 msgstr "Licence"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Link Start"
 msgid "Link Start"
 msgstr ""
 msgstr ""
 
 
@@ -939,8 +946,8 @@ msgstr ""
 msgid "Load Average:"
 msgid "Load Average:"
 msgstr "Charges moyennes :"
 msgstr "Charges moyennes :"
 
 
-#: src/components/EnvIndicator/EnvIndicator.vue:38
-#: src/components/NodeSelector/NodeSelector.vue:51
+#: src/components/EnvIndicator/EnvIndicator.vue:40
+#: src/components/NodeSelector/NodeSelector.vue:71
 #, fuzzy
 #, fuzzy
 msgid "Local"
 msgid "Local"
 msgstr "Localisation"
 msgstr "Localisation"
@@ -972,7 +979,7 @@ msgstr "Connexion réussie"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Déconnexion réussie"
 msgstr "Déconnexion réussie"
 
 
-#: src/views/preference/Preference.vue:112
+#: src/views/preference/Preference.vue:119
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1018,6 +1025,7 @@ msgid "Managed Certificate"
 msgstr "Changer de certificat"
 msgstr "Changer de certificat"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
+#: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
 msgstr "Mémoire"
 msgstr "Mémoire"
 
 
@@ -1029,12 +1037,12 @@ msgstr "Mémoire et stockage"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:26
+#: src/views/preference/OpenAISettings.vue:27
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Mode d'exécution"
 msgstr "Mode d'exécution"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:244
+#: src/components/ChatGPT/ChatGPT.vue:249
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 msgid "Modify"
 msgid "Modify"
@@ -1062,7 +1070,7 @@ msgstr "Directive multiligne"
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
-#: src/views/domain/cert/ChangeCert.vue:18
+#: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
@@ -1074,19 +1082,19 @@ msgstr "Directive multiligne"
 msgid "Name"
 msgid "Name"
 msgstr "Nom"
 msgstr "Nom"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:319
+#: src/views/dashboard/ServerAnalytic.vue:322
 msgid "Network"
 msgid "Network"
 msgstr "Réseau"
 msgstr "Réseau"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:261
+#: src/views/dashboard/ServerAnalytic.vue:264
 msgid "Network Statistics"
 msgid "Network Statistics"
 msgstr "Statistiques du réseau"
 msgstr "Statistiques du réseau"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:268
+#: src/views/dashboard/ServerAnalytic.vue:271
 msgid "Network Total Receive"
 msgid "Network Total Receive"
 msgstr "Réception totale du réseau"
 msgstr "Réception totale du réseau"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:274
+#: src/views/dashboard/ServerAnalytic.vue:277
 msgid "Network Total Send"
 msgid "Network Total Send"
 msgstr "Envoi total réseau"
 msgstr "Envoi total réseau"
 
 
@@ -1100,7 +1108,7 @@ msgstr "Nouvelle version publiée"
 msgid "Next"
 msgid "Next"
 msgstr "Suivant"
 msgstr "Suivant"
 
 
-#: src/views/preference/Preference.vue:100
+#: src/views/preference/Preference.vue:107
 #, fuzzy
 #, fuzzy
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Journal Nginx"
 msgstr "Journal Nginx"
@@ -1113,7 +1121,7 @@ msgstr "Chemin du journal d'accès Nginx"
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Erreur d'analyse de configuration Nginx"
 msgstr "Erreur d'analyse de configuration Nginx"
 
 
-#: src/components/NginxControl/NginxControl.vue:62
+#: src/components/NginxControl/NginxControl.vue:65
 msgid "Nginx Control"
 msgid "Nginx Control"
 msgstr "Contrôle Nginx"
 msgstr "Contrôle Nginx"
 
 
@@ -1125,15 +1133,15 @@ msgstr "Chemin du journal des erreurs Nginx"
 msgid "Nginx Log"
 msgid "Nginx Log"
 msgstr "Journal Nginx"
 msgstr "Journal Nginx"
 
 
-#: src/components/NginxControl/NginxControl.vue:22
+#: src/components/NginxControl/NginxControl.vue:23
 msgid "Nginx reloaded successfully"
 msgid "Nginx reloaded successfully"
 msgstr "Nginx a été rechargé avec succès"
 msgstr "Nginx a été rechargé avec succès"
 
 
-#: src/components/NginxControl/NginxControl.vue:36
+#: src/components/NginxControl/NginxControl.vue:39
 msgid "Nginx restarted successfully"
 msgid "Nginx restarted successfully"
 msgstr "Nginx a redémarré avec succès"
 msgstr "Nginx a redémarré avec succès"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:265
+#: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/Notification/Notification.vue:82
 #: src/components/Notification/Notification.vue:82
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
@@ -1186,22 +1194,22 @@ msgstr "Obtenir un certificat"
 msgid "Obtaining certificate"
 msgid "Obtaining certificate"
 msgstr "Obtention du certificat"
 msgstr "Obtention du certificat"
 
 
-#: src/components/NodeSelector/NodeSelector.vue:75
-#: src/views/dashboard/Environments.vue:95
-#: src/views/environment/Environment.vue:86
+#: src/components/NodeSelector/NodeSelector.vue:95
+#: src/views/dashboard/Environments.vue:106
+#: src/views/environment/Environment.vue:88
 msgid "Offline"
 msgid "Offline"
 msgstr ""
 msgstr ""
 
 
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:154
 msgid "Ok"
 msgid "Ok"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:266
+#: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/Notification/Notification.vue:83
 #: src/components/Notification/Notification.vue:83
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:103
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/RightSettings.vue:50
 #: src/views/domain/components/RightSettings.vue:50
@@ -1220,14 +1228,14 @@ msgstr "OK"
 msgid "Once the verification is complete, the records will be removed."
 msgid "Once the verification is complete, the records will be removed."
 msgstr ""
 msgstr ""
 
 
-#: src/components/NodeSelector/NodeSelector.vue:54
-#: src/components/NodeSelector/NodeSelector.vue:69
-#: src/views/dashboard/Environments.vue:88
-#: src/views/environment/Environment.vue:82
+#: src/components/NodeSelector/NodeSelector.vue:74
+#: src/components/NodeSelector/NodeSelector.vue:89
+#: src/views/dashboard/Environments.vue:99
+#: src/views/environment/Environment.vue:84
 msgid "Online"
 msgid "Online"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:106
+#: src/views/preference/Preference.vue:113
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "OpenAI"
 msgstr "OpenAI"
 
 
@@ -1327,7 +1335,7 @@ msgstr ""
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:89
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
 msgid "Preference"
 msgid "Preference"
 msgstr "Préférence"
 msgstr "Préférence"
 
 
@@ -1353,13 +1361,13 @@ msgid "Provider"
 msgstr "Fournisseur"
 msgstr "Fournisseur"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:28
 #: src/views/dashboard/ServerAnalytic.vue:28
-#: src/views/dashboard/ServerAnalytic.vue:375
+#: src/views/dashboard/ServerAnalytic.vue:378
 #, fuzzy
 #, fuzzy
 msgid "Reads"
 msgid "Reads"
 msgstr "Lectures"
 msgstr "Lectures"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:24
 #: src/views/dashboard/ServerAnalytic.vue:24
-#: src/views/dashboard/ServerAnalytic.vue:326
+#: src/views/dashboard/ServerAnalytic.vue:329
 #, fuzzy
 #, fuzzy
 msgid "Receive"
 msgid "Receive"
 msgstr "Recevoir"
 msgstr "Recevoir"
@@ -1377,7 +1385,7 @@ msgstr "Enregistré avec succès"
 msgid "Recursive Nameservers"
 msgid "Recursive Nameservers"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:278
+#: src/components/ChatGPT/ChatGPT.vue:283
 msgid "Regenerate response"
 msgid "Regenerate response"
 msgstr "Régénérer la réponse"
 msgstr "Régénérer la réponse"
 
 
@@ -1413,12 +1421,12 @@ msgstr "Réinstaller"
 msgid "Release Note"
 msgid "Release Note"
 msgstr "Note de version"
 msgstr "Note de version"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:254
-#: src/components/NginxControl/NginxControl.vue:97
+#: src/components/ChatGPT/ChatGPT.vue:259
+#: src/components/NginxControl/NginxControl.vue:100
 msgid "Reload"
 msgid "Reload"
 msgstr "Recharger"
 msgstr "Recharger"
 
 
-#: src/components/NginxControl/NginxControl.vue:71
+#: src/components/NginxControl/NginxControl.vue:74
 msgid "Reloading"
 msgid "Reloading"
 msgstr "Rechargement"
 msgstr "Rechargement"
 
 
@@ -1466,11 +1474,11 @@ msgstr ""
 msgid "Reset"
 msgid "Reset"
 msgstr "Réinitialiser"
 msgstr "Réinitialiser"
 
 
-#: src/components/NginxControl/NginxControl.vue:90
+#: src/components/NginxControl/NginxControl.vue:93
 msgid "Restart"
 msgid "Restart"
 msgstr "Redémarrer"
 msgstr "Redémarrer"
 
 
-#: src/components/NginxControl/NginxControl.vue:76
+#: src/components/NginxControl/NginxControl.vue:79
 msgid "Restarting"
 msgid "Restarting"
 msgstr "Redémarrage"
 msgstr "Redémarrage"
 
 
@@ -1478,15 +1486,15 @@ msgstr "Redémarrage"
 msgid "Run Mode"
 msgid "Run Mode"
 msgstr "Mode d'exécution"
 msgstr "Mode d'exécution"
 
 
-#: src/components/NginxControl/NginxControl.vue:66
+#: src/components/NginxControl/NginxControl.vue:69
 msgid "Running"
 msgid "Running"
 msgstr "En cours d'éxécution"
 msgstr "En cours d'éxécution"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:247
+#: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:123 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
 msgid "Save"
 msgid "Save"
 msgstr "Enregistrer"
 msgstr "Enregistrer"
 
 
@@ -1502,7 +1510,7 @@ msgstr "Enregistrer l'erreur %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:45
 #: src/views/certificate/CertificateEditor.vue:45
-#: src/views/preference/Preference.vue:59
+#: src/views/preference/Preference.vue:66
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Sauvegarde réussie"
 msgstr "Sauvegarde réussie"
 
 
@@ -1517,24 +1525,24 @@ msgstr "Enregistré avec succès"
 msgid "SDK"
 msgid "SDK"
 msgstr ""
 msgstr ""
 
 
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:104
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:155
 msgid "Selector"
 msgid "Selector"
 msgstr "Sélecteur"
 msgstr "Sélecteur"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:25
 #: src/views/dashboard/ServerAnalytic.vue:25
-#: src/views/dashboard/ServerAnalytic.vue:336
+#: src/views/dashboard/ServerAnalytic.vue:339
 msgid "Send"
 msgid "Send"
 msgstr "Envoyer"
 msgstr "Envoyer"
 
 
-#: src/components/NginxControl/NginxControl.vue:28
-#: src/components/NginxControl/NginxControl.vue:42
+#: src/components/NginxControl/NginxControl.vue:29
+#: src/components/NginxControl/NginxControl.vue:45
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:63
+#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:70
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
@@ -1544,6 +1552,11 @@ msgstr "Erreur du serveur"
 msgid "Server Info"
 msgid "Server Info"
 msgstr "Informations sur le serveur"
 msgstr "Informations sur le serveur"
 
 
+#: src/views/preference/BasicSettings.vue:117
+#, fuzzy
+msgid "Server Name"
+msgstr "Informations sur le serveur"
+
 #: src/views/domain/cert/components/ObtainCert.vue:102
 #: src/views/domain/cert/components/ObtainCert.vue:102
 msgid "server_name not found in directives"
 msgid "server_name not found in directives"
 msgstr "server_name introuvable dans les directives"
 msgstr "server_name introuvable dans les directives"
@@ -1617,15 +1630,16 @@ msgstr "Tableau"
 
 
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
-#: src/views/environment/Environment.vue:75 src/views/stream/StreamList.vue:22
+#: src/views/environment/Environment.vue:76 src/views/stream/StreamList.vue:22
 msgid "Status"
 msgid "Status"
 msgstr "Statut"
 msgstr "Statut"
 
 
-#: src/components/NginxControl/NginxControl.vue:81
+#: src/components/NginxControl/NginxControl.vue:84
 msgid "Stopped"
 msgid "Stopped"
 msgstr "Arrêté"
 msgstr "Arrêté"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:243
+#: src/views/dashboard/ServerAnalytic.vue:245
+#: src/views/dashboard/ServerAnalytic.vue:246
 msgid "Storage"
 msgid "Storage"
 msgstr "Stockage"
 msgstr "Stockage"
 
 
@@ -1638,7 +1652,8 @@ msgstr "Nom du sujet : %{name}"
 msgid "Success"
 msgid "Success"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:230
+#: src/views/dashboard/ServerAnalytic.vue:231
+#: src/views/dashboard/ServerAnalytic.vue:232
 #, fuzzy
 #, fuzzy
 msgid "Swap"
 msgid "Swap"
 msgstr "Échanger"
 msgstr "Échanger"
@@ -1690,6 +1705,10 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "Chemin de la clé du certificat SSL"
 msgstr "Chemin de la clé du certificat SSL"
 
 
+#: src/views/preference/OpenAISettings.vue:30
+msgid "The model name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/certificate/CertificateEditor.vue:165
 #: src/views/certificate/CertificateEditor.vue:165
 #, fuzzy
 #, fuzzy
 msgid "The path exists, but the file is not a certificate"
 msgid "The path exists, but the file is not a certificate"
@@ -1699,6 +1718,10 @@ msgstr "Chemin de la clé du certificat SSL"
 msgid "The path exists, but the file is not a private key"
 msgid "The path exists, but the file is not a private key"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/BasicSettings.vue:120
+msgid "The server name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #, fuzzy
 #, fuzzy
 msgid ""
 msgid ""
@@ -1711,9 +1734,12 @@ msgstr ""
 
 
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:50
 #: src/views/preference/BasicSettings.vue:50
-#: src/views/preference/OpenAISettings.vue:36
-#: src/views/preference/OpenAISettings.vue:48
-msgid "The url is not valid"
+msgid "The url is invalid"
+msgstr ""
+
+#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:54
+msgid "The url is invalid."
 msgstr ""
 msgstr ""
 
 
 #: src/language/constants.ts:2
 #: src/language/constants.ts:2
@@ -1761,7 +1787,7 @@ msgstr ""
 "transmettre la demande de l'autorité au backend, et nous devons enregistrer "
 "transmettre la demande de l'autorité au backend, et nous devons enregistrer "
 "ce fichier et recharger le Nginx. Êtes-vous sûr de vouloir continuer?"
 "ce fichier et recharger le Nginx. Êtes-vous sûr de vouloir continuer?"
 
 
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:66
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
@@ -1778,7 +1804,7 @@ msgstr "Type"
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/components/RightSettings.vue:86
-#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:95
+#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:122
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 msgid "Updated at"
 msgid "Updated at"
@@ -1809,11 +1835,11 @@ msgstr ""
 msgid "Uptime:"
 msgid "Uptime:"
 msgstr "Disponibilité :"
 msgstr "Disponibilité :"
 
 
-#: src/views/environment/Environment.vue:21
+#: src/views/environment/Environment.vue:22
 msgid "URL"
 msgid "URL"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 #, fuzzy
 #, fuzzy
 msgid "User"
 msgid "User"
 msgstr "Nom d'utilisateur"
 msgstr "Nom d'utilisateur"
@@ -1871,7 +1897,7 @@ msgstr ""
 "recharger le Nginx. Êtes-vous sûr de vouloir continuer?"
 "recharger le Nginx. Êtes-vous sûr de vouloir continuer?"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:27
 #: src/views/dashboard/ServerAnalytic.vue:27
-#: src/views/dashboard/ServerAnalytic.vue:365
+#: src/views/dashboard/ServerAnalytic.vue:368
 msgid "Writes"
 msgid "Writes"
 msgstr "Écritures"
 msgstr "Écritures"
 
 
@@ -1919,10 +1945,6 @@ msgstr "Vous pouvez vérifier la mise à niveau de Nginx UI sur cette page."
 #~ msgid "Table"
 #~ msgid "Table"
 #~ msgstr "Tableau"
 #~ msgstr "Tableau"
 
 
-#, fuzzy
-#~ msgid "Server"
-#~ msgstr "Informations sur le serveur"
-
 #, fuzzy
 #, fuzzy
 #~ msgid "Leave blank will not change anything."
 #~ msgid "Leave blank will not change anything."
 #~ msgstr "Laisser vide pour aucun changement"
 #~ msgstr "Laisser vide pour aucun changement"

+ 112 - 85
app/src/language/ko_KR/app.po

@@ -22,7 +22,7 @@ msgid "Access Logs"
 msgstr "접근 로그"
 msgstr "접근 로그"
 
 
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
-#: src/views/certificate/ACMEUserSelector.vue:79
+#: src/views/certificate/ACMEUserSelector.vue:84
 #, fuzzy
 #, fuzzy
 msgid "ACME User"
 msgid "ACME User"
 msgstr "사용자 이름"
 msgstr "사용자 이름"
@@ -30,7 +30,7 @@ msgstr "사용자 이름"
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
-#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:102
+#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:35
 #: src/views/notification/Notification.vue:35
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
@@ -75,7 +75,7 @@ msgstr "추가적인"
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "고급 모드"
 msgstr "고급 모드"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:39
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "API 기본 URL"
 msgstr "API 기본 URL"
 
 
@@ -84,11 +84,11 @@ msgstr "API 기본 URL"
 msgid "API Document"
 msgid "API Document"
 msgstr "API 토큰"
 msgstr "API 토큰"
 
 
-#: src/views/preference/OpenAISettings.vue:45
+#: src/views/preference/OpenAISettings.vue:51
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "API 프록시"
 msgstr "API 프록시"
 
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:63
 msgid "API Token"
 msgid "API Token"
 msgstr "API 토큰"
 msgstr "API 토큰"
 
 
@@ -101,7 +101,7 @@ msgstr "아키텍처"
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "모든 알림을 지우시겠습니까?"
 msgstr "모든 알림을 지우시겠습니까?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:267
+#: src/components/ChatGPT/ChatGPT.vue:272
 msgid "Are you sure you want to clear the record of chat?"
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "기록을 지우시겠습니까?"
 msgstr "기록을 지우시겠습니까?"
 
 
@@ -132,11 +132,11 @@ msgstr "이 지시문을 정말로 제거하시겠습니까?"
 msgid "Are you sure you want to remove this location?"
 msgid "Are you sure you want to remove this location?"
 msgstr "이 위치를 제거하시겠습니까?"
 msgstr "이 위치를 제거하시겠습니까?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:211
+#: src/components/ChatGPT/ChatGPT.vue:216
 msgid "Ask ChatGPT for Help"
 msgid "Ask ChatGPT for Help"
 msgstr "ChatGPT에게 도움 요청"
 msgstr "ChatGPT에게 도움 요청"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "Assistant"
 msgid "Assistant"
 msgstr "조수"
 msgstr "조수"
 
 
@@ -145,7 +145,7 @@ msgstr "조수"
 msgid "Author"
 msgid "Author"
 msgstr "저자"
 msgstr "저자"
 
 
-#: src/views/domain/cert/ChangeCert.vue:34
+#: src/views/domain/cert/ChangeCert.vue:33
 msgid "Auto Cert"
 msgid "Auto Cert"
 msgstr "자동 인증"
 msgstr "자동 인증"
 
 
@@ -178,7 +178,7 @@ msgstr "기본 정보"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:94
+#: src/views/preference/Preference.vue:101
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "기본"
 msgstr "기본"
@@ -204,10 +204,10 @@ msgstr ""
 msgid "CADir"
 msgid "CADir"
 msgstr "CA 디렉토리"
 msgstr "CA 디렉토리"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:248
+#: src/components/ChatGPT/ChatGPT.vue:253
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:102
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:153
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/RightSettings.vue:51
 #: src/views/domain/components/RightSettings.vue:51
@@ -249,8 +249,8 @@ msgstr "인증서 목록"
 msgid "Challenge Method"
 msgid "Challenge Method"
 msgstr "인증 방법"
 msgstr "인증 방법"
 
 
-#: src/views/domain/cert/ChangeCert.vue:88
-#: src/views/domain/cert/ChangeCert.vue:92
+#: src/views/domain/cert/ChangeCert.vue:95
+#: src/views/domain/cert/ChangeCert.vue:99
 msgid "Change Certificate"
 msgid "Change Certificate"
 msgstr "인증서 변경"
 msgstr "인증서 변경"
 
 
@@ -266,7 +266,7 @@ msgstr "다시 확인"
 msgid "Cleaning environment variables"
 msgid "Cleaning environment variables"
 msgstr "환경 변수 정리"
 msgstr "환경 변수 정리"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:271
+#: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/Notification/Notification.vue:89
 #: src/components/Notification/Notification.vue:89
 #: src/views/notification/Notification.vue:75
 #: src/views/notification/Notification.vue:75
 msgid "Clear"
 msgid "Clear"
@@ -308,7 +308,7 @@ msgstr "구성들"
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "SSL 구성하기"
 msgstr "SSL 구성하기"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Connected"
 msgid "Connected"
 msgstr "연결됨"
 msgstr "연결됨"
 
 
@@ -322,7 +322,7 @@ msgstr "내용"
 msgid "Core Upgrade"
 msgid "Core Upgrade"
 msgstr "코어 업그레이드"
 msgstr "코어 업그레이드"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:293
+#: src/views/dashboard/ServerAnalytic.vue:296
 msgid "CPU Status"
 msgid "CPU Status"
 msgstr "CPU 상태"
 msgstr "CPU 상태"
 
 
@@ -363,6 +363,12 @@ msgstr "현재 버전"
 msgid "Custom"
 msgid "Custom"
 msgstr "사용자 정의"
 msgstr "사용자 정의"
 
 
+#: src/views/preference/BasicSettings.vue:121
+msgid ""
+"Customize the name of local server to be displayed in the environment "
+"indicator."
+msgstr ""
+
 #: src/routes/index.ts:39
 #: src/routes/index.ts:39
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "대시보드"
 msgstr "대시보드"
@@ -450,9 +456,9 @@ msgstr "비활성화"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "%{name}의 자동 갱신 비활성화 실패"
 msgstr "%{name}의 자동 갱신 비활성화 실패"
 
 
-#: src/views/domain/cert/ChangeCert.vue:45 src/views/domain/DomainEdit.vue:185
-#: src/views/domain/DomainList.vue:33 src/views/stream/StreamEdit.vue:177
-#: src/views/stream/StreamList.vue:33
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
+#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "비활성화됨"
 msgstr "비활성화됨"
 
 
@@ -463,7 +469,7 @@ msgstr "비활성화됨"
 msgid "Disabled successfully"
 msgid "Disabled successfully"
 msgstr "성공적으로 비활성화됨"
 msgstr "성공적으로 비활성화됨"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:358
+#: src/views/dashboard/ServerAnalytic.vue:361
 msgid "Disk IO"
 msgid "Disk IO"
 msgstr "디스크 IO"
 msgstr "디스크 IO"
 
 
@@ -631,9 +637,10 @@ msgstr "성공적으로 활성화"
 msgid "Enable TLS"
 msgid "Enable TLS"
 msgstr "TLS 활성화"
 msgstr "TLS 활성화"
 
 
-#: src/views/domain/cert/ChangeCert.vue:41
+#: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
@@ -653,11 +660,11 @@ msgstr "성공적으로 활성화됨"
 msgid "Encrypt website with Let's Encrypt"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Let's Encrypt로 웹사이트 암호화"
 msgstr "Let's Encrypt로 웹사이트 암호화"
 
 
-#: src/routes/index.ts:212 src/views/environment/Environment.vue:110
+#: src/routes/index.ts:212 src/views/environment/Environment.vue:137
 msgid "Environment"
 msgid "Environment"
 msgstr "환경"
 msgstr "환경"
 
 
-#: src/views/dashboard/Environments.vue:71
+#: src/views/dashboard/Environments.vue:82
 msgid "Environments"
 msgid "Environments"
 msgstr "환경"
 msgstr "환경"
 
 
@@ -883,7 +890,7 @@ msgstr "마지막 확인 시간"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "변경사항이 없으면 비워두세요"
 msgstr "변경사항이 없으면 비워두세요"
 
 
-#: src/views/preference/OpenAISettings.vue:41
+#: src/views/preference/OpenAISettings.vue:47
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "기본값을 사용하려면 비워 두세요: https://api.openai.com/"
 msgstr "기본값을 사용하려면 비워 두세요: https://api.openai.com/"
 
 
@@ -898,7 +905,7 @@ msgstr "변경사항이 없으면 비워두세요"
 msgid "License"
 msgid "License"
 msgstr "라이센스"
 msgstr "라이센스"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Link Start"
 msgid "Link Start"
 msgstr "링크 시작"
 msgstr "링크 시작"
 
 
@@ -912,8 +919,8 @@ msgstr ""
 msgid "Load Average:"
 msgid "Load Average:"
 msgstr "부하 평균:"
 msgstr "부하 평균:"
 
 
-#: src/components/EnvIndicator/EnvIndicator.vue:38
-#: src/components/NodeSelector/NodeSelector.vue:51
+#: src/components/EnvIndicator/EnvIndicator.vue:40
+#: src/components/NodeSelector/NodeSelector.vue:71
 #, fuzzy
 #, fuzzy
 msgid "Local"
 msgid "Local"
 msgstr "지역"
 msgstr "지역"
@@ -943,7 +950,7 @@ msgstr "로그인 성공"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "로그아웃 성공"
 msgstr "로그아웃 성공"
 
 
-#: src/views/preference/Preference.vue:112
+#: src/views/preference/Preference.vue:119
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr "로그관리"
 msgstr "로그관리"
 
 
@@ -994,6 +1001,7 @@ msgid "Managed Certificate"
 msgstr "인증서 유효"
 msgstr "인증서 유효"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
+#: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
 msgstr "메모리"
 msgstr "메모리"
 
 
@@ -1005,12 +1013,12 @@ msgstr "메모리 및 저장소"
 msgid "Minutes"
 msgid "Minutes"
 msgstr "분"
 msgstr "분"
 
 
-#: src/views/preference/OpenAISettings.vue:26
+#: src/views/preference/OpenAISettings.vue:27
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "실행 모드"
 msgstr "실행 모드"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:244
+#: src/components/ChatGPT/ChatGPT.vue:249
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #, fuzzy
 #, fuzzy
@@ -1040,7 +1048,7 @@ msgstr "단일 지시문"
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
-#: src/views/domain/cert/ChangeCert.vue:18
+#: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
@@ -1052,19 +1060,19 @@ msgstr "단일 지시문"
 msgid "Name"
 msgid "Name"
 msgstr "이름"
 msgstr "이름"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:319
+#: src/views/dashboard/ServerAnalytic.vue:322
 msgid "Network"
 msgid "Network"
 msgstr "네트워크"
 msgstr "네트워크"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:261
+#: src/views/dashboard/ServerAnalytic.vue:264
 msgid "Network Statistics"
 msgid "Network Statistics"
 msgstr "네트워크 통계"
 msgstr "네트워크 통계"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:268
+#: src/views/dashboard/ServerAnalytic.vue:271
 msgid "Network Total Receive"
 msgid "Network Total Receive"
 msgstr "네트워크 총 수신"
 msgstr "네트워크 총 수신"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:274
+#: src/views/dashboard/ServerAnalytic.vue:277
 msgid "Network Total Send"
 msgid "Network Total Send"
 msgstr "네트워크 총 송신"
 msgstr "네트워크 총 송신"
 
 
@@ -1078,7 +1086,7 @@ msgstr "새 버전 출시"
 msgid "Next"
 msgid "Next"
 msgstr "다음"
 msgstr "다음"
 
 
-#: src/views/preference/Preference.vue:100
+#: src/views/preference/Preference.vue:107
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Nginx"
 msgstr "Nginx"
 
 
@@ -1091,7 +1099,7 @@ msgstr "Nginx 접근 로그 경로"
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Nginx 구성 오류름"
 msgstr "Nginx 구성 오류름"
 
 
-#: src/components/NginxControl/NginxControl.vue:62
+#: src/components/NginxControl/NginxControl.vue:65
 msgid "Nginx Control"
 msgid "Nginx Control"
 msgstr "Nginx 제어"
 msgstr "Nginx 제어"
 
 
@@ -1103,17 +1111,17 @@ msgstr "Nginx 오류 로그 경로"
 msgid "Nginx Log"
 msgid "Nginx Log"
 msgstr "Nginx 로그"
 msgstr "Nginx 로그"
 
 
-#: src/components/NginxControl/NginxControl.vue:22
+#: src/components/NginxControl/NginxControl.vue:23
 #, fuzzy
 #, fuzzy
 msgid "Nginx reloaded successfully"
 msgid "Nginx reloaded successfully"
 msgstr "Nginx가 성공적으로 리로드됨"
 msgstr "Nginx가 성공적으로 리로드됨"
 
 
-#: src/components/NginxControl/NginxControl.vue:36
+#: src/components/NginxControl/NginxControl.vue:39
 #, fuzzy
 #, fuzzy
 msgid "Nginx restarted successfully"
 msgid "Nginx restarted successfully"
 msgstr "Nginx가 성공적으로 재시작됨"
 msgstr "Nginx가 성공적으로 재시작됨"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:265
+#: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/Notification/Notification.vue:82
 #: src/components/Notification/Notification.vue:82
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
@@ -1166,22 +1174,22 @@ msgstr "인증서 획득"
 msgid "Obtaining certificate"
 msgid "Obtaining certificate"
 msgstr "인증서 획득 중"
 msgstr "인증서 획득 중"
 
 
-#: src/components/NodeSelector/NodeSelector.vue:75
-#: src/views/dashboard/Environments.vue:95
-#: src/views/environment/Environment.vue:86
+#: src/components/NodeSelector/NodeSelector.vue:95
+#: src/views/dashboard/Environments.vue:106
+#: src/views/environment/Environment.vue:88
 msgid "Offline"
 msgid "Offline"
 msgstr "오프라인"
 msgstr "오프라인"
 
 
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:154
 msgid "Ok"
 msgid "Ok"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:266
+#: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/Notification/Notification.vue:83
 #: src/components/Notification/Notification.vue:83
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:103
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/RightSettings.vue:50
 #: src/views/domain/components/RightSettings.vue:50
@@ -1200,14 +1208,14 @@ msgstr "확인"
 msgid "Once the verification is complete, the records will be removed."
 msgid "Once the verification is complete, the records will be removed."
 msgstr "검증이 완료되면, 레코드는 제거됩니다."
 msgstr "검증이 완료되면, 레코드는 제거됩니다."
 
 
-#: src/components/NodeSelector/NodeSelector.vue:54
-#: src/components/NodeSelector/NodeSelector.vue:69
-#: src/views/dashboard/Environments.vue:88
-#: src/views/environment/Environment.vue:82
+#: src/components/NodeSelector/NodeSelector.vue:74
+#: src/components/NodeSelector/NodeSelector.vue:89
+#: src/views/dashboard/Environments.vue:99
+#: src/views/environment/Environment.vue:84
 msgid "Online"
 msgid "Online"
 msgstr "온라인"
 msgstr "온라인"
 
 
-#: src/views/preference/Preference.vue:106
+#: src/views/preference/Preference.vue:113
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "오픈AI"
 msgstr "오픈AI"
 
 
@@ -1303,7 +1311,7 @@ msgstr "적어도 하나의 노드를 선택해주세요!"
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr "사전 출시"
 msgstr "사전 출시"
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:89
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
 msgid "Preference"
 msgid "Preference"
 msgstr "환경설정"
 msgstr "환경설정"
 
 
@@ -1329,12 +1337,12 @@ msgid "Provider"
 msgstr "제공자"
 msgstr "제공자"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:28
 #: src/views/dashboard/ServerAnalytic.vue:28
-#: src/views/dashboard/ServerAnalytic.vue:375
+#: src/views/dashboard/ServerAnalytic.vue:378
 msgid "Reads"
 msgid "Reads"
 msgstr "읽기"
 msgstr "읽기"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:24
 #: src/views/dashboard/ServerAnalytic.vue:24
-#: src/views/dashboard/ServerAnalytic.vue:326
+#: src/views/dashboard/ServerAnalytic.vue:329
 msgid "Receive"
 msgid "Receive"
 msgstr "수신"
 msgstr "수신"
 
 
@@ -1351,7 +1359,7 @@ msgstr "성공적으로 제거됨"
 msgid "Recursive Nameservers"
 msgid "Recursive Nameservers"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:278
+#: src/components/ChatGPT/ChatGPT.vue:283
 msgid "Regenerate response"
 msgid "Regenerate response"
 msgstr "응답 재생성"
 msgstr "응답 재생성"
 
 
@@ -1388,12 +1396,12 @@ msgstr "재설치"
 msgid "Release Note"
 msgid "Release Note"
 msgstr "릴리스 노트"
 msgstr "릴리스 노트"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:254
-#: src/components/NginxControl/NginxControl.vue:97
+#: src/components/ChatGPT/ChatGPT.vue:259
+#: src/components/NginxControl/NginxControl.vue:100
 msgid "Reload"
 msgid "Reload"
 msgstr "리로드"
 msgstr "리로드"
 
 
-#: src/components/NginxControl/NginxControl.vue:71
+#: src/components/NginxControl/NginxControl.vue:74
 msgid "Reloading"
 msgid "Reloading"
 msgstr "리로딩 중"
 msgstr "리로딩 중"
 
 
@@ -1441,11 +1449,11 @@ msgstr "잘못된 매개변수로 요청됨"
 msgid "Reset"
 msgid "Reset"
 msgstr "재설정"
 msgstr "재설정"
 
 
-#: src/components/NginxControl/NginxControl.vue:90
+#: src/components/NginxControl/NginxControl.vue:93
 msgid "Restart"
 msgid "Restart"
 msgstr "재시작"
 msgstr "재시작"
 
 
-#: src/components/NginxControl/NginxControl.vue:76
+#: src/components/NginxControl/NginxControl.vue:79
 msgid "Restarting"
 msgid "Restarting"
 msgstr "재시작 중"
 msgstr "재시작 중"
 
 
@@ -1454,15 +1462,15 @@ msgstr "재시작 중"
 msgid "Run Mode"
 msgid "Run Mode"
 msgstr "실행 모드"
 msgstr "실행 모드"
 
 
-#: src/components/NginxControl/NginxControl.vue:66
+#: src/components/NginxControl/NginxControl.vue:69
 msgid "Running"
 msgid "Running"
 msgstr "실행 중"
 msgstr "실행 중"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:247
+#: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:123 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
 msgid "Save"
 msgid "Save"
 msgstr "저장"
 msgstr "저장"
 
 
@@ -1478,7 +1486,7 @@ msgstr "저장 오류 %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:45
 #: src/views/certificate/CertificateEditor.vue:45
-#: src/views/preference/Preference.vue:59
+#: src/views/preference/Preference.vue:66
 #, fuzzy
 #, fuzzy
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "성공적으로 저장됨"
 msgstr "성공적으로 저장됨"
@@ -1494,24 +1502,24 @@ msgstr "성공적으로 저장됨"
 msgid "SDK"
 msgid "SDK"
 msgstr ""
 msgstr ""
 
 
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:104
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:155
 msgid "Selector"
 msgid "Selector"
 msgstr "선택"
 msgstr "선택"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:25
 #: src/views/dashboard/ServerAnalytic.vue:25
-#: src/views/dashboard/ServerAnalytic.vue:336
+#: src/views/dashboard/ServerAnalytic.vue:339
 msgid "Send"
 msgid "Send"
 msgstr "보내기"
 msgstr "보내기"
 
 
-#: src/components/NginxControl/NginxControl.vue:28
-#: src/components/NginxControl/NginxControl.vue:42
+#: src/components/NginxControl/NginxControl.vue:29
+#: src/components/NginxControl/NginxControl.vue:45
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:63
+#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:70
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
@@ -1521,6 +1529,11 @@ msgstr "서버 오류"
 msgid "Server Info"
 msgid "Server Info"
 msgstr "서버 정보"
 msgstr "서버 정보"
 
 
+#: src/views/preference/BasicSettings.vue:117
+#, fuzzy
+msgid "Server Name"
+msgstr "Server Info"
+
 #: src/views/domain/cert/components/ObtainCert.vue:102
 #: src/views/domain/cert/components/ObtainCert.vue:102
 msgid "server_name not found in directives"
 msgid "server_name not found in directives"
 msgstr "directives에서 server_name을 찾을 수 없습니다"
 msgstr "directives에서 server_name을 찾을 수 없습니다"
@@ -1594,15 +1607,16 @@ msgstr "활성화됨"
 
 
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
-#: src/views/environment/Environment.vue:75 src/views/stream/StreamList.vue:22
+#: src/views/environment/Environment.vue:76 src/views/stream/StreamList.vue:22
 msgid "Status"
 msgid "Status"
 msgstr "상태"
 msgstr "상태"
 
 
-#: src/components/NginxControl/NginxControl.vue:81
+#: src/components/NginxControl/NginxControl.vue:84
 msgid "Stopped"
 msgid "Stopped"
 msgstr "정지됨"
 msgstr "정지됨"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:243
+#: src/views/dashboard/ServerAnalytic.vue:245
+#: src/views/dashboard/ServerAnalytic.vue:246
 msgid "Storage"
 msgid "Storage"
 msgstr "저장소"
 msgstr "저장소"
 
 
@@ -1615,7 +1629,8 @@ msgstr "제목 이름: %{name}"
 msgid "Success"
 msgid "Success"
 msgstr "성공"
 msgstr "성공"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:230
+#: src/views/dashboard/ServerAnalytic.vue:231
+#: src/views/dashboard/ServerAnalytic.vue:232
 msgid "Swap"
 msgid "Swap"
 msgstr "스왑"
 msgstr "스왑"
 
 
@@ -1666,6 +1681,10 @@ msgstr "입력이 SSL 인증서가 아닙니다"
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "Certificate Status"
 msgstr "Certificate Status"
 
 
+#: src/views/preference/OpenAISettings.vue:30
+msgid "The model name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/certificate/CertificateEditor.vue:165
 #: src/views/certificate/CertificateEditor.vue:165
 #, fuzzy
 #, fuzzy
 msgid "The path exists, but the file is not a certificate"
 msgid "The path exists, but the file is not a certificate"
@@ -1675,6 +1694,10 @@ msgstr "Certificate Status"
 msgid "The path exists, but the file is not a private key"
 msgid "The path exists, but the file is not a private key"
 msgstr "경로는 존재하지만 파일은 개인 키가 아닙니다"
 msgstr "경로는 존재하지만 파일은 개인 키가 아닙니다"
 
 
+#: src/views/preference/BasicSettings.vue:120
+msgid "The server name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #, fuzzy
 #, fuzzy
 msgid ""
 msgid ""
@@ -1686,9 +1709,14 @@ msgstr ""
 
 
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:50
 #: src/views/preference/BasicSettings.vue:50
-#: src/views/preference/OpenAISettings.vue:36
-#: src/views/preference/OpenAISettings.vue:48
-msgid "The url is not valid"
+#, fuzzy
+msgid "The url is invalid"
+msgstr "유효한 URL이 아닙니다"
+
+#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:54
+#, fuzzy
+msgid "The url is invalid."
 msgstr "유효한 URL이 아닙니다"
 msgstr "유효한 URL이 아닙니다"
 
 
 #: src/language/constants.ts:2
 #: src/language/constants.ts:2
@@ -1732,7 +1760,7 @@ msgstr ""
 "시할 수 있는 위치를 추가해야 하며,이 파일을 저장하고 Nginx를 다시로드해야 합"
 "시할 수 있는 위치를 추가해야 하며,이 파일을 저장하고 Nginx를 다시로드해야 합"
 "니다.계속하시겠습니까?"
 "니다.계속하시겠습니까?"
 
 
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:66
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr "토큰이 유효하지 않습니다"
 msgstr "토큰이 유효하지 않습니다"
 
 
@@ -1749,7 +1777,7 @@ msgstr "유형"
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/components/RightSettings.vue:86
-#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:95
+#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:122
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 msgid "Updated at"
 msgid "Updated at"
@@ -1782,11 +1810,11 @@ msgstr "업스트림 이름"
 msgid "Uptime:"
 msgid "Uptime:"
 msgstr "가동 시간:"
 msgstr "가동 시간:"
 
 
-#: src/views/environment/Environment.vue:21
+#: src/views/environment/Environment.vue:22
 msgid "URL"
 msgid "URL"
 msgstr "URL"
 msgstr "URL"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 #, fuzzy
 #, fuzzy
 msgid "User"
 msgid "User"
 msgstr "사용자 이름"
 msgstr "사용자 이름"
@@ -1847,7 +1875,7 @@ msgstr ""
 "속하시겠습니까?"
 "속하시겠습니까?"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:27
 #: src/views/dashboard/ServerAnalytic.vue:27
-#: src/views/dashboard/ServerAnalytic.vue:365
+#: src/views/dashboard/ServerAnalytic.vue:368
 msgid "Writes"
 msgid "Writes"
 msgstr "쓰기"
 msgstr "쓰기"
 
 
@@ -1873,6 +1901,9 @@ msgstr "최신 버전을 사용하고 있습니다"
 msgid "You can check Nginx UI upgrade at this page."
 msgid "You can check Nginx UI upgrade at this page."
 msgstr "이 페이지에서 Nginx UI 업그레이드를 확인할 수 있습니다."
 msgstr "이 페이지에서 Nginx UI 업그레이드를 확인할 수 있습니다."
 
 
+#~ msgid "The url is not valid"
+#~ msgstr "유효한 URL이 아닙니다"
+
 #~ msgid "ChatGPT Model"
 #~ msgid "ChatGPT Model"
 #~ msgstr "ChatGPT 모델"
 #~ msgstr "ChatGPT 모델"
 
 
@@ -1896,10 +1927,6 @@ msgstr "이 페이지에서 Nginx UI 업그레이드를 확인할 수 있습니
 #~ msgid "Table"
 #~ msgid "Table"
 #~ msgstr "활성화됨"
 #~ msgstr "활성화됨"
 
 
-#, fuzzy
-#~ msgid "Server"
-#~ msgstr "Server Info"
-
 #, fuzzy
 #, fuzzy
 #~ msgid "Leave blank will not change anything."
 #~ msgid "Leave blank will not change anything."
 #~ msgstr "Leave blank for no change"
 #~ msgstr "Leave blank for no change"

+ 103 - 79
app/src/language/messages.pot

@@ -13,7 +13,7 @@ msgstr ""
 
 
 #: src/routes/index.ts:128
 #: src/routes/index.ts:128
 #: src/views/certificate/ACMEUser.vue:76
 #: src/views/certificate/ACMEUser.vue:76
-#: src/views/certificate/ACMEUserSelector.vue:79
+#: src/views/certificate/ACMEUserSelector.vue:84
 msgid "ACME User"
 msgid "ACME User"
 msgstr ""
 msgstr ""
 
 
@@ -22,7 +22,7 @@ msgstr ""
 #: src/views/certificate/DNSCredential.vue:29
 #: src/views/certificate/DNSCredential.vue:29
 #: src/views/config/config.ts:34
 #: src/views/config/config.ts:34
 #: src/views/domain/DomainList.vue:47
 #: src/views/domain/DomainList.vue:47
-#: src/views/environment/Environment.vue:102
+#: src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:35
 #: src/views/notification/Notification.vue:35
 #: src/views/stream/StreamList.vue:47
 #: src/views/stream/StreamList.vue:47
 #: src/views/user/User.vue:43
 #: src/views/user/User.vue:43
@@ -70,7 +70,7 @@ msgstr ""
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:39
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr ""
 msgstr ""
 
 
@@ -78,11 +78,11 @@ msgstr ""
 msgid "API Document"
 msgid "API Document"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:45
+#: src/views/preference/OpenAISettings.vue:51
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:63
 msgid "API Token"
 msgid "API Token"
 msgstr ""
 msgstr ""
 
 
@@ -95,7 +95,7 @@ msgstr ""
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:267
+#: src/components/ChatGPT/ChatGPT.vue:272
 msgid "Are you sure you want to clear the record of chat?"
 msgid "Are you sure you want to clear the record of chat?"
 msgstr ""
 msgstr ""
 
 
@@ -124,11 +124,11 @@ msgstr ""
 msgid "Are you sure you want to remove this location?"
 msgid "Are you sure you want to remove this location?"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:211
+#: src/components/ChatGPT/ChatGPT.vue:216
 msgid "Ask ChatGPT for Help"
 msgid "Ask ChatGPT for Help"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "Assistant"
 msgid "Assistant"
 msgstr ""
 msgstr ""
 
 
@@ -137,7 +137,7 @@ msgstr ""
 msgid "Author"
 msgid "Author"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/cert/ChangeCert.vue:34
+#: src/views/domain/cert/ChangeCert.vue:33
 msgid "Auto Cert"
 msgid "Auto Cert"
 msgstr ""
 msgstr ""
 
 
@@ -172,7 +172,7 @@ msgstr ""
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:94
+#: src/views/preference/Preference.vue:101
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr ""
 msgstr ""
@@ -199,10 +199,10 @@ msgstr ""
 msgid "CADir"
 msgid "CADir"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:248
+#: src/components/ChatGPT/ChatGPT.vue:253
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:102
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:153
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/RightSettings.vue:51
 #: src/views/domain/components/RightSettings.vue:51
@@ -244,8 +244,8 @@ msgstr ""
 msgid "Challenge Method"
 msgid "Challenge Method"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/cert/ChangeCert.vue:88
-#: src/views/domain/cert/ChangeCert.vue:92
+#: src/views/domain/cert/ChangeCert.vue:95
+#: src/views/domain/cert/ChangeCert.vue:99
 msgid "Change Certificate"
 msgid "Change Certificate"
 msgstr ""
 msgstr ""
 
 
@@ -261,7 +261,7 @@ msgstr ""
 msgid "Cleaning environment variables"
 msgid "Cleaning environment variables"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:271
+#: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/Notification/Notification.vue:89
 #: src/components/Notification/Notification.vue:89
 #: src/views/notification/Notification.vue:75
 #: src/views/notification/Notification.vue:75
 msgid "Clear"
 msgid "Clear"
@@ -303,7 +303,7 @@ msgstr ""
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Connected"
 msgid "Connected"
 msgstr ""
 msgstr ""
 
 
@@ -317,7 +317,7 @@ msgstr ""
 msgid "Core Upgrade"
 msgid "Core Upgrade"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:293
+#: src/views/dashboard/ServerAnalytic.vue:296
 msgid "CPU Status"
 msgid "CPU Status"
 msgstr ""
 msgstr ""
 
 
@@ -359,6 +359,10 @@ msgstr ""
 msgid "Custom"
 msgid "Custom"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/BasicSettings.vue:121
+msgid "Customize the name of local server to be displayed in the environment indicator."
+msgstr ""
+
 #: src/routes/index.ts:39
 #: src/routes/index.ts:39
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr ""
 msgstr ""
@@ -447,9 +451,10 @@ msgstr ""
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/cert/ChangeCert.vue:45
+#: src/views/domain/cert/ChangeCert.vue:44
 #: src/views/domain/DomainEdit.vue:185
 #: src/views/domain/DomainEdit.vue:185
 #: src/views/domain/DomainList.vue:33
 #: src/views/domain/DomainList.vue:33
+#: src/views/environment/Environment.vue:93
 #: src/views/stream/StreamEdit.vue:177
 #: src/views/stream/StreamEdit.vue:177
 #: src/views/stream/StreamList.vue:33
 #: src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
@@ -462,7 +467,7 @@ msgstr ""
 msgid "Disabled successfully"
 msgid "Disabled successfully"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:358
+#: src/views/dashboard/ServerAnalytic.vue:361
 msgid "Disk IO"
 msgid "Disk IO"
 msgstr ""
 msgstr ""
 
 
@@ -630,10 +635,11 @@ msgstr ""
 msgid "Enable TLS"
 msgid "Enable TLS"
 msgstr ""
 msgstr ""
 
 
-#: src/views/domain/cert/ChangeCert.vue:41
+#: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/DomainEdit.vue:179
 #: src/views/domain/DomainEdit.vue:179
 #: src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainList.vue:29
+#: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/StreamEdit.vue:171
 #: src/views/stream/StreamEdit.vue:171
@@ -656,11 +662,11 @@ msgid "Encrypt website with Let's Encrypt"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/index.ts:212
 #: src/routes/index.ts:212
-#: src/views/environment/Environment.vue:110
+#: src/views/environment/Environment.vue:137
 msgid "Environment"
 msgid "Environment"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/Environments.vue:71
+#: src/views/dashboard/Environments.vue:82
 msgid "Environments"
 msgid "Environments"
 msgstr ""
 msgstr ""
 
 
@@ -879,7 +885,7 @@ msgstr ""
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:41
+#: src/views/preference/OpenAISettings.vue:47
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr ""
 msgstr ""
 
 
@@ -892,7 +898,7 @@ msgstr ""
 msgid "License"
 msgid "License"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Link Start"
 msgid "Link Start"
 msgstr ""
 msgstr ""
 
 
@@ -905,8 +911,8 @@ msgstr ""
 msgid "Load Average:"
 msgid "Load Average:"
 msgstr ""
 msgstr ""
 
 
-#: src/components/EnvIndicator/EnvIndicator.vue:38
-#: src/components/NodeSelector/NodeSelector.vue:51
+#: src/components/EnvIndicator/EnvIndicator.vue:40
+#: src/components/NodeSelector/NodeSelector.vue:71
 msgid "Local"
 msgid "Local"
 msgstr ""
 msgstr ""
 
 
@@ -936,7 +942,7 @@ msgstr ""
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:112
+#: src/views/preference/Preference.vue:119
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -972,6 +978,7 @@ msgid "Managed Certificate"
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
+#: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
 msgstr ""
 msgstr ""
 
 
@@ -983,11 +990,11 @@ msgstr ""
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:26
+#: src/views/preference/OpenAISettings.vue:27
 msgid "Model"
 msgid "Model"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:244
+#: src/components/ChatGPT/ChatGPT.vue:249
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 msgid "Modify"
 msgid "Modify"
@@ -1015,7 +1022,7 @@ msgstr ""
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/DNSCredential.vue:10
 #: src/views/certificate/DNSCredential.vue:10
 #: src/views/config/config.ts:7
 #: src/views/config/config.ts:7
-#: src/views/domain/cert/ChangeCert.vue:18
+#: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
@@ -1028,19 +1035,19 @@ msgstr ""
 msgid "Name"
 msgid "Name"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:319
+#: src/views/dashboard/ServerAnalytic.vue:322
 msgid "Network"
 msgid "Network"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:261
+#: src/views/dashboard/ServerAnalytic.vue:264
 msgid "Network Statistics"
 msgid "Network Statistics"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:268
+#: src/views/dashboard/ServerAnalytic.vue:271
 msgid "Network Total Receive"
 msgid "Network Total Receive"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:274
+#: src/views/dashboard/ServerAnalytic.vue:277
 msgid "Network Total Send"
 msgid "Network Total Send"
 msgstr ""
 msgstr ""
 
 
@@ -1054,7 +1061,7 @@ msgstr ""
 msgid "Next"
 msgid "Next"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:100
+#: src/views/preference/Preference.vue:107
 msgid "Nginx"
 msgid "Nginx"
 msgstr ""
 msgstr ""
 
 
@@ -1067,7 +1074,7 @@ msgstr ""
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:62
+#: src/components/NginxControl/NginxControl.vue:65
 msgid "Nginx Control"
 msgid "Nginx Control"
 msgstr ""
 msgstr ""
 
 
@@ -1080,15 +1087,15 @@ msgstr ""
 msgid "Nginx Log"
 msgid "Nginx Log"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:22
+#: src/components/NginxControl/NginxControl.vue:23
 msgid "Nginx reloaded successfully"
 msgid "Nginx reloaded successfully"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:36
+#: src/components/NginxControl/NginxControl.vue:39
 msgid "Nginx restarted successfully"
 msgid "Nginx restarted successfully"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:265
+#: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/Notification/Notification.vue:82
 #: src/components/Notification/Notification.vue:82
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
@@ -1139,22 +1146,22 @@ msgstr ""
 msgid "Obtaining certificate"
 msgid "Obtaining certificate"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NodeSelector/NodeSelector.vue:75
-#: src/views/dashboard/Environments.vue:95
-#: src/views/environment/Environment.vue:86
+#: src/components/NodeSelector/NodeSelector.vue:95
+#: src/views/dashboard/Environments.vue:106
+#: src/views/environment/Environment.vue:88
 msgid "Offline"
 msgid "Offline"
 msgstr ""
 msgstr ""
 
 
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:154
 msgid "Ok"
 msgid "Ok"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:266
+#: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/Notification/Notification.vue:83
 #: src/components/Notification/Notification.vue:83
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:103
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/RightSettings.vue:50
 #: src/views/domain/components/RightSettings.vue:50
@@ -1173,14 +1180,14 @@ msgstr ""
 msgid "Once the verification is complete, the records will be removed."
 msgid "Once the verification is complete, the records will be removed."
 msgstr ""
 msgstr ""
 
 
-#: src/components/NodeSelector/NodeSelector.vue:54
-#: src/components/NodeSelector/NodeSelector.vue:69
-#: src/views/dashboard/Environments.vue:88
-#: src/views/environment/Environment.vue:82
+#: src/components/NodeSelector/NodeSelector.vue:74
+#: src/components/NodeSelector/NodeSelector.vue:89
+#: src/views/dashboard/Environments.vue:99
+#: src/views/environment/Environment.vue:84
 msgid "Online"
 msgid "Online"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:106
+#: src/views/preference/Preference.vue:113
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr ""
 msgstr ""
 
 
@@ -1271,7 +1278,7 @@ msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
 #: src/routes/index.ts:239
 #: src/routes/index.ts:239
-#: src/views/preference/Preference.vue:89
+#: src/views/preference/Preference.vue:96
 msgid "Preference"
 msgid "Preference"
 msgstr ""
 msgstr ""
 
 
@@ -1296,12 +1303,12 @@ msgid "Provider"
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:28
 #: src/views/dashboard/ServerAnalytic.vue:28
-#: src/views/dashboard/ServerAnalytic.vue:375
+#: src/views/dashboard/ServerAnalytic.vue:378
 msgid "Reads"
 msgid "Reads"
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:24
 #: src/views/dashboard/ServerAnalytic.vue:24
-#: src/views/dashboard/ServerAnalytic.vue:326
+#: src/views/dashboard/ServerAnalytic.vue:329
 msgid "Receive"
 msgid "Receive"
 msgstr ""
 msgstr ""
 
 
@@ -1317,7 +1324,7 @@ msgstr ""
 msgid "Recursive Nameservers"
 msgid "Recursive Nameservers"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:278
+#: src/components/ChatGPT/ChatGPT.vue:283
 msgid "Regenerate response"
 msgid "Regenerate response"
 msgstr ""
 msgstr ""
 
 
@@ -1349,12 +1356,12 @@ msgstr ""
 msgid "Release Note"
 msgid "Release Note"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:254
-#: src/components/NginxControl/NginxControl.vue:97
+#: src/components/ChatGPT/ChatGPT.vue:259
+#: src/components/NginxControl/NginxControl.vue:100
 msgid "Reload"
 msgid "Reload"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:71
+#: src/components/NginxControl/NginxControl.vue:74
 msgid "Reloading"
 msgid "Reloading"
 msgstr ""
 msgstr ""
 
 
@@ -1396,11 +1403,11 @@ msgstr ""
 msgid "Reset"
 msgid "Reset"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:90
+#: src/components/NginxControl/NginxControl.vue:93
 msgid "Restart"
 msgid "Restart"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:76
+#: src/components/NginxControl/NginxControl.vue:79
 msgid "Restarting"
 msgid "Restarting"
 msgstr ""
 msgstr ""
 
 
@@ -1408,16 +1415,16 @@ msgstr ""
 msgid "Run Mode"
 msgid "Run Mode"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:66
+#: src/components/NginxControl/NginxControl.vue:69
 msgid "Running"
 msgid "Running"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:247
+#: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/ConfigEdit.vue:96
 #: src/views/config/ConfigEdit.vue:96
 #: src/views/domain/DomainEdit.vue:263
 #: src/views/domain/DomainEdit.vue:263
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:123
+#: src/views/preference/Preference.vue:130
 #: src/views/stream/StreamEdit.vue:254
 #: src/views/stream/StreamEdit.vue:254
 msgid "Save"
 msgid "Save"
 msgstr ""
 msgstr ""
@@ -1435,7 +1442,7 @@ msgstr ""
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:45
 #: src/views/certificate/CertificateEditor.vue:45
-#: src/views/preference/Preference.vue:59
+#: src/views/preference/Preference.vue:66
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr ""
 msgstr ""
 
 
@@ -1451,17 +1458,17 @@ msgstr ""
 msgid "SDK"
 msgid "SDK"
 msgstr ""
 msgstr ""
 
 
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:104
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:155
 msgid "Selector"
 msgid "Selector"
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:25
 #: src/views/dashboard/ServerAnalytic.vue:25
-#: src/views/dashboard/ServerAnalytic.vue:336
+#: src/views/dashboard/ServerAnalytic.vue:339
 msgid "Send"
 msgid "Send"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:28
-#: src/components/NginxControl/NginxControl.vue:42
+#: src/components/NginxControl/NginxControl.vue:29
+#: src/components/NginxControl/NginxControl.vue:45
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
@@ -1470,7 +1477,7 @@ msgstr ""
 #: src/views/config/ConfigEdit.vue:40
 #: src/views/config/ConfigEdit.vue:40
 #: src/views/domain/DomainList.vue:81
 #: src/views/domain/DomainList.vue:81
 #: src/views/other/Install.vue:70
 #: src/views/other/Install.vue:70
-#: src/views/preference/Preference.vue:63
+#: src/views/preference/Preference.vue:70
 #: src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:113
 #: src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
@@ -1481,6 +1488,10 @@ msgstr ""
 msgid "Server Info"
 msgid "Server Info"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/BasicSettings.vue:117
+msgid "Server Name"
+msgstr ""
+
 #: src/views/domain/cert/components/ObtainCert.vue:102
 #: src/views/domain/cert/components/ObtainCert.vue:102
 msgid "server_name not found in directives"
 msgid "server_name not found in directives"
 msgstr ""
 msgstr ""
@@ -1548,16 +1559,17 @@ msgstr ""
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/Certificate.vue:83
 #: src/views/certificate/Certificate.vue:83
 #: src/views/domain/DomainList.vue:22
 #: src/views/domain/DomainList.vue:22
-#: src/views/environment/Environment.vue:75
+#: src/views/environment/Environment.vue:76
 #: src/views/stream/StreamList.vue:22
 #: src/views/stream/StreamList.vue:22
 msgid "Status"
 msgid "Status"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:81
+#: src/components/NginxControl/NginxControl.vue:84
 msgid "Stopped"
 msgid "Stopped"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:243
+#: src/views/dashboard/ServerAnalytic.vue:245
+#: src/views/dashboard/ServerAnalytic.vue:246
 msgid "Storage"
 msgid "Storage"
 msgstr ""
 msgstr ""
 
 
@@ -1569,7 +1581,8 @@ msgstr ""
 msgid "Success"
 msgid "Success"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:230
+#: src/views/dashboard/ServerAnalytic.vue:231
+#: src/views/dashboard/ServerAnalytic.vue:232
 msgid "Swap"
 msgid "Swap"
 msgstr ""
 msgstr ""
 
 
@@ -1615,6 +1628,10 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/OpenAISettings.vue:30
+msgid "The model name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/certificate/CertificateEditor.vue:165
 #: src/views/certificate/CertificateEditor.vue:165
 msgid "The path exists, but the file is not a certificate"
 msgid "The path exists, but the file is not a certificate"
 msgstr ""
 msgstr ""
@@ -1623,15 +1640,22 @@ msgstr ""
 msgid "The path exists, but the file is not a private key"
 msgid "The path exists, but the file is not a private key"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/BasicSettings.vue:120
+msgid "The server name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 msgid "The server_name in the current configuration must be the domain name you need to get the certificate, supportmultiple domains."
 msgid "The server_name in the current configuration must be the domain name you need to get the certificate, supportmultiple domains."
 msgstr ""
 msgstr ""
 
 
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:50
 #: src/views/preference/BasicSettings.vue:50
-#: src/views/preference/OpenAISettings.vue:36
-#: src/views/preference/OpenAISettings.vue:48
-msgid "The url is not valid"
+msgid "The url is invalid"
+msgstr ""
+
+#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:54
+msgid "The url is invalid."
 msgstr ""
 msgstr ""
 
 
 #: src/language/constants.ts:2
 #: src/language/constants.ts:2
@@ -1668,7 +1692,7 @@ msgstr ""
 msgid "To make sure the certification auto-renewal can work normally, we need to add a location which can proxy the request from authority to backend, and we need to save this file and reload the Nginx. Are you sure you want to continue?"
 msgid "To make sure the certification auto-renewal can work normally, we need to add a location which can proxy the request from authority to backend, and we need to save this file and reload the Nginx. Are you sure you want to continue?"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:66
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
@@ -1688,7 +1712,7 @@ msgstr ""
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/DomainList.vue:41
 #: src/views/domain/DomainList.vue:41
-#: src/views/environment/Environment.vue:95
+#: src/views/environment/Environment.vue:122
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/StreamList.vue:41
 #: src/views/stream/StreamList.vue:41
 #: src/views/user/User.vue:37
 #: src/views/user/User.vue:37
@@ -1721,11 +1745,11 @@ msgstr ""
 msgid "Uptime:"
 msgid "Uptime:"
 msgstr ""
 msgstr ""
 
 
-#: src/views/environment/Environment.vue:21
+#: src/views/environment/Environment.vue:22
 msgid "URL"
 msgid "URL"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "User"
 msgid "User"
 msgstr ""
 msgstr ""
 
 
@@ -1776,7 +1800,7 @@ msgid "We will remove the HTTPChallenge configuration from this file and reload
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:27
 #: src/views/dashboard/ServerAnalytic.vue:27
-#: src/views/dashboard/ServerAnalytic.vue:365
+#: src/views/dashboard/ServerAnalytic.vue:368
 msgid "Writes"
 msgid "Writes"
 msgstr ""
 msgstr ""
 
 

+ 112 - 85
app/src/language/ru_RU/app.po

@@ -18,7 +18,7 @@ msgid "Access Logs"
 msgstr "Журнал доступа"
 msgstr "Журнал доступа"
 
 
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
-#: src/views/certificate/ACMEUserSelector.vue:79
+#: src/views/certificate/ACMEUserSelector.vue:84
 #, fuzzy
 #, fuzzy
 msgid "ACME User"
 msgid "ACME User"
 msgstr "Пользователь"
 msgstr "Пользователь"
@@ -26,7 +26,7 @@ msgstr "Пользователь"
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
-#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:102
+#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:35
 #: src/views/notification/Notification.vue:35
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
@@ -74,7 +74,7 @@ msgstr "Дополнительно"
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Расширенный режим"
 msgstr "Расширенный режим"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:39
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr ""
 msgstr ""
 
 
@@ -82,11 +82,11 @@ msgstr ""
 msgid "API Document"
 msgid "API Document"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:45
+#: src/views/preference/OpenAISettings.vue:51
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:63
 msgid "API Token"
 msgid "API Token"
 msgstr ""
 msgstr ""
 
 
@@ -100,7 +100,7 @@ msgstr ""
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Вы уверены, что хотите удалить все уведомления?"
 msgstr "Вы уверены, что хотите удалить все уведомления?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:267
+#: src/components/ChatGPT/ChatGPT.vue:272
 #, fuzzy
 #, fuzzy
 msgid "Are you sure you want to clear the record of chat?"
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Вы уверены, что хотите очистить сообщения чата?"
 msgstr "Вы уверены, что хотите очистить сообщения чата?"
@@ -134,11 +134,11 @@ msgstr "Вы уверены, что хотите удалить эту дире
 msgid "Are you sure you want to remove this location?"
 msgid "Are you sure you want to remove this location?"
 msgstr "Вы уверены, что хотите удалить эту директиву?"
 msgstr "Вы уверены, что хотите удалить эту директиву?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:211
+#: src/components/ChatGPT/ChatGPT.vue:216
 msgid "Ask ChatGPT for Help"
 msgid "Ask ChatGPT for Help"
 msgstr "Обратитесь за помощью к ChatGPT"
 msgstr "Обратитесь за помощью к ChatGPT"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "Assistant"
 msgid "Assistant"
 msgstr "Ассистент"
 msgstr "Ассистент"
 
 
@@ -147,7 +147,7 @@ msgstr "Ассистент"
 msgid "Author"
 msgid "Author"
 msgstr "Автор"
 msgstr "Автор"
 
 
-#: src/views/domain/cert/ChangeCert.vue:34
+#: src/views/domain/cert/ChangeCert.vue:33
 msgid "Auto Cert"
 msgid "Auto Cert"
 msgstr "Авто Сертификат"
 msgstr "Авто Сертификат"
 
 
@@ -181,7 +181,7 @@ msgstr "Основная информация"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:94
+#: src/views/preference/Preference.vue:101
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Basic"
 msgid "Basic"
@@ -209,10 +209,10 @@ msgstr ""
 msgid "CADir"
 msgid "CADir"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:248
+#: src/components/ChatGPT/ChatGPT.vue:253
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:102
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:153
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/RightSettings.vue:51
 #: src/views/domain/components/RightSettings.vue:51
@@ -256,8 +256,8 @@ msgstr "Список"
 msgid "Challenge Method"
 msgid "Challenge Method"
 msgstr "Метод Challenge"
 msgstr "Метод Challenge"
 
 
-#: src/views/domain/cert/ChangeCert.vue:88
-#: src/views/domain/cert/ChangeCert.vue:92
+#: src/views/domain/cert/ChangeCert.vue:95
+#: src/views/domain/cert/ChangeCert.vue:99
 #, fuzzy
 #, fuzzy
 msgid "Change Certificate"
 msgid "Change Certificate"
 msgstr "Сертификат действителен"
 msgstr "Сертификат действителен"
@@ -274,7 +274,7 @@ msgstr "Проверить повторно"
 msgid "Cleaning environment variables"
 msgid "Cleaning environment variables"
 msgstr "Очистка переменных среды"
 msgstr "Очистка переменных среды"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:271
+#: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/Notification/Notification.vue:89
 #: src/components/Notification/Notification.vue:89
 #: src/views/notification/Notification.vue:75
 #: src/views/notification/Notification.vue:75
 msgid "Clear"
 msgid "Clear"
@@ -319,7 +319,7 @@ msgstr "Конфигурации"
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Настроить SSL"
 msgstr "Настроить SSL"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Connected"
 msgid "Connected"
 msgstr "Подключено"
 msgstr "Подключено"
 
 
@@ -333,7 +333,7 @@ msgstr "Содержание"
 msgid "Core Upgrade"
 msgid "Core Upgrade"
 msgstr "Обновление ядра"
 msgstr "Обновление ядра"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:293
+#: src/views/dashboard/ServerAnalytic.vue:296
 msgid "CPU Status"
 msgid "CPU Status"
 msgstr "Нагрузка CPU"
 msgstr "Нагрузка CPU"
 
 
@@ -375,6 +375,12 @@ msgstr "Текущяя версия"
 msgid "Custom"
 msgid "Custom"
 msgstr "Пользовательский"
 msgstr "Пользовательский"
 
 
+#: src/views/preference/BasicSettings.vue:121
+msgid ""
+"Customize the name of local server to be displayed in the environment "
+"indicator."
+msgstr ""
+
 #: src/routes/index.ts:39
 #: src/routes/index.ts:39
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Доска"
 msgstr "Доска"
@@ -466,9 +472,9 @@ msgstr "Отключить"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "Не удалось отключить автоматическое продление для %{name}"
 msgstr "Не удалось отключить автоматическое продление для %{name}"
 
 
-#: src/views/domain/cert/ChangeCert.vue:45 src/views/domain/DomainEdit.vue:185
-#: src/views/domain/DomainList.vue:33 src/views/stream/StreamEdit.vue:177
-#: src/views/stream/StreamList.vue:33
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
+#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Отключено"
 msgstr "Отключено"
 
 
@@ -479,7 +485,7 @@ msgstr "Отключено"
 msgid "Disabled successfully"
 msgid "Disabled successfully"
 msgstr "Отключено успешно"
 msgstr "Отключено успешно"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:358
+#: src/views/dashboard/ServerAnalytic.vue:361
 msgid "Disk IO"
 msgid "Disk IO"
 msgstr "Нагрузка на Диск IO"
 msgstr "Нагрузка на Диск IO"
 
 
@@ -662,9 +668,10 @@ msgstr "Активировано успешно"
 msgid "Enable TLS"
 msgid "Enable TLS"
 msgstr "Включить TLS"
 msgstr "Включить TLS"
 
 
-#: src/views/domain/cert/ChangeCert.vue:41
+#: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
@@ -684,11 +691,11 @@ msgstr "Активировано успешно"
 msgid "Encrypt website with Let's Encrypt"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Использовать для сайта Let's Encrypt"
 msgstr "Использовать для сайта Let's Encrypt"
 
 
-#: src/routes/index.ts:212 src/views/environment/Environment.vue:110
+#: src/routes/index.ts:212 src/views/environment/Environment.vue:137
 msgid "Environment"
 msgid "Environment"
 msgstr "Окружение"
 msgstr "Окружение"
 
 
-#: src/views/dashboard/Environments.vue:71
+#: src/views/dashboard/Environments.vue:82
 #, fuzzy
 #, fuzzy
 msgid "Environments"
 msgid "Environments"
 msgstr "Комментарии"
 msgstr "Комментарии"
@@ -917,7 +924,7 @@ msgstr "Последняя проверка в"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Оставьте пустым без изменений"
 msgstr "Оставьте пустым без изменений"
 
 
-#: src/views/preference/OpenAISettings.vue:41
+#: src/views/preference/OpenAISettings.vue:47
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Оставьте пустым для значения по умолчанию: https://api.openai.com/"
 msgstr "Оставьте пустым для значения по умолчанию: https://api.openai.com/"
 
 
@@ -932,7 +939,7 @@ msgstr "Оставьте пустым без изменений"
 msgid "License"
 msgid "License"
 msgstr "Лицензия"
 msgstr "Лицензия"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Link Start"
 msgid "Link Start"
 msgstr ""
 msgstr ""
 
 
@@ -946,8 +953,8 @@ msgstr ""
 msgid "Load Average:"
 msgid "Load Average:"
 msgstr "Средняя нагрузка:"
 msgstr "Средняя нагрузка:"
 
 
-#: src/components/EnvIndicator/EnvIndicator.vue:38
-#: src/components/NodeSelector/NodeSelector.vue:51
+#: src/components/EnvIndicator/EnvIndicator.vue:40
+#: src/components/NodeSelector/NodeSelector.vue:71
 #, fuzzy
 #, fuzzy
 msgid "Local"
 msgid "Local"
 msgstr "Location"
 msgstr "Location"
@@ -977,7 +984,7 @@ msgstr "Авторизация успешна"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Выход выполнен успешно"
 msgstr "Выход выполнен успешно"
 
 
-#: src/views/preference/Preference.vue:112
+#: src/views/preference/Preference.vue:119
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1023,6 +1030,7 @@ msgid "Managed Certificate"
 msgstr "Управление сертификатами"
 msgstr "Управление сертификатами"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
+#: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
 msgstr "Память"
 msgstr "Память"
 
 
@@ -1034,12 +1042,12 @@ msgstr "Память и хранилище"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:26
+#: src/views/preference/OpenAISettings.vue:27
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Расширенный режим"
 msgstr "Расширенный режим"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:244
+#: src/components/ChatGPT/ChatGPT.vue:249
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #, fuzzy
 #, fuzzy
@@ -1069,7 +1077,7 @@ msgstr "Одиночная директива"
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
-#: src/views/domain/cert/ChangeCert.vue:18
+#: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
@@ -1081,19 +1089,19 @@ msgstr "Одиночная директива"
 msgid "Name"
 msgid "Name"
 msgstr "Имя"
 msgstr "Имя"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:319
+#: src/views/dashboard/ServerAnalytic.vue:322
 msgid "Network"
 msgid "Network"
 msgstr "Сеть"
 msgstr "Сеть"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:261
+#: src/views/dashboard/ServerAnalytic.vue:264
 msgid "Network Statistics"
 msgid "Network Statistics"
 msgstr "Статистика сети"
 msgstr "Статистика сети"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:268
+#: src/views/dashboard/ServerAnalytic.vue:271
 msgid "Network Total Receive"
 msgid "Network Total Receive"
 msgstr "Всего получено"
 msgstr "Всего получено"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:274
+#: src/views/dashboard/ServerAnalytic.vue:277
 msgid "Network Total Send"
 msgid "Network Total Send"
 msgstr "Всего отправлено"
 msgstr "Всего отправлено"
 
 
@@ -1107,7 +1115,7 @@ msgstr "Вышла новая версия"
 msgid "Next"
 msgid "Next"
 msgstr "Дальше"
 msgstr "Дальше"
 
 
-#: src/views/preference/Preference.vue:100
+#: src/views/preference/Preference.vue:107
 #, fuzzy
 #, fuzzy
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Журнал"
 msgstr "Журнал"
@@ -1121,7 +1129,7 @@ msgstr "Путь для Nginx Access Log"
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Ошибка синтаксического анализа конфигурации Nginx"
 msgstr "Ошибка синтаксического анализа конфигурации Nginx"
 
 
-#: src/components/NginxControl/NginxControl.vue:62
+#: src/components/NginxControl/NginxControl.vue:65
 msgid "Nginx Control"
 msgid "Nginx Control"
 msgstr "Управление Nginx"
 msgstr "Управление Nginx"
 
 
@@ -1133,17 +1141,17 @@ msgstr "Путь для Nginx Error Log"
 msgid "Nginx Log"
 msgid "Nginx Log"
 msgstr "Журнал"
 msgstr "Журнал"
 
 
-#: src/components/NginxControl/NginxControl.vue:22
+#: src/components/NginxControl/NginxControl.vue:23
 #, fuzzy
 #, fuzzy
 msgid "Nginx reloaded successfully"
 msgid "Nginx reloaded successfully"
 msgstr "Nginx перезагружен успешно"
 msgstr "Nginx перезагружен успешно"
 
 
-#: src/components/NginxControl/NginxControl.vue:36
+#: src/components/NginxControl/NginxControl.vue:39
 #, fuzzy
 #, fuzzy
 msgid "Nginx restarted successfully"
 msgid "Nginx restarted successfully"
 msgstr "Nginx успешно перезапущен"
 msgstr "Nginx успешно перезапущен"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:265
+#: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/Notification/Notification.vue:82
 #: src/components/Notification/Notification.vue:82
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
@@ -1196,22 +1204,22 @@ msgstr "Получить сертификат"
 msgid "Obtaining certificate"
 msgid "Obtaining certificate"
 msgstr "Получение сертификата"
 msgstr "Получение сертификата"
 
 
-#: src/components/NodeSelector/NodeSelector.vue:75
-#: src/views/dashboard/Environments.vue:95
-#: src/views/environment/Environment.vue:86
+#: src/components/NodeSelector/NodeSelector.vue:95
+#: src/views/dashboard/Environments.vue:106
+#: src/views/environment/Environment.vue:88
 msgid "Offline"
 msgid "Offline"
 msgstr ""
 msgstr ""
 
 
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:154
 msgid "Ok"
 msgid "Ok"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:266
+#: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/Notification/Notification.vue:83
 #: src/components/Notification/Notification.vue:83
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:103
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/RightSettings.vue:50
 #: src/views/domain/components/RightSettings.vue:50
@@ -1230,14 +1238,14 @@ msgstr ""
 msgid "Once the verification is complete, the records will be removed."
 msgid "Once the verification is complete, the records will be removed."
 msgstr ""
 msgstr ""
 
 
-#: src/components/NodeSelector/NodeSelector.vue:54
-#: src/components/NodeSelector/NodeSelector.vue:69
-#: src/views/dashboard/Environments.vue:88
-#: src/views/environment/Environment.vue:82
+#: src/components/NodeSelector/NodeSelector.vue:74
+#: src/components/NodeSelector/NodeSelector.vue:89
+#: src/views/dashboard/Environments.vue:99
+#: src/views/environment/Environment.vue:84
 msgid "Online"
 msgid "Online"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/Preference.vue:106
+#: src/views/preference/Preference.vue:113
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr ""
 msgstr ""
 
 
@@ -1333,7 +1341,7 @@ msgstr ""
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:89
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
 msgid "Preference"
 msgid "Preference"
 msgstr "Настройки"
 msgstr "Настройки"
 
 
@@ -1359,12 +1367,12 @@ msgid "Provider"
 msgstr "Провайдер"
 msgstr "Провайдер"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:28
 #: src/views/dashboard/ServerAnalytic.vue:28
-#: src/views/dashboard/ServerAnalytic.vue:375
+#: src/views/dashboard/ServerAnalytic.vue:378
 msgid "Reads"
 msgid "Reads"
 msgstr "Чтение"
 msgstr "Чтение"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:24
 #: src/views/dashboard/ServerAnalytic.vue:24
-#: src/views/dashboard/ServerAnalytic.vue:326
+#: src/views/dashboard/ServerAnalytic.vue:329
 msgid "Receive"
 msgid "Receive"
 msgstr "Принято"
 msgstr "Принято"
 
 
@@ -1381,7 +1389,7 @@ msgstr "Успешно сохранено"
 msgid "Recursive Nameservers"
 msgid "Recursive Nameservers"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:278
+#: src/components/ChatGPT/ChatGPT.vue:283
 msgid "Regenerate response"
 msgid "Regenerate response"
 msgstr "Восстановить ответ"
 msgstr "Восстановить ответ"
 
 
@@ -1418,12 +1426,12 @@ msgstr "Переустановить"
 msgid "Release Note"
 msgid "Release Note"
 msgstr "Что нового"
 msgstr "Что нового"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:254
-#: src/components/NginxControl/NginxControl.vue:97
+#: src/components/ChatGPT/ChatGPT.vue:259
+#: src/components/NginxControl/NginxControl.vue:100
 msgid "Reload"
 msgid "Reload"
 msgstr "Перегрузить"
 msgstr "Перегрузить"
 
 
-#: src/components/NginxControl/NginxControl.vue:71
+#: src/components/NginxControl/NginxControl.vue:74
 msgid "Reloading"
 msgid "Reloading"
 msgstr "Перезагружается"
 msgstr "Перезагружается"
 
 
@@ -1471,11 +1479,11 @@ msgstr "Запрос с неправильными параметрами"
 msgid "Reset"
 msgid "Reset"
 msgstr "Сброс"
 msgstr "Сброс"
 
 
-#: src/components/NginxControl/NginxControl.vue:90
+#: src/components/NginxControl/NginxControl.vue:93
 msgid "Restart"
 msgid "Restart"
 msgstr "Перезапуск"
 msgstr "Перезапуск"
 
 
-#: src/components/NginxControl/NginxControl.vue:76
+#: src/components/NginxControl/NginxControl.vue:79
 msgid "Restarting"
 msgid "Restarting"
 msgstr "Перезапускается"
 msgstr "Перезапускается"
 
 
@@ -1484,15 +1492,15 @@ msgstr "Перезапускается"
 msgid "Run Mode"
 msgid "Run Mode"
 msgstr "Расширенный режим"
 msgstr "Расширенный режим"
 
 
-#: src/components/NginxControl/NginxControl.vue:66
+#: src/components/NginxControl/NginxControl.vue:69
 msgid "Running"
 msgid "Running"
 msgstr "Выполняется"
 msgstr "Выполняется"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:247
+#: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:123 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
 msgid "Save"
 msgid "Save"
 msgstr "Сохранить"
 msgstr "Сохранить"
 
 
@@ -1508,7 +1516,7 @@ msgstr "Ошибка сохранения %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:45
 #: src/views/certificate/CertificateEditor.vue:45
-#: src/views/preference/Preference.vue:59
+#: src/views/preference/Preference.vue:66
 #, fuzzy
 #, fuzzy
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Успешно сохранено"
 msgstr "Успешно сохранено"
@@ -1524,24 +1532,24 @@ msgstr "Успешно сохранено"
 msgid "SDK"
 msgid "SDK"
 msgstr ""
 msgstr ""
 
 
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:104
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:155
 msgid "Selector"
 msgid "Selector"
 msgstr "Выбор"
 msgstr "Выбор"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:25
 #: src/views/dashboard/ServerAnalytic.vue:25
-#: src/views/dashboard/ServerAnalytic.vue:336
+#: src/views/dashboard/ServerAnalytic.vue:339
 msgid "Send"
 msgid "Send"
 msgstr "Отправлено"
 msgstr "Отправлено"
 
 
-#: src/components/NginxControl/NginxControl.vue:28
-#: src/components/NginxControl/NginxControl.vue:42
+#: src/components/NginxControl/NginxControl.vue:29
+#: src/components/NginxControl/NginxControl.vue:45
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:63
+#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:70
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
@@ -1551,6 +1559,11 @@ msgstr "Ошибка сервера"
 msgid "Server Info"
 msgid "Server Info"
 msgstr "Информация о сервере"
 msgstr "Информация о сервере"
 
 
+#: src/views/preference/BasicSettings.vue:117
+#, fuzzy
+msgid "Server Name"
+msgstr "Информация о сервере"
+
 #: src/views/domain/cert/components/ObtainCert.vue:102
 #: src/views/domain/cert/components/ObtainCert.vue:102
 msgid "server_name not found in directives"
 msgid "server_name not found in directives"
 msgstr "server_name не нашел в директивах"
 msgstr "server_name не нашел в директивах"
@@ -1625,15 +1638,16 @@ msgstr "Таблица"
 
 
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
-#: src/views/environment/Environment.vue:75 src/views/stream/StreamList.vue:22
+#: src/views/environment/Environment.vue:76 src/views/stream/StreamList.vue:22
 msgid "Status"
 msgid "Status"
 msgstr "Статус"
 msgstr "Статус"
 
 
-#: src/components/NginxControl/NginxControl.vue:81
+#: src/components/NginxControl/NginxControl.vue:84
 msgid "Stopped"
 msgid "Stopped"
 msgstr "Остановлен"
 msgstr "Остановлен"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:243
+#: src/views/dashboard/ServerAnalytic.vue:245
+#: src/views/dashboard/ServerAnalytic.vue:246
 msgid "Storage"
 msgid "Storage"
 msgstr "Хранилище"
 msgstr "Хранилище"
 
 
@@ -1646,7 +1660,8 @@ msgstr "Название темы: %{name}"
 msgid "Success"
 msgid "Success"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:230
+#: src/views/dashboard/ServerAnalytic.vue:231
+#: src/views/dashboard/ServerAnalytic.vue:232
 msgid "Swap"
 msgid "Swap"
 msgstr "Своп"
 msgstr "Своп"
 
 
@@ -1697,6 +1712,10 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "Путь к ключу сертификата SSL"
 msgstr "Путь к ключу сертификата SSL"
 
 
+#: src/views/preference/OpenAISettings.vue:30
+msgid "The model name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/certificate/CertificateEditor.vue:165
 #: src/views/certificate/CertificateEditor.vue:165
 #, fuzzy
 #, fuzzy
 msgid "The path exists, but the file is not a certificate"
 msgid "The path exists, but the file is not a certificate"
@@ -1706,6 +1725,10 @@ msgstr "Путь к ключу сертификата SSL"
 msgid "The path exists, but the file is not a private key"
 msgid "The path exists, but the file is not a private key"
 msgstr "Путь существует, но файл не является приватным ключом"
 msgstr "Путь существует, но файл не является приватным ключом"
 
 
+#: src/views/preference/BasicSettings.vue:120
+msgid "The server name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #, fuzzy
 #, fuzzy
 msgid ""
 msgid ""
@@ -1717,9 +1740,14 @@ msgstr ""
 
 
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:50
 #: src/views/preference/BasicSettings.vue:50
-#: src/views/preference/OpenAISettings.vue:36
-#: src/views/preference/OpenAISettings.vue:48
-msgid "The url is not valid"
+#, fuzzy
+msgid "The url is invalid"
+msgstr "URL-адрес неверный"
+
+#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:54
+#, fuzzy
+msgid "The url is invalid."
 msgstr "URL-адрес неверный"
 msgstr "URL-адрес неверный"
 
 
 #: src/language/constants.ts:2
 #: src/language/constants.ts:2
@@ -1761,7 +1789,7 @@ msgid ""
 "continue?"
 "continue?"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:66
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
@@ -1778,7 +1806,7 @@ msgstr "Тип"
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/components/RightSettings.vue:86
-#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:95
+#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:122
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 msgid "Updated at"
 msgid "Updated at"
@@ -1811,11 +1839,11 @@ msgstr ""
 msgid "Uptime:"
 msgid "Uptime:"
 msgstr "Аптайм:"
 msgstr "Аптайм:"
 
 
-#: src/views/environment/Environment.vue:21
+#: src/views/environment/Environment.vue:22
 msgid "URL"
 msgid "URL"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 #, fuzzy
 #, fuzzy
 msgid "User"
 msgid "User"
 msgstr "Пользователь"
 msgstr "Пользователь"
@@ -1873,7 +1901,7 @@ msgid ""
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:27
 #: src/views/dashboard/ServerAnalytic.vue:27
-#: src/views/dashboard/ServerAnalytic.vue:365
+#: src/views/dashboard/ServerAnalytic.vue:368
 msgid "Writes"
 msgid "Writes"
 msgstr "Запись"
 msgstr "Запись"
 
 
@@ -1899,6 +1927,9 @@ msgstr "Вы используете последнюю версию"
 msgid "You can check Nginx UI upgrade at this page."
 msgid "You can check Nginx UI upgrade at this page."
 msgstr "Вы можете проверить обновление Nginx UI на этой странице."
 msgstr "Вы можете проверить обновление Nginx UI на этой странице."
 
 
+#~ msgid "The url is not valid"
+#~ msgstr "URL-адрес неверный"
+
 #, fuzzy
 #, fuzzy
 #~ msgid "Save Successfully"
 #~ msgid "Save Successfully"
 #~ msgstr "Успешно сохранено"
 #~ msgstr "Успешно сохранено"
@@ -1907,10 +1938,6 @@ msgstr "Вы можете проверить обновление Nginx UI на
 #~ msgid "Table"
 #~ msgid "Table"
 #~ msgstr "Таблица"
 #~ msgstr "Таблица"
 
 
-#, fuzzy
-#~ msgid "Server"
-#~ msgstr "Информация о сервере"
-
 #, fuzzy
 #, fuzzy
 #~ msgid "Leave blank will not change anything."
 #~ msgid "Leave blank will not change anything."
 #~ msgstr "Оставьте пустым без изменений"
 #~ msgstr "Оставьте пустым без изменений"

+ 107 - 85
app/src/language/vi_VN/app.po

@@ -18,7 +18,7 @@ msgid "Access Logs"
 msgstr "Log truy cập"
 msgstr "Log truy cập"
 
 
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
-#: src/views/certificate/ACMEUserSelector.vue:79
+#: src/views/certificate/ACMEUserSelector.vue:84
 #, fuzzy
 #, fuzzy
 msgid "ACME User"
 msgid "ACME User"
 msgstr "Người dùng"
 msgstr "Người dùng"
@@ -26,7 +26,7 @@ msgstr "Người dùng"
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
-#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:102
+#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:35
 #: src/views/notification/Notification.vue:35
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
@@ -74,7 +74,7 @@ msgstr "Tùy chọn bổ sung"
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "Nâng cao"
 msgstr "Nâng cao"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:39
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr ""
 msgstr ""
 
 
@@ -82,11 +82,11 @@ msgstr ""
 msgid "API Document"
 msgid "API Document"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:45
+#: src/views/preference/OpenAISettings.vue:51
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:63
 msgid "API Token"
 msgid "API Token"
 msgstr ""
 msgstr ""
 
 
@@ -100,7 +100,7 @@ msgstr ""
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "Bạn có chắc chắn muốn xóa tất cả thông báo không ?"
 msgstr "Bạn có chắc chắn muốn xóa tất cả thông báo không ?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:267
+#: src/components/ChatGPT/ChatGPT.vue:272
 #, fuzzy
 #, fuzzy
 msgid "Are you sure you want to clear the record of chat?"
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "Bạn có chắc chắn muốn xóa lịch sử trò chuyện không ?"
 msgstr "Bạn có chắc chắn muốn xóa lịch sử trò chuyện không ?"
@@ -134,11 +134,11 @@ msgstr "Bạn chắc chắn muốn xoá directive này ?"
 msgid "Are you sure you want to remove this location?"
 msgid "Are you sure you want to remove this location?"
 msgstr "Bạn chắc chắn muốn xoá location này ?"
 msgstr "Bạn chắc chắn muốn xoá location này ?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:211
+#: src/components/ChatGPT/ChatGPT.vue:216
 msgid "Ask ChatGPT for Help"
 msgid "Ask ChatGPT for Help"
 msgstr "Hỏi ChatGPT"
 msgstr "Hỏi ChatGPT"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "Assistant"
 msgid "Assistant"
 msgstr "Trợ lý"
 msgstr "Trợ lý"
 
 
@@ -147,7 +147,7 @@ msgstr "Trợ lý"
 msgid "Author"
 msgid "Author"
 msgstr "Tác giả"
 msgstr "Tác giả"
 
 
-#: src/views/domain/cert/ChangeCert.vue:34
+#: src/views/domain/cert/ChangeCert.vue:33
 msgid "Auto Cert"
 msgid "Auto Cert"
 msgstr "Tự động ký chứng chỉ SSL"
 msgstr "Tự động ký chứng chỉ SSL"
 
 
@@ -181,7 +181,7 @@ msgstr "Thông tin"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:94
+#: src/views/preference/Preference.vue:101
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 #, fuzzy
 #, fuzzy
 msgid "Basic"
 msgid "Basic"
@@ -209,10 +209,10 @@ msgstr ""
 msgid "CADir"
 msgid "CADir"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:248
+#: src/components/ChatGPT/ChatGPT.vue:253
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:102
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:153
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/RightSettings.vue:51
 #: src/views/domain/components/RightSettings.vue:51
@@ -256,8 +256,8 @@ msgstr "Danh sách chứng chỉ"
 msgid "Challenge Method"
 msgid "Challenge Method"
 msgstr "Phương pháp xác thực"
 msgstr "Phương pháp xác thực"
 
 
-#: src/views/domain/cert/ChangeCert.vue:88
-#: src/views/domain/cert/ChangeCert.vue:92
+#: src/views/domain/cert/ChangeCert.vue:95
+#: src/views/domain/cert/ChangeCert.vue:99
 #, fuzzy
 #, fuzzy
 msgid "Change Certificate"
 msgid "Change Certificate"
 msgstr "Thay đổi chứng chỉ"
 msgstr "Thay đổi chứng chỉ"
@@ -274,7 +274,7 @@ msgstr "Kiểm tra lại"
 msgid "Cleaning environment variables"
 msgid "Cleaning environment variables"
 msgstr "Xoá các biến môi trường"
 msgstr "Xoá các biến môi trường"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:271
+#: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/Notification/Notification.vue:89
 #: src/components/Notification/Notification.vue:89
 #: src/views/notification/Notification.vue:75
 #: src/views/notification/Notification.vue:75
 msgid "Clear"
 msgid "Clear"
@@ -319,7 +319,7 @@ msgstr "Cấu hình"
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "Cấu hình SSL"
 msgstr "Cấu hình SSL"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Connected"
 msgid "Connected"
 msgstr "Đã kết nối"
 msgstr "Đã kết nối"
 
 
@@ -333,7 +333,7 @@ msgstr "Nội dung"
 msgid "Core Upgrade"
 msgid "Core Upgrade"
 msgstr "Cập nhật core"
 msgstr "Cập nhật core"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:293
+#: src/views/dashboard/ServerAnalytic.vue:296
 msgid "CPU Status"
 msgid "CPU Status"
 msgstr "Trạng thái CPU"
 msgstr "Trạng thái CPU"
 
 
@@ -375,6 +375,12 @@ msgstr "Phiên bản hiện tại"
 msgid "Custom"
 msgid "Custom"
 msgstr "Tuỳ chỉnh"
 msgstr "Tuỳ chỉnh"
 
 
+#: src/views/preference/BasicSettings.vue:121
+msgid ""
+"Customize the name of local server to be displayed in the environment "
+"indicator."
+msgstr ""
+
 #: src/routes/index.ts:39
 #: src/routes/index.ts:39
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "Bảng điều khiển"
 msgstr "Bảng điều khiển"
@@ -467,9 +473,9 @@ msgstr "Tắt"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "Tắt tự động gia hạn SSL cho %{name} thất bại"
 msgstr "Tắt tự động gia hạn SSL cho %{name} thất bại"
 
 
-#: src/views/domain/cert/ChangeCert.vue:45 src/views/domain/DomainEdit.vue:185
-#: src/views/domain/DomainList.vue:33 src/views/stream/StreamEdit.vue:177
-#: src/views/stream/StreamList.vue:33
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
+#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "Đã tắt"
 msgstr "Đã tắt"
 
 
@@ -480,7 +486,7 @@ msgstr "Đã tắt"
 msgid "Disabled successfully"
 msgid "Disabled successfully"
 msgstr "Đã tắt thành công"
 msgstr "Đã tắt thành công"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:358
+#: src/views/dashboard/ServerAnalytic.vue:361
 msgid "Disk IO"
 msgid "Disk IO"
 msgstr "Disk IO"
 msgstr "Disk IO"
 
 
@@ -663,9 +669,10 @@ msgstr "Đã bật"
 msgid "Enable TLS"
 msgid "Enable TLS"
 msgstr "Bật TLS"
 msgstr "Bật TLS"
 
 
-#: src/views/domain/cert/ChangeCert.vue:41
+#: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
@@ -685,11 +692,11 @@ msgstr "Đã bật"
 msgid "Encrypt website with Let's Encrypt"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "Bảo mật trang web với Let's Encrypt"
 msgstr "Bảo mật trang web với Let's Encrypt"
 
 
-#: src/routes/index.ts:212 src/views/environment/Environment.vue:110
+#: src/routes/index.ts:212 src/views/environment/Environment.vue:137
 msgid "Environment"
 msgid "Environment"
 msgstr "Environment"
 msgstr "Environment"
 
 
-#: src/views/dashboard/Environments.vue:71
+#: src/views/dashboard/Environments.vue:82
 #, fuzzy
 #, fuzzy
 msgid "Environments"
 msgid "Environments"
 msgstr "Environments"
 msgstr "Environments"
@@ -919,7 +926,7 @@ msgstr "Kiểm tra lần cuối lúc"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "Bỏ trống nếu không thay đổi"
 msgstr "Bỏ trống nếu không thay đổi"
 
 
-#: src/views/preference/OpenAISettings.vue:41
+#: src/views/preference/OpenAISettings.vue:47
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "Bỏ trống để sử dụng địa chỉ mặc định: https://api.openai.com/"
 msgstr "Bỏ trống để sử dụng địa chỉ mặc định: https://api.openai.com/"
 
 
@@ -934,7 +941,7 @@ msgstr "Bỏ trống nếu không thay đổi"
 msgid "License"
 msgid "License"
 msgstr "Giấy phép"
 msgstr "Giấy phép"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Link Start"
 msgid "Link Start"
 msgstr "Liên kết bắt đầu"
 msgstr "Liên kết bắt đầu"
 
 
@@ -948,8 +955,8 @@ msgstr ""
 msgid "Load Average:"
 msgid "Load Average:"
 msgstr "Tải trung bình:"
 msgstr "Tải trung bình:"
 
 
-#: src/components/EnvIndicator/EnvIndicator.vue:38
-#: src/components/NodeSelector/NodeSelector.vue:51
+#: src/components/EnvIndicator/EnvIndicator.vue:40
+#: src/components/NodeSelector/NodeSelector.vue:71
 #, fuzzy
 #, fuzzy
 msgid "Local"
 msgid "Local"
 msgstr "Location"
 msgstr "Location"
@@ -979,7 +986,7 @@ msgstr "Đăng nhập thành công"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "Đã đăng xuất"
 msgstr "Đã đăng xuất"
 
 
-#: src/views/preference/Preference.vue:112
+#: src/views/preference/Preference.vue:119
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -1024,6 +1031,7 @@ msgid "Managed Certificate"
 msgstr ""
 msgstr ""
 
 
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
+#: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
 msgstr "Memory"
 msgstr "Memory"
 
 
@@ -1035,12 +1043,12 @@ msgstr "Memory và Storage"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:26
+#: src/views/preference/OpenAISettings.vue:27
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "Run Mode"
 msgstr "Run Mode"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:244
+#: src/components/ChatGPT/ChatGPT.vue:249
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #, fuzzy
 #, fuzzy
@@ -1070,7 +1078,7 @@ msgstr "Single Directive"
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
-#: src/views/domain/cert/ChangeCert.vue:18
+#: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
@@ -1082,19 +1090,19 @@ msgstr "Single Directive"
 msgid "Name"
 msgid "Name"
 msgstr "Tên"
 msgstr "Tên"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:319
+#: src/views/dashboard/ServerAnalytic.vue:322
 msgid "Network"
 msgid "Network"
 msgstr "Mạng"
 msgstr "Mạng"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:261
+#: src/views/dashboard/ServerAnalytic.vue:264
 msgid "Network Statistics"
 msgid "Network Statistics"
 msgstr "Thống kê mạng"
 msgstr "Thống kê mạng"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:268
+#: src/views/dashboard/ServerAnalytic.vue:271
 msgid "Network Total Receive"
 msgid "Network Total Receive"
 msgstr "Tổng lưu lượng mạng đã nhận"
 msgstr "Tổng lưu lượng mạng đã nhận"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:274
+#: src/views/dashboard/ServerAnalytic.vue:277
 msgid "Network Total Send"
 msgid "Network Total Send"
 msgstr "Tổng lưu lượng mạng đã gửi"
 msgstr "Tổng lưu lượng mạng đã gửi"
 
 
@@ -1108,7 +1116,7 @@ msgstr "Đã có phiên bản mới"
 msgid "Next"
 msgid "Next"
 msgstr "Tiếp theo"
 msgstr "Tiếp theo"
 
 
-#: src/views/preference/Preference.vue:100
+#: src/views/preference/Preference.vue:107
 msgid "Nginx"
 msgid "Nginx"
 msgstr ""
 msgstr ""
 
 
@@ -1121,7 +1129,7 @@ msgstr "Vị trí lưu log truy cập (Access log) của Nginx"
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Lỗi phân tích cú pháp cấu hình Nginx"
 msgstr "Lỗi phân tích cú pháp cấu hình Nginx"
 
 
-#: src/components/NginxControl/NginxControl.vue:62
+#: src/components/NginxControl/NginxControl.vue:65
 msgid "Nginx Control"
 msgid "Nginx Control"
 msgstr ""
 msgstr ""
 
 
@@ -1133,17 +1141,17 @@ msgstr "Vị trí lưu log lỗi (Error log) của Nginx"
 msgid "Nginx Log"
 msgid "Nginx Log"
 msgstr ""
 msgstr ""
 
 
-#: src/components/NginxControl/NginxControl.vue:22
+#: src/components/NginxControl/NginxControl.vue:23
 #, fuzzy
 #, fuzzy
 msgid "Nginx reloaded successfully"
 msgid "Nginx reloaded successfully"
 msgstr "Reload Nginx thành công"
 msgstr "Reload Nginx thành công"
 
 
-#: src/components/NginxControl/NginxControl.vue:36
+#: src/components/NginxControl/NginxControl.vue:39
 #, fuzzy
 #, fuzzy
 msgid "Nginx restarted successfully"
 msgid "Nginx restarted successfully"
 msgstr "Restart Nginx thành công"
 msgstr "Restart Nginx thành công"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:265
+#: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/Notification/Notification.vue:82
 #: src/components/Notification/Notification.vue:82
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
@@ -1196,22 +1204,22 @@ msgstr "Nhận chứng chỉ"
 msgid "Obtaining certificate"
 msgid "Obtaining certificate"
 msgstr "Đang nhận chứng chỉ"
 msgstr "Đang nhận chứng chỉ"
 
 
-#: src/components/NodeSelector/NodeSelector.vue:75
-#: src/views/dashboard/Environments.vue:95
-#: src/views/environment/Environment.vue:86
+#: src/components/NodeSelector/NodeSelector.vue:95
+#: src/views/dashboard/Environments.vue:106
+#: src/views/environment/Environment.vue:88
 msgid "Offline"
 msgid "Offline"
 msgstr "Ngoại tuyến"
 msgstr "Ngoại tuyến"
 
 
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:154
 msgid "Ok"
 msgid "Ok"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:266
+#: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/Notification/Notification.vue:83
 #: src/components/Notification/Notification.vue:83
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:103
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/RightSettings.vue:50
 #: src/views/domain/components/RightSettings.vue:50
@@ -1230,14 +1238,14 @@ msgstr ""
 msgid "Once the verification is complete, the records will be removed."
 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."
 msgstr "Sau khi quá trình xác minh hoàn tất, bản ghi sẽ bị xóa."
 
 
-#: src/components/NodeSelector/NodeSelector.vue:54
-#: src/components/NodeSelector/NodeSelector.vue:69
-#: src/views/dashboard/Environments.vue:88
-#: src/views/environment/Environment.vue:82
+#: src/components/NodeSelector/NodeSelector.vue:74
+#: src/components/NodeSelector/NodeSelector.vue:89
+#: src/views/dashboard/Environments.vue:99
+#: src/views/environment/Environment.vue:84
 msgid "Online"
 msgid "Online"
 msgstr "Trực tuyến"
 msgstr "Trực tuyến"
 
 
-#: src/views/preference/Preference.vue:106
+#: src/views/preference/Preference.vue:113
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr ""
 msgstr ""
 
 
@@ -1335,7 +1343,7 @@ msgstr ""
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr ""
 msgstr ""
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:89
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
 msgid "Preference"
 msgid "Preference"
 msgstr "Cài đặt"
 msgstr "Cài đặt"
 
 
@@ -1361,12 +1369,12 @@ msgid "Provider"
 msgstr "Nhà cung cấp"
 msgstr "Nhà cung cấp"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:28
 #: src/views/dashboard/ServerAnalytic.vue:28
-#: src/views/dashboard/ServerAnalytic.vue:375
+#: src/views/dashboard/ServerAnalytic.vue:378
 msgid "Reads"
 msgid "Reads"
 msgstr "Đọc"
 msgstr "Đọc"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:24
 #: src/views/dashboard/ServerAnalytic.vue:24
-#: src/views/dashboard/ServerAnalytic.vue:326
+#: src/views/dashboard/ServerAnalytic.vue:329
 msgid "Receive"
 msgid "Receive"
 msgstr "Nhận"
 msgstr "Nhận"
 
 
@@ -1383,7 +1391,7 @@ msgstr "Xoá thành công"
 msgid "Recursive Nameservers"
 msgid "Recursive Nameservers"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:278
+#: src/components/ChatGPT/ChatGPT.vue:283
 msgid "Regenerate response"
 msgid "Regenerate response"
 msgstr "Tạo lại câu trả lời"
 msgstr "Tạo lại câu trả lời"
 
 
@@ -1420,12 +1428,12 @@ msgstr "Cài lại"
 msgid "Release Note"
 msgid "Release Note"
 msgstr "Ghi chú phát hành"
 msgstr "Ghi chú phát hành"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:254
-#: src/components/NginxControl/NginxControl.vue:97
+#: src/components/ChatGPT/ChatGPT.vue:259
+#: src/components/NginxControl/NginxControl.vue:100
 msgid "Reload"
 msgid "Reload"
 msgstr "Tải lại"
 msgstr "Tải lại"
 
 
-#: src/components/NginxControl/NginxControl.vue:71
+#: src/components/NginxControl/NginxControl.vue:74
 msgid "Reloading"
 msgid "Reloading"
 msgstr "Đang tải lại"
 msgstr "Đang tải lại"
 
 
@@ -1473,11 +1481,11 @@ msgstr "Yêu cầu có chứa tham số sai"
 msgid "Reset"
 msgid "Reset"
 msgstr "Đặt lại"
 msgstr "Đặt lại"
 
 
-#: src/components/NginxControl/NginxControl.vue:90
+#: src/components/NginxControl/NginxControl.vue:93
 msgid "Restart"
 msgid "Restart"
 msgstr "Khởi động lại"
 msgstr "Khởi động lại"
 
 
-#: src/components/NginxControl/NginxControl.vue:76
+#: src/components/NginxControl/NginxControl.vue:79
 msgid "Restarting"
 msgid "Restarting"
 msgstr "Đang khởi động lại"
 msgstr "Đang khởi động lại"
 
 
@@ -1486,15 +1494,15 @@ msgstr "Đang khởi động lại"
 msgid "Run Mode"
 msgid "Run Mode"
 msgstr "Run Mode"
 msgstr "Run Mode"
 
 
-#: src/components/NginxControl/NginxControl.vue:66
+#: src/components/NginxControl/NginxControl.vue:69
 msgid "Running"
 msgid "Running"
 msgstr "Running"
 msgstr "Running"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:247
+#: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:123 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
 msgid "Save"
 msgid "Save"
 msgstr "Lưu"
 msgstr "Lưu"
 
 
@@ -1510,7 +1518,7 @@ msgstr "Đã xảy ra lỗi khi lưu %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:45
 #: src/views/certificate/CertificateEditor.vue:45
-#: src/views/preference/Preference.vue:59
+#: src/views/preference/Preference.vue:66
 #, fuzzy
 #, fuzzy
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "Lưu thành công"
 msgstr "Lưu thành công"
@@ -1526,24 +1534,24 @@ msgstr "Lưu thành công"
 msgid "SDK"
 msgid "SDK"
 msgstr ""
 msgstr ""
 
 
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:104
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:155
 msgid "Selector"
 msgid "Selector"
 msgstr "Bộ chọn"
 msgstr "Bộ chọn"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:25
 #: src/views/dashboard/ServerAnalytic.vue:25
-#: src/views/dashboard/ServerAnalytic.vue:336
+#: src/views/dashboard/ServerAnalytic.vue:339
 msgid "Send"
 msgid "Send"
 msgstr "Gửi"
 msgstr "Gửi"
 
 
-#: src/components/NginxControl/NginxControl.vue:28
-#: src/components/NginxControl/NginxControl.vue:42
+#: src/components/NginxControl/NginxControl.vue:29
+#: src/components/NginxControl/NginxControl.vue:45
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:63
+#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:70
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
@@ -1553,6 +1561,11 @@ msgstr "Lỗi máy chủ"
 msgid "Server Info"
 msgid "Server Info"
 msgstr "Thông tin máy chủ"
 msgstr "Thông tin máy chủ"
 
 
+#: src/views/preference/BasicSettings.vue:117
+#, fuzzy
+msgid "Server Name"
+msgstr "Thông tin máy chủ"
+
 #: src/views/domain/cert/components/ObtainCert.vue:102
 #: src/views/domain/cert/components/ObtainCert.vue:102
 msgid "server_name not found in directives"
 msgid "server_name not found in directives"
 msgstr "không tìm thấy server_name trong directives"
 msgstr "không tìm thấy server_name trong directives"
@@ -1623,15 +1636,16 @@ msgstr "Ổn định"
 
 
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
-#: src/views/environment/Environment.vue:75 src/views/stream/StreamList.vue:22
+#: src/views/environment/Environment.vue:76 src/views/stream/StreamList.vue:22
 msgid "Status"
 msgid "Status"
 msgstr "Trạng thái"
 msgstr "Trạng thái"
 
 
-#: src/components/NginxControl/NginxControl.vue:81
+#: src/components/NginxControl/NginxControl.vue:84
 msgid "Stopped"
 msgid "Stopped"
 msgstr "Đã dừng"
 msgstr "Đã dừng"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:243
+#: src/views/dashboard/ServerAnalytic.vue:245
+#: src/views/dashboard/ServerAnalytic.vue:246
 msgid "Storage"
 msgid "Storage"
 msgstr "Storage"
 msgstr "Storage"
 
 
@@ -1644,7 +1658,8 @@ msgstr "Tên chủ đề: %{name}"
 msgid "Success"
 msgid "Success"
 msgstr "Thành công"
 msgstr "Thành công"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:230
+#: src/views/dashboard/ServerAnalytic.vue:231
+#: src/views/dashboard/ServerAnalytic.vue:232
 msgid "Swap"
 msgid "Swap"
 msgstr "Swap"
 msgstr "Swap"
 
 
@@ -1694,6 +1709,10 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/OpenAISettings.vue:30
+msgid "The model name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/certificate/CertificateEditor.vue:165
 #: src/views/certificate/CertificateEditor.vue:165
 msgid "The path exists, but the file is not a certificate"
 msgid "The path exists, but the file is not a certificate"
 msgstr ""
 msgstr ""
@@ -1702,6 +1721,10 @@ msgstr ""
 msgid "The path exists, but the file is not a private key"
 msgid "The path exists, but the file is not a private key"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/BasicSettings.vue:120
+msgid "The server name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #, fuzzy
 #, fuzzy
 msgid ""
 msgid ""
@@ -1712,9 +1735,12 @@ msgstr ""
 
 
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:50
 #: src/views/preference/BasicSettings.vue:50
-#: src/views/preference/OpenAISettings.vue:36
-#: src/views/preference/OpenAISettings.vue:48
-msgid "The url is not valid"
+msgid "The url is invalid"
+msgstr ""
+
+#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:54
+msgid "The url is invalid."
 msgstr ""
 msgstr ""
 
 
 #: src/language/constants.ts:2
 #: src/language/constants.ts:2
@@ -1759,7 +1785,7 @@ msgstr ""
 "quyền đến chương trình phụ trợ và chúng tôi cần lưu tệp này và tải lại "
 "quyền đến chương trình phụ trợ và chúng tôi cần lưu tệp này và tải lại "
 "Nginx. Bạn có chắc chắn muốn Tiếp tục?"
 "Nginx. Bạn có chắc chắn muốn Tiếp tục?"
 
 
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:66
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
@@ -1776,7 +1802,7 @@ msgstr "Loại"
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/components/RightSettings.vue:86
-#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:95
+#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:122
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 msgid "Updated at"
 msgid "Updated at"
@@ -1809,11 +1835,11 @@ msgstr ""
 msgid "Uptime:"
 msgid "Uptime:"
 msgstr "Thời gian hoạt động:"
 msgstr "Thời gian hoạt động:"
 
 
-#: src/views/environment/Environment.vue:21
+#: src/views/environment/Environment.vue:22
 msgid "URL"
 msgid "URL"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 #, fuzzy
 #, fuzzy
 msgid "User"
 msgid "User"
 msgstr "Người dùng"
 msgstr "Người dùng"
@@ -1874,7 +1900,7 @@ msgstr ""
 "có muốn tiếp tục không?"
 "có muốn tiếp tục không?"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:27
 #: src/views/dashboard/ServerAnalytic.vue:27
-#: src/views/dashboard/ServerAnalytic.vue:365
+#: src/views/dashboard/ServerAnalytic.vue:368
 msgid "Writes"
 msgid "Writes"
 msgstr "Ghi"
 msgstr "Ghi"
 
 
@@ -1908,10 +1934,6 @@ msgstr "Bạn có thể kiểm tra nâng cấp Nginx UI tại trang này"
 #~ msgid "Table"
 #~ msgid "Table"
 #~ msgstr "Mục lục"
 #~ msgstr "Mục lục"
 
 
-#, fuzzy
-#~ msgid "Server"
-#~ msgstr "Thông tin máy chủ"
-
 #, fuzzy
 #, fuzzy
 #~ msgid "Leave blank will not change anything."
 #~ msgid "Leave blank will not change anything."
 #~ msgstr "Bỏ trống nếu không thay đổi"
 #~ msgstr "Bỏ trống nếu không thay đổi"

BIN
app/src/language/zh_CN/app.mo


+ 111 - 85
app/src/language/zh_CN/app.po

@@ -22,14 +22,14 @@ msgid "Access Logs"
 msgstr "访问日志"
 msgstr "访问日志"
 
 
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
-#: src/views/certificate/ACMEUserSelector.vue:79
+#: src/views/certificate/ACMEUserSelector.vue:84
 msgid "ACME User"
 msgid "ACME User"
 msgstr "ACME 用户"
 msgstr "ACME 用户"
 
 
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
-#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:102
+#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:35
 #: src/views/notification/Notification.vue:35
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
@@ -74,7 +74,7 @@ msgstr "额外选项"
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "高级模式"
 msgstr "高级模式"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:39
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "API 地址"
 msgstr "API 地址"
 
 
@@ -82,11 +82,11 @@ msgstr "API 地址"
 msgid "API Document"
 msgid "API Document"
 msgstr "API 文档"
 msgstr "API 文档"
 
 
-#: src/views/preference/OpenAISettings.vue:45
+#: src/views/preference/OpenAISettings.vue:51
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "API 代理"
 msgstr "API 代理"
 
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:63
 msgid "API Token"
 msgid "API Token"
 msgstr "API Token"
 msgstr "API Token"
 
 
@@ -99,7 +99,7 @@ msgstr "架构"
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "您确定要清除所有通知吗?"
 msgstr "您确定要清除所有通知吗?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:267
+#: src/components/ChatGPT/ChatGPT.vue:272
 msgid "Are you sure you want to clear the record of chat?"
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "你确定你要清除聊天记录吗?"
 msgstr "你确定你要清除聊天记录吗?"
 
 
@@ -127,11 +127,11 @@ msgstr "您确定要删除这个项目吗?"
 msgid "Are you sure you want to remove this location?"
 msgid "Are you sure you want to remove this location?"
 msgstr "您确定要删除这个 Location?"
 msgstr "您确定要删除这个 Location?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:211
+#: src/components/ChatGPT/ChatGPT.vue:216
 msgid "Ask ChatGPT for Help"
 msgid "Ask ChatGPT for Help"
 msgstr "与ChatGPT聊天"
 msgstr "与ChatGPT聊天"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "Assistant"
 msgid "Assistant"
 msgstr "助手"
 msgstr "助手"
 
 
@@ -140,7 +140,7 @@ msgstr "助手"
 msgid "Author"
 msgid "Author"
 msgstr "作者"
 msgstr "作者"
 
 
-#: src/views/domain/cert/ChangeCert.vue:34
+#: src/views/domain/cert/ChangeCert.vue:33
 msgid "Auto Cert"
 msgid "Auto Cert"
 msgstr "自动更新"
 msgstr "自动更新"
 
 
@@ -173,7 +173,7 @@ msgstr "基本信息"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:94
+#: src/views/preference/Preference.vue:101
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "基本"
 msgstr "基本"
@@ -199,10 +199,10 @@ msgstr "CA Dir"
 msgid "CADir"
 msgid "CADir"
 msgstr "CADir"
 msgstr "CADir"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:248
+#: src/components/ChatGPT/ChatGPT.vue:253
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:102
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:153
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/RightSettings.vue:51
 #: src/views/domain/components/RightSettings.vue:51
@@ -243,8 +243,8 @@ msgstr "证书列表"
 msgid "Challenge Method"
 msgid "Challenge Method"
 msgstr "挑战方法"
 msgstr "挑战方法"
 
 
-#: src/views/domain/cert/ChangeCert.vue:88
-#: src/views/domain/cert/ChangeCert.vue:92
+#: src/views/domain/cert/ChangeCert.vue:95
+#: src/views/domain/cert/ChangeCert.vue:99
 msgid "Change Certificate"
 msgid "Change Certificate"
 msgstr "更改证书"
 msgstr "更改证书"
 
 
@@ -260,7 +260,7 @@ msgstr "重新检查"
 msgid "Cleaning environment variables"
 msgid "Cleaning environment variables"
 msgstr "正在清理环境变量"
 msgstr "正在清理环境变量"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:271
+#: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/Notification/Notification.vue:89
 #: src/components/Notification/Notification.vue:89
 #: src/views/notification/Notification.vue:75
 #: src/views/notification/Notification.vue:75
 msgid "Clear"
 msgid "Clear"
@@ -302,7 +302,7 @@ msgstr "配置"
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "配置 SSL"
 msgstr "配置 SSL"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Connected"
 msgid "Connected"
 msgstr "已连接"
 msgstr "已连接"
 
 
@@ -316,7 +316,7 @@ msgstr "内容"
 msgid "Core Upgrade"
 msgid "Core Upgrade"
 msgstr "核心升级"
 msgstr "核心升级"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:293
+#: src/views/dashboard/ServerAnalytic.vue:296
 msgid "CPU Status"
 msgid "CPU Status"
 msgstr "CPU 状态"
 msgstr "CPU 状态"
 
 
@@ -357,6 +357,12 @@ msgstr "当前版本"
 msgid "Custom"
 msgid "Custom"
 msgstr "自定义"
 msgstr "自定义"
 
 
+#: src/views/preference/BasicSettings.vue:121
+msgid ""
+"Customize the name of local server to be displayed in the environment "
+"indicator."
+msgstr "自定义显示在环境指示器中的本地服务器名称。"
+
 #: src/routes/index.ts:39
 #: src/routes/index.ts:39
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "仪表盘"
 msgstr "仪表盘"
@@ -444,9 +450,9 @@ msgstr "禁用"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "关闭 %{name} 自动续签失败"
 msgstr "关闭 %{name} 自动续签失败"
 
 
-#: src/views/domain/cert/ChangeCert.vue:45 src/views/domain/DomainEdit.vue:185
-#: src/views/domain/DomainList.vue:33 src/views/stream/StreamEdit.vue:177
-#: src/views/stream/StreamList.vue:33
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
+#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "禁用"
 msgstr "禁用"
 
 
@@ -457,7 +463,7 @@ msgstr "禁用"
 msgid "Disabled successfully"
 msgid "Disabled successfully"
 msgstr "禁用成功"
 msgstr "禁用成功"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:358
+#: src/views/dashboard/ServerAnalytic.vue:361
 msgid "Disk IO"
 msgid "Disk IO"
 msgstr "磁盘 IO"
 msgstr "磁盘 IO"
 
 
@@ -621,9 +627,10 @@ msgstr "启用成功"
 msgid "Enable TLS"
 msgid "Enable TLS"
 msgstr "启用 TLS"
 msgstr "启用 TLS"
 
 
-#: src/views/domain/cert/ChangeCert.vue:41
+#: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
@@ -643,11 +650,11 @@ msgstr "启用成功"
 msgid "Encrypt website with Let's Encrypt"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "用 Let's Encrypt 对网站进行加密"
 msgstr "用 Let's Encrypt 对网站进行加密"
 
 
-#: src/routes/index.ts:212 src/views/environment/Environment.vue:110
+#: src/routes/index.ts:212 src/views/environment/Environment.vue:137
 msgid "Environment"
 msgid "Environment"
 msgstr "环境"
 msgstr "环境"
 
 
-#: src/views/dashboard/Environments.vue:71
+#: src/views/dashboard/Environments.vue:82
 msgid "Environments"
 msgid "Environments"
 msgstr "环境"
 msgstr "环境"
 
 
@@ -860,7 +867,7 @@ msgstr "最后检查时间"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "留空表示不修改"
 msgstr "留空表示不修改"
 
 
-#: src/views/preference/OpenAISettings.vue:41
+#: src/views/preference/OpenAISettings.vue:47
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "留空为默认:https://api.openai.com/"
 msgstr "留空为默认:https://api.openai.com/"
 
 
@@ -873,7 +880,7 @@ msgstr "留空不做任何更改"
 msgid "License"
 msgid "License"
 msgstr "开源许可"
 msgstr "开源许可"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Link Start"
 msgid "Link Start"
 msgstr "链接"
 msgstr "链接"
 
 
@@ -886,8 +893,8 @@ msgstr "列表"
 msgid "Load Average:"
 msgid "Load Average:"
 msgstr "系统负载:"
 msgstr "系统负载:"
 
 
-#: src/components/EnvIndicator/EnvIndicator.vue:38
-#: src/components/NodeSelector/NodeSelector.vue:51
+#: src/components/EnvIndicator/EnvIndicator.vue:40
+#: src/components/NodeSelector/NodeSelector.vue:71
 msgid "Local"
 msgid "Local"
 msgstr "本地"
 msgstr "本地"
 
 
@@ -915,7 +922,7 @@ msgstr "登录成功"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "登出成功"
 msgstr "登出成功"
 
 
-#: src/views/preference/Preference.vue:112
+#: src/views/preference/Preference.vue:119
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr "Logrotate"
 msgstr "Logrotate"
 
 
@@ -962,6 +969,7 @@ msgid "Managed Certificate"
 msgstr "托管证书"
 msgstr "托管证书"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
+#: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
 msgstr "内存"
 msgstr "内存"
 
 
@@ -973,11 +981,11 @@ msgstr "内存与存储"
 msgid "Minutes"
 msgid "Minutes"
 msgstr "分钟"
 msgstr "分钟"
 
 
-#: src/views/preference/OpenAISettings.vue:26
+#: src/views/preference/OpenAISettings.vue:27
 msgid "Model"
 msgid "Model"
 msgstr "模型"
 msgstr "模型"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:244
+#: src/components/ChatGPT/ChatGPT.vue:249
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 msgid "Modify"
 msgid "Modify"
@@ -1003,7 +1011,7 @@ msgstr "多行指令"
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
-#: src/views/domain/cert/ChangeCert.vue:18
+#: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
@@ -1015,19 +1023,19 @@ msgstr "多行指令"
 msgid "Name"
 msgid "Name"
 msgstr "名称"
 msgstr "名称"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:319
+#: src/views/dashboard/ServerAnalytic.vue:322
 msgid "Network"
 msgid "Network"
 msgstr "网络"
 msgstr "网络"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:261
+#: src/views/dashboard/ServerAnalytic.vue:264
 msgid "Network Statistics"
 msgid "Network Statistics"
 msgstr "流量统计"
 msgstr "流量统计"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:268
+#: src/views/dashboard/ServerAnalytic.vue:271
 msgid "Network Total Receive"
 msgid "Network Total Receive"
 msgstr "下载流量"
 msgstr "下载流量"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:274
+#: src/views/dashboard/ServerAnalytic.vue:277
 msgid "Network Total Send"
 msgid "Network Total Send"
 msgstr "上传流量"
 msgstr "上传流量"
 
 
@@ -1041,7 +1049,7 @@ msgstr "新版本发布"
 msgid "Next"
 msgid "Next"
 msgstr "下一步"
 msgstr "下一步"
 
 
-#: src/views/preference/Preference.vue:100
+#: src/views/preference/Preference.vue:107
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Nginx"
 msgstr "Nginx"
 
 
@@ -1053,7 +1061,7 @@ msgstr "Nginx 访问日志路径"
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Nginx 配置解析错误"
 msgstr "Nginx 配置解析错误"
 
 
-#: src/components/NginxControl/NginxControl.vue:62
+#: src/components/NginxControl/NginxControl.vue:65
 msgid "Nginx Control"
 msgid "Nginx Control"
 msgstr "控制 Nginx"
 msgstr "控制 Nginx"
 
 
@@ -1065,15 +1073,15 @@ msgstr "Nginx 错误日志路径"
 msgid "Nginx Log"
 msgid "Nginx Log"
 msgstr "Nginx 日志"
 msgstr "Nginx 日志"
 
 
-#: src/components/NginxControl/NginxControl.vue:22
+#: src/components/NginxControl/NginxControl.vue:23
 msgid "Nginx reloaded successfully"
 msgid "Nginx reloaded successfully"
 msgstr "Nginx 重载成功"
 msgstr "Nginx 重载成功"
 
 
-#: src/components/NginxControl/NginxControl.vue:36
+#: src/components/NginxControl/NginxControl.vue:39
 msgid "Nginx restarted successfully"
 msgid "Nginx restarted successfully"
 msgstr "Nginx 重启成功"
 msgstr "Nginx 重启成功"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:265
+#: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/Notification/Notification.vue:82
 #: src/components/Notification/Notification.vue:82
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
@@ -1123,22 +1131,22 @@ msgstr "获取证书"
 msgid "Obtaining certificate"
 msgid "Obtaining certificate"
 msgstr "正在获取证书"
 msgstr "正在获取证书"
 
 
-#: src/components/NodeSelector/NodeSelector.vue:75
-#: src/views/dashboard/Environments.vue:95
-#: src/views/environment/Environment.vue:86
+#: src/components/NodeSelector/NodeSelector.vue:95
+#: src/views/dashboard/Environments.vue:106
+#: src/views/environment/Environment.vue:88
 msgid "Offline"
 msgid "Offline"
 msgstr "离线"
 msgstr "离线"
 
 
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:154
 msgid "Ok"
 msgid "Ok"
 msgstr "确定"
 msgstr "确定"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:266
+#: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/Notification/Notification.vue:83
 #: src/components/Notification/Notification.vue:83
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:103
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/RightSettings.vue:50
 #: src/views/domain/components/RightSettings.vue:50
@@ -1157,14 +1165,14 @@ msgstr "确定"
 msgid "Once the verification is complete, the records will be removed."
 msgid "Once the verification is complete, the records will be removed."
 msgstr "一旦验证完成,这些记录将被删除。"
 msgstr "一旦验证完成,这些记录将被删除。"
 
 
-#: src/components/NodeSelector/NodeSelector.vue:54
-#: src/components/NodeSelector/NodeSelector.vue:69
-#: src/views/dashboard/Environments.vue:88
-#: src/views/environment/Environment.vue:82
+#: src/components/NodeSelector/NodeSelector.vue:74
+#: src/components/NodeSelector/NodeSelector.vue:89
+#: src/views/dashboard/Environments.vue:99
+#: src/views/environment/Environment.vue:84
 msgid "Online"
 msgid "Online"
 msgstr "在线"
 msgstr "在线"
 
 
-#: src/views/preference/Preference.vue:106
+#: src/views/preference/Preference.vue:113
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "OpenAI"
 msgstr "OpenAI"
 
 
@@ -1259,7 +1267,7 @@ msgstr "请至少选择一个节点!"
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr "预发布"
 msgstr "预发布"
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:89
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
 msgid "Preference"
 msgid "Preference"
 msgstr "偏好设置"
 msgstr "偏好设置"
 
 
@@ -1284,12 +1292,12 @@ msgid "Provider"
 msgstr "提供商"
 msgstr "提供商"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:28
 #: src/views/dashboard/ServerAnalytic.vue:28
-#: src/views/dashboard/ServerAnalytic.vue:375
+#: src/views/dashboard/ServerAnalytic.vue:378
 msgid "Reads"
 msgid "Reads"
 msgstr "读"
 msgstr "读"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:24
 #: src/views/dashboard/ServerAnalytic.vue:24
-#: src/views/dashboard/ServerAnalytic.vue:326
+#: src/views/dashboard/ServerAnalytic.vue:329
 msgid "Receive"
 msgid "Receive"
 msgstr "下载"
 msgstr "下载"
 
 
@@ -1305,7 +1313,7 @@ msgstr "恢复成功"
 msgid "Recursive Nameservers"
 msgid "Recursive Nameservers"
 msgstr "递归域名服务器"
 msgstr "递归域名服务器"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:278
+#: src/components/ChatGPT/ChatGPT.vue:283
 msgid "Regenerate response"
 msgid "Regenerate response"
 msgstr "重新生成响应"
 msgstr "重新生成响应"
 
 
@@ -1337,12 +1345,12 @@ msgstr "重新安装"
 msgid "Release Note"
 msgid "Release Note"
 msgstr "发行日志"
 msgstr "发行日志"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:254
-#: src/components/NginxControl/NginxControl.vue:97
+#: src/components/ChatGPT/ChatGPT.vue:259
+#: src/components/NginxControl/NginxControl.vue:100
 msgid "Reload"
 msgid "Reload"
 msgstr "重载"
 msgstr "重载"
 
 
-#: src/components/NginxControl/NginxControl.vue:71
+#: src/components/NginxControl/NginxControl.vue:74
 msgid "Reloading"
 msgid "Reloading"
 msgstr "重载中"
 msgstr "重载中"
 
 
@@ -1384,11 +1392,11 @@ msgstr "请求参数错误"
 msgid "Reset"
 msgid "Reset"
 msgstr "重置"
 msgstr "重置"
 
 
-#: src/components/NginxControl/NginxControl.vue:90
+#: src/components/NginxControl/NginxControl.vue:93
 msgid "Restart"
 msgid "Restart"
 msgstr "重启"
 msgstr "重启"
 
 
-#: src/components/NginxControl/NginxControl.vue:76
+#: src/components/NginxControl/NginxControl.vue:79
 msgid "Restarting"
 msgid "Restarting"
 msgstr "重启中"
 msgstr "重启中"
 
 
@@ -1396,15 +1404,15 @@ msgstr "重启中"
 msgid "Run Mode"
 msgid "Run Mode"
 msgstr "运行模式"
 msgstr "运行模式"
 
 
-#: src/components/NginxControl/NginxControl.vue:66
+#: src/components/NginxControl/NginxControl.vue:69
 msgid "Running"
 msgid "Running"
 msgstr "运行中"
 msgstr "运行中"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:247
+#: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:123 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
 msgid "Save"
 msgid "Save"
 msgstr "保存"
 msgstr "保存"
 
 
@@ -1420,7 +1428,7 @@ msgstr "保存错误 %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:45
 #: src/views/certificate/CertificateEditor.vue:45
-#: src/views/preference/Preference.vue:59
+#: src/views/preference/Preference.vue:66
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "保存成功"
 msgstr "保存成功"
 
 
@@ -1435,24 +1443,24 @@ msgstr "保存成功"
 msgid "SDK"
 msgid "SDK"
 msgstr "SDK"
 msgstr "SDK"
 
 
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:104
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:155
 msgid "Selector"
 msgid "Selector"
 msgstr "选择器"
 msgstr "选择器"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:25
 #: src/views/dashboard/ServerAnalytic.vue:25
-#: src/views/dashboard/ServerAnalytic.vue:336
+#: src/views/dashboard/ServerAnalytic.vue:339
 msgid "Send"
 msgid "Send"
 msgstr "上传"
 msgstr "上传"
 
 
-#: src/components/NginxControl/NginxControl.vue:28
-#: src/components/NginxControl/NginxControl.vue:42
+#: src/components/NginxControl/NginxControl.vue:29
+#: src/components/NginxControl/NginxControl.vue:45
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:63
+#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:70
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
@@ -1462,6 +1470,10 @@ msgstr "服务器错误"
 msgid "Server Info"
 msgid "Server Info"
 msgstr "服务器信息"
 msgstr "服务器信息"
 
 
+#: src/views/preference/BasicSettings.vue:117
+msgid "Server Name"
+msgstr "服务器名称"
+
 #: src/views/domain/cert/components/ObtainCert.vue:102
 #: src/views/domain/cert/components/ObtainCert.vue:102
 msgid "server_name not found in directives"
 msgid "server_name not found in directives"
 msgstr "未在指令集合中找到 server_name"
 msgstr "未在指令集合中找到 server_name"
@@ -1529,15 +1541,16 @@ msgstr "稳定"
 
 
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
-#: src/views/environment/Environment.vue:75 src/views/stream/StreamList.vue:22
+#: src/views/environment/Environment.vue:76 src/views/stream/StreamList.vue:22
 msgid "Status"
 msgid "Status"
 msgstr "状态"
 msgstr "状态"
 
 
-#: src/components/NginxControl/NginxControl.vue:81
+#: src/components/NginxControl/NginxControl.vue:84
 msgid "Stopped"
 msgid "Stopped"
 msgstr "已停止"
 msgstr "已停止"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:243
+#: src/views/dashboard/ServerAnalytic.vue:245
+#: src/views/dashboard/ServerAnalytic.vue:246
 msgid "Storage"
 msgid "Storage"
 msgstr "存储"
 msgstr "存储"
 
 
@@ -1549,7 +1562,8 @@ msgstr "主体名称: %{subject}"
 msgid "Success"
 msgid "Success"
 msgstr "成功"
 msgstr "成功"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:230
+#: src/views/dashboard/ServerAnalytic.vue:231
+#: src/views/dashboard/ServerAnalytic.vue:232
 msgid "Swap"
 msgid "Swap"
 msgstr "Swap"
 msgstr "Swap"
 
 
@@ -1598,6 +1612,10 @@ msgstr "输入的内容不是 SSL 证书"
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "输入的内容不是 SSL 证书密钥"
 msgstr "输入的内容不是 SSL 证书密钥"
 
 
+#: src/views/preference/OpenAISettings.vue:30
+msgid "The model name should only contain letters, numbers, dashes, and dots."
+msgstr "模型只能包含字母、数字、破折号和点。"
+
 #: src/views/certificate/CertificateEditor.vue:165
 #: src/views/certificate/CertificateEditor.vue:165
 msgid "The path exists, but the file is not a certificate"
 msgid "The path exists, but the file is not a certificate"
 msgstr "路径存在,但文件不是证书"
 msgstr "路径存在,但文件不是证书"
@@ -1606,6 +1624,10 @@ msgstr "路径存在,但文件不是证书"
 msgid "The path exists, but the file is not a private key"
 msgid "The path exists, but the file is not a private key"
 msgstr "路径存在,但文件不是私钥"
 msgstr "路径存在,但文件不是私钥"
 
 
+#: src/views/preference/BasicSettings.vue:120
+msgid "The server name should only contain letters, numbers, dashes, and dots."
+msgstr "服务器名称只能包含字母、数字、破折号和点。"
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 msgid ""
 msgid ""
 "The server_name in the current configuration must be the domain name you "
 "The server_name in the current configuration must be the domain name you "
@@ -1614,10 +1636,14 @@ msgstr "当前配置中的 server_name 必须是获取证书所需的域名,
 
 
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:50
 #: src/views/preference/BasicSettings.vue:50
-#: src/views/preference/OpenAISettings.vue:36
-#: src/views/preference/OpenAISettings.vue:48
-msgid "The url is not valid"
-msgstr "URL 无效"
+#, fuzzy
+msgid "The url is invalid"
+msgstr "URL 无效."
+
+#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:54
+msgid "The url is invalid."
+msgstr "URL 无效."
 
 
 #: src/language/constants.ts:2
 #: src/language/constants.ts:2
 msgid "The username or password is incorrect"
 msgid "The username or password is incorrect"
@@ -1659,7 +1685,7 @@ msgstr ""
 "为了确保认证自动更新能够正常工作,我们需要添加一个能够代理从权威机构到后端的"
 "为了确保认证自动更新能够正常工作,我们需要添加一个能够代理从权威机构到后端的"
 "请求的 Location,并且我们需要保存这个文件并重新加载Nginx。你确定要继续吗?"
 "请求的 Location,并且我们需要保存这个文件并重新加载Nginx。你确定要继续吗?"
 
 
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:66
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr "Token 无效"
 msgstr "Token 无效"
 
 
@@ -1676,7 +1702,7 @@ msgstr "类型"
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/components/RightSettings.vue:86
-#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:95
+#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:122
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 msgid "Updated at"
 msgid "Updated at"
@@ -1707,11 +1733,11 @@ msgstr "Upstream 名称"
 msgid "Uptime:"
 msgid "Uptime:"
 msgstr "运行时间:"
 msgstr "运行时间:"
 
 
-#: src/views/environment/Environment.vue:21
+#: src/views/environment/Environment.vue:22
 msgid "URL"
 msgid "URL"
 msgstr "URL"
 msgstr "URL"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "User"
 msgid "User"
 msgstr "用户"
 msgstr "用户"
 
 
@@ -1765,7 +1791,7 @@ msgstr ""
 "我们将从这个文件中删除HTTPChallenge的配置,并重新加载Nginx。你确定要继续吗?"
 "我们将从这个文件中删除HTTPChallenge的配置,并重新加载Nginx。你确定要继续吗?"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:27
 #: src/views/dashboard/ServerAnalytic.vue:27
-#: src/views/dashboard/ServerAnalytic.vue:365
+#: src/views/dashboard/ServerAnalytic.vue:368
 msgid "Writes"
 msgid "Writes"
 msgstr "写"
 msgstr "写"
 
 
@@ -1791,6 +1817,9 @@ msgstr "您使用的是最新版本"
 msgid "You can check Nginx UI upgrade at this page."
 msgid "You can check Nginx UI upgrade at this page."
 msgstr "你可以在这个页面检查Nginx UI的升级。"
 msgstr "你可以在这个页面检查Nginx UI的升级。"
 
 
+#~ msgid "The url is not valid"
+#~ msgstr "URL 无效"
+
 #~ msgid "Enable this option will significantly increase the token usage."
 #~ msgid "Enable this option will significantly increase the token usage."
 #~ msgstr "启用该选项将显著增加 token 的使用量。"
 #~ msgstr "启用该选项将显著增加 token 的使用量。"
 
 
@@ -1824,9 +1853,6 @@ msgstr "你可以在这个页面检查Nginx UI的升级。"
 #~ msgid "Rename Upstream"
 #~ msgid "Rename Upstream"
 #~ msgstr "重新命名 Upstream"
 #~ msgstr "重新命名 Upstream"
 
 
-#~ msgid "Server"
-#~ msgstr "Server"
-
 #~ msgid "Leave blank will not change anything."
 #~ msgid "Leave blank will not change anything."
 #~ msgstr "留空不会有任何变化。"
 #~ msgstr "留空不会有任何变化。"
 
 

+ 112 - 85
app/src/language/zh_TW/app.po

@@ -23,7 +23,7 @@ msgid "Access Logs"
 msgstr "存取日誌"
 msgstr "存取日誌"
 
 
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
 #: src/routes/index.ts:128 src/views/certificate/ACMEUser.vue:76
-#: src/views/certificate/ACMEUserSelector.vue:79
+#: src/views/certificate/ACMEUserSelector.vue:84
 #, fuzzy
 #, fuzzy
 msgid "ACME User"
 msgid "ACME User"
 msgstr "使用者名稱"
 msgstr "使用者名稱"
@@ -31,7 +31,7 @@ msgstr "使用者名稱"
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/ACMEUser.vue:59
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/Certificate.vue:108
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
 #: src/views/certificate/DNSCredential.vue:29 src/views/config/config.ts:34
-#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:102
+#: src/views/domain/DomainList.vue:47 src/views/environment/Environment.vue:129
 #: src/views/notification/Notification.vue:35
 #: src/views/notification/Notification.vue:35
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 #: src/views/stream/StreamList.vue:47 src/views/user/User.vue:43
 msgid "Action"
 msgid "Action"
@@ -78,7 +78,7 @@ msgstr "其他設定"
 msgid "Advance Mode"
 msgid "Advance Mode"
 msgstr "進階模式"
 msgstr "進階模式"
 
 
-#: src/views/preference/OpenAISettings.vue:33
+#: src/views/preference/OpenAISettings.vue:39
 msgid "API Base Url"
 msgid "API Base Url"
 msgstr "API 基礎網址"
 msgstr "API 基礎網址"
 
 
@@ -87,11 +87,11 @@ msgstr "API 基礎網址"
 msgid "API Document"
 msgid "API Document"
 msgstr "API Token"
 msgstr "API Token"
 
 
-#: src/views/preference/OpenAISettings.vue:45
+#: src/views/preference/OpenAISettings.vue:51
 msgid "API Proxy"
 msgid "API Proxy"
 msgstr "API 代理"
 msgstr "API 代理"
 
 
-#: src/views/preference/OpenAISettings.vue:57
+#: src/views/preference/OpenAISettings.vue:63
 msgid "API Token"
 msgid "API Token"
 msgstr "API Token"
 msgstr "API Token"
 
 
@@ -105,7 +105,7 @@ msgstr "架構"
 msgid "Are you sure you want to clear all notifications?"
 msgid "Are you sure you want to clear all notifications?"
 msgstr "您確定要清除聊天記錄嗎?"
 msgstr "您確定要清除聊天記錄嗎?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:267
+#: src/components/ChatGPT/ChatGPT.vue:272
 msgid "Are you sure you want to clear the record of chat?"
 msgid "Are you sure you want to clear the record of chat?"
 msgstr "您確定要清除聊天記錄嗎?"
 msgstr "您確定要清除聊天記錄嗎?"
 
 
@@ -136,11 +136,11 @@ msgstr "您確定要刪除這條指令嗎?"
 msgid "Are you sure you want to remove this location?"
 msgid "Are you sure you want to remove this location?"
 msgstr "您確定要刪除此 Location 嗎?"
 msgstr "您確定要刪除此 Location 嗎?"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:211
+#: src/components/ChatGPT/ChatGPT.vue:216
 msgid "Ask ChatGPT for Help"
 msgid "Ask ChatGPT for Help"
 msgstr "向 ChatGPT 尋求幫助"
 msgstr "向 ChatGPT 尋求幫助"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "Assistant"
 msgid "Assistant"
 msgstr "助理"
 msgstr "助理"
 
 
@@ -149,7 +149,7 @@ msgstr "助理"
 msgid "Author"
 msgid "Author"
 msgstr "作者"
 msgstr "作者"
 
 
-#: src/views/domain/cert/ChangeCert.vue:34
+#: src/views/domain/cert/ChangeCert.vue:33
 msgid "Auto Cert"
 msgid "Auto Cert"
 msgstr "自動憑證"
 msgstr "自動憑證"
 
 
@@ -182,7 +182,7 @@ msgstr "基本資訊"
 
 
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/config/ConfigEdit.vue:115
 #: src/views/domain/components/RightSettings.vue:75
 #: src/views/domain/components/RightSettings.vue:75
-#: src/views/preference/Preference.vue:94
+#: src/views/preference/Preference.vue:101
 #: src/views/stream/components/RightSettings.vue:74
 #: src/views/stream/components/RightSettings.vue:74
 msgid "Basic"
 msgid "Basic"
 msgstr "基本"
 msgstr "基本"
@@ -208,10 +208,10 @@ msgstr ""
 msgid "CADir"
 msgid "CADir"
 msgstr "CADir"
 msgstr "CADir"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:248
+#: src/components/ChatGPT/ChatGPT.vue:253
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:55
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:263
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:102
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:153
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/cert/components/ObtainCert.vue:137
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/Deploy.vue:21
 #: src/views/domain/components/RightSettings.vue:51
 #: src/views/domain/components/RightSettings.vue:51
@@ -255,8 +255,8 @@ msgstr "憑證清單"
 msgid "Challenge Method"
 msgid "Challenge Method"
 msgstr "驗證方式"
 msgstr "驗證方式"
 
 
-#: src/views/domain/cert/ChangeCert.vue:88
-#: src/views/domain/cert/ChangeCert.vue:92
+#: src/views/domain/cert/ChangeCert.vue:95
+#: src/views/domain/cert/ChangeCert.vue:99
 msgid "Change Certificate"
 msgid "Change Certificate"
 msgstr "更換憑證"
 msgstr "更換憑證"
 
 
@@ -272,7 +272,7 @@ msgstr "再次檢查"
 msgid "Cleaning environment variables"
 msgid "Cleaning environment variables"
 msgstr "清理環境變數"
 msgstr "清理環境變數"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:271
+#: src/components/ChatGPT/ChatGPT.vue:276
 #: src/components/Notification/Notification.vue:89
 #: src/components/Notification/Notification.vue:89
 #: src/views/notification/Notification.vue:75
 #: src/views/notification/Notification.vue:75
 msgid "Clear"
 msgid "Clear"
@@ -316,7 +316,7 @@ msgstr "設定"
 msgid "Configure SSL"
 msgid "Configure SSL"
 msgstr "設定 SSL"
 msgstr "設定 SSL"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Connected"
 msgid "Connected"
 msgstr "已連結"
 msgstr "已連結"
 
 
@@ -330,7 +330,7 @@ msgstr "內容"
 msgid "Core Upgrade"
 msgid "Core Upgrade"
 msgstr "核心升級"
 msgstr "核心升級"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:293
+#: src/views/dashboard/ServerAnalytic.vue:296
 msgid "CPU Status"
 msgid "CPU Status"
 msgstr "中央處理器狀態"
 msgstr "中央處理器狀態"
 
 
@@ -372,6 +372,12 @@ msgstr "目前版本"
 msgid "Custom"
 msgid "Custom"
 msgstr "自訂"
 msgstr "自訂"
 
 
+#: src/views/preference/BasicSettings.vue:121
+msgid ""
+"Customize the name of local server to be displayed in the environment "
+"indicator."
+msgstr ""
+
 #: src/routes/index.ts:39
 #: src/routes/index.ts:39
 msgid "Dashboard"
 msgid "Dashboard"
 msgstr "儀表板"
 msgstr "儀表板"
@@ -462,9 +468,9 @@ msgstr "停用"
 msgid "Disable auto-renewal failed for %{name}"
 msgid "Disable auto-renewal failed for %{name}"
 msgstr "關閉 %{name} 自動續簽失敗"
 msgstr "關閉 %{name} 自動續簽失敗"
 
 
-#: src/views/domain/cert/ChangeCert.vue:45 src/views/domain/DomainEdit.vue:185
-#: src/views/domain/DomainList.vue:33 src/views/stream/StreamEdit.vue:177
-#: src/views/stream/StreamList.vue:33
+#: src/views/domain/cert/ChangeCert.vue:44 src/views/domain/DomainEdit.vue:185
+#: src/views/domain/DomainList.vue:33 src/views/environment/Environment.vue:93
+#: src/views/stream/StreamEdit.vue:177 src/views/stream/StreamList.vue:33
 msgid "Disabled"
 msgid "Disabled"
 msgstr "停用"
 msgstr "停用"
 
 
@@ -475,7 +481,7 @@ msgstr "停用"
 msgid "Disabled successfully"
 msgid "Disabled successfully"
 msgstr "成功停用"
 msgstr "成功停用"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:358
+#: src/views/dashboard/ServerAnalytic.vue:361
 msgid "Disk IO"
 msgid "Disk IO"
 msgstr "磁碟 IO"
 msgstr "磁碟 IO"
 
 
@@ -645,9 +651,10 @@ msgstr "啟用成功"
 msgid "Enable TLS"
 msgid "Enable TLS"
 msgstr "啟用 TLS"
 msgstr "啟用 TLS"
 
 
-#: src/views/domain/cert/ChangeCert.vue:41
+#: src/views/domain/cert/ChangeCert.vue:40
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/components/RightSettings.vue:77
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
 #: src/views/domain/DomainEdit.vue:179 src/views/domain/DomainList.vue:29
+#: src/views/environment/Environment.vue:102
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/preference/LogrotateSettings.vue:20
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/components/RightSettings.vue:76
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
 #: src/views/stream/StreamEdit.vue:171 src/views/stream/StreamList.vue:29
@@ -667,11 +674,11 @@ msgstr "成功啟用"
 msgid "Encrypt website with Let's Encrypt"
 msgid "Encrypt website with Let's Encrypt"
 msgstr "用 Let's Encrypt 對網站進行加密"
 msgstr "用 Let's Encrypt 對網站進行加密"
 
 
-#: src/routes/index.ts:212 src/views/environment/Environment.vue:110
+#: src/routes/index.ts:212 src/views/environment/Environment.vue:137
 msgid "Environment"
 msgid "Environment"
 msgstr "環境"
 msgstr "環境"
 
 
-#: src/views/dashboard/Environments.vue:71
+#: src/views/dashboard/Environments.vue:82
 msgid "Environments"
 msgid "Environments"
 msgstr "環境"
 msgstr "環境"
 
 
@@ -895,7 +902,7 @@ msgstr "上次檢查時間"
 msgid "Leave blank for no change"
 msgid "Leave blank for no change"
 msgstr "留空表示不修改"
 msgstr "留空表示不修改"
 
 
-#: src/views/preference/OpenAISettings.vue:41
+#: src/views/preference/OpenAISettings.vue:47
 msgid "Leave blank for the default: https://api.openai.com/"
 msgid "Leave blank for the default: https://api.openai.com/"
 msgstr "預設留空:https://api.openai.com/"
 msgstr "預設留空:https://api.openai.com/"
 
 
@@ -910,7 +917,7 @@ msgstr "留空表示不修改"
 msgid "License"
 msgid "License"
 msgstr "授權條款"
 msgstr "授權條款"
 
 
-#: src/views/dashboard/Environments.vue:128
+#: src/views/dashboard/Environments.vue:139
 msgid "Link Start"
 msgid "Link Start"
 msgstr "連結開始"
 msgstr "連結開始"
 
 
@@ -924,8 +931,8 @@ msgstr ""
 msgid "Load Average:"
 msgid "Load Average:"
 msgstr "系統負載:"
 msgstr "系統負載:"
 
 
-#: src/components/EnvIndicator/EnvIndicator.vue:38
-#: src/components/NodeSelector/NodeSelector.vue:51
+#: src/components/EnvIndicator/EnvIndicator.vue:40
+#: src/components/NodeSelector/NodeSelector.vue:71
 msgid "Local"
 msgid "Local"
 msgstr "本機"
 msgstr "本機"
 
 
@@ -954,7 +961,7 @@ msgstr "登入成功"
 msgid "Logout successful"
 msgid "Logout successful"
 msgstr "登出成功"
 msgstr "登出成功"
 
 
-#: src/views/preference/Preference.vue:112
+#: src/views/preference/Preference.vue:119
 msgid "Logrotate"
 msgid "Logrotate"
 msgstr ""
 msgstr ""
 
 
@@ -998,6 +1005,7 @@ msgid "Managed Certificate"
 msgstr "更換憑證"
 msgstr "更換憑證"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:217
 #: src/views/dashboard/ServerAnalytic.vue:217
+#: src/views/dashboard/ServerAnalytic.vue:218
 msgid "Memory"
 msgid "Memory"
 msgstr "記憶體"
 msgstr "記憶體"
 
 
@@ -1009,12 +1017,12 @@ msgstr "記憶體與儲存"
 msgid "Minutes"
 msgid "Minutes"
 msgstr ""
 msgstr ""
 
 
-#: src/views/preference/OpenAISettings.vue:26
+#: src/views/preference/OpenAISettings.vue:27
 #, fuzzy
 #, fuzzy
 msgid "Model"
 msgid "Model"
 msgstr "執行模式"
 msgstr "執行模式"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:244
+#: src/components/ChatGPT/ChatGPT.vue:249
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:194
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:491
 msgid "Modify"
 msgid "Modify"
@@ -1042,7 +1050,7 @@ msgstr "多行指令"
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/Certificate.vue:20
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/CertificateEditor.vue:146
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
 #: src/views/certificate/DNSCredential.vue:10 src/views/config/config.ts:7
-#: src/views/domain/cert/ChangeCert.vue:18
+#: src/views/domain/cert/ChangeCert.vue:17
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/RightSettings.vue:83
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/components/SiteDuplicate.vue:133
 #: src/views/domain/DomainList.vue:13
 #: src/views/domain/DomainList.vue:13
@@ -1054,19 +1062,19 @@ msgstr "多行指令"
 msgid "Name"
 msgid "Name"
 msgstr "名稱"
 msgstr "名稱"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:319
+#: src/views/dashboard/ServerAnalytic.vue:322
 msgid "Network"
 msgid "Network"
 msgstr "網路"
 msgstr "網路"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:261
+#: src/views/dashboard/ServerAnalytic.vue:264
 msgid "Network Statistics"
 msgid "Network Statistics"
 msgstr "網路統計"
 msgstr "網路統計"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:268
+#: src/views/dashboard/ServerAnalytic.vue:271
 msgid "Network Total Receive"
 msgid "Network Total Receive"
 msgstr "下載流量"
 msgstr "下載流量"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:274
+#: src/views/dashboard/ServerAnalytic.vue:277
 msgid "Network Total Send"
 msgid "Network Total Send"
 msgstr "上傳流量"
 msgstr "上傳流量"
 
 
@@ -1080,7 +1088,7 @@ msgstr "新版本發布"
 msgid "Next"
 msgid "Next"
 msgstr "下一步"
 msgstr "下一步"
 
 
-#: src/views/preference/Preference.vue:100
+#: src/views/preference/Preference.vue:107
 msgid "Nginx"
 msgid "Nginx"
 msgstr "Nginx"
 msgstr "Nginx"
 
 
@@ -1092,7 +1100,7 @@ msgstr "Nginx 存取日誌路徑"
 msgid "Nginx Configuration Parse Error"
 msgid "Nginx Configuration Parse Error"
 msgstr "Nginx 設定解析錯誤"
 msgstr "Nginx 設定解析錯誤"
 
 
-#: src/components/NginxControl/NginxControl.vue:62
+#: src/components/NginxControl/NginxControl.vue:65
 msgid "Nginx Control"
 msgid "Nginx Control"
 msgstr "Nginx 控制元件"
 msgstr "Nginx 控制元件"
 
 
@@ -1104,15 +1112,15 @@ msgstr "Nginx 錯誤日誌路徑"
 msgid "Nginx Log"
 msgid "Nginx Log"
 msgstr "Nginx 日誌"
 msgstr "Nginx 日誌"
 
 
-#: src/components/NginxControl/NginxControl.vue:22
+#: src/components/NginxControl/NginxControl.vue:23
 msgid "Nginx reloaded successfully"
 msgid "Nginx reloaded successfully"
 msgstr "Nginx 重新載入成功"
 msgstr "Nginx 重新載入成功"
 
 
-#: src/components/NginxControl/NginxControl.vue:36
+#: src/components/NginxControl/NginxControl.vue:39
 msgid "Nginx restarted successfully"
 msgid "Nginx restarted successfully"
 msgstr "Nginx 重啟成功"
 msgstr "Nginx 重啟成功"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:265
+#: src/components/ChatGPT/ChatGPT.vue:270
 #: src/components/Notification/Notification.vue:82
 #: src/components/Notification/Notification.vue:82
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:507
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:521
@@ -1164,22 +1172,22 @@ msgstr "取得憑證"
 msgid "Obtaining certificate"
 msgid "Obtaining certificate"
 msgstr "正在取得憑證"
 msgstr "正在取得憑證"
 
 
-#: src/components/NodeSelector/NodeSelector.vue:75
-#: src/views/dashboard/Environments.vue:95
-#: src/views/environment/Environment.vue:86
+#: src/components/NodeSelector/NodeSelector.vue:95
+#: src/views/dashboard/Environments.vue:106
+#: src/views/environment/Environment.vue:88
 msgid "Offline"
 msgid "Offline"
 msgstr "離線"
 msgstr "離線"
 
 
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:264
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:154
 msgid "Ok"
 msgid "Ok"
 msgstr ""
 msgstr ""
 
 
-#: src/components/ChatGPT/ChatGPT.vue:266
+#: src/components/ChatGPT/ChatGPT.vue:271
 #: src/components/Notification/Notification.vue:83
 #: src/components/Notification/Notification.vue:83
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:56
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:508
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:522
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:103
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/cert/components/ObtainCert.vue:136
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/Deploy.vue:20
 #: src/views/domain/components/RightSettings.vue:50
 #: src/views/domain/components/RightSettings.vue:50
@@ -1198,14 +1206,14 @@ msgstr "確定"
 msgid "Once the verification is complete, the records will be removed."
 msgid "Once the verification is complete, the records will be removed."
 msgstr ""
 msgstr ""
 
 
-#: src/components/NodeSelector/NodeSelector.vue:54
-#: src/components/NodeSelector/NodeSelector.vue:69
-#: src/views/dashboard/Environments.vue:88
-#: src/views/environment/Environment.vue:82
+#: src/components/NodeSelector/NodeSelector.vue:74
+#: src/components/NodeSelector/NodeSelector.vue:89
+#: src/views/dashboard/Environments.vue:99
+#: src/views/environment/Environment.vue:84
 msgid "Online"
 msgid "Online"
 msgstr "線上"
 msgstr "線上"
 
 
-#: src/views/preference/Preference.vue:106
+#: src/views/preference/Preference.vue:113
 msgid "OpenAI"
 msgid "OpenAI"
 msgstr "OpenAI"
 msgstr "OpenAI"
 
 
@@ -1301,7 +1309,7 @@ msgstr "請至少選擇一個節點!"
 msgid "Pre-release"
 msgid "Pre-release"
 msgstr "預先發布"
 msgstr "預先發布"
 
 
-#: src/routes/index.ts:239 src/views/preference/Preference.vue:89
+#: src/routes/index.ts:239 src/views/preference/Preference.vue:96
 msgid "Preference"
 msgid "Preference"
 msgstr "偏好設定"
 msgstr "偏好設定"
 
 
@@ -1326,12 +1334,12 @@ msgid "Provider"
 msgstr "供應商"
 msgstr "供應商"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:28
 #: src/views/dashboard/ServerAnalytic.vue:28
-#: src/views/dashboard/ServerAnalytic.vue:375
+#: src/views/dashboard/ServerAnalytic.vue:378
 msgid "Reads"
 msgid "Reads"
 msgstr "讀取"
 msgstr "讀取"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:24
 #: src/views/dashboard/ServerAnalytic.vue:24
-#: src/views/dashboard/ServerAnalytic.vue:326
+#: src/views/dashboard/ServerAnalytic.vue:329
 msgid "Receive"
 msgid "Receive"
 msgstr "接收"
 msgstr "接收"
 
 
@@ -1349,7 +1357,7 @@ msgstr "儲存成功"
 msgid "Recursive Nameservers"
 msgid "Recursive Nameservers"
 msgstr "網站域名 (server_name)"
 msgstr "網站域名 (server_name)"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:278
+#: src/components/ChatGPT/ChatGPT.vue:283
 msgid "Regenerate response"
 msgid "Regenerate response"
 msgstr "重新產生回應"
 msgstr "重新產生回應"
 
 
@@ -1385,12 +1393,12 @@ msgstr "重新安裝"
 msgid "Release Note"
 msgid "Release Note"
 msgstr "發行公告"
 msgstr "發行公告"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:254
-#: src/components/NginxControl/NginxControl.vue:97
+#: src/components/ChatGPT/ChatGPT.vue:259
+#: src/components/NginxControl/NginxControl.vue:100
 msgid "Reload"
 msgid "Reload"
 msgstr "重新載入"
 msgstr "重新載入"
 
 
-#: src/components/NginxControl/NginxControl.vue:71
+#: src/components/NginxControl/NginxControl.vue:74
 msgid "Reloading"
 msgid "Reloading"
 msgstr "重新載入中"
 msgstr "重新載入中"
 
 
@@ -1438,11 +1446,11 @@ msgstr "請求參數錯誤"
 msgid "Reset"
 msgid "Reset"
 msgstr "重設"
 msgstr "重設"
 
 
-#: src/components/NginxControl/NginxControl.vue:90
+#: src/components/NginxControl/NginxControl.vue:93
 msgid "Restart"
 msgid "Restart"
 msgstr "重新啟動"
 msgstr "重新啟動"
 
 
-#: src/components/NginxControl/NginxControl.vue:76
+#: src/components/NginxControl/NginxControl.vue:79
 msgid "Restarting"
 msgid "Restarting"
 msgstr "正在重新啟動"
 msgstr "正在重新啟動"
 
 
@@ -1450,15 +1458,15 @@ msgstr "正在重新啟動"
 msgid "Run Mode"
 msgid "Run Mode"
 msgstr "執行模式"
 msgstr "執行模式"
 
 
-#: src/components/NginxControl/NginxControl.vue:66
+#: src/components/NginxControl/NginxControl.vue:69
 msgid "Running"
 msgid "Running"
 msgstr "執行中"
 msgstr "執行中"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:247
+#: src/components/ChatGPT/ChatGPT.vue:252
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/certificate/CertificateEditor.vue:242
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/config/ConfigEdit.vue:96 src/views/domain/DomainEdit.vue:263
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
 #: src/views/domain/ngx_conf/directive/DirectiveEditorItem.vue:120
-#: src/views/preference/Preference.vue:123 src/views/stream/StreamEdit.vue:254
+#: src/views/preference/Preference.vue:130 src/views/stream/StreamEdit.vue:254
 msgid "Save"
 msgid "Save"
 msgstr "儲存"
 msgstr "儲存"
 
 
@@ -1474,7 +1482,7 @@ msgstr "儲存錯誤 %{msg}"
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:39
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/components/StdDesign/StdDataDisplay/StdCurd.vue:104
 #: src/views/certificate/CertificateEditor.vue:45
 #: src/views/certificate/CertificateEditor.vue:45
-#: src/views/preference/Preference.vue:59
+#: src/views/preference/Preference.vue:66
 msgid "Save successfully"
 msgid "Save successfully"
 msgstr "儲存成功"
 msgstr "儲存成功"
 
 
@@ -1489,24 +1497,24 @@ msgstr "儲存成功"
 msgid "SDK"
 msgid "SDK"
 msgstr ""
 msgstr ""
 
 
-#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:104
+#: src/components/StdDesign/StdDataEntry/components/StdSelector.vue:155
 msgid "Selector"
 msgid "Selector"
 msgstr "選擇器"
 msgstr "選擇器"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:25
 #: src/views/dashboard/ServerAnalytic.vue:25
-#: src/views/dashboard/ServerAnalytic.vue:336
+#: src/views/dashboard/ServerAnalytic.vue:339
 msgid "Send"
 msgid "Send"
 msgstr "傳送"
 msgstr "傳送"
 
 
-#: src/components/NginxControl/NginxControl.vue:28
-#: src/components/NginxControl/NginxControl.vue:42
+#: src/components/NginxControl/NginxControl.vue:29
+#: src/components/NginxControl/NginxControl.vue:45
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/exportCsv.ts:46
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/methods/sortable.ts:126
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdBatchEdit.vue:42
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:182
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/components/StdDesign/StdDataDisplay/StdTable.vue:221
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
 #: src/views/config/ConfigEdit.vue:40 src/views/domain/DomainList.vue:81
-#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:63
+#: src/views/other/Install.vue:70 src/views/preference/Preference.vue:70
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/stream/StreamList.vue:113 src/views/stream/StreamList.vue:81
 #: src/views/system/Upgrade.vue:42
 #: src/views/system/Upgrade.vue:42
 msgid "Server error"
 msgid "Server error"
@@ -1516,6 +1524,11 @@ msgstr "伺服器錯誤"
 msgid "Server Info"
 msgid "Server Info"
 msgstr "伺服器資訊"
 msgstr "伺服器資訊"
 
 
+#: src/views/preference/BasicSettings.vue:117
+#, fuzzy
+msgid "Server Name"
+msgstr "伺服器資訊"
+
 #: src/views/domain/cert/components/ObtainCert.vue:102
 #: src/views/domain/cert/components/ObtainCert.vue:102
 msgid "server_name not found in directives"
 msgid "server_name not found in directives"
 msgstr "在指令中未找到 server_name"
 msgstr "在指令中未找到 server_name"
@@ -1588,15 +1601,16 @@ msgstr "穩定"
 
 
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/ACMEUser.vue:42
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
 #: src/views/certificate/Certificate.vue:83 src/views/domain/DomainList.vue:22
-#: src/views/environment/Environment.vue:75 src/views/stream/StreamList.vue:22
+#: src/views/environment/Environment.vue:76 src/views/stream/StreamList.vue:22
 msgid "Status"
 msgid "Status"
 msgstr "狀態"
 msgstr "狀態"
 
 
-#: src/components/NginxControl/NginxControl.vue:81
+#: src/components/NginxControl/NginxControl.vue:84
 msgid "Stopped"
 msgid "Stopped"
 msgstr "已停止"
 msgstr "已停止"
 
 
-#: src/views/dashboard/ServerAnalytic.vue:243
+#: src/views/dashboard/ServerAnalytic.vue:245
+#: src/views/dashboard/ServerAnalytic.vue:246
 msgid "Storage"
 msgid "Storage"
 msgstr "儲存空間"
 msgstr "儲存空間"
 
 
@@ -1609,7 +1623,8 @@ msgstr "主體名稱: %{name}"
 msgid "Success"
 msgid "Success"
 msgstr ""
 msgstr ""
 
 
-#: src/views/dashboard/ServerAnalytic.vue:230
+#: src/views/dashboard/ServerAnalytic.vue:231
+#: src/views/dashboard/ServerAnalytic.vue:232
 msgid "Swap"
 msgid "Swap"
 msgstr "交換空間"
 msgstr "交換空間"
 
 
@@ -1660,6 +1675,10 @@ msgstr ""
 msgid "The input is not a SSL Certificate Key"
 msgid "The input is not a SSL Certificate Key"
 msgstr "SSL 憑證金鑰路徑"
 msgstr "SSL 憑證金鑰路徑"
 
 
+#: src/views/preference/OpenAISettings.vue:30
+msgid "The model name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/certificate/CertificateEditor.vue:165
 #: src/views/certificate/CertificateEditor.vue:165
 #, fuzzy
 #, fuzzy
 msgid "The path exists, but the file is not a certificate"
 msgid "The path exists, but the file is not a certificate"
@@ -1669,6 +1688,10 @@ msgstr "SSL 憑證金鑰路徑"
 msgid "The path exists, but the file is not a private key"
 msgid "The path exists, but the file is not a private key"
 msgstr ""
 msgstr ""
 
 
+#: src/views/preference/BasicSettings.vue:120
+msgid "The server name should only contain letters, numbers, dashes, and dots."
+msgstr ""
+
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #: src/views/domain/cert/components/AutoCertStepOne.vue:50
 #, fuzzy
 #, fuzzy
 msgid ""
 msgid ""
@@ -1678,10 +1701,14 @@ msgstr "注意:目前設定中的 server_name 必須為需要申請憑證的
 
 
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:38
 #: src/views/preference/BasicSettings.vue:50
 #: src/views/preference/BasicSettings.vue:50
-#: src/views/preference/OpenAISettings.vue:36
-#: src/views/preference/OpenAISettings.vue:48
 #, fuzzy
 #, fuzzy
-msgid "The url is not valid"
+msgid "The url is invalid"
+msgstr "此功能在演示中不可用。"
+
+#: src/views/preference/OpenAISettings.vue:42
+#: src/views/preference/OpenAISettings.vue:54
+#, fuzzy
+msgid "The url is invalid."
 msgstr "此功能在演示中不可用。"
 msgstr "此功能在演示中不可用。"
 
 
 #: src/language/constants.ts:2
 #: src/language/constants.ts:2
@@ -1725,7 +1752,7 @@ msgstr ""
 "為了確保憑證自動續期能夠正常運作,我們需要新增一個 Location 來代理從授權後端"
 "為了確保憑證自動續期能夠正常運作,我們需要新增一個 Location 來代理從授權後端"
 "的請求,我們需要儲存這個檔案並重新載入 Nginx。你確定你要繼續嗎?"
 "的請求,我們需要儲存這個檔案並重新載入 Nginx。你確定你要繼續嗎?"
 
 
-#: src/views/preference/OpenAISettings.vue:60
+#: src/views/preference/OpenAISettings.vue:66
 msgid "Token is not valid"
 msgid "Token is not valid"
 msgstr ""
 msgstr ""
 
 
@@ -1742,7 +1769,7 @@ msgstr "類型"
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/certificate/DNSCredential.vue:23 src/views/config/config.ts:27
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/config/ConfigEdit.vue:121
 #: src/views/domain/components/RightSettings.vue:86
 #: src/views/domain/components/RightSettings.vue:86
-#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:95
+#: src/views/domain/DomainList.vue:41 src/views/environment/Environment.vue:122
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/components/RightSettings.vue:85
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 #: src/views/stream/StreamList.vue:41 src/views/user/User.vue:37
 msgid "Updated at"
 msgid "Updated at"
@@ -1773,11 +1800,11 @@ msgstr ""
 msgid "Uptime:"
 msgid "Uptime:"
 msgstr "運作時間:"
 msgstr "運作時間:"
 
 
-#: src/views/environment/Environment.vue:21
+#: src/views/environment/Environment.vue:22
 msgid "URL"
 msgid "URL"
 msgstr "URL"
 msgstr "URL"
 
 
-#: src/components/ChatGPT/ChatGPT.vue:225
+#: src/components/ChatGPT/ChatGPT.vue:230
 msgid "User"
 msgid "User"
 msgstr "使用者名稱"
 msgstr "使用者名稱"
 
 
@@ -1834,7 +1861,7 @@ msgstr ""
 "繼續嗎?"
 "繼續嗎?"
 
 
 #: src/views/dashboard/ServerAnalytic.vue:27
 #: src/views/dashboard/ServerAnalytic.vue:27
-#: src/views/dashboard/ServerAnalytic.vue:365
+#: src/views/dashboard/ServerAnalytic.vue:368
 msgid "Writes"
 msgid "Writes"
 msgstr "寫"
 msgstr "寫"
 
 
@@ -1860,6 +1887,10 @@ msgstr "您正在使用最新版本"
 msgid "You can check Nginx UI upgrade at this page."
 msgid "You can check Nginx UI upgrade at this page."
 msgstr "您可以在此頁面檢查 Nginx UI 的升級。"
 msgstr "您可以在此頁面檢查 Nginx UI 的升級。"
 
 
+#, fuzzy
+#~ msgid "The url is not valid"
+#~ msgstr "此功能在演示中不可用。"
+
 #~ msgid "ChatGPT Model"
 #~ msgid "ChatGPT Model"
 #~ msgstr "ChatGPT 模型"
 #~ msgstr "ChatGPT 模型"
 
 
@@ -1881,10 +1912,6 @@ msgstr "您可以在此頁面檢查 Nginx UI 的升級。"
 #~ msgid "Table"
 #~ msgid "Table"
 #~ msgstr "表格"
 #~ msgstr "表格"
 
 
-#, fuzzy
-#~ msgid "Server"
-#~ msgstr "伺服器資訊"
-
 #, fuzzy
 #, fuzzy
 #~ msgid "Leave blank will not change anything."
 #~ msgid "Leave blank will not change anything."
 #~ msgstr "留空表示不修改"
 #~ msgstr "留空表示不修改"

+ 9 - 4
app/src/layouts/BaseLayout.vue

@@ -1,9 +1,12 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import _ from 'lodash'
 import _ from 'lodash'
+import { storeToRefs } from 'pinia'
 import FooterLayout from './FooterLayout.vue'
 import FooterLayout from './FooterLayout.vue'
 import SideBar from './SideBar.vue'
 import SideBar from './SideBar.vue'
 import HeaderLayout from './HeaderLayout.vue'
 import HeaderLayout from './HeaderLayout.vue'
 import PageHeader from '@/components/PageHeader/PageHeader.vue'
 import PageHeader from '@/components/PageHeader/PageHeader.vue'
+import { useSettingsStore } from '@/pinia'
+import settings from '@/api/settings'
 
 
 const drawer_visible = ref(false)
 const drawer_visible = ref(false)
 const collapsed = ref(collapse())
 const collapsed = ref(collapse())
@@ -19,6 +22,12 @@ function getClientWidth() {
 function collapse() {
 function collapse() {
   return getClientWidth() < 1280
   return getClientWidth() < 1280
 }
 }
+
+const { server_name } = storeToRefs(useSettingsStore())
+
+settings.get_server_name().then(r => {
+  server_name.value = r.name
+})
 </script>
 </script>
 
 
 <template>
 <template>
@@ -150,10 +159,6 @@ body {
   font-size: 13px;
   font-size: 13px;
 }
 }
 
 
-.ant-card-bordered {
-
-}
-
 .header-notice-wrapper .ant-tabs-content {
 .header-notice-wrapper .ant-tabs-content {
   max-height: 250px;
   max-height: 250px;
 }
 }

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

@@ -42,7 +42,7 @@ interface meta {
 
 
 interface sidebar {
 interface sidebar {
   path: string
   path: string
-  name: () => string
+  name: string
   meta: meta
   meta: meta
   children: sidebar[]
   children: sidebar[]
 }
 }
@@ -56,7 +56,7 @@ const visible: ComputedRef<sidebar[]> = computed(() => {
 
 
     const t: sidebar = {
     const t: sidebar = {
       path: s.path,
       path: s.path,
-      name: s?.meta?.name ?? (() => ''),
+      name: s.name as string,
       meta: s.meta as unknown as meta,
       meta: s.meta as unknown as meta,
       children: [],
       children: [],
     };
     };

+ 1 - 0
app/src/pinia/moudule/settings.ts

@@ -9,6 +9,7 @@ export const useSettingsStore = defineStore('settings', {
       id: 0,
       id: 0,
       name: 'Local',
       name: 'Local',
     },
     },
+    server_name: '',
   }),
   }),
   getters: {
   getters: {
     is_remote(): boolean {
     is_remote(): boolean {

+ 1 - 1
app/src/version.json

@@ -1 +1 @@
-{"version":"2.0.0-beta.22","build_id":131,"total_build":335}
+{"version":"2.0.0-beta.23","build_id":133,"total_build":337}

+ 10 - 5
app/src/views/certificate/ACMEUserSelector.vue

@@ -42,12 +42,17 @@ onMounted(async () => {
   users.value = []
   users.value = []
   let page = 1
   let page = 1
   while (true) {
   while (true) {
-    const r = await acme_user.get_list({ page })
-
-    users.value.push(...r.data)
-    if (r?.data?.length < r?.pagination?.per_page)
+    try {
+      const r = await acme_user.get_list({ page })
+
+      users.value.push(...r.data)
+      if (r?.data?.length < r?.pagination?.per_page)
+        break
+      page++
+    }
+    catch (e) {
       break
       break
-    page++
+    }
   }
   }
 
 
   init()
   init()

+ 7 - 1
app/src/views/dashboard/DashBoard.vue

@@ -1,11 +1,17 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import ServerAnalytic from '@/views/dashboard/ServerAnalytic.vue'
 import ServerAnalytic from '@/views/dashboard/ServerAnalytic.vue'
 import Environments from '@/views/dashboard/Environments.vue'
 import Environments from '@/views/dashboard/Environments.vue'
+
+const key = ref(0)
+
+setInterval(() => {
+  key.value++
+}, 5 * 60 * 1000)
 </script>
 </script>
 
 
 <template>
 <template>
   <div>
   <div>
-    <ServerAnalytic />
+    <ServerAnalytic :key />
     <Environments />
     <Environments />
   </div>
   </div>
 </template>
 </template>

+ 14 - 3
app/src/views/dashboard/Environments.vue

@@ -25,10 +25,21 @@ const node_map = computed(() => {
 
 
 let websocket: ReconnectingWebSocket | WebSocket
 let websocket: ReconnectingWebSocket | WebSocket
 
 
+onMounted(async () => {
+  let hasMore = true
+  let page = 1
+  while (hasMore) {
+    await environment.get_list({ page, enabled: true }).then(r => {
+      data.value.push(...r.data)
+      hasMore = r.data.length === r.pagination.per_page
+      page++
+    }).catch(() => {
+      hasMore = false
+    })
+  }
+})
+
 onMounted(() => {
 onMounted(() => {
-  environment.get_list().then(r => {
-    data.value = r.data
-  })
   websocket = analytic.nodes()
   websocket = analytic.nodes()
   websocket.onmessage = async m => {
   websocket.onmessage = async m => {
     const nodes = JSON.parse(m.data)
     const nodes = JSON.parse(m.data)

+ 49 - 8
app/src/views/environment/Environment.vue

@@ -1,11 +1,11 @@
 <script setup lang="tsx">
 <script setup lang="tsx">
 import { h } from 'vue'
 import { h } from 'vue'
-import { Badge } from 'ant-design-vue'
+import { Badge, Tag, message } from 'ant-design-vue'
 import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
 import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
 import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
 import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
 import environment from '@/api/environment'
 import environment from '@/api/environment'
 import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
 import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
-import { input } from '@/components/StdDesign/StdDataEntry'
+import { input, switcher } from '@/components/StdDesign/StdDataEntry'
 import type { Column, JSXElements } from '@/components/StdDesign/types'
 import type { Column, JSXElements } from '@/components/StdDesign/types'
 
 
 const columns: Column[] = [{
 const columns: Column[] = [{
@@ -16,6 +16,7 @@ const columns: Column[] = [{
   edit: {
   edit: {
     type: input,
     type: input,
   },
   },
+  search: true,
 },
 },
 {
 {
   title: () => $gettext('URL'),
   title: () => $gettext('URL'),
@@ -77,13 +78,19 @@ const columns: Column[] = [{
   customRender: (args: customRender) => {
   customRender: (args: customRender) => {
     const template: JSXElements = []
     const template: JSXElements = []
     const { text } = args
     const { text } = args
-    if (text === true || text > 0) {
-      template.push(<Badge status="success"/>)
-      template.push($gettext('Online'))
+    if (args.record.enabled) {
+      if (text === true || text > 0) {
+        template.push(<Badge status="success"/>)
+        template.push($gettext('Online'))
+      }
+      else {
+        template.push(<Badge status="error"/>)
+        template.push($gettext('Offline'))
+      }
     }
     }
     else {
     else {
-      template.push(<Badge status="error"/>)
-      template.push($gettext('Offline'))
+      template.push(<Badge status="default"/>)
+      template.push($gettext('Disabled'))
     }
     }
 
 
     return h('div', template)
     return h('div', template)
@@ -91,6 +98,26 @@ const columns: Column[] = [{
   sortable: true,
   sortable: true,
   pithy: true,
   pithy: true,
 },
 },
+{
+  title: () => $gettext('Enabled'),
+  dataIndex: 'enabled',
+  customRender: (args: customRender) => {
+    const template: JSXElements = []
+    const { text } = args
+    if (text === true || text > 0)
+      template.push(<Tag color="green">{$gettext('Enabled')}</Tag>)
+
+    else
+      template.push(<Tag color="orange">{$gettext('Disabled')}</Tag>)
+
+    return h('div', template)
+  },
+  edit: {
+    type: switcher,
+  },
+  sortable: true,
+  pithy: true,
+},
 {
 {
   title: () => $gettext('Updated at'),
   title: () => $gettext('Updated at'),
   dataIndex: 'updated_at',
   dataIndex: 'updated_at',
@@ -103,14 +130,28 @@ const columns: Column[] = [{
   dataIndex: 'action',
   dataIndex: 'action',
 }]
 }]
 
 
+const curd = ref()
+function load_from_settings() {
+  environment.load_from_settings().then(() => {
+    curd.value.get_list()
+    message.success($gettext('Load successfully'))
+  }).catch(e => {
+    message.error(`${$gettext('Server error')} ${e?.message}`)
+  })
+}
 </script>
 </script>
 
 
 <template>
 <template>
   <StdCurd
   <StdCurd
+    ref="curd"
     :title="$gettext('Environment')"
     :title="$gettext('Environment')"
     :api="environment"
     :api="environment"
     :columns="columns"
     :columns="columns"
-  />
+  >
+    <template #extra>
+      <a @click="load_from_settings">{{ $gettext('Load from settings') }}</a>
+    </template>
+  </StdCurd>
 </template>
 </template>
 
 
 <style lang="less" scoped>
 <style lang="less" scoped>

+ 0 - 2
app/src/views/other/Error.vue

@@ -5,8 +5,6 @@ const route = useRoute()
 const info = computed(() => {
 const info = computed(() => {
   if (typeof route.meta.error === 'function')
   if (typeof route.meta.error === 'function')
     return route.meta.error()
     return route.meta.error()
-  else if (typeof route.meta.error === 'string')
-    return route.meta.error
   else
   else
     return $gettext('File Not Found')
     return $gettext('File Not Found')
 })
 })

+ 11 - 2
app/src/views/preference/BasicSettings.vue

@@ -35,7 +35,7 @@ const errors: Record<string, Record<string, string>> = inject('errors') as Recor
       :label="$gettext('Github Proxy')"
       :label="$gettext('Github Proxy')"
       :validate-status="errors?.server?.github_proxy ? 'error' : ''"
       :validate-status="errors?.server?.github_proxy ? 'error' : ''"
       :help="errors?.server?.github_proxy === 'url'
       :help="errors?.server?.github_proxy === 'url'
-        ? $gettext('The url is not valid')
+        ? $gettext('The url is invalid')
         : ''"
         : ''"
     >
     >
       <AInput
       <AInput
@@ -47,7 +47,7 @@ const errors: Record<string, Record<string, string>> = inject('errors') as Recor
       :label="$gettext('CADir')"
       :label="$gettext('CADir')"
       :validate-status="errors?.server?.ca_dir ? 'error' : ''"
       :validate-status="errors?.server?.ca_dir ? 'error' : ''"
       :help="errors?.server?.ca_dir === 'url'
       :help="errors?.server?.ca_dir === 'url'
-        ? $gettext('The url is not valid')
+        ? $gettext('The url is invalid')
         : ''"
         : ''"
     >
     >
       <AInput v-model:value="data.server.ca_dir" />
       <AInput v-model:value="data.server.ca_dir" />
@@ -113,6 +113,15 @@ const errors: Record<string, Record<string, string>> = inject('errors') as Recor
         </template>
         </template>
       </Draggable>
       </Draggable>
     </AFormItem>
     </AFormItem>
+    <AFormItem
+      :label="$gettext('Server Name')"
+      :validate-status="errors?.server?.name ? 'error' : ''"
+      :help="errors?.server?.name.includes('alpha_num_dash_dot')
+        ? $gettext('The server name should only contain letters, numbers, dashes, and dots.')
+        : $gettext('Customize the name of local server to be displayed in the environment indicator.')"
+    >
+      <AInput v-model:value="data.server.name" />
+    </AFormItem>
   </AForm>
   </AForm>
 </template>
 </template>
 
 

+ 9 - 3
app/src/views/preference/OpenAISettings.vue

@@ -23,7 +23,13 @@ const models = shallowRef([
 
 
 <template>
 <template>
   <AForm layout="vertical">
   <AForm layout="vertical">
-    <AFormItem :label="$gettext('Model')">
+    <AFormItem
+      :label="$gettext('Model')"
+      :validate-status="errors?.openai?.model ? 'error' : ''"
+      :help="errors?.openai?.model === 'alpha_num_dash_dot'
+        ? $gettext('The model name should only contain letters, numbers, dashes, and dots.')
+        : ''"
+    >
       <AAutoComplete
       <AAutoComplete
         v-model:value="data.openai.model"
         v-model:value="data.openai.model"
         :options="models"
         :options="models"
@@ -33,7 +39,7 @@ const models = shallowRef([
       :label="$gettext('API Base Url')"
       :label="$gettext('API Base Url')"
       :validate-status="errors?.openai?.base_url ? 'error' : ''"
       :validate-status="errors?.openai?.base_url ? 'error' : ''"
       :help="errors?.openai?.base_url === 'url'
       :help="errors?.openai?.base_url === 'url'
-        ? $gettext('The url is not valid')
+        ? $gettext('The url is invalid.')
         : ''"
         : ''"
     >
     >
       <AInput
       <AInput
@@ -45,7 +51,7 @@ const models = shallowRef([
       :label="$gettext('API Proxy')"
       :label="$gettext('API Proxy')"
       :validate-status="errors?.openai?.proxy ? 'error' : ''"
       :validate-status="errors?.openai?.proxy ? 'error' : ''"
       :help="errors?.openai?.proxy === 'url'
       :help="errors?.openai?.proxy === 'url'
-        ? $gettext('The url is not valid')
+        ? $gettext('The url is invalid.')
         : ''"
         : ''"
     >
     >
       <AInput
       <AInput

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

@@ -1,6 +1,7 @@
 <script setup lang="ts">
 <script setup lang="ts">
 import { message } from 'ant-design-vue'
 import { message } from 'ant-design-vue'
 import type { Ref } from 'vue'
 import type { Ref } from 'vue'
+import { storeToRefs } from 'pinia'
 import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
 import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
 import settings from '@/api/settings'
 import settings from '@/api/settings'
 import BasicSettings from '@/views/preference/BasicSettings.vue'
 import BasicSettings from '@/views/preference/BasicSettings.vue'
@@ -8,6 +9,7 @@ import OpenAISettings from '@/views/preference/OpenAISettings.vue'
 import NginxSettings from '@/views/preference/NginxSettings.vue'
 import NginxSettings from '@/views/preference/NginxSettings.vue'
 import type { Settings } from '@/views/preference/typedef'
 import type { Settings } from '@/views/preference/typedef'
 import LogrotateSettings from '@/views/preference/LogrotateSettings.vue'
 import LogrotateSettings from '@/views/preference/LogrotateSettings.vue'
+import { useSettingsStore } from '@/pinia'
 
 
 const data = ref<Settings>({
 const data = ref<Settings>({
   server: {
   server: {
@@ -23,6 +25,7 @@ const data = ref<Settings>({
     node_secret: '',
     node_secret: '',
     cert_renewal_interval: 7,
     cert_renewal_interval: 7,
     recursive_nameservers: [],
     recursive_nameservers: [],
+    name: '',
   },
   },
   nginx: {
   nginx: {
     access_log_path: '',
     access_log_path: '',
@@ -49,12 +52,16 @@ settings.get().then(r => {
   data.value = r
   data.value = r
 })
 })
 
 
+const settingsStore = useSettingsStore()
+const { server_name } = storeToRefs(settingsStore)
 const errors = ref({}) as Ref<Record<string, Record<string, string>>>
 const errors = ref({}) as Ref<Record<string, Record<string, string>>>
 
 
 async function save() {
 async function save() {
   // fix type
   // fix type
   data.value.server.http_challenge_port = data.value.server.http_challenge_port.toString()
   data.value.server.http_challenge_port = data.value.server.http_challenge_port.toString()
   settings.save(data.value).then(r => {
   settings.save(data.value).then(r => {
+    if (!settingsStore.is_remote)
+      server_name.value = r?.server?.name ?? ''
     data.value = r
     data.value = r
     message.success($gettext('Save successfully'))
     message.success($gettext('Save successfully'))
     errors.value = {}
     errors.value = {}

+ 1 - 0
app/src/views/preference/typedef.ts

@@ -12,6 +12,7 @@ export interface Settings {
     ca_dir: string
     ca_dir: string
     cert_renewal_interval: number
     cert_renewal_interval: number
     recursive_nameservers: string[]
     recursive_nameservers: string[]
+    name: string
   }
   }
   nginx: {
   nginx: {
     access_log_path: string
     access_log_path: string

+ 1 - 1
app/version.json

@@ -1 +1 @@
-{"version":"2.0.0-beta.22","build_id":131,"total_build":335}
+{"version":"2.0.0-beta.23","build_id":133,"total_build":337}

+ 12 - 6
demo.Dockerfile

@@ -9,11 +9,17 @@ EXPOSE 80
 COPY resources/demo/ojbk.me /etc/nginx/sites-available/ojbk.me
 COPY resources/demo/ojbk.me /etc/nginx/sites-available/ojbk.me
 COPY resources/demo/app.ini /etc/nginx-ui/app.ini
 COPY resources/demo/app.ini /etc/nginx-ui/app.ini
 COPY resources/demo/demo.db /etc/nginx-ui/database.db
 COPY resources/demo/demo.db /etc/nginx-ui/database.db
-COPY resources/docker/nginx.conf /etc/nginx/nginx.conf
-COPY resources/docker/nginx-ui.conf /etc/nginx/conf.d/nginx-ui.conf
-COPY resources/docker/start.sh /app/start.sh
-COPY nginx-ui-$TARGETOS-$TARGETARCH$TARGETVARIANT/nginx-ui /app/nginx-ui
 
 
-RUN cd /app && chmod a+x start.sh && rm -f /etc/nginx/conf.d/default.conf
+# register nginx-ui service
+COPY resources/docker/nginx-ui.run /etc/s6-overlay/s6-rc.d/nginx-ui/run
+RUN echo 'longrun' > /etc/s6-overlay/s6-rc.d/nginx-ui/type && \
+    touch /etc/s6-overlay/s6-rc.d/user/contents.d/nginx-ui
 
 
-ENTRYPOINT ["./start.sh"]
+# copy nginx config
+COPY resources/docker/nginx.conf /usr/local/etc/nginx/nginx.conf
+COPY resources/docker/nginx-ui.conf /usr/local/etc/nginx/conf.d/nginx-ui.conf
+
+# copy nginx-ui executable binary
+COPY nginx-ui-$TARGETOS-$TARGETARCH$TARGETVARIANT/nginx-ui /usr/local/bin/nginx-ui
+
+RUN rm -f /etc/nginx/conf.d/default.conf

+ 2 - 1
docs/.vitepress/config/en.ts

@@ -38,7 +38,8 @@ export const enConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
             {text: 'Nginx', link: '/guide/config-nginx'},
             {text: 'Nginx', link: '/guide/config-nginx'},
             {text: 'Open AI', link: '/guide/config-openai'},
             {text: 'Open AI', link: '/guide/config-openai'},
             {text: 'Casdoor', link: '/guide/config-casdoor'},
             {text: 'Casdoor', link: '/guide/config-casdoor'},
-            {text: 'Logrotate', link: '/guide/config-logrotate'}
+            {text: 'Logrotate', link: '/guide/config-logrotate'},
+            {text: 'Cluster', link: '/guide/config-cluster'}
           ]
           ]
         },
         },
         {
         {

+ 2 - 1
docs/.vitepress/config/zh_CN.ts

@@ -43,7 +43,8 @@ export const zhCNConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
             {text: 'Nginx', link: '/zh_CN/guide/config-nginx'},
             {text: 'Nginx', link: '/zh_CN/guide/config-nginx'},
             {text: 'Open AI', link: '/zh_CN/guide/config-openai'},
             {text: 'Open AI', link: '/zh_CN/guide/config-openai'},
             {text: 'Casdoor', link: '/zh_CN/guide/config-casdoor'},
             {text: 'Casdoor', link: '/zh_CN/guide/config-casdoor'},
-            {text: 'Logrotate', link: '/zh_CN/guide/config-logrotate'}
+            {text: 'Logrotate', link: '/zh_CN/guide/config-logrotate'},
+            {text: '集群', link: '/zh_CN/guide/config-cluster'}
           ]
           ]
         },
         },
         {
         {

+ 2 - 1
docs/.vitepress/config/zh_TW.ts

@@ -42,7 +42,8 @@ export const zhTWConfig: LocaleSpecificConfig<DefaultTheme.Config> = {
             {text: 'Nginx', link: '/zh_TW/guide/config-nginx'},
             {text: 'Nginx', link: '/zh_TW/guide/config-nginx'},
             {text: 'Open AI', link: '/zh_TW/guide/config-openai'},
             {text: 'Open AI', link: '/zh_TW/guide/config-openai'},
             {text: 'Casdoor', link: '/zh_TW/guide/config-casdoor'},
             {text: 'Casdoor', link: '/zh_TW/guide/config-casdoor'},
-            {text: 'Logrotate', link: '/zh_CN/guide/config-logrotate'}
+            {text: 'Logrotate', link: '/zh_TW/guide/config-logrotate'},
+            {text: '集群', link: '/zh_TW/guide/config-cluster'}
           ]
           ]
         },
         },
         {
         {

+ 24 - 0
docs/guide/config-cluster.md

@@ -0,0 +1,24 @@
+# 集群
+From v2.0.0-beta.23, you can define multiple environments in the `cluster` section of the configuration file.
+
+## Node
+- Type: `string`
+- Structure:`Scheme://Host(:Port)?name=ENV_NAME&node_secret=NODE_SECRET&enabled=(true/false)`
+- Example: `http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true`
+
+If you have multiple environments to configure, please refer to the following configuration:
+```ini
+[cluster]
+Node = http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true
+Node = http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=false
+Node = http://10.0.0.3?name=node3&node_secret=my-node-secret&enabled=true
+```
+
+By default, Nginx UI will create the predefined environments during the bootstrapping stage.
+You can also find the "Load from Config" button in the environment list in the WebUI to manually update the environments.
+
+In order to avoid conflicts with the environemnts that already exist in the database,
+Nginx UI will check if the `Scheme://Host(:Port)` part is unique.
+If it does not exist, it will be created according to the configuration, otherwise no action will be taken.
+
+Please note that if you delete a node from the configuration file, Nginx UI will not delete the record from the database.

+ 0 - 30
docs/guide/config-nginx.md

@@ -9,36 +9,6 @@ Starting from Nginx UI v2.0.0-beta.3, we have renamed the `nginx_log` configurat
 ## Logs
 ## Logs
 Nginx logs are crucial for monitoring, troubleshooting, and maintaining your web server. They provide valuable insights into server performance, user behavior, and potential issues.
 Nginx logs are crucial for monitoring, troubleshooting, and maintaining your web server. They provide valuable insights into server performance, user behavior, and potential issues.
 
 
-In this section, we will discuss two main types of logs: access logs and error logs.
-
-For Nginx-UI Docker users upgrading from version v1.5.2 or earlier, you need to add separate `access_log` and `error_log` directives in `nginx.conf` before configuring `app.ini`.
-
-In the Nginx-UI container, `/var/log/nginx/access.log` is a symbolic link to `/dev/stdout`, and `/var/log/nginx/error.log` is a symbolic link to `/dev/stderr`. This setup allows you to view Nginx and Nginx-UI logs using the `docker logs nginx-ui` command. However, these devices do not support the `tail` command, so it is necessary to use additional log files to record Nginx logs.
-
-Example:
-
-```nginx
-error_log /var/log/nginx/error.log notice;
-error_log /var/log/nginx/error.local.log notice;
-
-http {
-...
-    access_log /var/log/nginx/access.log main;
-    access_log /var/log/nginx/access.local.log main;
-...
-}
-```
-
-Afterward, set the nginx access log and error log paths in `app.ini`, then restart nginx-ui.
-
-Example:
-
-```ini
-[nginx]
-AccessLogPath = /var/log/nginx/access.local.log
-ErrorLogPath = /var/log/nginx/error.local.log
-```
-
 ### AccessLogPath
 ### AccessLogPath
 
 
 - Type: `string`
 - Type: `string`

+ 25 - 0
docs/guide/config-server.md

@@ -106,6 +106,7 @@ allows them to set a proxy for github.com to improve accessibility.
 
 
 ## CertRenewalInterval
 ## CertRenewalInterval
 
 
+- Version:`>= v2.0.0-beta.22`
 - Type: `int`
 - Type: `int`
 - Default value: `7`
 - Default value: `7`
 
 
@@ -114,9 +115,33 @@ By default, Nginx UI will automatically renew the certificate every 7 days.
 
 
 ## RecursiveNameservers
 ## RecursiveNameservers
 
 
+- Version:`>= v2.0.0-beta.22`
 - Type: `[]string`
 - Type: `[]string`
 - Example: `8.8.8.8:53,1.1.1.1:53`
 - Example: `8.8.8.8:53,1.1.1.1:53`
 
 
 This option is used to set the recursive nameservers used by
 This option is used to set the recursive nameservers used by
 Nginx UI in the DNS challenge step of applying for a certificate.
 Nginx UI in the DNS challenge step of applying for a certificate.
 If this option is not configured, Nginx UI will use the nameservers settings of the operating system.
 If this option is not configured, Nginx UI will use the nameservers settings of the operating system.
+
+## SkipInstallation
+
+- Version:`>= v2.0.0-beta.23`
+- Type: `bool`
+- Default value: `false`
+
+You can skip the installation of the Nginx UI server by setting this option to `true`.
+This is useful when you want to deploy Nginx UI to multiple servers with
+a same configuration file or environment variables.
+
+By default, if you enabled the skip installation mode without setting the `JWTSecret` and `NodeSecret` options
+in the server section, Nginx UI will generate a random UUID value for these two options.
+
+Plus, if you don't set the `Email` option also in the server section,
+Nginx UI will not create a system initial acme user, this means you can't apply for an SSL certificate in this server.
+
+## Name
+
+- Version:`>= v2.0.0-beta.23`
+- Type: `string`
+
+Use this option to customize the name of local server to be displayed in the environment indicator.

+ 1 - 1
docs/zh_CN/guide/build.md

@@ -31,5 +31,5 @@ pnpm build
 请在项目的根目录执行以下命令。
 请在项目的根目录执行以下命令。
 
 
 ```shell
 ```shell
-go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'" -o dist/nginx-ui -v main.go
+go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'" -o nginx-ui -v main.go
 ```
 ```

+ 24 - 0
docs/zh_CN/guide/config-cluster.md

@@ -0,0 +1,24 @@
+# 集群
+
+自 v2.0.0-beta.23 起,您可以在配置文件的 `cluster` 分区中定义多个环境。
+
+## Node
+- 类型: `string`
+- 结构:`Scheme://Host(:Port)?name=环境名称&node_secret=节点密钥&enabled=是否启用`
+- 示例: `http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true`
+
+
+如果您需要配置多个环境,请参考下面的配置:
+```ini
+[cluster]
+Node = http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true
+Node = http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=false
+Node = http://10.0.0.3?name=node3&node_secret=my-node-secret&enabled=true
+```
+
+默认情况下,Nginx UI 将在启动阶段执行环境的创建操作,您也可以在 WebUI 中的环境列表中找到「从配置中加载」按钮,手动更新环境。
+
+为了避免与数据库内已经存在的环境冲突,Nginx UI 会检查 `Scheme://Host(:Port)` 部分是否应是否唯一,
+如果不存在,则按照配置进行创建,反之则不会进行任何操作。
+
+注意:如果您删除了配置文件中的某个节点,Nginx UI 不会删除数据库中的记录。

+ 0 - 33
docs/zh_CN/guide/config-nginx.md

@@ -10,39 +10,6 @@
 ## 日志
 ## 日志
 Nginx 日志对于监控、排查问题和维护您的 Web 服务器至关重要。它们提供了有关服务器性能、用户行为和潜在问题的宝贵见解。
 Nginx 日志对于监控、排查问题和维护您的 Web 服务器至关重要。它们提供了有关服务器性能、用户行为和潜在问题的宝贵见解。
 
 
-在本节中,我们将讨论两种主要类型的日志:访问日志和错误日志。
-
-对于从 v1.5.2 或更早版本升级的 Nginx-UI Docker 用户,在配置 `app.ini` 之前,您需要在 `nginx.conf`
-中添加单独的 `access_log` 和 `error_log` 指令。
-
-在 Nginx-UI 容器中,`/var/log/nginx/access.log` 是一个指向 `/dev/stdout` 的符号链接,而 `/var/log/nginx/error.log`
-是一个指向 `/dev/stderr` 的符号链接。这种设置允许您使用 `docker logs nginx-ui` 命令查看 Nginx 和 Nginx-UI 日志。然而,这两个设备不支持
-`tail` 命令,因此有必要使用额外的日志文件来记录 Nginx 日志。
-
-示例:
-
-```nginx
-error_log /var/log/nginx/error.log notice;
-error_log /var/log/nginx/error.local.log notice;
-
-http {
-...
-    access_log /var/log/nginx/access.log main;
-    access_log /var/log/nginx/access.local.log main;
-...
-}
-```
-
-之后,请在 `app.ini` 中设置 nginx 访问日志和错误日志路径,然后重新启动 nginx-ui。
-
-示例:
-
-```ini
-[nginx]
-AccessLogPath = /var/log/nginx/access.local.log
-ErrorLogPath = /var/log/nginx/error.local.log
-```
-
 ### AccessLogPath
 ### AccessLogPath
 
 
 - 类型:`string`
 - 类型:`string`

+ 24 - 0
docs/zh_CN/guide/config-server.md

@@ -97,6 +97,7 @@ JWT 是一种用于验证用户身份的标准,它可以在用户登录后生
 
 
 ## CertRenewalInterval
 ## CertRenewalInterval
 
 
+- 版本:`>= v2.0.0-beta.22`
 - 类型:`int`
 - 类型:`int`
 - 默认值: `7`
 - 默认值: `7`
 
 
@@ -104,7 +105,30 @@ JWT 是一种用于验证用户身份的标准,它可以在用户登录后生
 
 
 ## RecursiveNameservers
 ## RecursiveNameservers
 
 
+- 版本:`>= v2.0.0-beta.22`
 - 类型: `[]string`
 - 类型: `[]string`
 - 示例: `8.8.8.8:53,1.1.1.1:53`
 - 示例: `8.8.8.8:53,1.1.1.1:53`
 
 
 此选项用于设置 Nginx UI 在申请证书的 DNS 挑战步骤所使用的递归域名服务器。在不配置此项目的情况下,Nginx UI 使用操作系统的域名服务器设置。
 此选项用于设置 Nginx UI 在申请证书的 DNS 挑战步骤所使用的递归域名服务器。在不配置此项目的情况下,Nginx UI 使用操作系统的域名服务器设置。
+
+## SkipInstallation
+
+- 版本:`>= v2.0.0-beta.23`
+- 类型:`bool`
+- 默认值:`false`
+
+通过将此选项设置为 `true`,您可以跳过 Nginx UI 服务器的安装。
+当您希望使用相同的配置文件或环境变量将 Nginx UI 部署到多个服务器时,这非常有用。
+
+默认情况下,如果您启用了跳过安装模式,而没有在服务器部分设置 `JWTSecret` 和 `NodeSecret` 选项,
+Nginx UI 将为这两个选项生成一个随机的 UUID 值。
+
+此外,如果您也没有在服务器部分设置 `Email` 选项,
+Nginx UI 将不会创建系统初始的 acme 用户,这意味着您无法在此服务器上申请 SSL 证书。
+
+## Name
+
+- 版本:`>= v2.0.0-beta.23`
+- 类型:`string`
+
+使用此选项自定义本地服务器的名称,以在环境指示器中显示。

+ 1 - 1
docs/zh_TW/guide/build.md

@@ -31,5 +31,5 @@ pnpm build
 請在專案的根資料夾執行以下命令。
 請在專案的根資料夾執行以下命令。
 
 
 ```shell
 ```shell
-go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'" -o dist/nginx-ui -v main.go
+go build -tags=jsoniter -ldflags "$LD_FLAGS -X 'github.com/0xJacky/Nginx-UI/settings.buildTime=$(date +%s)'" -o nginx-ui -v main.go
 ```
 ```

+ 26 - 0
docs/zh_TW/guide/config-cluster.md

@@ -0,0 +1,26 @@
+# 集群
+
+自 v2.0.0-beta.23 起,您可以在配置文件的 `cluster` 分區中定義多個環境。
+
+## Node
+
+- 版本:`>= v2.0.0-beta.23`
+- 類型: `string`
+- 結構:`Scheme://Host(:Port)?name=環境名稱&node_secret=節點密鑰&enabled=是否啟用`
+- 範例: `http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true`
+
+
+如果您需要配置多個環境,請參考下面的配置:
+```ini
+[cluster]
+Node = http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true
+Node = http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=false
+Node = http://10.0.0.3?name=node3&node_secret=my-node-secret&enabled=true
+```
+
+預設情況下,Nginx UI 將在啟動階段執行環境的創建操作,您也可以在 WebUI 中的環境列表中找到「從配置中加載」按鈕,手動更新環境。
+
+為了避免與資料庫內已經存在的環境衝突,Nginx UI 會檢查 Scheme://Host(:Port) 部分是否應是否唯一,
+如果不存在,則按照配置進行創建,反之則不會進行任何操作。
+
+注意:如果您刪除了配置文件中的某個節點,Nginx UI 不會刪除資料庫中的記錄。

+ 0 - 33
docs/zh_TW/guide/config-nginx.md

@@ -9,39 +9,6 @@
 ## 日誌
 ## 日誌
 Nginx 日誌對於監控、排查問題和維護您的 Web 伺服器至關重要。它們提供了有關伺服器性能、用戶行為和潛在問題的寶貴見解。
 Nginx 日誌對於監控、排查問題和維護您的 Web 伺服器至關重要。它們提供了有關伺服器性能、用戶行為和潛在問題的寶貴見解。
 
 
-在本節中,我們將討論兩種主要類型的日誌:訪問日誌和錯誤日誌。
-
-對於從 v1.5.2 或更早版本升級的 Nginx-UI Docker 用戶,在配置 `app.ini` 之前,您需要在 `nginx.conf`
-中添加單獨的 `access_log` 和 `error_log` 指令。
-
-在 Nginx-UI 容器中,`/var/log/nginx/access.log` 是一個指向 `/dev/stdout` 的符號鏈接,而 `/var/log/nginx/error.log`
-是一個指向 `/dev/stderr` 的符號鏈接。這種設置允許您使用 `docker logs nginx-ui` 命令查看 Nginx 和 Nginx-UI 日誌。然而,這兩個設備不支持
-`tail` 命令,因此有必要使用額外的日誌文件來記錄 Nginx 日誌。
-
-範例:
-
-```nginx
-error_log /var/log/nginx/error.log notice;
-error_log /var/log/nginx/error.local.log notice;
-
-http {
-...
-    access_log /var/log/nginx/access.log main;
-    access_log /var/log/nginx/access.local.log main;
-...
-}
-```
-
-之後,請在 `app.ini` 中設置 nginx 訪問日誌和錯誤日誌路徑,然後重新啟動 nginx-ui。
-
-範例:
-
-```ini
-[nginx]
-AccessLogPath = /var/log/nginx/access.local.log
-ErrorLogPath = /var/log/nginx/error.local.log
-```
-
 ### AccessLogPath
 ### AccessLogPath
 
 
 - 類型:`string`
 - 類型:`string`

+ 24 - 0
docs/zh_TW/guide/config-server.md

@@ -98,6 +98,7 @@ JWT 是一種用於驗證用戶身份的標準,它可以在用戶登錄後生
 
 
 ## CertRenewalInterval
 ## CertRenewalInterval
 
 
+- 版本:`>= v2.0.0-beta.22`
 - 類型:`int`
 - 類型:`int`
 - 預設值: `7`
 - 預設值: `7`
 
 
@@ -105,7 +106,30 @@ JWT 是一種用於驗證用戶身份的標準,它可以在用戶登錄後生
 
 
 ## RecursiveNameservers
 ## RecursiveNameservers
 
 
+- 版本:`>= v2.0.0-beta.22`
 - 類型: `[]string`
 - 類型: `[]string`
 - 範例: `8.8.8.8:53,1.1.1.1:53`
 - 範例: `8.8.8.8:53,1.1.1.1:53`
 
 
 此選項用於設定 Nginx UI 在申請證書的 DNS 挑戰步驟所使用的遞迴域名伺服器。在不配置此項目的情況下,Nginx UI 使用作業系統的域名伺服器設定。
 此選項用於設定 Nginx UI 在申請證書的 DNS 挑戰步驟所使用的遞迴域名伺服器。在不配置此項目的情況下,Nginx UI 使用作業系統的域名伺服器設定。
+
+## SkipInstallation
+
+- 版本:`>= v2.0.0-beta.23`
+- 類型:`bool`
+- 預設值:`false`
+
+透過將此選項設定為 `true`,您可以跳過 Nginx UI 伺服器的安裝。
+當您希望使用相同的配置文件或環境變數將 Nginx UI 部署到多個伺服器時,這非常有用。
+
+預設情況下,如果您啟用了跳過安裝模式,而沒有在伺服器部分設定 `JWTSecret` 和 `NodeSecret` 選項,
+Nginx UI 將為這兩個選項生成一個隨機的 UUID 值。
+
+此外,如果您也沒有在伺服器部分設定 `Email` 選項,
+Nginx UI 將不會創建系統初始的 acme 使用者,這意味著您無法在此伺服器上申請 SSL 證書。
+
+## Name
+
+- 版本:`>= v2.0.0-beta.23`
+- 類型:`string`
+
+使用此選項自定義本地伺服器的名稱,以在環境指示器中顯示。

+ 31 - 30
go.mod

@@ -5,15 +5,16 @@ go 1.22.0
 require (
 require (
 	github.com/0xJacky/pofile v0.2.1
 	github.com/0xJacky/pofile v0.2.1
 	github.com/BurntSushi/toml v1.3.2
 	github.com/BurntSushi/toml v1.3.2
-	github.com/casdoor/casdoor-go-sdk v0.43.0
+	github.com/caarlos0/env/v11 v11.0.0
+	github.com/casdoor/casdoor-go-sdk v0.45.0
 	github.com/creack/pty v1.1.21
 	github.com/creack/pty v1.1.21
 	github.com/dustin/go-humanize v1.0.1
 	github.com/dustin/go-humanize v1.0.1
 	github.com/fatih/color v1.16.0
 	github.com/fatih/color v1.16.0
-	github.com/gin-contrib/static v1.1.1
-	github.com/gin-gonic/gin v1.9.1
+	github.com/gin-contrib/static v1.1.2
+	github.com/gin-gonic/gin v1.10.0
 	github.com/go-acme/lego/v4 v4.16.1
 	github.com/go-acme/lego/v4 v4.16.1
 	github.com/go-co-op/gocron v1.37.0
 	github.com/go-co-op/gocron v1.37.0
-	github.com/go-playground/validator/v10 v10.19.0
+	github.com/go-playground/validator/v10 v10.20.0
 	github.com/golang-jwt/jwt v3.2.2+incompatible
 	github.com/golang-jwt/jwt v3.2.2+incompatible
 	github.com/google/uuid v1.6.0
 	github.com/google/uuid v1.6.0
 	github.com/gorilla/websocket v1.5.1
 	github.com/gorilla/websocket v1.5.1
@@ -25,12 +26,12 @@ require (
 	github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308
 	github.com/pretty66/websocketproxy v0.0.0-20220507015215-930b3a686308
 	github.com/samber/lo v1.39.0
 	github.com/samber/lo v1.39.0
 	github.com/sashabaranov/go-openai v1.23.0
 	github.com/sashabaranov/go-openai v1.23.0
-	github.com/shirou/gopsutil/v3 v3.24.3
+	github.com/shirou/gopsutil/v3 v3.24.4
 	github.com/shopspring/decimal v1.4.0
 	github.com/shopspring/decimal v1.4.0
 	github.com/spf13/cast v1.6.0
 	github.com/spf13/cast v1.6.0
 	github.com/tufanbarisyildirim/gonginx v0.0.0-20240109151651-bb3e845a7a2a
 	github.com/tufanbarisyildirim/gonginx v0.0.0-20240109151651-bb3e845a7a2a
 	go.uber.org/zap v1.27.0
 	go.uber.org/zap v1.27.0
-	golang.org/x/crypto v0.22.0
+	golang.org/x/crypto v0.23.0
 	gopkg.in/guregu/null.v4 v4.0.0
 	gopkg.in/guregu/null.v4 v4.0.0
 	gopkg.in/ini.v1 v1.67.0
 	gopkg.in/ini.v1 v1.67.0
 	gorm.io/driver/sqlite v1.5.5
 	gorm.io/driver/sqlite v1.5.5
@@ -42,14 +43,14 @@ require (
 require (
 require (
 	cloud.google.com/go/auth v0.3.0 // indirect
 	cloud.google.com/go/auth v0.3.0 // indirect
 	cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
 	cloud.google.com/go/auth/oauth2adapt v0.2.2 // indirect
-	cloud.google.com/go/compute v1.25.1 // indirect
+	cloud.google.com/go/compute v1.26.0 // indirect
 	cloud.google.com/go/compute/metadata v0.3.0 // indirect
 	cloud.google.com/go/compute/metadata v0.3.0 // indirect
 	filippo.io/edwards25519 v1.1.0 // indirect
 	filippo.io/edwards25519 v1.1.0 // indirect
 	github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
 	github.com/AdamSLevy/jsonrpc2/v14 v14.1.0 // indirect
 	github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
 	github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.2 // indirect
-	github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 // indirect
+	github.com/Azure/azure-sdk-for-go/sdk/internal v1.7.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 // indirect
 	github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/privatedns/armprivatedns v1.2.0 // indirect
 	github.com/Azure/go-autorest v14.2.0+incompatible // indirect
 	github.com/Azure/go-autorest v14.2.0+incompatible // indirect
@@ -69,7 +70,7 @@ require (
 	github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
 	github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
 	github.com/StackExchange/wmi v1.2.1 // indirect
 	github.com/StackExchange/wmi v1.2.1 // indirect
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
-	github.com/aliyun/alibaba-cloud-sdk-go v1.62.726 // indirect
+	github.com/aliyun/alibaba-cloud-sdk-go v1.62.731 // indirect
 	github.com/andybalholm/brotli v1.1.0 // indirect
 	github.com/andybalholm/brotli v1.1.0 // indirect
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
 	github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
 	github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect
 	github.com/aws/aws-sdk-go-v2 v1.26.1 // indirect
@@ -136,7 +137,7 @@ require (
 	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/gofuzz v1.2.0 // indirect
 	github.com/google/s2a-go v0.1.7 // indirect
 	github.com/google/s2a-go v0.1.7 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
 	github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
-	github.com/googleapis/gax-go/v2 v2.12.3 // indirect
+	github.com/googleapis/gax-go/v2 v2.12.4 // indirect
 	github.com/gophercloud/gophercloud v1.11.0 // indirect
 	github.com/gophercloud/gophercloud v1.11.0 // indirect
 	github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
 	github.com/gophercloud/utils v0.0.0-20231010081019-80377eca5d56 // indirect
 	github.com/gorilla/css v1.0.1 // indirect
 	github.com/gorilla/css v1.0.1 // indirect
@@ -171,7 +172,7 @@ require (
 	github.com/labstack/echo/v4 v4.12.0 // indirect
 	github.com/labstack/echo/v4 v4.12.0 // indirect
 	github.com/labstack/gommon v0.4.2 // indirect
 	github.com/labstack/gommon v0.4.2 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
 	github.com/leodido/go-urn v1.4.0 // indirect
-	github.com/linode/linodego v1.33.0 // indirect
+	github.com/linode/linodego v1.33.1 // indirect
 	github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
 	github.com/liquidweb/liquidweb-cli v0.7.0 // indirect
 	github.com/liquidweb/liquidweb-go v1.6.4 // indirect
 	github.com/liquidweb/liquidweb-go v1.6.4 // indirect
 	github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 // indirect
 	github.com/lufia/plan9stats v0.0.0-20240408141607-282e7b5d6b74 // indirect
@@ -202,7 +203,7 @@ require (
 	github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
 	github.com/oracle/oci-go-sdk v24.3.0+incompatible // indirect
 	github.com/ovh/go-ovh v1.5.1 // indirect
 	github.com/ovh/go-ovh v1.5.1 // indirect
 	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
 	github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
-	github.com/pelletier/go-toml/v2 v2.2.1 // indirect
+	github.com/pelletier/go-toml/v2 v2.2.2 // indirect
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
 	github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/pmezard/go-difflib v1.0.0 // indirect
 	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
 	github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
@@ -224,22 +225,22 @@ require (
 	github.com/stretchr/testify v1.9.0 // indirect
 	github.com/stretchr/testify v1.9.0 // indirect
 	github.com/tdewolff/minify/v2 v2.20.20 // indirect
 	github.com/tdewolff/minify/v2 v2.20.20 // indirect
 	github.com/tdewolff/parse/v2 v2.7.13 // indirect
 	github.com/tdewolff/parse/v2 v2.7.13 // indirect
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.910 // indirect
-	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.910 // indirect
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.914 // indirect
+	github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.914 // indirect
 	github.com/tklauser/go-sysconf v0.3.14 // indirect
 	github.com/tklauser/go-sysconf v0.3.14 // indirect
 	github.com/tklauser/numcpus v0.8.0 // indirect
 	github.com/tklauser/numcpus v0.8.0 // indirect
 	github.com/transip/gotransip/v6 v6.23.0 // indirect
 	github.com/transip/gotransip/v6 v6.23.0 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
 	github.com/ugorji/go/codec v1.2.12 // indirect
 	github.com/ugorji/go/codec v1.2.12 // indirect
-	github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a // indirect
+	github.com/ultradns/ultradns-go-sdk v1.6.2-20240501171831-432d643 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
 	github.com/valyala/bytebufferpool v1.0.0 // indirect
 	github.com/valyala/fasttemplate v1.2.2 // indirect
 	github.com/valyala/fasttemplate v1.2.2 // indirect
 	github.com/vinyldns/go-vinyldns v0.9.16 // indirect
 	github.com/vinyldns/go-vinyldns v0.9.16 // indirect
 	github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
 	github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
 	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
 	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
 	github.com/vultr/govultr/v2 v2.17.2 // indirect
 	github.com/vultr/govultr/v2 v2.17.2 // indirect
-	github.com/yandex-cloud/go-genproto v0.0.0-20240425114406-68c9b49389a1 // indirect
-	github.com/yandex-cloud/go-sdk v0.0.0-20240425115054-85caccb84041 // indirect
+	github.com/yandex-cloud/go-genproto v0.0.0-20240502080826-5fa7aabf7673 // indirect
+	github.com/yandex-cloud/go-sdk v0.0.0-20240502081211-7639841896bb // indirect
 	github.com/yosssi/ace v0.0.5 // indirect
 	github.com/yosssi/ace v0.0.5 // indirect
 	github.com/yusufpapurcu/wmi v1.2.4 // indirect
 	github.com/yusufpapurcu/wmi v1.2.4 // indirect
 	go.opencensus.io v0.24.0 // indirect
 	go.opencensus.io v0.24.0 // indirect
@@ -250,23 +251,23 @@ require (
 	go.uber.org/atomic v1.11.0 // indirect
 	go.uber.org/atomic v1.11.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/multierr v1.11.0 // indirect
 	go.uber.org/ratelimit v0.3.1 // indirect
 	go.uber.org/ratelimit v0.3.1 // indirect
-	golang.org/x/arch v0.7.0 // indirect
-	golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f // indirect
+	golang.org/x/arch v0.8.0 // indirect
+	golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 // indirect
 	golang.org/x/mod v0.17.0 // indirect
 	golang.org/x/mod v0.17.0 // indirect
-	golang.org/x/net v0.24.0 // indirect
-	golang.org/x/oauth2 v0.19.0 // indirect
+	golang.org/x/net v0.25.0 // indirect
+	golang.org/x/oauth2 v0.20.0 // indirect
 	golang.org/x/sync v0.7.0 // indirect
 	golang.org/x/sync v0.7.0 // indirect
-	golang.org/x/sys v0.19.0 // indirect
-	golang.org/x/text v0.14.0 // indirect
+	golang.org/x/sys v0.20.0 // indirect
+	golang.org/x/text v0.15.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
 	golang.org/x/time v0.5.0 // indirect
-	golang.org/x/tools v0.20.0 // indirect
-	google.golang.org/api v0.176.1 // indirect
+	golang.org/x/tools v0.21.0 // indirect
+	google.golang.org/api v0.177.0 // indirect
 	google.golang.org/appengine v1.6.8 // indirect
 	google.golang.org/appengine v1.6.8 // indirect
-	google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be // indirect
-	google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be // indirect
-	google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be // indirect
+	google.golang.org/genproto v0.0.0-20240506185236-b8a5c65736ae // indirect
+	google.golang.org/genproto/googleapis/api v0.0.0-20240506185236-b8a5c65736ae // indirect
+	google.golang.org/genproto/googleapis/rpc v0.0.0-20240506185236-b8a5c65736ae // indirect
 	google.golang.org/grpc v1.63.2 // indirect
 	google.golang.org/grpc v1.63.2 // indirect
-	google.golang.org/protobuf v1.33.0 // indirect
+	google.golang.org/protobuf v1.34.1 // indirect
 	gopkg.in/fsnotify.v1 v1.4.7 // indirect
 	gopkg.in/fsnotify.v1 v1.4.7 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/ns1/ns1-go.v2 v2.7.13 // indirect
 	gopkg.in/ns1/ns1-go.v2 v2.7.13 // indirect
@@ -279,7 +280,7 @@ require (
 	k8s.io/api v0.30.0 // indirect
 	k8s.io/api v0.30.0 // indirect
 	k8s.io/apimachinery v0.30.0 // indirect
 	k8s.io/apimachinery v0.30.0 // indirect
 	k8s.io/klog/v2 v2.120.1 // indirect
 	k8s.io/klog/v2 v2.120.1 // indirect
-	k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 // indirect
+	k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 // indirect
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
 )
 )

+ 62 - 0
go.sum

@@ -181,6 +181,8 @@ cloud.google.com/go/compute v1.23.4 h1:EBT9Nw4q3zyE7G45Wvv3MzolIrCJEuHys5muLY0wv
 cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI=
 cloud.google.com/go/compute v1.23.4/go.mod h1:/EJMj55asU6kAFnuZET8zqgwgJ9FvXWXOkkfQZa4ioI=
 cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU=
 cloud.google.com/go/compute v1.25.1 h1:ZRpHJedLtTpKgr3RV1Fx23NuaAEN1Zfx9hw1u4aJdjU=
 cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls=
 cloud.google.com/go/compute v1.25.1/go.mod h1:oopOIR53ly6viBYxaDhBfJwzUAxf1zE//uf3IB011ls=
+cloud.google.com/go/compute v1.26.0 h1:uHf0NN2nvxl1Gh4QO83yRCOdMK4zivtMS5gv0dEX0hg=
+cloud.google.com/go/compute v1.26.0/go.mod h1:T9RIRap4pVHCGUkVFRJ9hygT3KCXjip41X1GgWtBBII=
 cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
 cloud.google.com/go/compute/metadata v0.1.0/go.mod h1:Z1VN+bulIf6bt4P/C37K4DyZYZEXYonfTBHHFPO/4UU=
 cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
 cloud.google.com/go/compute/metadata v0.2.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
 cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
 cloud.google.com/go/compute/metadata v0.2.1/go.mod h1:jgHgmJd2RKBGzXqF5LR2EZMGxBkeanZ9wwa75XHJgOM=
@@ -630,6 +632,8 @@ github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aM
 github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
 github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
 github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 h1:sUFnFjzDUie80h24I7mrKtwCKgLY9L8h5Tp2x9+TWqk=
 github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0 h1:sUFnFjzDUie80h24I7mrKtwCKgLY9L8h5Tp2x9+TWqk=
 github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0/go.mod h1:52JbnQTp15qg5mRkMBHwp0j0ZFwHJ42Sx3zVV5RE9p0=
 github.com/Azure/azure-sdk-for-go/sdk/internal v1.6.0/go.mod h1:52JbnQTp15qg5mRkMBHwp0j0ZFwHJ42Sx3zVV5RE9p0=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.7.0 h1:rTfKOCZGy5ViVrlA74ZPE99a+SgoEE2K/yg3RyW9dFA=
+github.com/Azure/azure-sdk-for-go/sdk/internal v1.7.0/go.mod h1:4OG6tQ9EOP/MT0NMjDlRzWoVFxfu9rN9B2X+tlSVktg=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0 h1:lpOxwrQ919lCZoNCd69rVt8u1eLZuMORrGXqy8sNf3c=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/dns/armdns v1.2.0/go.mod h1:fSvRkb8d26z9dbL40Uf/OO6Vo9iExtZK3D0ulRV+8M0=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/internal/v2 v2.0.0 h1:PTFGRSlMKCQelWwxUyYVEUqseBJVemLyqWJjvMyt0do=
@@ -709,6 +713,8 @@ github.com/aliyun/alibaba-cloud-sdk-go v1.62.676 h1:ChWMMr76tXrRh3ximWQyg83EROEf
 github.com/aliyun/alibaba-cloud-sdk-go v1.62.676/go.mod h1:CJJYa1ZMxjlN/NbXEwmejEnBkhi0DV+Yb3B2lxf+74o=
 github.com/aliyun/alibaba-cloud-sdk-go v1.62.676/go.mod h1:CJJYa1ZMxjlN/NbXEwmejEnBkhi0DV+Yb3B2lxf+74o=
 github.com/aliyun/alibaba-cloud-sdk-go v1.62.726 h1:vCatyVjwoeS9PSyd6PnPBjQnxR1b8eyFhbJ0obHE6Ok=
 github.com/aliyun/alibaba-cloud-sdk-go v1.62.726 h1:vCatyVjwoeS9PSyd6PnPBjQnxR1b8eyFhbJ0obHE6Ok=
 github.com/aliyun/alibaba-cloud-sdk-go v1.62.726/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/aliyun/alibaba-cloud-sdk-go v1.62.726/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
+github.com/aliyun/alibaba-cloud-sdk-go v1.62.731 h1:Zo2TSHK/E5Q+uWPVnFyaQ26ODrY/NpJzsiQnQKfFIiY=
+github.com/aliyun/alibaba-cloud-sdk-go v1.62.731/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
 github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
 github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
 github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
@@ -811,10 +817,14 @@ github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4
 github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
 github.com/c-bata/go-prompt v0.2.5/go.mod h1:vFnjEGDIIA/Lib7giyE4E9c50Lvl8j0S+7FVlAwDAVw=
 github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY=
 github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY=
 github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
 github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
+github.com/caarlos0/env/v11 v11.0.0 h1:ZIlkOjuL3xoZS0kmUJlF74j2Qj8GMOq3CDLX/Viak8Q=
+github.com/caarlos0/env/v11 v11.0.0/go.mod h1:2RC3HQu8BQqtEK3V4iHPxj0jOdWdbPpWJ6pOueeU1xM=
 github.com/casdoor/casdoor-go-sdk v0.35.1 h1:vOGBjHQPw7U5BbnkJgX6/ZUf+PEix1wv4greuNzDCUY=
 github.com/casdoor/casdoor-go-sdk v0.35.1 h1:vOGBjHQPw7U5BbnkJgX6/ZUf+PEix1wv4greuNzDCUY=
 github.com/casdoor/casdoor-go-sdk v0.35.1/go.mod h1:hVSgmSdwTCsBEJNt9r2K5aLVsoeMc37/N4Zzescy5SA=
 github.com/casdoor/casdoor-go-sdk v0.35.1/go.mod h1:hVSgmSdwTCsBEJNt9r2K5aLVsoeMc37/N4Zzescy5SA=
 github.com/casdoor/casdoor-go-sdk v0.43.0 h1:iKDEJlHYwFNY70iWhdVrTTIKqdoqthv3Rxv4x1+rWko=
 github.com/casdoor/casdoor-go-sdk v0.43.0 h1:iKDEJlHYwFNY70iWhdVrTTIKqdoqthv3Rxv4x1+rWko=
 github.com/casdoor/casdoor-go-sdk v0.43.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4=
 github.com/casdoor/casdoor-go-sdk v0.43.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4=
+github.com/casdoor/casdoor-go-sdk v0.45.0 h1:pww5N1V686ehebo8tHaCczdUAAVX9inwUJCCjlZnPPA=
+github.com/casdoor/casdoor-go-sdk v0.45.0/go.mod h1:cMnkCQJgMYpgAlgEx8reSt1AVaDIQLcJ1zk5pzBaz+4=
 github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
 github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
 github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
 github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
@@ -946,9 +956,13 @@ github.com/gin-contrib/static v0.0.1 h1:JVxuvHPuUfkoul12N7dtQw7KRn/pSMq7Ue1Va9Sw
 github.com/gin-contrib/static v0.0.1/go.mod h1:CSxeF+wep05e0kCOsqWdAWbSszmc31zTIbD8TvWl7Hs=
 github.com/gin-contrib/static v0.0.1/go.mod h1:CSxeF+wep05e0kCOsqWdAWbSszmc31zTIbD8TvWl7Hs=
 github.com/gin-contrib/static v1.1.1 h1:XEvBd4DDLG1HBlyPBQU1XO8NlTpw6mgdqcPteetYA5k=
 github.com/gin-contrib/static v1.1.1 h1:XEvBd4DDLG1HBlyPBQU1XO8NlTpw6mgdqcPteetYA5k=
 github.com/gin-contrib/static v1.1.1/go.mod h1:yRGmar7+JYvbMLRPIi4H5TVVSBwULfT9vetnVD0IO74=
 github.com/gin-contrib/static v1.1.1/go.mod h1:yRGmar7+JYvbMLRPIi4H5TVVSBwULfT9vetnVD0IO74=
+github.com/gin-contrib/static v1.1.2 h1:c3kT4bFkUJn2aoRU3s6XnMjJT8J6nNWJkR0NglqmlZ4=
+github.com/gin-contrib/static v1.1.2/go.mod h1:Fw90ozjHCmZBWbgrsqrDvO28YbhKEKzKp8GixhR4yLw=
 github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
 github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
 github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
 github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
+github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
+github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
 github.com/go-acme/lego/v4 v4.15.0 h1:A7MHEU3b+TDFqhC/HmzMJnzPbyeaYvMZQBbqgvbThhU=
 github.com/go-acme/lego/v4 v4.15.0 h1:A7MHEU3b+TDFqhC/HmzMJnzPbyeaYvMZQBbqgvbThhU=
 github.com/go-acme/lego/v4 v4.15.0/go.mod h1:eeGhjW4zWT7Ccqa3sY7ayEqFLCAICx+mXgkMHKIkLxg=
 github.com/go-acme/lego/v4 v4.15.0/go.mod h1:eeGhjW4zWT7Ccqa3sY7ayEqFLCAICx+mXgkMHKIkLxg=
 github.com/go-acme/lego/v4 v4.16.1 h1:JxZ93s4KG0jL27rZ30UsIgxap6VGzKuREsSkkyzeoCQ=
 github.com/go-acme/lego/v4 v4.16.1 h1:JxZ93s4KG0jL27rZ30UsIgxap6VGzKuREsSkkyzeoCQ=
@@ -1012,6 +1026,8 @@ github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ
 github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
 github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
 github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
 github.com/go-playground/validator/v10 v10.19.0 h1:ol+5Fu+cSq9JD7SoSqe04GMI92cbn0+wvQ3bZ8b/AU4=
 github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
 github.com/go-playground/validator/v10 v10.19.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
+github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
+github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
 github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
 github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
 github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
 github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
 github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
 github.com/go-resty/resty/v2 v2.12.0 h1:rsVL8P90LFvkUYq/V5BTVe203WfRIU4gvcf+yfzJzGA=
@@ -1186,6 +1202,8 @@ github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56
 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
 github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU=
 github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
 github.com/googleapis/gax-go/v2 v2.12.3 h1:5/zPPDvw8Q1SuXjrqrZslrqT7dL/uJT2CQii/cLCKqA=
 github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
 github.com/googleapis/gax-go/v2 v2.12.3/go.mod h1:AKloxT6GtNbaLm8QTNSidHUVsHYcBHwWRvkNFJUQcS4=
+github.com/googleapis/gax-go/v2 v2.12.4 h1:9gWcmF85Wvq4ryPFvGFaOgPIs1AQX0d0bcbGw4Z96qg=
+github.com/googleapis/gax-go/v2 v2.12.4/go.mod h1:KYEYLorsnIGDi/rPC8b5TdlB9kbKoFubselGIoBMCwI=
 github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
 github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
 github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
 github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
 github.com/gophercloud/gophercloud v1.3.0/go.mod h1:aAVqcocTSXh2vYFZ1JTvx4EQmfgzxRcNupUfxZbBNDM=
@@ -1392,6 +1410,8 @@ github.com/linode/linodego v1.28.0 h1:lzxxJebsYg5cCWRNDLyL2StW3sfMyAwf/FYfxFjFrl
 github.com/linode/linodego v1.28.0/go.mod h1:5oAsx+uinHtVo6U77nXXXtox7MWzUW6aEkTOKXxA9uo=
 github.com/linode/linodego v1.28.0/go.mod h1:5oAsx+uinHtVo6U77nXXXtox7MWzUW6aEkTOKXxA9uo=
 github.com/linode/linodego v1.33.0 h1:cX2FYry7r6CA1ujBMsdqiM4VhvIQtnWsOuVblzfBhCw=
 github.com/linode/linodego v1.33.0 h1:cX2FYry7r6CA1ujBMsdqiM4VhvIQtnWsOuVblzfBhCw=
 github.com/linode/linodego v1.33.0/go.mod h1:dSJJgIwqZCF5wnpuC6w5cyIbRtcexAm7uVvuJopGB40=
 github.com/linode/linodego v1.33.0/go.mod h1:dSJJgIwqZCF5wnpuC6w5cyIbRtcexAm7uVvuJopGB40=
+github.com/linode/linodego v1.33.1 h1:GcI7ozlHHzZbfthD8edLNInhHjQ452iCwtphza+FJGc=
+github.com/linode/linodego v1.33.1/go.mod h1:rEjoJQACp1gKZn9LfxtCJPwS8ri/+h2B3ScJrgBPPdI=
 github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/go-lwApi v0.0.0-20190605172801-52a4864d2738/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/go-lwApi v0.0.5/go.mod h1:0sYF9rMXb0vlG+4SzdiGMXHheCZxjguMq+Zb4S2BfBs=
 github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
 github.com/liquidweb/liquidweb-cli v0.6.9/go.mod h1:cE1uvQ+x24NGUL75D0QagOFCG8Wdvmwu8aL9TLmA/eQ=
@@ -1575,6 +1595,8 @@ github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOS
 github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
 github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
 github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg=
 github.com/pelletier/go-toml/v2 v2.2.1 h1:9TA9+T8+8CUCO2+WYnDLCgrYi9+omqKXyjDtosvtEhg=
 github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
 github.com/pelletier/go-toml/v2 v2.2.1/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
+github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
+github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
 github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
 github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY=
 github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
@@ -1680,6 +1702,8 @@ github.com/shirou/gopsutil/v3 v3.24.1 h1:R3t6ondCEvmARp3wxODhXMTLC/klMa87h2PHUw5
 github.com/shirou/gopsutil/v3 v3.24.1/go.mod h1:UU7a2MSBQa+kW1uuDq8DeEBS8kmrnQwsv2b5O513rwU=
 github.com/shirou/gopsutil/v3 v3.24.1/go.mod h1:UU7a2MSBQa+kW1uuDq8DeEBS8kmrnQwsv2b5O513rwU=
 github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
 github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE=
 github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
 github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg=
+github.com/shirou/gopsutil/v3 v3.24.4 h1:dEHgzZXt4LMNm+oYELpzl9YCqV65Yr/6SfrvgRBtXeU=
+github.com/shirou/gopsutil/v3 v3.24.4/go.mod h1:lTd2mdiOspcqLgAnr9/nGi71NkeMpWKdmhuxm9GusH8=
 github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
 github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM=
 github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
 github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ=
 github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
 github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU=
@@ -1774,10 +1798,14 @@ github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.857 h1:6TxC
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.857/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.857/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.910 h1:u+rAnHhLixQaNYy8vtnuClj4kYWs77VAHEbi9jl8k/4=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.910 h1:u+rAnHhLixQaNYy8vtnuClj4kYWs77VAHEbi9jl8k/4=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.910/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.910/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.914 h1:CByhsxUgtDkGg6cxzwdgfMAZ4yiBEn1RIXYyq62nwwI=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.914/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.857 h1:EYkAGRkx8q+e+X190mCc6e5z+sHkb50iw7ZHGgoc2c0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.857 h1:EYkAGRkx8q+e+X190mCc6e5z+sHkb50iw7ZHGgoc2c0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.857/go.mod h1:4nCgJQrj+kq8IW4bqilFqlG6b9hPb2F9Y2WpGMOazE0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.857/go.mod h1:4nCgJQrj+kq8IW4bqilFqlG6b9hPb2F9Y2WpGMOazE0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.910 h1:dO8s0rMnCO6FkP9LocS2zzn0AmTnQsjFcBhH55e8mOM=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.910 h1:dO8s0rMnCO6FkP9LocS2zzn0AmTnQsjFcBhH55e8mOM=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.910/go.mod h1:SzZONdscLNC9REG/GV7prP42YNAQ3ft8ovurtGNWTec=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.910/go.mod h1:SzZONdscLNC9REG/GV7prP42YNAQ3ft8ovurtGNWTec=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.914 h1:R13gTV0eWyYBhUnban4hQczfhKD5MT7IsMgiwOCMJaY=
+github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.914/go.mod h1:yV15O8egeJgEjab302lvaqDUS8poWajUZKf8DXgW244=
 github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
 github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI=
 github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
 github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4=
 github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
 github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0=
@@ -1804,6 +1832,8 @@ github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65E
 github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
 github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a h1:w4PK5/N9kq8PfNxBv8a5t1bqlYRrVT7XzT7iTPTtiPk=
 github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a h1:w4PK5/N9kq8PfNxBv8a5t1bqlYRrVT7XzT7iTPTtiPk=
 github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a/go.mod h1:Xwz7o+ExFtxR/i0aJDnTXuiccQJlOxDgNe6FsZC4TzQ=
 github.com/ultradns/ultradns-go-sdk v1.6.1-20231103022937-8589b6a/go.mod h1:Xwz7o+ExFtxR/i0aJDnTXuiccQJlOxDgNe6FsZC4TzQ=
+github.com/ultradns/ultradns-go-sdk v1.6.2-20240501171831-432d643 h1:Y2gOdFNdP0QrXN7HkhrT42686bxBmDPqq5Xu8RgeU2s=
+github.com/ultradns/ultradns-go-sdk v1.6.2-20240501171831-432d643/go.mod h1:mqka31zT/P4yfNKj1qbOXUqamham/YO05GgUc/dOrl8=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
 github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
 github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
@@ -1829,10 +1859,14 @@ github.com/yandex-cloud/go-genproto v0.0.0-20240205090910-007acb101be5 h1:HVYr9E
 github.com/yandex-cloud/go-genproto v0.0.0-20240205090910-007acb101be5/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
 github.com/yandex-cloud/go-genproto v0.0.0-20240205090910-007acb101be5/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
 github.com/yandex-cloud/go-genproto v0.0.0-20240425114406-68c9b49389a1 h1:VDGcTxVXpQ6N2sKdKVzSrt1Rp6xm4thrCH5TeqMoWtY=
 github.com/yandex-cloud/go-genproto v0.0.0-20240425114406-68c9b49389a1 h1:VDGcTxVXpQ6N2sKdKVzSrt1Rp6xm4thrCH5TeqMoWtY=
 github.com/yandex-cloud/go-genproto v0.0.0-20240425114406-68c9b49389a1/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
 github.com/yandex-cloud/go-genproto v0.0.0-20240425114406-68c9b49389a1/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
+github.com/yandex-cloud/go-genproto v0.0.0-20240502080826-5fa7aabf7673 h1:N4xWIsknZx9pK0o7tJ8GGNj4JdHzGyN3y4g5fnpO9rw=
+github.com/yandex-cloud/go-genproto v0.0.0-20240502080826-5fa7aabf7673/go.mod h1:HEUYX/p8966tMUHHT+TsS0hF/Ca/NYwqprC5WXSDMfE=
 github.com/yandex-cloud/go-sdk v0.0.0-20240205112400-7fabb70436b0 h1:dfin4M6ZEpoBAbaxM8RJ0G0NsSE/ZUh8t4+sFRJcPAI=
 github.com/yandex-cloud/go-sdk v0.0.0-20240205112400-7fabb70436b0 h1:dfin4M6ZEpoBAbaxM8RJ0G0NsSE/ZUh8t4+sFRJcPAI=
 github.com/yandex-cloud/go-sdk v0.0.0-20240205112400-7fabb70436b0/go.mod h1:v0wy5uhpD/Ts0YfY6tg4CpWvv1+sse6ovKdF/KSgXV8=
 github.com/yandex-cloud/go-sdk v0.0.0-20240205112400-7fabb70436b0/go.mod h1:v0wy5uhpD/Ts0YfY6tg4CpWvv1+sse6ovKdF/KSgXV8=
 github.com/yandex-cloud/go-sdk v0.0.0-20240425115054-85caccb84041 h1:CJFVkjTl0Jxgx7ha9rNgG4y7YCcZqCl1lZDkk8Kw3ac=
 github.com/yandex-cloud/go-sdk v0.0.0-20240425115054-85caccb84041 h1:CJFVkjTl0Jxgx7ha9rNgG4y7YCcZqCl1lZDkk8Kw3ac=
 github.com/yandex-cloud/go-sdk v0.0.0-20240425115054-85caccb84041/go.mod h1:gf3YxmV6R09JmNxOQrfoeV8mRIXqr7EQ7Yh7sAG2UhA=
 github.com/yandex-cloud/go-sdk v0.0.0-20240425115054-85caccb84041/go.mod h1:gf3YxmV6R09JmNxOQrfoeV8mRIXqr7EQ7Yh7sAG2UhA=
+github.com/yandex-cloud/go-sdk v0.0.0-20240502081211-7639841896bb h1:neUOrst9RECDTfeCpjaFRrDY93vNpFsrhvb4cbYUPsg=
+github.com/yandex-cloud/go-sdk v0.0.0-20240502081211-7639841896bb/go.mod h1:M54BPoNxIcDFSlTe0xHmDPCJVJmWxZp8MOIcjlINiL8=
 github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
 github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
 github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
 github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
 github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
 github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
@@ -1913,6 +1947,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
 golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
 golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
 golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
+golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
+golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -1940,6 +1976,8 @@ golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
 golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
 golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
 golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
 golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
 golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
 golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -1959,6 +1997,8 @@ golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3 h1:/RIbNt/Zr7rVhIkQhooTxCxFc
 golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
 golang.org/x/exp v0.0.0-20240205201215-2c58cdc269a3/go.mod h1:idGWGoKP1toJGkd5/ig9ZLuPcZBC3ewk7SzmH0uou08=
 golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
 golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f h1:99ci1mjWVBWwJiEKYY6jWa4d2nTQVIEhZIptnrVb1XY=
 golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
 golang.org/x/exp v0.0.0-20240416160154-fe59bbe5cc7f/go.mod h1:/lliqkxwWAhPjf5oSOIJup2XcqJaw8RGS6k3TGEc7GI=
+golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842 h1:vr/HnozRka3pE4EsMEg1lgkXJkTFJCVUX+S/ZT6wYzM=
+golang.org/x/exp v0.0.0-20240506185415-9bf2ced13842/go.mod h1:XtvwrStGgqGPLc4cjQfWqZHG1YFdYs6swckp8vpsjnc=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
@@ -2088,6 +2128,8 @@ golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
 golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
 golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
 golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
 golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
 golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -2121,6 +2163,8 @@ golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ=
 golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
 golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o=
 golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
 golang.org/x/oauth2 v0.19.0 h1:9+E/EZBCbTLNrbN35fHv/a/d/mOBatymz1zbtQrXpIg=
 golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
 golang.org/x/oauth2 v0.19.0/go.mod h1:vYi7skDa1x015PmRRYZ7+s1cWyPgrPiSYRe4rnsexc8=
+golang.org/x/oauth2 v0.20.0 h1:4mQdhULixXKP1rwYBW0vAijoXnkTG0BLCDRzfe1idMo=
+golang.org/x/oauth2 v0.20.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -2263,6 +2307,8 @@ golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
 golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
 golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
 golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
+golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
@@ -2297,6 +2343,8 @@ golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -2383,6 +2431,8 @@ golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
 golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
 golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
 golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
 golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
 golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
 golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
+golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
+golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -2461,6 +2511,8 @@ google.golang.org/api v0.162.0 h1:Vhs54HkaEpkMBdgGdOT2P6F0csGG/vxDS0hWHJzmmps=
 google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0=
 google.golang.org/api v0.162.0/go.mod h1:6SulDkfoBIg4NFmCuZ39XeeAgSHCPecfSUuDyYlAHs0=
 google.golang.org/api v0.176.1 h1:DJSXnV6An+NhJ1J+GWtoF2nHEuqB1VNoTfnIbjNvwD4=
 google.golang.org/api v0.176.1 h1:DJSXnV6An+NhJ1J+GWtoF2nHEuqB1VNoTfnIbjNvwD4=
 google.golang.org/api v0.176.1/go.mod h1:j2MaSDYcvYV1lkZ1+SMW4IeF90SrEyFA+tluDYWRrFg=
 google.golang.org/api v0.176.1/go.mod h1:j2MaSDYcvYV1lkZ1+SMW4IeF90SrEyFA+tluDYWRrFg=
+google.golang.org/api v0.177.0 h1:8a0p/BbPa65GlqGWtUKxot4p0TV8OGOfyTjtmkXNXmk=
+google.golang.org/api v0.177.0/go.mod h1:srbhue4MLjkjbkux5p3dw/ocYOSZTaIEvf7bCOnFQDw=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
 google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@@ -2608,14 +2660,20 @@ google.golang.org/genproto v0.0.0-20240205150955-31a09d347014 h1:g/4bk7P6TPMkAUb
 google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M=
 google.golang.org/genproto v0.0.0-20240205150955-31a09d347014/go.mod h1:xEgQu1e4stdSSsxPDK8Azkrk/ECl5HvdPf6nbZrTS5M=
 google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be h1:g4aX8SUFA8V5F4LrSY5EclyGYw1OZN4HS1jTyjB9ZDc=
 google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be h1:g4aX8SUFA8V5F4LrSY5EclyGYw1OZN4HS1jTyjB9ZDc=
 google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be/go.mod h1:FeSdT5fk+lkxatqJP38MsUicGqHax5cLtmy/6TAuxO4=
 google.golang.org/genproto v0.0.0-20240415180920-8c6c420018be/go.mod h1:FeSdT5fk+lkxatqJP38MsUicGqHax5cLtmy/6TAuxO4=
+google.golang.org/genproto v0.0.0-20240506185236-b8a5c65736ae h1:HjgkYCl6cWQEKSHkpUp4Q8VB74swzyBwTz1wtTzahm0=
+google.golang.org/genproto v0.0.0-20240506185236-b8a5c65736ae/go.mod h1:i4np6Wrjp8EujFAUn0CM0SH+iZhY1EbrfzEIJbFkHFM=
 google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A=
 google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014 h1:x9PwdEgd11LgK+orcck69WVRo7DezSO4VUMPI4xpc8A=
 google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I=
 google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.mod h1:rbHMSEDyoYX62nRVLOCc4Qt1HbsdytAYoVwgjiOhF3I=
 google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be h1:Zz7rLWqp0ApfsR/l7+zSHhY3PMiH2xqgxlfYfAfNpoU=
 google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be h1:Zz7rLWqp0ApfsR/l7+zSHhY3PMiH2xqgxlfYfAfNpoU=
 google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w=
 google.golang.org/genproto/googleapis/api v0.0.0-20240415180920-8c6c420018be/go.mod h1:dvdCTIoAGbkWbcIKBniID56/7XHTt6WfxXNMxuziJ+w=
+google.golang.org/genproto/googleapis/api v0.0.0-20240506185236-b8a5c65736ae h1:AH34z6WAGVNkllnKs5raNq3yRq93VnjBG6rpfub/jYk=
+google.golang.org/genproto/googleapis/api v0.0.0-20240506185236-b8a5c65736ae/go.mod h1:FfiGhwUm6CJviekPrc0oJ+7h29e+DmWU6UtjX0ZvI7Y=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014 h1:FSL3lRCkhaPFxqi0s9o+V4UI2WTzAVOvkgbd4kVV4Wg=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20240205150955-31a09d347014/go.mod h1:SaPjaZGWb0lPqs6Ittu0spdfrOArqji4ZdeP5IC/9N4=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be h1:LG9vZxsWGOmUKieR8wPAUR3u3MpnYFQZROPIMaXh7/A=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
 google.golang.org/genproto/googleapis/rpc v0.0.0-20240415180920-8c6c420018be/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240506185236-b8a5c65736ae h1:c55+MER4zkBS14uJhSZMGGmya0yJx5iHV4x/fpOSNRk=
+google.golang.org/genproto/googleapis/rpc v0.0.0-20240506185236-b8a5c65736ae/go.mod h1:I7Y+G38R2bu5j1aLzfFmQfTcU/WnFuqDwLZAbvKTKpM=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
 google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -2682,6 +2740,8 @@ google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqw
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
 google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
 google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
+google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@@ -2793,6 +2853,8 @@ k8s.io/utils v0.0.0-20240102154912-e7106e64919e h1:eQ/4ljkx21sObifjzXwlPKpdGLrCf
 k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 k8s.io/utils v0.0.0-20240102154912-e7106e64919e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ=
 k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ=
 k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
+k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCIXHaathvJg1C3ak=
+k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
 lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
 lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
 lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
 modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
 modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=

+ 78 - 70
internal/analytic/node.go

@@ -16,26 +16,26 @@ import (
 )
 )
 
 
 type NodeInfo struct {
 type NodeInfo struct {
-    NodeRuntimeInfo upgrader.RuntimeInfo `json:"node_runtime_info"`
-    Version         string               `json:"version"`
-    CPUNum          int                  `json:"cpu_num"`
-    MemoryTotal     string               `json:"memory_total"`
-    DiskTotal       string               `json:"disk_total"`
+	NodeRuntimeInfo upgrader.RuntimeInfo `json:"node_runtime_info"`
+	Version         string               `json:"version"`
+	CPUNum          int                  `json:"cpu_num"`
+	MemoryTotal     string               `json:"memory_total"`
+	DiskTotal       string               `json:"disk_total"`
 }
 }
 
 
 type NodeStat struct {
 type NodeStat struct {
-    AvgLoad       *load.AvgStat      `json:"avg_load"`
-    CPUPercent    float64            `json:"cpu_percent"`
-    MemoryPercent float64            `json:"memory_percent"`
-    DiskPercent   float64            `json:"disk_percent"`
-    Network       net.IOCountersStat `json:"network"`
-    Status        bool               `json:"status"`
-    ResponseAt    time.Time          `json:"response_at"`
+	AvgLoad       *load.AvgStat      `json:"avg_load"`
+	CPUPercent    float64            `json:"cpu_percent"`
+	MemoryPercent float64            `json:"memory_percent"`
+	DiskPercent   float64            `json:"disk_percent"`
+	Network       net.IOCountersStat `json:"network"`
+	Status        bool               `json:"status"`
+	ResponseAt    time.Time          `json:"response_at"`
 }
 }
 
 
 type Node struct {
 type Node struct {
-    EnvironmentID int `json:"environment_id,omitempty"`
-    *model.Environment
+	EnvironmentID int `json:"environment_id,omitempty"`
+	*model.Environment
 	NodeStat
 	NodeStat
 	NodeInfo
 	NodeInfo
 }
 }
@@ -47,66 +47,74 @@ type TNodeMap map[int]*Node
 var NodeMap TNodeMap
 var NodeMap TNodeMap
 
 
 func init() {
 func init() {
-    NodeMap = make(TNodeMap)
+	NodeMap = make(TNodeMap)
 }
 }
 
 
 func GetNode(env *model.Environment) (n *Node) {
 func GetNode(env *model.Environment) (n *Node) {
-    if env == nil {
-        logger.Error("env is nil")
-        return
-    }
-    n, ok := NodeMap[env.ID]
-    if !ok {
-        n = &Node{}
-    }
-    n.Environment = env
-    return n
+	if env == nil {
+		// this should never happen
+		logger.Error("env is nil")
+		return
+	}
+	if !env.Enabled {
+		return &Node{
+			Environment: env,
+		}
+	}
+	n, ok := NodeMap[env.ID]
+	if !ok {
+		n = &Node{}
+	}
+	n.Environment = env
+	return n
 }
 }
 
 
 func InitNode(env *model.Environment) (n *Node) {
 func InitNode(env *model.Environment) (n *Node) {
-    n = &Node{
-        Environment: env,
-    }
-
-    u, err := url.JoinPath(env.URL, "/api/node")
-
-    if err != nil {
-        logger.Error(err)
-        return
-    }
-
-    if err != nil {
-        logger.Error(err)
-        return
-    }
-    client := http.Client{
-        Transport: &http.Transport{
-            TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
-        },
-    }
-    req, err := http.NewRequest("GET", u, nil)
-    req.Header.Set("X-Node-Secret", env.Token)
-
-    resp, err := client.Do(req)
-
-    if err != nil {
-        logger.Error(err)
-        return
-    }
-
-    defer resp.Body.Close()
-    bytes, _ := io.ReadAll(resp.Body)
-
-    if resp.StatusCode != 200 {
-        logger.Error(string(bytes))
-        return
-    }
-
-    err = json.Unmarshal(bytes, &n.NodeInfo)
-    if err != nil {
-        logger.Error(err)
-        return
-    }
-
-    return
+	n = &Node{
+		Environment: env,
+	}
+
+	u, err := url.JoinPath(env.URL, "/api/node")
+
+	if err != nil {
+		logger.Error(err)
+		return
+	}
+
+	client := http.Client{
+		Transport: &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+		},
+	}
+
+	req, err := http.NewRequest("GET", u, nil)
+	if err != nil {
+		logger.Error(err)
+		return
+	}
+
+	req.Header.Set("X-Node-Secret", env.Token)
+
+	resp, err := client.Do(req)
+
+	if err != nil {
+		logger.Error(err)
+		return
+	}
+
+	defer resp.Body.Close()
+	bytes, _ := io.ReadAll(resp.Body)
+
+	if resp.StatusCode != http.StatusOK {
+		logger.Error(string(bytes))
+		return
+	}
+
+	err = json.Unmarshal(bytes, &n.NodeInfo)
+	if err != nil {
+		logger.Error(err)
+		return
+	}
+
+	return
 }
 }

+ 71 - 0
internal/cluster/cluster.go

@@ -0,0 +1,71 @@
+package cluster
+
+import (
+	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/query"
+	"github.com/0xJacky/Nginx-UI/settings"
+	"gorm.io/gen/field"
+	"net/url"
+	"strings"
+)
+
+func RegisterPredefinedNodes() {
+	if len(settings.ClusterSettings.Node) == 0 {
+		return
+	}
+
+	q := query.Environment
+	for _, nodeUrl := range settings.ClusterSettings.Node {
+		func() {
+			node, err := parseNodeUrl(nodeUrl)
+			if err != nil {
+				logger.Error(nodeUrl, err)
+				return
+			}
+
+			if node.Name == "" {
+				logger.Error(nodeUrl, "Node name is required")
+				return
+			}
+
+			if node.URL == "" {
+				logger.Error(nodeUrl, "Node URL is required")
+				return
+			}
+
+			if node.Token == "" {
+				logger.Error(nodeUrl, "Node Token is required")
+				return
+			}
+
+			_, err = q.Where(q.URL.Eq(node.URL)).
+				Attrs(field.Attrs(node)).
+				FirstOrCreate()
+			if err != nil {
+				logger.Error(node.URL, err)
+			}
+		}()
+	}
+}
+
+func parseNodeUrl(nodeUrl string) (env *model.Environment, err error) {
+	u, err := url.Parse(nodeUrl)
+	if err != nil {
+		return
+	}
+	var sb strings.Builder
+	sb.WriteString(u.Scheme)
+	sb.WriteString("://")
+	sb.WriteString(u.Host)
+	sb.WriteString(u.Path)
+
+	env = &model.Environment{
+		Name:    u.Query().Get("name"),
+		URL:     sb.String(),
+		Token:   u.Query().Get("node_secret"),
+		Enabled: u.Query().Get("enabled") == "true",
+	}
+
+	return
+}

+ 47 - 0
internal/cluster/cluster_test.go

@@ -0,0 +1,47 @@
+package cluster
+
+import (
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func Test_parseNodeUrl(t *testing.T) {
+	settings.Init("../../app.example.ini")
+	t.Log(settings.ClusterSettings.Node)
+	node := settings.ClusterSettings.Node[0]
+
+	env, err := parseNodeUrl(node)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.Equal(t, "node1", env.Name)
+	assert.Equal(t, "http://10.0.0.1:9000", env.URL)
+	assert.Equal(t, "my-node-secret", env.Token)
+	assert.Equal(t, true, env.Enabled)
+
+	node = settings.ClusterSettings.Node[1]
+
+	env, err = parseNodeUrl(node)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.Equal(t, "node2", env.Name)
+	assert.Equal(t, "http://10.0.0.2:9000", env.URL)
+	assert.Equal(t, "my-node-secret", env.Token)
+	assert.Equal(t, true, env.Enabled)
+
+	node = settings.ClusterSettings.Node[2]
+
+	env, err = parseNodeUrl(node)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	assert.Equal(t, "node3", env.Name)
+	assert.Equal(t, "http://10.0.0.3", env.URL)
+	assert.Equal(t, "my-node-secret", env.Token)
+	assert.Equal(t, true, env.Enabled)
+}

+ 0 - 23
internal/environment/environment.go

@@ -1,23 +0,0 @@
-package environment
-
-import (
-	"github.com/0xJacky/Nginx-UI/internal/analytic"
-	"github.com/0xJacky/Nginx-UI/query"
-)
-
-func RetrieveEnvironmentList() (envs []*analytic.Node, err error) {
-	envQuery := query.Environment
-
-	data, err := envQuery.Find()
-	if err != nil {
-		return
-	}
-
-	for _, v := range data {
-		t := analytic.GetNode(v)
-
-		envs = append(envs, t)
-	}
-
-	return
-}

+ 8 - 1
internal/kernal/boot.go

@@ -3,6 +3,7 @@ package kernal
 import (
 import (
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
 	"github.com/0xJacky/Nginx-UI/internal/analytic"
 	"github.com/0xJacky/Nginx-UI/internal/cert"
 	"github.com/0xJacky/Nginx-UI/internal/cert"
+	"github.com/0xJacky/Nginx-UI/internal/cluster"
 	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/logrotate"
 	"github.com/0xJacky/Nginx-UI/internal/logrotate"
 	"github.com/0xJacky/Nginx-UI/internal/validation"
 	"github.com/0xJacky/Nginx-UI/internal/validation"
@@ -41,8 +42,10 @@ func Boot() {
 
 
 func InitAfterDatabase() {
 func InitAfterDatabase() {
 	syncs := []func(){
 	syncs := []func(){
+		registerPredefinedUser,
 		cert.InitRegister,
 		cert.InitRegister,
 		InitCronJobs,
 		InitCronJobs,
+		cluster.RegisterPredefinedNodes,
 		analytic.RetrieveNodesStatus,
 		analytic.RetrieveNodesStatus,
 	}
 	}
 
 
@@ -60,6 +63,11 @@ func recovery() {
 }
 }
 
 
 func InitDatabase() {
 func InitDatabase() {
+	// Skip install
+	if settings.ServerSettings.SkipInstallation {
+		skipInstall()
+	}
+
 	if "" != settings.ServerSettings.JwtSecret {
 	if "" != settings.ServerSettings.JwtSecret {
 		db := model.Init()
 		db := model.Init()
 		query.Init(db)
 		query.Init(db)
@@ -72,7 +80,6 @@ func InitNodeSecret() {
 	if "" == settings.ServerSettings.NodeSecret {
 	if "" == settings.ServerSettings.NodeSecret {
 		logger.Warn("NodeSecret is empty, generating...")
 		logger.Warn("NodeSecret is empty, generating...")
 		settings.ServerSettings.NodeSecret = uuid.New().String()
 		settings.ServerSettings.NodeSecret = uuid.New().String()
-		settings.ReflectFrom()
 
 
 		err := settings.Save()
 		err := settings.Save()
 		if err != nil {
 		if err != nil {

+ 74 - 0
internal/kernal/skip_install.go

@@ -0,0 +1,74 @@
+package kernal
+
+import (
+	"github.com/0xJacky/Nginx-UI/internal/logger"
+	"github.com/0xJacky/Nginx-UI/model"
+	"github.com/0xJacky/Nginx-UI/query"
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/caarlos0/env/v11"
+	"github.com/google/uuid"
+	"github.com/pkg/errors"
+	"golang.org/x/crypto/bcrypt"
+	"gorm.io/gorm"
+)
+
+type predefinedUser struct {
+	Name     string `json:"name"`
+	Password string `json:"password"`
+}
+
+func skipInstall() {
+	logger.Info("Skip installation mode enabled")
+
+	if settings.ServerSettings.JwtSecret == "" {
+		settings.ServerSettings.JwtSecret = uuid.New().String()
+	}
+
+	if settings.ServerSettings.NodeSecret == "" {
+		settings.ServerSettings.NodeSecret = uuid.New().String()
+		logger.Infof("NodeSecret: %s", settings.ServerSettings.NodeSecret)
+	}
+
+	err := settings.Save()
+	if err != nil {
+		logger.Fatal(err)
+	}
+}
+
+func registerPredefinedUser() {
+	// when skip installation mode is enabled, the predefined user will be created
+	if !settings.ServerSettings.SkipInstallation {
+		return
+	}
+	pUser := &predefinedUser{}
+
+	err := env.ParseWithOptions(pUser, env.Options{
+		Prefix:                "NGINX_UI_PREDEFINED_USER_",
+		UseFieldNameByDefault: true,
+	})
+
+	if err != nil {
+		logger.Fatal(err)
+	}
+
+	u := query.Auth
+
+	_, err = u.First()
+
+	// Only effect when there is no user in the database
+	if !errors.Is(err, gorm.ErrRecordNotFound) || pUser.Name == "" || pUser.Password == "" {
+		return
+	}
+
+	// Create a new user with the predefined name and password
+	pwd, _ := bcrypt.GenerateFromPassword([]byte(pUser.Password), bcrypt.DefaultCost)
+
+	err = u.Create(&model.Auth{
+		Name:     pUser.Name,
+		Password: string(pwd),
+	})
+
+	if err != nil {
+		logger.Error(err)
+	}
+}

+ 45 - 22
internal/nginx/nginx.go

@@ -3,27 +3,18 @@ package nginx
 import (
 import (
 	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/0xJacky/Nginx-UI/settings"
 	"os/exec"
 	"os/exec"
+	"sync"
+	"time"
 )
 )
 
 
-func execShell(cmd string) (out string) {
-	bytes, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput()
-	out = string(bytes)
-	if err != nil {
-		out += " " + err.Error()
-	}
-	return
-}
-
-func execCommand(name string, cmd ...string) (out string) {
-	bytes, err := exec.Command(name, cmd...).CombinedOutput()
-	out = string(bytes)
-	if err != nil {
-		out += " " + err.Error()
-	}
-	return
-}
+var (
+	mutex      sync.Mutex
+	lastOutput string
+)
 
 
 func TestConf() (out string) {
 func TestConf() (out string) {
+	mutex.Lock()
+	defer mutex.Unlock()
 	if settings.NginxSettings.TestConfigCmd != "" {
 	if settings.NginxSettings.TestConfigCmd != "" {
 		out = execShell(settings.NginxSettings.TestConfigCmd)
 		out = execShell(settings.NginxSettings.TestConfigCmd)
 
 
@@ -36,6 +27,8 @@ func TestConf() (out string) {
 }
 }
 
 
 func Reload() (out string) {
 func Reload() (out string) {
+	mutex.Lock()
+	defer mutex.Unlock()
 	if settings.NginxSettings.ReloadCmd != "" {
 	if settings.NginxSettings.ReloadCmd != "" {
 		out = execShell(settings.NginxSettings.ReloadCmd)
 		out = execShell(settings.NginxSettings.ReloadCmd)
 		return
 		return
@@ -46,9 +39,15 @@ func Reload() (out string) {
 	return
 	return
 }
 }
 
 
-func Restart() (out string) {
+func Restart() {
+	mutex.Lock()
+	defer mutex.Unlock()
+
+	// fix(docker): nginx restart always output network error
+	time.Sleep(500 * time.Millisecond)
+
 	if settings.NginxSettings.RestartCmd != "" {
 	if settings.NginxSettings.RestartCmd != "" {
-		out = execShell(settings.NginxSettings.RestartCmd)
+		lastOutput = execShell(settings.NginxSettings.RestartCmd)
 
 
 		return
 		return
 	}
 	}
@@ -56,15 +55,39 @@ func Restart() (out string) {
 	pidPath := GetPIDPath()
 	pidPath := GetPIDPath()
 	daemon := GetSbinPath()
 	daemon := GetSbinPath()
 
 
-	out = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
+	lastOutput = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
 
 
 	if daemon == "" {
 	if daemon == "" {
-		out += execCommand("nginx")
+		lastOutput += execCommand("nginx")
 
 
 		return
 		return
 	}
 	}
 
 
-	out += execCommand("start-stop-daemon", "--start", "--quiet", "--pidfile", pidPath, "--exec", daemon)
+	lastOutput += execCommand("start-stop-daemon", "--start", "--quiet", "--pidfile", pidPath, "--exec", daemon)
 
 
 	return
 	return
 }
 }
+
+func GetLastOutput() string {
+	mutex.Lock()
+	defer mutex.Unlock()
+	return lastOutput
+}
+
+func execShell(cmd string) (out string) {
+	bytes, err := exec.Command("/bin/sh", "-c", cmd).CombinedOutput()
+	out = string(bytes)
+	if err != nil {
+		out += " " + err.Error()
+	}
+	return
+}
+
+func execCommand(name string, cmd ...string) (out string) {
+	bytes, err := exec.Command(name, cmd...).CombinedOutput()
+	out = string(bytes)
+	if err != nil {
+		out += " " + err.Error()
+	}
+	return
+}

+ 1 - 0
model/environment.go

@@ -10,6 +10,7 @@ type Environment struct {
 	Name          string `json:"name"`
 	Name          string `json:"name"`
 	URL           string `json:"url"`
 	URL           string `json:"url"`
 	Token         string `json:"token"`
 	Token         string `json:"token"`
+	Enabled       bool   `json:"enabled" gorm:"default:true"`
 	OperationSync bool   `json:"operation_sync"`
 	OperationSync bool   `json:"operation_sync"`
 	SyncApiRegex  string `json:"sync_api_regex"`
 	SyncApiRegex  string `json:"sync_api_regex"`
 }
 }

+ 4 - 4
resources/demo/app.ini

@@ -1,16 +1,16 @@
 [server]
 [server]
 HttpPort = 9000
 HttpPort = 9000
 RunMode = release
 RunMode = release
-JwtSecret = 2E1CE615-BB15-44F5-B5BE-6B5DA3581D0F
+JwtSecret = 6EEB622E-5C73-4082-AF76-7BAC337772F2
 Email = test@jackyu.cn
 Email = test@jackyu.cn
 HTTPChallengePort = 9180
 HTTPChallengePort = 9180
 StartCmd = bash
 StartCmd = bash
-NodeSecret = fdc7764f-92d2-454c-9640-6a09be121139
+NodeSecret = 57D079F2-CA8B-412A-B5C0-FDA291C13391
 Demo = true
 Demo = true
 
 
 [nginx]
 [nginx]
-AccessLogPath = /var/log/nginx/access.local.log
-ErrorLogPath = /var/log/nginx/error.local.log
+AccessLogPath =
+ErrorLogPath =
 
 
 [openai]
 [openai]
 Model   = gpt-3.5-turbo
 Model   = gpt-3.5-turbo

+ 3 - 0
resources/docker/nginx-ui.run

@@ -0,0 +1,3 @@
+#!/command/with-contenv sh
+env
+nginx-ui --config /etc/nginx-ui/app.ini

+ 3 - 2
resources/docker/nginx.conf

@@ -5,11 +5,13 @@ error_log  /var/log/nginx/error.log notice;
 error_log  /var/log/nginx/error.local.log notice;
 error_log  /var/log/nginx/error.local.log notice;
 pid        /var/run/nginx.pid;
 pid        /var/run/nginx.pid;
 
 
-
 events {
 events {
     worker_connections  1024;
     worker_connections  1024;
 }
 }
 
 
+stream {
+    include /etc/nginx/streams-enabled/*.conf;
+}
 
 
 http {
 http {
     include       /etc/nginx/mime.types;
     include       /etc/nginx/mime.types;
@@ -20,7 +22,6 @@ http {
                       '"$http_user_agent" "$http_x_forwarded_for"';
                       '"$http_user_agent" "$http_x_forwarded_for"';
 
 
     access_log  /var/log/nginx/access.log  main;
     access_log  /var/log/nginx/access.log  main;
-    access_log  /var/log/nginx/access.local.log  main;
 
 
     sendfile        on;
     sendfile        on;
     #tcp_nopush     on;
     #tcp_nopush     on;

+ 0 - 10
resources/docker/start.sh

@@ -1,10 +0,0 @@
-#!/bin/bash
-
-if [ "$(ls -A /etc/nginx)" = "" ]; then
-    echo "Initialing Nginx config dir"
-    cp -rp /usr/etc/nginx/* /etc/nginx/
-    echo "Initialed Nginx config dir"
-fi
-
-nginx &
-/app/nginx-ui --config /etc/nginx-ui/app.ini

+ 19 - 0
settings/cluster.go

@@ -0,0 +1,19 @@
+package settings
+
+type Cluster struct {
+	Node []string `ini:",,allowshadow"`
+}
+
+var ClusterSettings = Cluster{
+	Node: []string{},
+}
+
+func ReloadCluster() (err error) {
+	err = load()
+
+	if err != nil {
+		return err
+	}
+
+	return mapTo("cluster", &ClusterSettings)
+}

+ 15 - 0
settings/cluster_test.go

@@ -0,0 +1,15 @@
+package settings
+
+import (
+	"github.com/stretchr/testify/assert"
+	"testing"
+)
+
+func TestCluster(t *testing.T) {
+	Init("../app.example.ini")
+
+	assert.Equal(t, []string{
+		"http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true",
+		"http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=true",
+	}, ClusterSettings.Node)
+}

+ 2 - 0
settings/server.go

@@ -20,6 +20,8 @@ type Server struct {
 	GithubProxy          string   `json:"github_proxy" binding:"omitempty,url"`
 	GithubProxy          string   `json:"github_proxy" binding:"omitempty,url"`
 	CertRenewalInterval  int      `json:"cert_renewal_interval" binding:"min=7,max=21"`
 	CertRenewalInterval  int      `json:"cert_renewal_interval" binding:"min=7,max=21"`
 	RecursiveNameservers []string `json:"recursive_nameservers" binding:"omitempty,dive,hostname_port"`
 	RecursiveNameservers []string `json:"recursive_nameservers" binding:"omitempty,dive,hostname_port"`
+	SkipInstallation     bool     `json:"skip_installation" protected:"true"`
+	Name                 string   `json:"name" binding:"omitempty,alpha_num_dash_dot"`
 }
 }
 
 
 func (s *Server) GetCADir() string {
 func (s *Server) GetCADir() string {

+ 71 - 18
settings/settings.go

@@ -1,21 +1,24 @@
 package settings
 package settings
 
 
 import (
 import (
+	"github.com/caarlos0/env/v11"
 	"github.com/spf13/cast"
 	"github.com/spf13/cast"
 	"gopkg.in/ini.v1"
 	"gopkg.in/ini.v1"
 	"log"
 	"log"
+	"os"
+	"reflect"
 	"strings"
 	"strings"
 	"time"
 	"time"
 )
 )
 
 
-var Conf *ini.File
-
 var (
 var (
 	buildTime    string
 	buildTime    string
 	LastModified string
 	LastModified string
-)
 
 
-var ConfPath string
+	Conf      *ini.File
+	ConfPath  string
+	EnvPrefix = "NGINX_UI_"
+)
 
 
 var sections = map[string]interface{}{
 var sections = map[string]interface{}{
 	"server":    &ServerSettings,
 	"server":    &ServerSettings,
@@ -23,6 +26,7 @@ var sections = map[string]interface{}{
 	"openai":    &OpenAISettings,
 	"openai":    &OpenAISettings,
 	"casdoor":   &CasdoorSettings,
 	"casdoor":   &CasdoorSettings,
 	"logrotate": &LogrotateSettings,
 	"logrotate": &LogrotateSettings,
+	"cluster":   &ClusterSettings,
 }
 }
 
 
 func init() {
 func init() {
@@ -35,34 +39,81 @@ func Init(confPath string) {
 	Setup()
 	Setup()
 }
 }
 
 
+func load() (err error) {
+	Conf, err = ini.LoadSources(ini.LoadOptions{
+		Loose:        true,
+		AllowShadows: true,
+	}, ConfPath)
+
+	return
+}
+
 func Setup() {
 func Setup() {
-	var err error
-	Conf, err = ini.LooseLoad(ConfPath)
+	err := load()
+
 	if err != nil {
 	if err != nil {
-		log.Fatalf("setting.Setup: %v\n", err)
+		log.Fatalf("settings.Setup: %v\n", err)
 	}
 	}
+
 	MapTo()
 	MapTo()
+
+	parseEnv(&ServerSettings, "SERVER_")
+	parseEnv(&NginxSettings, "NGINX_")
+	parseEnv(&OpenAISettings, "OPENAI_")
+	parseEnv(&CasdoorSettings, "CASDOOR_")
+	parseEnv(&LogrotateSettings, "LOGROTATE_")
+
+	// if in official docker, set the restart cmd of nginx to "nginx -s stop",
+	// then the supervisor of s6-overlay will start the nginx again.
+	if cast.ToBool(os.Getenv("NGINX_UI_OFFICIAL_DOCKER")) {
+		NginxSettings.RestartCmd = "nginx -s stop"
+	}
+
+	err = Save()
+	if err != nil {
+		log.Fatalf("settings.Setup: %v\n", err)
+	}
 }
 }
 
 
 func MapTo() {
 func MapTo() {
 	for k, v := range sections {
 	for k, v := range sections {
-		mapTo(k, v)
+		err := mapTo(k, v)
+
+		if err != nil {
+			log.Fatalf("Cfg.MapTo %s err: %v", k, err)
+		}
 	}
 	}
 }
 }
 
 
-func ReflectFrom() {
+func Save() (err error) {
 	for k, v := range sections {
 	for k, v := range sections {
 		reflectFrom(k, v)
 		reflectFrom(k, v)
 	}
 	}
-}
 
 
-func mapTo(section string, v interface{}) {
-	err := Conf.Section(section).MapTo(v)
+	err = Conf.SaveTo(ConfPath)
 	if err != nil {
 	if err != nil {
-		log.Fatalf("Cfg.MapTo %s err: %v", section, err)
+		return
+	}
+	return
+}
+
+func ProtectedFill(targetSettings interface{}, newSettings interface{}) {
+	s := reflect.TypeOf(targetSettings).Elem()
+	vt := reflect.ValueOf(targetSettings).Elem()
+	vn := reflect.ValueOf(newSettings).Elem()
+
+	// copy the values from new to target settings if it is not protected
+	for i := 0; i < s.NumField(); i++ {
+		if s.Field(i).Tag.Get("protected") != "true" {
+			vt.Field(i).Set(vn.Field(i))
+		}
 	}
 	}
 }
 }
 
 
+func mapTo(section string, v interface{}) error {
+	return Conf.Section(section).MapTo(v)
+}
+
 func reflectFrom(section string, v interface{}) {
 func reflectFrom(section string, v interface{}) {
 	err := Conf.Section(section).ReflectFrom(v)
 	err := Conf.Section(section).ReflectFrom(v)
 	if err != nil {
 	if err != nil {
@@ -70,11 +121,13 @@ func reflectFrom(section string, v interface{}) {
 	}
 	}
 }
 }
 
 
-func Save() (err error) {
-	err = Conf.SaveTo(ConfPath)
+func parseEnv(ptr interface{}, prefix string) {
+	err := env.ParseWithOptions(ptr, env.Options{
+		Prefix:                EnvPrefix + prefix,
+		UseFieldNameByDefault: true,
+	})
+
 	if err != nil {
 	if err != nil {
-		return
+		log.Fatalf("settings.parseEnv: %v\n", err)
 	}
 	}
-	Setup()
-	return
 }
 }

+ 103 - 0
settings/settings_test.go

@@ -0,0 +1,103 @@
+package settings
+
+import (
+	"github.com/stretchr/testify/assert"
+	"os"
+	"testing"
+)
+
+func TestSetup(t *testing.T) {
+	Init("../app.example.ini")
+
+	_ = os.Setenv("NGINX_UI_OFFICIAL_DOCKER", "true")
+
+	_ = os.Setenv("NGINX_UI_SERVER_HTTP_PORT", "8080")
+	_ = os.Setenv("NGINX_UI_SERVER_RUN_MODE", "test")
+	_ = os.Setenv("NGINX_UI_SERVER_JWT_SECRET", "newSecret123")
+	_ = os.Setenv("NGINX_UI_SERVER_HTTP_CHALLENGE_PORT", "9181")
+	_ = os.Setenv("NGINX_UI_SERVER_START_CMD", "start")
+	_ = os.Setenv("NGINX_UI_SERVER_DATABASE", "testDB")
+	_ = os.Setenv("NGINX_UI_SERVER_CA_DIR", "/test/ca")
+	_ = os.Setenv("NGINX_UI_SERVER_GITHUB_PROXY", "http://proxy.example.com")
+	_ = os.Setenv("NGINX_UI_SERVER_NODE_SECRET", "nodeSecret")
+	_ = os.Setenv("NGINX_UI_SERVER_DEMO", "true")
+	_ = os.Setenv("NGINX_UI_SERVER_PAGE_SIZE", "20")
+	_ = os.Setenv("NGINX_UI_SERVER_HTTP_HOST", "127.0.0.1")
+	_ = os.Setenv("NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL", "14")
+	_ = os.Setenv("NGINX_UI_SERVER_RECURSIVE_NAMESERVERS", "8.8.8.8")
+	_ = os.Setenv("NGINX_UI_SERVER_SKIP_INSTALLATION", "true")
+	_ = os.Setenv("NGINX_UI_SERVER_NAME", "test")
+
+	_ = os.Setenv("NGINX_UI_NGINX_ACCESS_LOG_PATH", "/tmp/nginx/access.log")
+	_ = os.Setenv("NGINX_UI_NGINX_ERROR_LOG_PATH", "/tmp/nginx/error.log")
+	_ = os.Setenv("NGINX_UI_NGINX_CONFIG_DIR", "/etc/nginx/conf")
+	_ = os.Setenv("NGINX_UI_NGINX_PID_PATH", "/var/run/nginx.pid")
+	_ = os.Setenv("NGINX_UI_NGINX_TEST_CONFIG_CMD", "nginx -t")
+	_ = os.Setenv("NGINX_UI_NGINX_RELOAD_CMD", "nginx -s reload")
+	_ = os.Setenv("NGINX_UI_NGINX_RESTART_CMD", "nginx -s restart")
+
+	_ = os.Setenv("NGINX_UI_OPENAI_MODEL", "davinci")
+	_ = os.Setenv("NGINX_UI_OPENAI_BASE_URL", "https://api.openai.com")
+	_ = os.Setenv("NGINX_UI_OPENAI_PROXY", "https://proxy.openai.com")
+	_ = os.Setenv("NGINX_UI_OPENAI_TOKEN", "token123")
+
+	_ = os.Setenv("NGINX_UI_CASDOOR_ENDPOINT", "https://casdoor.example.com")
+	_ = os.Setenv("NGINX_UI_CASDOOR_CLIENT_ID", "clientId")
+	_ = os.Setenv("NGINX_UI_CASDOOR_CLIENT_SECRET", "clientSecret")
+	_ = os.Setenv("NGINX_UI_CASDOOR_CERTIFICATE", "cert.pem")
+	_ = os.Setenv("NGINX_UI_CASDOOR_ORGANIZATION", "org1")
+	_ = os.Setenv("NGINX_UI_CASDOOR_APPLICATION", "app1")
+	_ = os.Setenv("NGINX_UI_CASDOOR_REDIRECT_URI", "https://redirect.example.com")
+
+	_ = os.Setenv("NGINX_UI_LOGROTATE_ENABLED", "true")
+	_ = os.Setenv("NGINX_UI_LOGROTATE_CMD", "logrotate /custom/logrotate.conf")
+	_ = os.Setenv("NGINX_UI_LOGROTATE_INTERVAL", "60")
+
+	ConfPath = "app.testing.ini"
+	Setup()
+
+	assert.Equal(t, "8080", ServerSettings.HttpPort)
+	assert.Equal(t, "test", ServerSettings.RunMode)
+	assert.Equal(t, "newSecret123", ServerSettings.JwtSecret)
+	assert.Equal(t, "9181", ServerSettings.HTTPChallengePort)
+	assert.Equal(t, "start", ServerSettings.StartCmd)
+	assert.Equal(t, "testDB", ServerSettings.Database)
+	assert.Equal(t, "/test/ca", ServerSettings.CADir)
+	assert.Equal(t, "http://proxy.example.com", ServerSettings.GithubProxy)
+	assert.Equal(t, "nodeSecret", ServerSettings.NodeSecret)
+	assert.Equal(t, true, ServerSettings.Demo)
+	assert.Equal(t, 20, ServerSettings.PageSize)
+	assert.Equal(t, "127.0.0.1", ServerSettings.HttpHost)
+	assert.Equal(t, 14, ServerSettings.CertRenewalInterval)
+	assert.Equal(t, []string{"8.8.8.8"}, ServerSettings.RecursiveNameservers)
+	assert.Equal(t, true, ServerSettings.SkipInstallation)
+	assert.Equal(t, "test", ServerSettings.Name)
+
+	assert.Equal(t, "/tmp/nginx/access.log", NginxSettings.AccessLogPath)
+	assert.Equal(t, "/tmp/nginx/error.log", NginxSettings.ErrorLogPath)
+	assert.Equal(t, "/etc/nginx/conf", NginxSettings.ConfigDir)
+	assert.Equal(t, "/var/run/nginx.pid", NginxSettings.PIDPath)
+	assert.Equal(t, "nginx -t", NginxSettings.TestConfigCmd)
+	assert.Equal(t, "nginx -s reload", NginxSettings.ReloadCmd)
+	assert.Equal(t, "nginx -s stop", NginxSettings.RestartCmd)
+
+	assert.Equal(t, "davinci", OpenAISettings.Model)
+	assert.Equal(t, "https://api.openai.com", OpenAISettings.BaseUrl)
+	assert.Equal(t, "https://proxy.openai.com", OpenAISettings.Proxy)
+	assert.Equal(t, "token123", OpenAISettings.Token)
+
+	assert.Equal(t, "https://casdoor.example.com", CasdoorSettings.Endpoint)
+	assert.Equal(t, "clientId", CasdoorSettings.ClientId)
+	assert.Equal(t, "clientSecret", CasdoorSettings.ClientSecret)
+	assert.Equal(t, "cert.pem", CasdoorSettings.Certificate)
+	assert.Equal(t, "org1", CasdoorSettings.Organization)
+	assert.Equal(t, "app1", CasdoorSettings.Application)
+	assert.Equal(t, "https://redirect.example.com", CasdoorSettings.RedirectUri)
+
+	assert.Equal(t, true, LogrotateSettings.Enabled)
+	assert.Equal(t, "logrotate /custom/logrotate.conf", LogrotateSettings.CMD)
+	assert.Equal(t, 60, LogrotateSettings.Interval)
+
+	os.Clearenv()
+	_ = os.Remove("app.testing.ini")
+}

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