Browse Source

feat(wip): docker ui only

Jacky 2 months ago
parent
commit
d4a4ed1e1c
43 changed files with 1268 additions and 371 deletions
  1. 23 0
      .devcontainer/docker-compose.yml
  2. 1 1
      .devcontainer/init-nginx.sh
  3. 1 1
      .devcontainer/start.sh
  4. 6 1
      api/config/add.go
  5. 21 4
      api/nginx/control.go
  6. 1 1
      api/nginx/router.go
  7. 6 3
      api/nginx/status.go
  8. 10 0
      app/src/constants/errors/docker.ts
  9. 1 0
      app/src/constants/errors/nginx.ts
  10. 62 21
      app/src/language/ar/app.po
  11. 63 22
      app/src/language/de_DE/app.po
  12. 62 22
      app/src/language/en/app.po
  13. 62 21
      app/src/language/es/app.po
  14. 61 21
      app/src/language/fr_FR/app.po
  15. 62 22
      app/src/language/ko_KR/app.po
  16. 53 21
      app/src/language/messages.pot
  17. 62 21
      app/src/language/ru_RU/app.po
  18. 62 21
      app/src/language/tr_TR/app.po
  19. 53 21
      app/src/language/uk_UA/app.po
  20. 62 22
      app/src/language/vi_VN/app.po
  21. 62 21
      app/src/language/zh_CN/app.po
  22. 62 21
      app/src/language/zh_TW/app.po
  23. 13 0
      go.mod
  24. 37 9
      go.sum
  25. 5 1
      internal/config/save.go
  26. 22 0
      internal/docker/docker.go
  27. 15 0
      internal/docker/errors.go
  28. 80 0
      internal/docker/exec.go
  29. 29 0
      internal/docker/stat_path.go
  30. 58 0
      internal/docker/status.go
  31. 1 0
      internal/nginx/errors.go
  32. 28 0
      internal/nginx/exec.go
  33. 38 51
      internal/nginx/nginx.go
  34. 4 1
      internal/site/disable.go
  35. 8 2
      internal/site/enable.go
  36. 16 4
      internal/site/maintenance.go
  37. 13 6
      internal/site/rename.go
  38. 9 2
      internal/site/save.go
  39. 4 1
      internal/stream/disable.go
  40. 8 2
      internal/stream/enable.go
  41. 8 2
      internal/stream/rename.go
  42. 9 2
      internal/stream/save.go
  43. 5 0
      settings/nginx.go

+ 23 - 0
.devcontainer/docker-compose.yml

@@ -7,6 +7,7 @@ services:
       - ../..:/workspaces:cached
       - ./go-path:/root/go
       - ./data/nginx:/etc/nginx
+      - /var/run/docker.sock:/var/run/docker.sock
     command: sleep infinity
     environment:
       - NGINX_UI_CERT_CA_DIR=https://pebble:14000/dir
@@ -25,6 +26,28 @@ services:
       - nginx-ui
     networks:
       nginxui:
+  nginx-ui-3:
+    image: nginx-ui-dev
+    container_name: nginx-ui-3
+    volumes:
+      - ../..:/workspaces:cached
+      - ./data/nginx-ui-3/nginx:/etc/nginx
+      - ./data/nginx-ui-3/nginx-ui:/etc/nginx-ui
+      - /var/run/docker.sock:/var/run/docker.sock
+    working_dir: /workspaces/nginx-ui
+    command: ./.devcontainer/node-supervisor.sh
+    depends_on:
+      - nginx-ui
+    networks:
+      nginxui:
+  nginx:
+    image: nginx-ui-dev
+    container_name: nginx
+    volumes:
+      - ./data/nginx-ui-3/nginx:/etc/nginx
+    command: sleep infinity
+    networks:
+      nginxui:
   pebble:
     image: ghcr.io/letsencrypt/pebble:latest
     volumes:

+ 1 - 1
.devcontainer/init-nginx.sh

@@ -6,4 +6,4 @@ if [ "$(ls -A /etc/nginx)" = "" ]; then
 fi
 
 # start nginx
-nginx -g "daemon off;"
+nginx

+ 1 - 1
.devcontainer/start.sh

@@ -3,7 +3,7 @@
 # install air
 go install github.com/air-verse/air@latest
 
-# install zsh-autosuggestions
+install zsh-autosuggestions
 git clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions
 
 if ! grep -q "zsh-autosuggestions" ~/.zshrc; then

+ 6 - 1
api/config/add.go

@@ -74,7 +74,12 @@ func AddConfig(c *gin.Context) {
 		return
 	}
 
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
+
 	if nginx.GetLogLevel(output) >= nginx.Warn {
 		cosy.ErrHandler(c, cosy.WrapErrorWithParams(config.ErrNginxReloadFailed, output))
 		return

+ 21 - 4
api/nginx/control.go

@@ -5,24 +5,36 @@ import (
 
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/gin-gonic/gin"
+	"github.com/uozi-tech/cosy"
 )
 
+// Reload reloads the nginx
 func Reload(c *gin.Context) {
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
 	c.JSON(http.StatusOK, gin.H{
 		"message": output,
 		"level":   nginx.GetLogLevel(output),
 	})
 }
 
-func Test(c *gin.Context) {
-	output := nginx.TestConf()
+// TestConfig tests the nginx config
+func TestConfig(c *gin.Context) {
+	output, err := nginx.TestConfig()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
 	c.JSON(http.StatusOK, gin.H{
 		"message": output,
 		"level":   nginx.GetLogLevel(output),
 	})
 }
 
+// Restart restarts the nginx
 func Restart(c *gin.Context) {
 	c.JSON(http.StatusOK, gin.H{
 		"message": "ok",
@@ -30,8 +42,13 @@ func Restart(c *gin.Context) {
 	go nginx.Restart()
 }
 
+// Status returns the status of the nginx
 func Status(c *gin.Context) {
-	lastOutput := nginx.GetLastOutput()
+	lastOutput, err := nginx.GetLastOutput()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
 
 	running := nginx.IsNginxRunning()
 

+ 1 - 1
api/nginx/router.go

@@ -11,7 +11,7 @@ func InitRouter(r *gin.RouterGroup) {
 	r.POST("ngx/format_code", FormatNginxConfig)
 	r.POST("nginx/reload", Reload)
 	r.POST("nginx/restart", Restart)
-	r.POST("nginx/test", Test)
+	r.POST("nginx/test", TestConfig)
 	r.GET("nginx/status", Status)
 	// Get detailed Nginx status information, including connection count, process information, etc. (Issue #850)
 	r.GET("nginx/detail_status", GetDetailStatus)

+ 6 - 3
api/nginx/status.go

@@ -4,7 +4,6 @@
 package nginx
 
 import (
-	"errors"
 	"net/http"
 	"strings"
 	"time"
@@ -119,10 +118,14 @@ func ToggleStubStatus(c *gin.Context) {
 	}
 
 	// Reload Nginx configuration
-	reloadOutput := nginx.Reload()
+	reloadOutput, err := nginx.Reload()
+	if err != nil {
+		cosy.ErrHandler(c, err)
+		return
+	}
 	if len(reloadOutput) > 0 && (strings.Contains(strings.ToLower(reloadOutput), "error") ||
 		strings.Contains(strings.ToLower(reloadOutput), "failed")) {
-		cosy.ErrHandler(c, errors.New("Reload Nginx failed"))
+		cosy.ErrHandler(c, cosy.WrapErrorWithParams(nginx.ErrReloadFailed, reloadOutput))
 		return
 	}
 

+ 10 - 0
app/src/constants/errors/docker.ts

@@ -0,0 +1,10 @@
+export default {
+  500001: () => $gettext('Docker client not initialized'),
+  500002: () => $gettext('Failed to exec command: {0}'),
+  500003: () => $gettext('Failed to attach to exec instance: {0}'),
+  500004: () => $gettext('Failed to read output: {0}'),
+  500005: () => $gettext('Command exited with unexpected exit code: {0}, error: {1}'),
+  500006: () => $gettext('Container status unknown'),
+  500007: () => $gettext('Failed to inspect container: {0}'),
+  500008: () => $gettext('Nginx is not running in another container'),
+}

+ 1 - 0
app/src/constants/errors/nginx.ts

@@ -1,3 +1,4 @@
 export default {
   50001: () => $gettext('Block is nil'),
+  50002: () => $gettext('Reload nginx failed: {0}'),
 }

+ 62 - 21
app/src/language/ar/app.po

@@ -80,7 +80,7 @@ msgid "Add a passkey"
 msgstr "أضف مفتاح مرور"
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgstr "إضافة تكوين"
 
@@ -301,7 +301,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -355,7 +355,7 @@ msgstr ""
 msgid "Base information"
 msgstr "المعلومات الأساسية"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -594,7 +594,7 @@ msgstr[3] "الشهادات المعدلة"
 msgstr[4] "الشهادات المعدلة"
 msgstr[5] "الشهادات المعدلة"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgstr "المسار المتغير"
 
@@ -707,6 +707,10 @@ msgstr ""
 msgid "Command"
 msgstr "أمر"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -787,6 +791,10 @@ msgstr "تم فقدان الاتصال، يرجى تحديث الصفحة."
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1018,7 +1026,7 @@ msgstr "تم الحذف بنجاح"
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "نشر"
 
@@ -1218,6 +1226,10 @@ msgstr "هل تريد إزالة هذا الخادم؟"
 msgid "Do you want to remove this upstream?"
 msgstr "هل تريد إزالة هذا المصدر؟"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
@@ -1281,7 +1293,7 @@ msgstr "تعديل %{n}"
 msgid "Edit %{n}"
 msgstr "تعديل %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "تعديل التكوين"
 
@@ -1495,6 +1507,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr "فشل في الحصول على الشهادة"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #, fuzzy
 msgid "Failed to backup Nginx config files: {0}"
@@ -1680,6 +1697,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "فشل في التفعيل %{msg}"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 msgid "Failed to extract archive: {0}"
@@ -1709,6 +1731,11 @@ msgstr "فشل في الحصول على معلومات الشهادة"
 msgid "Failed to get performance data"
 msgstr "فشل في الحصول على معلومات الشهادة"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 msgid "Failed to load history records"
@@ -1753,6 +1780,11 @@ msgstr "فشل في التفعيل %{msg}"
 msgid "Failed to read nginx.conf"
 msgstr "فشل في التفعيل %{msg}"
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 msgid "Failed to read symlink: {0}"
@@ -1838,14 +1870,10 @@ msgstr "للمستخدمين الصين: /https://mirror.ghproxy.com"
 msgid "Form parse failed"
 msgstr "فشل التكرار"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "تنسيق الكود"
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "خطأ في التنسيق %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgstr "تم التنسيق بنجاح"
@@ -1920,7 +1948,7 @@ msgstr "إخفاء"
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
@@ -2101,7 +2129,7 @@ msgid "Invalid file path: {0}"
 msgstr "رمز 2FA أو الاسترداد غير صالح"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgstr "اسم ملف غير صالح"
 
@@ -2525,7 +2553,7 @@ msgstr "توجيه متعدد الأسطر"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2568,7 +2596,7 @@ msgstr "تثبيت"
 msgid "New name"
 msgstr "اسم جديد"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgstr "مسار جديد"
 
@@ -2669,6 +2697,11 @@ msgstr "مسار سجل أخطاء Nginx"
 msgid "Nginx is not running"
 msgstr "Nginx لا يعمل"
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx لا يعمل"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 msgid "Nginx is running"
@@ -2999,11 +3032,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr "استخدم رمز الاسترداد"
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr "الكتابة فوق"
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr "الكتابة فوق الملف الموجود"
 
@@ -3054,7 +3087,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "مسار"
@@ -3150,7 +3183,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgstr "يرجى إدخال اسم الملف"
 
@@ -3386,6 +3419,11 @@ msgstr "إعادة تحميل"
 msgid "Reload Nginx"
 msgstr "إعادة تحميل nginx"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "فشل في التفعيل %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3675,7 +3713,7 @@ msgstr "يعمل"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4519,7 +4557,7 @@ msgstr "تم التحديث بنجاح"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4816,6 +4854,9 @@ msgstr ""
 msgid "Your passkeys"
 msgstr "مفاتيح المرور الخاصة بك"
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "خطأ في التنسيق %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "فشل في الحفظ، تم اكتشاف خطأ(أخطاء) في بناء الجملة في التكوين."
 

+ 63 - 22
app/src/language/de_DE/app.po

@@ -77,7 +77,7 @@ msgid "Add a passkey"
 msgstr "Passkey hinzufügen"
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 #, fuzzy
 msgid "Add Configuration"
 msgstr "Konfiguration bearbeiten"
@@ -315,7 +315,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -370,7 +370,7 @@ msgstr ""
 msgid "Base information"
 msgstr "Basisinformationen"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #, fuzzy
@@ -610,7 +610,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Zertifikat ist gültig"
 msgstr[1] "Zertifikat ist gültig"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "Changed Path"
 msgstr "Zertifikat ist gültig"
@@ -726,6 +726,10 @@ msgstr ""
 msgid "Command"
 msgstr "Kommando"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -806,6 +810,10 @@ msgstr "Ver"
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1045,7 +1053,7 @@ msgstr "Erfolgreich deaktiviert"
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "Ausführen"
 
@@ -1255,6 +1263,10 @@ msgstr "Bist du sicher, dass du diese Richtlinie löschen möchtest?"
 msgid "Do you want to remove this upstream?"
 msgstr "Bist du sicher, dass du diese Richtlinie löschen möchtest?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
@@ -1318,7 +1330,7 @@ msgstr "Bearbeiten %{n}"
 msgid "Edit %{n}"
 msgstr "Bearbeiten %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "Konfiguration bearbeiten"
 
@@ -1542,6 +1554,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr "Zertifikat ist gültig"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
@@ -1726,6 +1743,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Aktiviern von %{msg} fehlgeschlagen"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 msgid "Failed to extract archive: {0}"
@@ -1755,6 +1777,11 @@ msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 msgid "Failed to get performance data"
 msgstr "Fehler beim Abrufen von Zertifikatsinformationen"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 msgid "Failed to load history records"
@@ -1796,6 +1823,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgstr ""
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 msgid "Failed to read symlink: {0}"
@@ -1882,15 +1914,10 @@ msgstr "Für chinesische Benutzer: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgstr "Anlegen fehlgeschlagen"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "Formatcode"
 
-#: src/views/config/ConfigEditor.vue:218
-#, fuzzy
-msgid "Format error %{msg}"
-msgstr "Fehler beim Speichern %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #, fuzzy
 msgid "Format successfully"
@@ -1968,7 +1995,7 @@ msgstr "Verstecken"
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
@@ -2150,7 +2177,7 @@ msgid "Invalid file path: {0}"
 msgstr "Ungültige E-Mail!"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 #, fuzzy
 msgid "Invalid filename"
 msgstr "Ungültige E-Mail!"
@@ -2595,7 +2622,7 @@ msgstr "Einzelne Anweisung"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2639,7 +2666,7 @@ msgstr "Installieren"
 msgid "New name"
 msgstr "Benutzername"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "New Path"
 msgstr "Pfad"
@@ -2743,6 +2770,11 @@ msgstr "Nginx Fehlerlog-Pfad"
 msgid "Nginx is not running"
 msgstr "Nginx läuft nicht"
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx läuft nicht"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 msgid "Nginx is running"
@@ -3082,11 +3114,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr "Benuzte Wiederherstellungscode"
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr "Überschreiben"
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr "Zu überschreibende Datei existiert"
 
@@ -3137,7 +3169,7 @@ msgstr "Passwort darf nicht länger als 20 Zeichen sein"
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "Pfad"
@@ -3237,7 +3269,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 msgid "Please input a filename"
 msgstr "Bitte Benutzernamen eingeben!"
@@ -3488,6 +3520,11 @@ msgstr "Neu laden"
 msgid "Reload Nginx"
 msgstr "Lade Nginx neu"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Aktiviern von %{msg} fehlgeschlagen"
+
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3792,7 +3829,7 @@ msgstr "Arbeite"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4653,7 +4690,7 @@ msgstr "Speichern erfolgreich"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4961,6 +4998,10 @@ msgstr ""
 msgid "Your passkeys"
 msgstr "Deine Passkeys"
 
+#, fuzzy
+#~ msgid "Format error %{msg}"
+#~ msgstr "Fehler beim Speichern %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr ""
 #~ "Fehler beim Speichern, Syntaxfehler wurden in der Konfiguration erkannt."

+ 62 - 22
app/src/language/en/app.po

@@ -78,7 +78,7 @@ msgid "Add a passkey"
 msgstr ""
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 #, fuzzy
 msgid "Add Configuration"
 msgstr "Edit Configuration"
@@ -312,7 +312,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -367,7 +367,7 @@ msgstr ""
 msgid "Base information"
 msgstr "Base information"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #, fuzzy
@@ -603,7 +603,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Certificate is valid"
 msgstr[1] "Certificate is valid"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "Changed Path"
 msgstr "Certificate is valid"
@@ -718,6 +718,10 @@ msgstr ""
 msgid "Command"
 msgstr "Comments"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -798,6 +802,10 @@ msgstr ""
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1034,7 +1042,7 @@ msgstr "Disabled successfully"
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr ""
 
@@ -1243,6 +1251,10 @@ msgstr "Are you sure you want to remove this directive?"
 msgid "Do you want to remove this upstream?"
 msgstr "Are you sure you want to remove this directive?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
@@ -1302,7 +1314,7 @@ msgstr "Edit %{n}"
 msgid "Edit %{n}"
 msgstr "Edit %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "Edit Configuration"
 
@@ -1525,6 +1537,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr "Certificate is valid"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #, fuzzy
 msgid "Failed to backup Nginx config files: {0}"
@@ -1710,6 +1727,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Failed to enable %{msg}"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 msgid "Failed to extract archive: {0}"
@@ -1740,6 +1762,11 @@ msgstr "Certificate is valid"
 msgid "Failed to get performance data"
 msgstr "Certificate is valid"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 msgid "Failed to load history records"
@@ -1784,6 +1811,11 @@ msgstr "Failed to enable %{msg}"
 msgid "Failed to read nginx.conf"
 msgstr "Failed to enable %{msg}"
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 msgid "Failed to read symlink: {0}"
@@ -1869,15 +1901,10 @@ msgstr ""
 msgid "Form parse failed"
 msgstr "Enable failed"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:218
-#, fuzzy
-msgid "Format error %{msg}"
-msgstr "Save error %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #, fuzzy
 msgid "Format successfully"
@@ -1954,7 +1981,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
@@ -2129,7 +2156,7 @@ msgid "Invalid file path: {0}"
 msgstr "Invalid E-mail!"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 #, fuzzy
 msgid "Invalid filename"
 msgstr "Invalid E-mail!"
@@ -2567,7 +2594,7 @@ msgstr "Single Directive"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2611,7 +2638,7 @@ msgstr "Install"
 msgid "New name"
 msgstr "Username"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "New Path"
 msgstr "Path"
@@ -2714,6 +2741,10 @@ msgstr ""
 msgid "Nginx is not running"
 msgstr ""
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgstr ""
@@ -3045,11 +3076,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr ""
 
@@ -3097,7 +3128,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "Path"
@@ -3189,7 +3220,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 msgid "Please input a filename"
 msgstr "Please input your username!"
@@ -3431,6 +3462,11 @@ msgstr ""
 msgid "Reload Nginx"
 msgstr ""
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Failed to enable %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3734,7 +3770,7 @@ msgstr ""
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4573,7 +4609,7 @@ msgstr "Saved successfully"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4871,6 +4907,10 @@ msgstr ""
 msgid "Your passkeys"
 msgstr ""
 
+#, fuzzy
+#~ msgid "Format error %{msg}"
+#~ msgstr "Save error %{msg}"
+
 #, fuzzy
 #~ msgid "Access Token"
 #~ msgstr "Sites List"

+ 62 - 21
app/src/language/es/app.po

@@ -83,7 +83,7 @@ msgid "Add a passkey"
 msgstr "Agregar una llave de acceso"
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgstr "Agregar configuración"
 
@@ -306,7 +306,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -360,7 +360,7 @@ msgstr ""
 msgid "Base information"
 msgstr "Información general"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -593,7 +593,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Cambiar Certificado"
 msgstr[1] "Cambiar Certificados"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgstr "Ruta cambiada"
 
@@ -706,6 +706,10 @@ msgstr ""
 msgid "Command"
 msgstr "Comando"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -786,6 +790,10 @@ msgstr "Conexión perdida, por favor actualice la página."
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1019,7 +1027,7 @@ msgstr "Borrado exitoso"
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "Desplegar"
 
@@ -1219,6 +1227,10 @@ msgstr "¿Quieres eliminar este servidor?"
 msgid "Do you want to remove this upstream?"
 msgstr "¿Quieres eliminar esta transmisión?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
@@ -1281,7 +1293,7 @@ msgstr "Editar %{n}"
 msgid "Edit %{n}"
 msgstr "Editar %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "Editar Configuración"
 
@@ -1498,6 +1510,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr "Falla al obtener el certificado"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
@@ -1682,6 +1699,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Error al habilitar %{msg}"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 msgid "Failed to extract archive: {0}"
@@ -1711,6 +1733,11 @@ msgstr "No se pudo obtener la información del certificado"
 msgid "Failed to get performance data"
 msgstr "No se pudo obtener la información del certificado"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 msgid "Failed to load history records"
@@ -1752,6 +1779,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgstr ""
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 msgid "Failed to read symlink: {0}"
@@ -1838,14 +1870,10 @@ msgstr "Para usuario chino: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgstr "Duplicado fallido"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "Código de formato"
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "Error de formato %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgstr "Formateado correctamente"
@@ -1920,7 +1948,7 @@ msgstr "Ocultar"
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
@@ -2101,7 +2129,7 @@ msgid "Invalid file path: {0}"
 msgstr "Nombre de archivo inválido"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgstr "Nombre de archivo inválido"
 
@@ -2527,7 +2555,7 @@ msgstr "Directiva multilínea"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2570,7 +2598,7 @@ msgstr "Instalar"
 msgid "New name"
 msgstr "Nuevo nombre"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgstr "Nueva ruta"
 
@@ -2672,6 +2700,11 @@ msgstr "Ruta de registro de errores de Nginx"
 msgid "Nginx is not running"
 msgstr "Nginx no se está ejecutando"
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx no se está ejecutando"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 msgid "Nginx is running"
@@ -3006,11 +3039,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr "Usar código de recuperación"
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr "Sobrescribir"
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr "Sobrescribir archivo existente"
 
@@ -3062,7 +3095,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "Ruta"
@@ -3163,7 +3196,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgstr "Por favor, ingrese un nombre de archivo"
 
@@ -3410,6 +3443,11 @@ msgstr "Recargar"
 msgid "Reload Nginx"
 msgstr "Recargando Nginx"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Error al habilitar %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3702,7 +3740,7 @@ msgstr "Corriendo"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4560,7 +4598,7 @@ msgstr "Actualización exitosa"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4862,6 +4900,9 @@ msgstr ""
 msgid "Your passkeys"
 msgstr "Sus llaves de acceso"
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "Error de formato %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr ""
 #~ "No se pudo guardar, se detectó un error(es) de sintaxis en la "

+ 61 - 21
app/src/language/fr_FR/app.po

@@ -82,7 +82,7 @@ msgid "Add a passkey"
 msgstr "Ajouter une clé d'accès"
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 #, fuzzy
 msgid "Add Configuration"
 msgstr "Modifier la configuration"
@@ -319,7 +319,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -373,7 +373,7 @@ msgstr ""
 msgid "Base information"
 msgstr "Information générale"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -612,7 +612,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Changer de certificat"
 msgstr[1] "Changer de certificat"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "Changed Path"
 msgstr "Changer de certificat"
@@ -733,6 +733,10 @@ msgstr ""
 msgid "Command"
 msgstr "Commentaires"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -813,6 +817,10 @@ msgstr "Connexion perdue, merci de recharger la page."
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1053,7 +1061,7 @@ msgstr "Désactivé avec succès"
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "Déployer"
 
@@ -1262,6 +1270,10 @@ msgstr "Voulez-vous supprimer ce serveur ?"
 msgid "Do you want to remove this upstream?"
 msgstr "Voulez-vous supprimer ce serveur ?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
@@ -1327,7 +1339,7 @@ msgstr "Modifier %{n}"
 msgid "Edit %{n}"
 msgstr "Modifier %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "Modifier la configuration"
 
@@ -1552,6 +1564,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr "Obtenir un certificat"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/constants/errors/backup.ts:5
 #, fuzzy
 msgid "Failed to backup Nginx config files: {0}"
@@ -1737,6 +1754,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Impossible d'activer %{msg}"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 msgid "Failed to extract archive: {0}"
@@ -1766,6 +1788,11 @@ msgstr "Échec de l'obtention des informations sur le certificat"
 msgid "Failed to get performance data"
 msgstr "Échec de l'obtention des informations sur le certificat"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 msgid "Failed to load history records"
@@ -1811,6 +1838,11 @@ msgstr "Impossible d'activer %{msg}"
 msgid "Failed to read nginx.conf"
 msgstr "Impossible d'activer %{msg}"
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 msgid "Failed to read symlink: {0}"
@@ -1901,14 +1933,10 @@ msgstr "Utilisateur chinois : https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgstr "Dupliquer"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "Code de formatage"
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "Erreur de format %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgstr "Formaté avec succès"
@@ -1982,7 +2010,7 @@ msgstr "Cacher"
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
@@ -2170,7 +2198,7 @@ msgid "Invalid file path: {0}"
 msgstr "Format de la requête invalide"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgstr "Nom de fichier invalide"
 
@@ -2608,7 +2636,7 @@ msgstr "Directive multiligne"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2652,7 +2680,7 @@ msgstr "Installer"
 msgid "New name"
 msgstr "Nom d'utilisateur"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "New Path"
 msgstr "Chemin"
@@ -2756,6 +2784,10 @@ msgstr "Chemin du journal des erreurs Nginx"
 msgid "Nginx is not running"
 msgstr ""
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgstr ""
@@ -3086,11 +3118,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr ""
 
@@ -3138,7 +3170,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "Chemin"
@@ -3234,7 +3266,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgstr "Veuillez renseigner un nom de fichier"
 
@@ -3482,6 +3514,11 @@ msgstr "Recharger"
 msgid "Reload Nginx"
 msgstr "Rechargement de nginx"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Impossible d'activer %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3786,7 +3823,7 @@ msgstr "En cours d'éxécution"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4632,7 +4669,7 @@ msgstr "Mis à jour avec succés"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4927,6 +4964,9 @@ msgstr ""
 msgid "Your passkeys"
 msgstr ""
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "Erreur de format %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr ""
 #~ "Échec de l'enregistrement, une ou plusieurs erreurs de syntaxe ont été "

+ 62 - 22
app/src/language/ko_KR/app.po

@@ -81,7 +81,7 @@ msgid "Add a passkey"
 msgstr ""
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgstr "구성 추가"
 
@@ -296,7 +296,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr "사이트 및 스트림 구성에서 자동으로 색인됩니다."
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -350,7 +350,7 @@ msgstr ""
 msgid "Base information"
 msgstr "기본 정보"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -582,7 +582,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "인증서 변경"
 msgstr[1] "인증서 변경"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "Changed Path"
 msgstr "인증서 변경"
@@ -695,6 +695,10 @@ msgstr ""
 msgid "Command"
 msgstr "명령어"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -775,6 +779,10 @@ msgstr "연결이 끊어졌습니다. 페이지를 새로 고침하세요."
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1009,7 +1017,7 @@ msgstr "성공적으로 삭제됨"
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "배포"
 
@@ -1211,6 +1219,10 @@ msgstr "이 서버를 제거하시겠습니까?"
 msgid "Do you want to remove this upstream?"
 msgstr "이 업스트림을 제거하시겠습니까?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
@@ -1269,7 +1281,7 @@ msgstr "%{n} 편집"
 msgid "Edit %{n}"
 msgstr "%{n} 편집"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "구성 편집"
 
@@ -1491,6 +1503,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr "인증서 획득 실패"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
@@ -1675,6 +1692,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "%{msg} 활성화 실패"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 msgid "Failed to extract archive: {0}"
@@ -1704,6 +1726,11 @@ msgstr "인증서 정보 가져오기 실패"
 msgid "Failed to get performance data"
 msgstr "인증서 정보 가져오기 실패"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 msgid "Failed to load history records"
@@ -1745,6 +1772,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgstr ""
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 msgid "Failed to read symlink: {0}"
@@ -1829,15 +1861,10 @@ msgstr "중국 사용자를 위해: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgstr "복제 실패"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "코드 형식"
 
-#: src/views/config/ConfigEditor.vue:218
-#, fuzzy
-msgid "Format error %{msg}"
-msgstr "형식 오류 %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #, fuzzy
 msgid "Format successfully"
@@ -1913,7 +1940,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
@@ -2088,7 +2115,7 @@ msgid "Invalid file path: {0}"
 msgstr "Invalid E-mail!"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 #, fuzzy
 msgid "Invalid filename"
 msgstr "Invalid E-mail!"
@@ -2528,7 +2555,7 @@ msgstr "단일 지시문"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2572,7 +2599,7 @@ msgstr "설치"
 msgid "New name"
 msgstr "이름 변경"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "New Path"
 msgstr "경로"
@@ -2676,6 +2703,10 @@ msgstr "Nginx 오류 로그 경로"
 msgid "Nginx is not running"
 msgstr ""
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgstr ""
@@ -3008,11 +3039,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr "덮어쓰기"
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr "기존 파일 덮어쓰기"
 
@@ -3060,7 +3091,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "경로"
@@ -3153,7 +3184,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 msgid "Please input a filename"
 msgstr "사용자 이름을 입력해주세요!"
@@ -3402,6 +3433,11 @@ msgstr "리로드"
 msgid "Reload Nginx"
 msgstr "Nginx 리로딩 중"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "%{msg} 활성화 실패"
+
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3707,7 +3743,7 @@ msgstr "실행 중"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4544,7 +4580,7 @@ msgstr "성공적으로 저장되었습니다"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4844,6 +4880,10 @@ msgstr ""
 msgid "Your passkeys"
 msgstr ""
 
+#, fuzzy
+#~ msgid "Format error %{msg}"
+#~ msgstr "형식 오류 %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "저장 실패, 구성에서 구문 오류가 감지되었습니다."
 

+ 53 - 21
app/src/language/messages.pot

@@ -71,7 +71,7 @@ msgstr ""
 
 #: src/routes/modules/config.ts:20
 #: src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgstr ""
 
@@ -285,7 +285,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268
+#: src/views/config/ConfigEditor.vue:266
 #: src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195
 #: src/views/nginx_log/NginxLog.vue:173
@@ -338,7 +338,7 @@ msgstr ""
 msgid "Base information"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -553,7 +553,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] ""
 msgstr[1] ""
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgstr ""
 
@@ -659,6 +659,10 @@ msgstr ""
 msgid "Command"
 msgstr ""
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -734,6 +738,10 @@ msgstr ""
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -953,7 +961,7 @@ msgstr ""
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr ""
 
@@ -1144,6 +1152,10 @@ msgstr ""
 msgid "Do you want to remove this upstream?"
 msgstr ""
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 msgid "Document"
@@ -1198,7 +1210,7 @@ msgid "Edit %{n}"
 msgstr ""
 
 #: src/routes/modules/config.ts:30
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr ""
 
@@ -1403,6 +1415,10 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr ""
 
+#: src/constants/errors/docker.ts:4
+msgid "Failed to attach to exec instance: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
@@ -1563,6 +1579,10 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr ""
 
+#: src/constants/errors/docker.ts:3
+msgid "Failed to exec command: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:35
 msgid "Failed to extract archive: {0}"
 msgstr ""
@@ -1587,6 +1607,10 @@ msgstr ""
 msgid "Failed to get performance data"
 msgstr ""
 
+#: src/constants/errors/docker.ts:8
+msgid "Failed to inspect container: {0}"
+msgstr ""
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 msgid "Failed to load history records"
 msgstr ""
@@ -1623,6 +1647,10 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgstr ""
 
+#: src/constants/errors/docker.ts:5
+msgid "Failed to read output: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:21
 msgid "Failed to read symlink: {0}"
 msgstr ""
@@ -1701,14 +1729,10 @@ msgstr ""
 msgid "Form parse failed"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr ""
-
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgstr ""
@@ -1779,7 +1803,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
@@ -1938,7 +1962,7 @@ msgid "Invalid file path: {0}"
 msgstr ""
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgstr ""
 
@@ -2336,7 +2360,7 @@ msgstr ""
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
 #: src/views/config/configColumns.tsx:7
-#: src/views/config/ConfigEditor.vue:311
+#: src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2379,7 +2403,7 @@ msgstr ""
 msgid "New name"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgstr ""
 
@@ -2476,6 +2500,10 @@ msgstr ""
 msgid "Nginx is not running"
 msgstr ""
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgstr ""
@@ -2785,11 +2813,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr ""
 
@@ -2833,7 +2861,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr ""
@@ -2914,7 +2942,7 @@ msgid "Please generate new recovery codes in the preferences immediately to prev
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgstr ""
 
@@ -3137,6 +3165,10 @@ msgstr ""
 msgid "Reload Nginx"
 msgstr ""
 
+#: src/constants/errors/nginx.ts:3
+msgid "Reload nginx failed: {0}"
+msgstr ""
+
 #: src/components/Notification/notifications.ts:10
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgstr ""
@@ -3400,7 +3432,7 @@ msgstr ""
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4127,7 +4159,7 @@ msgstr ""
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
 #: src/views/config/configColumns.tsx:36
-#: src/views/config/ConfigEditor.vue:331
+#: src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38

+ 62 - 21
app/src/language/ru_RU/app.po

@@ -83,7 +83,7 @@ msgid "Add a passkey"
 msgstr "Добавить ключ доступа"
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgstr "Добавить конфигурацию"
 
@@ -300,7 +300,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -354,7 +354,7 @@ msgstr ""
 msgid "Base information"
 msgstr "Основная информация"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -581,7 +581,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Сертификат изменен"
 msgstr[1] "Сертификаты изменены"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgstr "Путь изменён"
 
@@ -694,6 +694,10 @@ msgstr ""
 msgid "Command"
 msgstr "Команда"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -774,6 +778,10 @@ msgstr "Соединение потеряно, пожалуйста, обнов
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1004,7 +1012,7 @@ msgstr "Удалено успешно"
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "Развернуть"
 
@@ -1207,6 +1215,10 @@ msgstr "Хотите удалить этот сервер?"
 msgid "Do you want to remove this upstream?"
 msgstr "Хотите удалить этот сервер?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
@@ -1268,7 +1280,7 @@ msgstr "Редактировать %{n}"
 msgid "Edit %{n}"
 msgstr "Редактировать %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "Редактировать Конфигурацию"
 
@@ -1482,6 +1494,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr "Не удалось получить сертификат"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
@@ -1666,6 +1683,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Не удалось включить %{msg}"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 msgid "Failed to extract archive: {0}"
@@ -1695,6 +1717,11 @@ msgstr "Не удалось получить информацию о серти
 msgid "Failed to get performance data"
 msgstr "Не удалось получить информацию о сертификате"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 msgid "Failed to load history records"
@@ -1736,6 +1763,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgstr ""
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 msgid "Failed to read symlink: {0}"
@@ -1822,14 +1854,10 @@ msgstr "Для китайских пользователей: https://mirror.ghp
 msgid "Form parse failed"
 msgstr "Дублирование не удалось"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "Форматировать код"
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "Ошибка формата %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgstr "Форматирование успешно"
@@ -1904,7 +1932,7 @@ msgstr "Скрыть"
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
@@ -2085,7 +2113,7 @@ msgid "Invalid file path: {0}"
 msgstr "Неверное имя файла"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgstr "Неверное имя файла"
 
@@ -2508,7 +2536,7 @@ msgstr "Многострочная директива"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2551,7 +2579,7 @@ msgstr "Установить"
 msgid "New name"
 msgstr "Новое имя"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgstr "Новый путь"
 
@@ -2653,6 +2681,11 @@ msgstr "Путь для Nginx Error Log"
 msgid "Nginx is not running"
 msgstr "Nginx не работает"
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx не работает"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 msgid "Nginx is running"
@@ -2983,11 +3016,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr "Код OTP или восстановления пуст"
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr "Перезаписать"
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr "Перезаписать существующий файл"
 
@@ -3035,7 +3068,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "Путь"
@@ -3134,7 +3167,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgstr "Пожалуйста, введите имя файла"
 
@@ -3380,6 +3413,11 @@ msgstr "Перегрузить"
 msgid "Reload Nginx"
 msgstr "Перезагружается nginx"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Не удалось включить %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3670,7 +3708,7 @@ msgstr "Выполняется"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4517,7 +4555,7 @@ msgstr "Успешно обновлено"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4811,6 +4849,9 @@ msgstr "Ваши старые коды больше не будут работа
 msgid "Your passkeys"
 msgstr ""
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "Ошибка формата %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr ""
 #~ "Не удалось сохранить, обнаружены синтаксические ошибки в конфигурации."

+ 62 - 21
app/src/language/tr_TR/app.po

@@ -80,7 +80,7 @@ msgid "Add a passkey"
 msgstr "Geçiş anahtarı ekleme"
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgstr "Yapılandırma Ekle"
 
@@ -297,7 +297,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -351,7 +351,7 @@ msgstr ""
 msgid "Base information"
 msgstr "Temel bilgiler"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -582,7 +582,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Değişen Sertifika"
 msgstr[1] "Değişen Sertifikalar"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgstr "Değişen Dosya Yolu"
 
@@ -695,6 +695,10 @@ msgstr ""
 msgid "Command"
 msgstr "Komut"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -775,6 +779,10 @@ msgstr "Bağlantı kesildi, lütfen sayfayı yenileyin."
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1011,7 +1019,7 @@ msgstr "Başarıyla silindi"
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "Yayınla"
 
@@ -1225,6 +1233,10 @@ msgstr "Bu sunucuyu kaldırmak istiyor musunuz?"
 msgid "Do you want to remove this upstream?"
 msgstr "Bu upstream'i kaldırmak istiyor musunuz?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
@@ -1287,7 +1299,7 @@ msgstr "Düzenle %{n}"
 msgid "Edit %{n}"
 msgstr "Düzenle %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "Yapılandırmayı Düzenle"
 
@@ -1515,6 +1527,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr "Sertifika alınamadı"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
@@ -1699,6 +1716,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Etkinleştirilemedi %{msg}"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 msgid "Failed to extract archive: {0}"
@@ -1728,6 +1750,11 @@ msgstr "Sertifika bilgileri alınamadı"
 msgid "Failed to get performance data"
 msgstr "Sertifika bilgileri alınamadı"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 msgid "Failed to load history records"
@@ -1769,6 +1796,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgstr ""
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 msgid "Failed to read symlink: {0}"
@@ -1855,14 +1887,10 @@ msgstr "Çinli kullanıcılar için: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgstr "Kopyalama başarısız oldu"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "Kodu Biçimlendir"
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "Biçimlendirme hatası %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgstr "Başarıyla biçimlendirildi"
@@ -1937,7 +1965,7 @@ msgstr "Gizle"
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
@@ -2119,7 +2147,7 @@ msgid "Invalid file path: {0}"
 msgstr "Geçersiz dosya adı"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgstr "Geçersiz dosya adı"
 
@@ -2559,7 +2587,7 @@ msgstr "Çok Hatlı Direktif"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2608,7 +2636,7 @@ msgstr "Yükle"
 msgid "New name"
 msgstr "Yeni Ad"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "New Path"
 msgstr "Yeni Yol"
@@ -2719,6 +2747,11 @@ msgstr "Nginx Hata Günlüğü Yolu"
 msgid "Nginx is not running"
 msgstr "Nginx çalışmıyor"
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx çalışmıyor"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 #, fuzzy
 msgid "Nginx is running"
@@ -3074,12 +3107,12 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr "Kurtarma kodunu kullanın"
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 #, fuzzy
 msgid "Overwrite"
 msgstr "Üzerine yaz"
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 #, fuzzy
 msgid "Overwrite exist file"
 msgstr "Mevcut dosyanın üzerine yaz"
@@ -3136,7 +3169,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 #, fuzzy
 msgid "Path"
@@ -3245,7 +3278,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 msgid "Please input a filename"
 msgstr "Lütfen bir dosya adı girin"
@@ -3522,6 +3555,11 @@ msgstr "Tekrar yükle"
 msgid "Reload Nginx"
 msgstr "Nginx'i yeniden yükleme"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Etkinleştirilemedi %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3843,7 +3881,7 @@ msgstr "Çalışıyor"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4768,7 +4806,7 @@ msgstr "Güncellendi"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -5098,6 +5136,9 @@ msgstr ""
 msgid "Your passkeys"
 msgstr "Geçiş anahtarlarınız"
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "Biçimlendirme hatası %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "Kaydedilemedi, yapılandırmada sözdizimi hatası(ları) tespit edildi."
 

+ 53 - 21
app/src/language/uk_UA/app.po

@@ -80,7 +80,7 @@ msgid "Add a passkey"
 msgstr ""
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgstr "Додати конфігурацію"
 
@@ -296,7 +296,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -347,7 +347,7 @@ msgstr ""
 msgid "Base information"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -566,7 +566,7 @@ msgstr[0] ""
 msgstr[1] ""
 msgstr[2] ""
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgstr ""
 
@@ -678,6 +678,10 @@ msgstr ""
 msgid "Command"
 msgstr ""
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -753,6 +757,10 @@ msgstr ""
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -971,7 +979,7 @@ msgstr ""
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr ""
 
@@ -1158,6 +1166,10 @@ msgstr ""
 msgid "Do you want to remove this upstream?"
 msgstr ""
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 msgid "Document"
@@ -1214,7 +1226,7 @@ msgstr ""
 msgid "Edit %{n}"
 msgstr ""
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr ""
 
@@ -1415,6 +1427,10 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr ""
 
+#: src/constants/errors/docker.ts:4
+msgid "Failed to attach to exec instance: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
@@ -1575,6 +1591,10 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr ""
 
+#: src/constants/errors/docker.ts:3
+msgid "Failed to exec command: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:35
 msgid "Failed to extract archive: {0}"
 msgstr ""
@@ -1599,6 +1619,10 @@ msgstr ""
 msgid "Failed to get performance data"
 msgstr ""
 
+#: src/constants/errors/docker.ts:8
+msgid "Failed to inspect container: {0}"
+msgstr ""
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 msgid "Failed to load history records"
 msgstr ""
@@ -1635,6 +1659,10 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgstr ""
 
+#: src/constants/errors/docker.ts:5
+msgid "Failed to read output: {0}"
+msgstr ""
+
 #: src/constants/errors/backup.ts:21
 msgid "Failed to read symlink: {0}"
 msgstr ""
@@ -1714,14 +1742,10 @@ msgstr ""
 msgid "Form parse failed"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr ""
-
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgstr ""
@@ -1792,7 +1816,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
@@ -1959,7 +1983,7 @@ msgid "Invalid file path: {0}"
 msgstr ""
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgstr ""
 
@@ -2358,7 +2382,7 @@ msgstr ""
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2400,7 +2424,7 @@ msgstr ""
 msgid "New name"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgstr ""
 
@@ -2496,6 +2520,10 @@ msgstr ""
 msgid "Nginx is not running"
 msgstr ""
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgstr ""
@@ -2807,11 +2835,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr ""
 
@@ -2857,7 +2885,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr ""
@@ -2947,7 +2975,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgstr ""
 
@@ -3175,6 +3203,10 @@ msgstr ""
 msgid "Reload Nginx"
 msgstr ""
 
+#: src/constants/errors/nginx.ts:3
+msgid "Reload nginx failed: {0}"
+msgstr ""
+
 #: src/components/Notification/notifications.ts:10
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgstr ""
@@ -3441,7 +3473,7 @@ msgstr ""
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4216,7 +4248,7 @@ msgstr ""
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38

+ 62 - 22
app/src/language/vi_VN/app.po

@@ -77,7 +77,7 @@ msgid "Add a passkey"
 msgstr ""
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 #, fuzzy
 msgid "Add Configuration"
 msgstr "Sửa cấu hình"
@@ -312,7 +312,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr ""
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -367,7 +367,7 @@ msgstr ""
 msgid "Base information"
 msgstr "Thông tin"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 #, fuzzy
@@ -606,7 +606,7 @@ msgid_plural "Changed Certificates"
 msgstr[0] "Thay đổi chứng chỉ"
 msgstr[1] "Thay đổi chứng chỉ"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "Changed Path"
 msgstr "Thay đổi chứng chỉ"
@@ -721,6 +721,10 @@ msgstr ""
 msgid "Command"
 msgstr "Bình luận"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -801,6 +805,10 @@ msgstr ""
 msgid "Connection timeout period"
 msgstr ""
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -1038,7 +1046,7 @@ msgstr "Đã xoá thành công"
 msgid "Demo"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "Triển khai"
 
@@ -1246,6 +1254,10 @@ msgstr "Bạn muốn xóa máy chủ này ?"
 msgid "Do you want to remove this upstream?"
 msgstr "Bạn muốn xóa máy chủ này ?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 #, fuzzy
@@ -1306,7 +1318,7 @@ msgstr "Sửa %{n}"
 msgid "Edit %{n}"
 msgstr "Sửa %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "Sửa cấu hình"
 
@@ -1531,6 +1543,11 @@ msgstr ""
 msgid "Fail to obtain certificate"
 msgstr "Nhận chứng chỉ"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr ""
@@ -1715,6 +1732,11 @@ msgstr ""
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "Không thể bật %{msg}"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/constants/errors/backup.ts:35
 #, fuzzy
 msgid "Failed to extract archive: {0}"
@@ -1744,6 +1766,11 @@ msgstr "Không thể truy xuất thông tin chứng chỉ"
 msgid "Failed to get performance data"
 msgstr "Không thể truy xuất thông tin chứng chỉ"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 #, fuzzy
 msgid "Failed to load history records"
@@ -1785,6 +1812,11 @@ msgstr ""
 msgid "Failed to read nginx.conf"
 msgstr ""
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/constants/errors/backup.ts:21
 #, fuzzy
 msgid "Failed to read symlink: {0}"
@@ -1870,15 +1902,10 @@ msgstr "Người dùng Trung Quốc: https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgstr "Nhân bản thất bại"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "Định dạng code"
 
-#: src/views/config/ConfigEditor.vue:218
-#, fuzzy
-msgid "Format error %{msg}"
-msgstr "Lưu lỗi %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 #, fuzzy
 msgid "Format successfully"
@@ -1954,7 +1981,7 @@ msgstr ""
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 #, fuzzy
@@ -2128,7 +2155,7 @@ msgid "Invalid file path: {0}"
 msgstr "E-mail không chính xác!"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 #, fuzzy
 msgid "Invalid filename"
 msgstr "E-mail không chính xác!"
@@ -2562,7 +2589,7 @@ msgstr "Single Directive"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2606,7 +2633,7 @@ msgstr "Cài đặt"
 msgid "New name"
 msgstr "Username"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 #, fuzzy
 msgid "New Path"
 msgstr "Đường dẫn"
@@ -2709,6 +2736,10 @@ msgstr "Vị trí lưu log lỗi (Error log) của Nginx"
 msgid "Nginx is not running"
 msgstr ""
 
+#: src/constants/errors/docker.ts:9
+msgid "Nginx is not running in another container"
+msgstr ""
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgstr ""
@@ -3039,11 +3070,11 @@ msgstr ""
 msgid "Otp or recovery code empty"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr "Ghi đè"
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr "Ghi đè tập tin đã tồn tại"
 
@@ -3091,7 +3122,7 @@ msgstr ""
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "Đường dẫn"
@@ -3185,7 +3216,7 @@ msgid ""
 msgstr ""
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 #, fuzzy
 msgid "Please input a filename"
 msgstr "Vui lòng nhập username!"
@@ -3431,6 +3462,11 @@ msgstr "Tải lại"
 msgid "Reload Nginx"
 msgstr "Tải lại nginx"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Không thể bật %{msg}"
+
 #: src/components/Notification/notifications.ts:10
 #, fuzzy
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
@@ -3736,7 +3772,7 @@ msgstr "Running"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4566,7 +4602,7 @@ msgstr "Cập nhật thành công"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4866,6 +4902,10 @@ msgstr ""
 msgid "Your passkeys"
 msgstr ""
 
+#, fuzzy
+#~ msgid "Format error %{msg}"
+#~ msgstr "Lưu lỗi %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "Không lưu được, đã phát hiện thấy (các) lỗi cú pháp trong cấu hình."
 

+ 62 - 21
app/src/language/zh_CN/app.po

@@ -81,7 +81,7 @@ msgid "Add a passkey"
 msgstr "添加 Passkey"
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgstr "添加配置"
 
@@ -294,7 +294,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr "自动索引站点和 Stream 的配置文件。"
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -345,7 +345,7 @@ msgstr "Bark"
 msgid "Base information"
 msgstr "基本信息"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -562,7 +562,7 @@ msgid "Changed Certificate"
 msgid_plural "Changed Certificates"
 msgstr[0] "变更证书"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgstr "变更后的路径"
 
@@ -677,6 +677,10 @@ msgstr "代码补全模型"
 msgid "Command"
 msgstr "命令"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -752,6 +756,10 @@ msgstr "连接中断,请刷新页面。"
 msgid "Connection timeout period"
 msgstr "连接超时时间"
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -971,7 +979,7 @@ msgstr "删除成功"
 msgid "Demo"
 msgstr "Demo"
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "部署"
 
@@ -1158,6 +1166,10 @@ msgstr "你想删除这个服务器吗?"
 msgid "Do you want to remove this upstream?"
 msgstr "你想删除这个 Upstream 吗?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 msgid "Document"
@@ -1214,7 +1226,7 @@ msgstr "编辑"
 msgid "Edit %{n}"
 msgstr "编辑 %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "编辑配置"
 
@@ -1415,6 +1427,11 @@ msgstr "外部通知"
 msgid "Fail to obtain certificate"
 msgstr "获取证书失败"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "解压缩失败:{0}"
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr "备份 Nginx 配置文件失败:{0}"
@@ -1575,6 +1592,11 @@ msgstr "加密 Nginx UI 目录失败:{0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "符号链接解析失败:{0}"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "读取文件失败:{0}"
+
 #: src/constants/errors/backup.ts:35
 msgid "Failed to extract archive: {0}"
 msgstr "解压缩失败:{0}"
@@ -1599,6 +1621,11 @@ msgstr "获取 Nginx 性能参数失败"
 msgid "Failed to get performance data"
 msgstr "获取性能数据失败"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "复制文件内容失败:{0}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 msgid "Failed to load history records"
 msgstr "加载历史记录失败"
@@ -1635,6 +1662,11 @@ msgstr "读取哈希信息文件失败:{0}"
 msgid "Failed to read nginx.conf"
 msgstr "读取 nginx.conf 失败"
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "读取文件失败:{0}"
+
 #: src/constants/errors/backup.ts:21
 msgid "Failed to read symlink: {0}"
 msgstr "读取符号链接失败:{0}"
@@ -1714,14 +1746,10 @@ msgstr "中国用户:https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgstr "表单解析失败"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "代码格式化"
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "保存错误 %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgstr "格式化成功"
@@ -1792,7 +1820,7 @@ msgstr "隐藏"
 msgid "Higher value means better connection reuse"
 msgstr "更高的值意味着更好的连接再利用"
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
@@ -1962,7 +1990,7 @@ msgid "Invalid file path: {0}"
 msgstr "文件路径无效:{0}"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgstr "文件名无效"
 
@@ -2368,7 +2396,7 @@ msgstr "多行指令"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2410,7 +2438,7 @@ msgstr "新安装"
 msgid "New name"
 msgstr "新名称"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgstr "新路径"
 
@@ -2506,6 +2534,11 @@ msgstr "Nginx 错误日志路径"
 msgid "Nginx is not running"
 msgstr "Nginx 未启动"
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx 未启动"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgstr "Nginx 正在运行"
@@ -2817,11 +2850,11 @@ msgstr "其他"
 msgid "Otp or recovery code empty"
 msgstr "OTP 或恢复代码为空"
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr "覆盖"
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr "覆盖现有文件"
 
@@ -2869,7 +2902,7 @@ msgstr "密码长度不能超过 20 个字符"
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "路径"
@@ -2961,7 +2994,7 @@ msgid ""
 msgstr "请立即在偏好设置中生成新的恢复码,以防止无法访问您的账户。"
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgstr "请输入文件名"
 
@@ -3191,6 +3224,11 @@ msgstr "重载"
 msgid "Reload Nginx"
 msgstr "重载 Nginx"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "Nginx 重载失败:{0}"
+
 #: src/components/Notification/notifications.ts:10
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgstr "在 %{node} 上重载 Nginx 失败,响应:%{resp}"
@@ -3459,7 +3497,7 @@ msgstr "运行中"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4252,7 +4290,7 @@ msgstr "更新成功"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4545,6 +4583,9 @@ msgstr "您的旧代码将不再有效。"
 msgid "Your passkeys"
 msgstr "你的 Passkeys"
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "保存错误 %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "保存失败,在配置中检测到语法错误。"
 

+ 62 - 21
app/src/language/zh_TW/app.po

@@ -85,7 +85,7 @@ msgid "Add a passkey"
 msgstr "新增通行金鑰"
 
 #: src/routes/modules/config.ts:20 src/views/config/ConfigEditor.vue:171
-#: src/views/config/ConfigEditor.vue:246
+#: src/views/config/ConfigEditor.vue:244
 msgid "Add Configuration"
 msgstr "新增設定"
 
@@ -298,7 +298,7 @@ msgid "Automatically indexed from site and stream configurations."
 msgstr "自動從網站和串流設定中索引。"
 
 #: src/views/certificate/components/CertificateEditor.vue:259
-#: src/views/config/ConfigEditor.vue:268 src/views/config/ConfigList.vue:112
+#: src/views/config/ConfigEditor.vue:266 src/views/config/ConfigList.vue:112
 #: src/views/config/ConfigList.vue:195 src/views/nginx_log/NginxLog.vue:173
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:150
 #: src/views/stream/components/StreamEditor.vue:106
@@ -349,7 +349,7 @@ msgstr "Bark"
 msgid "Base information"
 msgstr "基本資訊"
 
-#: src/views/config/ConfigEditor.vue:296
+#: src/views/config/ConfigEditor.vue:294
 #: src/views/site/site_edit/components/RightPanel/RightPanel.vue:30
 #: src/views/stream/components/RightPanel/RightPanel.vue:19
 msgid "Basic"
@@ -566,7 +566,7 @@ msgid "Changed Certificate"
 msgid_plural "Changed Certificates"
 msgstr[0] "變更後憑證"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "Changed Path"
 msgstr "變更後路徑"
 
@@ -685,6 +685,10 @@ msgstr ""
 msgid "Command"
 msgstr "命令"
 
+#: src/constants/errors/docker.ts:6
+msgid "Command exited with unexpected exit code: {0}, error: {1}"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:115
 #: src/components/NgxConfigEditor/LocationEditor.vue:104
 #: src/components/NgxConfigEditor/LocationEditor.vue:135
@@ -761,6 +765,10 @@ msgstr "連線中斷,請重新整理此頁面。"
 msgid "Connection timeout period"
 msgstr "連線逾時時間"
 
+#: src/constants/errors/docker.ts:7
+msgid "Container status unknown"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveEditorItem.vue:120
 #: src/components/NgxConfigEditor/LocationEditor.vue:116
 #: src/components/NgxConfigEditor/LocationEditor.vue:144
@@ -980,7 +988,7 @@ msgstr "刪除成功"
 msgid "Demo"
 msgstr "演示"
 
-#: src/views/config/ConfigEditor.vue:340
+#: src/views/config/ConfigEditor.vue:338
 msgid "Deploy"
 msgstr "部署"
 
@@ -1168,6 +1176,10 @@ msgstr "您要移除此伺服器嗎?"
 msgid "Do you want to remove this upstream?"
 msgstr "您要移除這個 Upstream 嗎?"
 
+#: src/constants/errors/docker.ts:2
+msgid "Docker client not initialized"
+msgstr ""
+
 #: src/components/NgxConfigEditor/directive/DirectiveAdd.vue:88
 #: src/components/NgxConfigEditor/directive/DirectiveDocuments.vue:16
 msgid "Document"
@@ -1224,7 +1236,7 @@ msgstr "編輯"
 msgid "Edit %{n}"
 msgstr "編輯 %{n}"
 
-#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:246
+#: src/routes/modules/config.ts:30 src/views/config/ConfigEditor.vue:244
 msgid "Edit Configuration"
 msgstr "編輯設定"
 
@@ -1425,6 +1437,11 @@ msgstr "外部通知"
 msgid "Fail to obtain certificate"
 msgstr "取得憑證失敗"
 
+#: src/constants/errors/docker.ts:4
+#, fuzzy
+msgid "Failed to attach to exec instance: {0}"
+msgstr "無法提取存檔:{0}"
+
 #: src/constants/errors/backup.ts:5
 msgid "Failed to backup Nginx config files: {0}"
 msgstr "備份 Nginx 設定檔案失敗:{0}"
@@ -1585,6 +1602,11 @@ msgstr "加密 Nginx UI 目錄失敗:{0}"
 msgid "Failed to evaluate symbolic links: {0}"
 msgstr "無法評估符號連結:{0}"
 
+#: src/constants/errors/docker.ts:3
+#, fuzzy
+msgid "Failed to exec command: {0}"
+msgstr "讀取檔案失敗:{0}"
+
 #: src/constants/errors/backup.ts:35
 msgid "Failed to extract archive: {0}"
 msgstr "無法提取存檔:{0}"
@@ -1609,6 +1631,11 @@ msgstr "無法取得 Nginx 效能設定"
 msgid "Failed to get performance data"
 msgstr "無法取得效能資料"
 
+#: src/constants/errors/docker.ts:8
+#, fuzzy
+msgid "Failed to inspect container: {0}"
+msgstr "複製檔案內容失敗:{0}"
+
 #: src/components/ConfigHistory/ConfigHistory.vue:77
 msgid "Failed to load history records"
 msgstr "無法載入歷史記錄"
@@ -1645,6 +1672,11 @@ msgstr "無法讀取雜湊資訊檔案:{0}"
 msgid "Failed to read nginx.conf"
 msgstr "讀取 nginx.conf 失敗"
 
+#: src/constants/errors/docker.ts:5
+#, fuzzy
+msgid "Failed to read output: {0}"
+msgstr "讀取檔案失敗:{0}"
+
 #: src/constants/errors/backup.ts:21
 msgid "Failed to read symlink: {0}"
 msgstr "讀取符號連結失敗:{0}"
@@ -1724,14 +1756,10 @@ msgstr "中國使用者:https://mirror.ghproxy.com/"
 msgid "Form parse failed"
 msgstr "表單解析失敗"
 
-#: src/views/config/ConfigEditor.vue:271
+#: src/views/config/ConfigEditor.vue:269
 msgid "Format Code"
 msgstr "格式化代碼"
 
-#: src/views/config/ConfigEditor.vue:218
-msgid "Format error %{msg}"
-msgstr "格式錯誤 %{msg}"
-
 #: src/views/config/ConfigEditor.vue:216
 msgid "Format successfully"
 msgstr "成功格式化"
@@ -1802,7 +1830,7 @@ msgstr "隱藏"
 msgid "Higher value means better connection reuse"
 msgstr ""
 
-#: src/views/config/ConfigEditor.vue:256
+#: src/views/config/ConfigEditor.vue:254
 #: src/views/site/site_edit/components/SiteEditor/SiteEditor.vue:81
 #: src/views/stream/components/StreamEditor.vue:43
 msgid "History"
@@ -1972,7 +2000,7 @@ msgid "Invalid file path: {0}"
 msgstr "無效的檔案路徑:{0}"
 
 #: src/views/config/components/Rename.vue:66
-#: src/views/config/ConfigEditor.vue:305
+#: src/views/config/ConfigEditor.vue:303
 msgid "Invalid filename"
 msgstr "無效的檔案名"
 
@@ -2379,7 +2407,7 @@ msgstr "多行指令"
 #: src/views/certificate/components/CertificateEditor.vue:162
 #: src/views/certificate/DNSCredential.vue:11
 #: src/views/config/components/Mkdir.vue:64
-#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:311
+#: src/views/config/configColumns.tsx:7 src/views/config/ConfigEditor.vue:309
 #: src/views/environments/group/columns.ts:8
 #: src/views/environments/list/envColumns.tsx:9
 #: src/views/nginx_log/NginxLogList.vue:33
@@ -2421,7 +2449,7 @@ msgstr "新安裝"
 msgid "New name"
 msgstr "新名稱"
 
-#: src/views/config/ConfigEditor.vue:324
+#: src/views/config/ConfigEditor.vue:322
 msgid "New Path"
 msgstr "新路徑"
 
@@ -2519,6 +2547,11 @@ msgstr "Nginx 錯誤日誌路徑"
 msgid "Nginx is not running"
 msgstr "Nginx 未執行"
 
+#: src/constants/errors/docker.ts:9
+#, fuzzy
+msgid "Nginx is not running in another container"
+msgstr "Nginx 未執行"
+
 #: src/views/dashboard/NginxDashBoard.vue:112
 msgid "Nginx is running"
 msgstr "Nginx 執行中"
@@ -2832,11 +2865,11 @@ msgstr "其他"
 msgid "Otp or recovery code empty"
 msgstr "OTP 或復原碼為空"
 
-#: src/views/config/ConfigEditor.vue:349
+#: src/views/config/ConfigEditor.vue:347
 msgid "Overwrite"
 msgstr "覆寫"
 
-#: src/views/config/ConfigEditor.vue:353
+#: src/views/config/ConfigEditor.vue:351
 msgid "Overwrite exist file"
 msgstr "覆寫現有檔案"
 
@@ -2884,7 +2917,7 @@ msgstr "密碼長度不能超過 20 個字元"
 
 #: src/components/NgxConfigEditor/LocationEditor.vue:110
 #: src/components/NgxConfigEditor/LocationEditor.vue:138
-#: src/views/config/ConfigEditor.vue:318
+#: src/views/config/ConfigEditor.vue:316
 #: src/views/nginx_log/NginxLogList.vue:41
 msgid "Path"
 msgstr "路徑"
@@ -2976,7 +3009,7 @@ msgid ""
 msgstr "請立即在偏好設定中產生新的恢復碼,以免無法存取您的賬戶。"
 
 #: src/views/config/components/Rename.vue:65
-#: src/views/config/ConfigEditor.vue:304
+#: src/views/config/ConfigEditor.vue:302
 msgid "Please input a filename"
 msgstr "請輸入檔案名稱"
 
@@ -3205,6 +3238,11 @@ msgstr "重新載入"
 msgid "Reload Nginx"
 msgstr "重新載入 Nginx"
 
+#: src/constants/errors/nginx.ts:3
+#, fuzzy
+msgid "Reload nginx failed: {0}"
+msgstr "讀取檔案失敗:{0}"
+
 #: src/components/Notification/notifications.ts:10
 msgid "Reload Nginx on %{node} failed, response: %{resp}"
 msgstr "在節點 %{node} 上重新載入 Nginx 失敗,回應:%{resp}"
@@ -3473,7 +3511,7 @@ msgstr "執行中"
 #: src/components/StdDesign/StdDetail/StdDetail.vue:93
 #: src/views/certificate/components/CertificateEditor.vue:266
 #: src/views/config/components/ConfigName.vue:59
-#: src/views/config/ConfigEditor.vue:277
+#: src/views/config/ConfigEditor.vue:275
 #: src/views/preference/components/Passkey.vue:130
 #: src/views/preference/Preference.vue:231
 #: src/views/site/site_edit/components/ConfigName/ConfigName.vue:52
@@ -4266,7 +4304,7 @@ msgstr "更新成功"
 
 #: src/views/certificate/ACMEUser.vue:88
 #: src/views/certificate/DNSCredential.vue:27
-#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:331
+#: src/views/config/configColumns.tsx:36 src/views/config/ConfigEditor.vue:329
 #: src/views/environments/group/columns.ts:37
 #: src/views/environments/list/envColumns.tsx:90
 #: src/views/site/site_edit/components/RightPanel/Basic.vue:38
@@ -4562,6 +4600,9 @@ msgstr "您的舊代碼將不再有效。"
 msgid "Your passkeys"
 msgstr "您的通行金鑰"
 
+#~ msgid "Format error %{msg}"
+#~ msgstr "格式錯誤 %{msg}"
+
 #~ msgid "Failed to save, syntax error(s) was detected in the configuration."
 #~ msgstr "儲存失敗,在設定中偵測到語法錯誤。"
 

+ 13 - 0
go.mod

@@ -9,6 +9,7 @@ require (
 	github.com/casdoor/casdoor-go-sdk v1.5.0
 	github.com/creack/pty v1.1.24
 	github.com/dgraph-io/ristretto/v2 v2.2.0
+	github.com/docker/docker v28.1.1+incompatible
 	github.com/dustin/go-humanize v1.0.1
 	github.com/elliotchance/orderedmap/v3 v3.1.0
 	github.com/fsnotify/fsnotify v1.9.0
@@ -75,6 +76,7 @@ require (
 	github.com/Azure/go-autorest/logger v0.2.2 // indirect
 	github.com/Azure/go-autorest/tracing v0.6.1 // indirect
 	github.com/AzureAD/microsoft-authentication-library-for-go v1.4.2 // indirect
+	github.com/Microsoft/go-winio v0.4.14 // indirect
 	github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 // indirect
 	github.com/StackExchange/wmi v1.2.1 // indirect
 	github.com/akamai/AkamaiOPEN-edgegrid-golang v1.2.2 // indirect
@@ -106,10 +108,14 @@ require (
 	github.com/civo/civogo v0.3.98 // indirect
 	github.com/cloudflare/cloudflare-go v0.115.0 // indirect
 	github.com/cloudwego/base64x v0.1.5 // indirect
+	github.com/containerd/log v0.1.0 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
+	github.com/distribution/reference v0.6.0 // indirect
 	github.com/dnsimple/dnsimple-go v1.7.0 // indirect
+	github.com/docker/go-connections v0.5.0 // indirect
+	github.com/docker/go-units v0.5.0 // indirect
 	github.com/ebitengine/purego v0.8.2 // indirect
 	github.com/exoscale/egoscale/v3 v3.1.14 // indirect
 	github.com/fatih/color v1.18.0 // indirect
@@ -184,8 +190,12 @@ require (
 	github.com/mimuret/golang-iij-dpf v0.9.1 // indirect
 	github.com/mitchellh/go-homedir v1.1.0 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
+	github.com/moby/docker-image-spec v1.3.1 // indirect
+	github.com/moby/sys/atomicwriter v0.1.0 // indirect
+	github.com/moby/term v0.5.2 // indirect
 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
 	github.com/modern-go/reflect2 v1.0.2 // indirect
+	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 // indirect
 	github.com/nrdcg/auroradns v1.1.0 // indirect
 	github.com/nrdcg/bunny-go v0.0.0-20250327222614-988a091fc7ea // indirect
@@ -199,6 +209,8 @@ require (
 	github.com/nrdcg/nodion v0.1.0 // indirect
 	github.com/nrdcg/porkbun v0.4.0 // indirect
 	github.com/nzdjb/go-metaname v1.0.0 // indirect
+	github.com/opencontainers/go-digest v1.0.0 // indirect
+	github.com/opencontainers/image-spec v1.1.1 // indirect
 	github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b // indirect
 	github.com/oracle/oci-go-sdk/v65 v65.89.1 // indirect
 	github.com/ovh/go-ovh v1.7.0 // indirect
@@ -257,6 +269,7 @@ require (
 	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
 	go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
 	go.opentelemetry.io/otel v1.35.0 // indirect
+	go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
 	go.opentelemetry.io/otel/metric v1.35.0 // indirect
 	go.opentelemetry.io/otel/trace v1.35.0 // indirect
 	go.uber.org/atomic v1.11.0 // indirect

+ 37 - 9
go.sum

@@ -632,6 +632,8 @@ github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourceg
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resourcegraph/armresourcegraph v0.9.0/go.mod h1:wVEOJfGTj0oPAUGA1JuRAvz/lxXQsWW16axmHPP47Bk=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0 h1:Dd+RhdJn0OTtVGaeDLZpcumkIVCtA/3/Fo42+eoYvVM=
 github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/resources/armresources v1.2.0/go.mod h1:5kakwfW5CjC9KK+Q4wjXAg+ShuIm2mBMua0ZFj2C8PE=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c h1:udKWzYgxTojEKWjV8V+WSxDXJ4NFATAsZjh8iIbsQIg=
+github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
 github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
 github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
 github.com/Azure/go-autorest/autorest v0.11.28/go.mod h1:MrkzG3Y3AH668QyF9KRk5neJnGgmhQ6krbhR8Q5eMvA=
@@ -675,6 +677,8 @@ github.com/HdrHistogram/hdrhistogram-go v1.1.2/go.mod h1:yDgFjdqOqDEKOvasDdhWNXY
 github.com/JohnCGriffin/overflow v0.0.0-20211019200055-46fa312c352c/go.mod h1:X0CRv0ky0k6m906ixxpzmDRLvX58TFUKS2eePweuyxk=
 github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
 github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
+github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
 github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87 h1:xPMsUicZ3iosVPSIP7bW5EcGUzjiiMl1OYTe14y/R24=
 github.com/OpenDNS/vegadns2client v0.0.0-20180418235048-a3fa4a771d87/go.mod h1:iGLljf5n9GjT6kc0HBvyI1nOKnGQbNB66VzSNbK5iks=
@@ -698,8 +702,6 @@ github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuy
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
 github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.105 h1:Bj8SsBTGElGniuL83+VqfHnxZIPc7n+rzpwDZIB4rZg=
-github.com/aliyun/alibaba-cloud-sdk-go v1.63.105/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/aliyun/alibaba-cloud-sdk-go v1.63.106 h1:+YPfQheppCKOPJxhWDmStF1UMJrxnA1iiwBH12t6Fa4=
 github.com/aliyun/alibaba-cloud-sdk-go v1.63.106/go.mod h1:SOSDHfe1kX91v3W5QiBsWSLqeLxImobbMX1mxrFHsVQ=
 github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
@@ -790,7 +792,6 @@ github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyY
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/census-instrumentation/opencensus-proto v0.4.1/go.mod h1:4T9NM4+4Vw91VeyqjLS6ao50K5bOcLKN6Q42XnYaRYw=
-github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
 github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
 github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
 github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
@@ -825,6 +826,8 @@ github.com/cncf/xds/go v0.0.0-20220314180256-7f1daf1720fc/go.mod h1:eXthEFrGJvWH
 github.com/cncf/xds/go v0.0.0-20230105202645-06c439db220b/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cncf/xds/go v0.0.0-20230310173818-32f1caf87195/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
+github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
+github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
 github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
 github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
 github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
@@ -853,8 +856,16 @@ github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cu
 github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
 github.com/dimchansky/utfbom v1.1.1 h1:vV6w1AhK4VMnhBno/TPVCoK9U/LP0PkLCS9tbxHdi/U=
 github.com/dimchansky/utfbom v1.1.1/go.mod h1:SxdoEBH5qIqFocHMyGOXVAybYJdr71b1Q/j0mACtrfE=
+github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk=
+github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E=
 github.com/dnsimple/dnsimple-go v1.7.0 h1:JKu9xJtZ3SqOC+BuYgAWeab7+EEx0sz422vu8j611ZY=
 github.com/dnsimple/dnsimple-go v1.7.0/go.mod h1:EKpuihlWizqYafSnQHGCd/gyvy3HkEQJ7ODB4KdV8T8=
+github.com/docker/docker v28.1.1+incompatible h1:49M11BFLsVO1gxY9UX9p/zwkE/rswggs8AdFmXQw51I=
+github.com/docker/docker v28.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c=
+github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc=
+github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
+github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
 github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
@@ -912,8 +923,6 @@ github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S
 github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
 github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
 github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
-github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
-github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
 github.com/gabriel-vasile/mimetype v1.4.9 h1:5k+WDwEsD9eTLL8Tz3L0VnmVh9QxGjRmjBvAG7U/oYY=
 github.com/gabriel-vasile/mimetype v1.4.9/go.mod h1:WnSQhFKJuBlRyLiKohA/2DtIlPFAbguNaG7QCHcyGok=
 github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
@@ -1168,9 +1177,12 @@ github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/ad
 github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
 github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
 github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
 github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.7.0/go.mod h1:hgWBS7lorOAVIJEQMi4ZsPv9hVvWI6+ch50m39Pf2Ks=
 github.com/grpc-ecosystem/grpc-gateway/v2 v2.11.3/go.mod h1:o//XUCC/F+yRGJoPO/VU0GSB0f8Nhgmxx0VIRUvaC0w=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
+github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
 github.com/guregu/null/v6 v6.0.0 h1:N14VRS+4di81i1PXRiprbQJ9EM9gqBa0+KVMeS/QSjQ=
 github.com/guregu/null/v6 v6.0.0/go.mod h1:hrMIhIfrOZeLPZhROSn149tpw2gHkidAqxoXNyeX3iQ=
 github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw=
@@ -1478,6 +1490,14 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR
 github.com/mitchellh/mapstructure v1.4.2/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
+github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0=
+github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
+github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw=
+github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs=
+github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU=
+github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko=
+github.com/moby/term v0.5.2 h1:6qk3FJAFDs6i/q3W/pQ97SX192qKfZgGjCQqfCJkgzQ=
+github.com/moby/term v0.5.2/go.mod h1:d3djjFCrjnB+fl8NJux+EJzu0msscUP+f8it8hPkFLc=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
 github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -1486,6 +1506,8 @@ github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3Rllmb
 github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
 github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/namedotcom/go v0.0.0-20180403034216-08470befbe04 h1:o6uBwrhM5C8Ll3MAAxrQxRHEu7FkapwTuI2WmL1rw4g=
@@ -1549,6 +1571,10 @@ github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5h
 github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
 github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
+github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
+github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
+github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
+github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
 github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b h1:FfH+VrHHk6Lxt9HdVS0PXzSXFyS2NbZKXv33FYPol0A=
 github.com/opentracing/opentracing-go v1.2.1-0.20220228012449-10b1cf09e00b/go.mod h1:AC62GU6hc0BrNm+9RK9VSiwa/EUe1bkIeFORAMcHvJU=
@@ -1770,8 +1796,6 @@ github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSW
 github.com/technoweenie/multipartstreamer v1.0.1 h1:XRztA5MXiR1TIRHxH2uNxXxaIkKQDeX7m2XsSOlQEnM=
 github.com/technoweenie/multipartstreamer v1.0.1/go.mod h1:jNVxdtShOxzAsukZwTSw6MDx5eUJoiEBsSvzDU9uzog=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1136/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1145 h1:DETyir/MtG+GLOD0OatzjrQTTXRguFSJo1ZtPXtbIQw=
-github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1145/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146 h1:PMhgU4BETyTiikegps6gDtLamNWUiLMEx4fv16UWspY=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/common v1.0.1146/go.mod h1:r5r4xbfxSaeR04b166HGsBa/R4U3SueirEUpXGuw+Q0=
 github.com/tencentcloud/tencentcloud-sdk-go/tencentcloud/dnspod v1.0.1136 h1:kMIdSU5IvpOROh27ToVQ3hlm6ym3lCRs9tnGCOBoZqk=
@@ -1817,8 +1841,6 @@ github.com/urfave/cli/v3 v3.1.1 h1:bNnl8pFI5dxPOjeONvFCDFoECLQsceDG4ejahs4Jtxk=
 github.com/urfave/cli/v3 v3.1.1/go.mod h1:FJSKtM/9AiiTOJL4fJ6TbMUkxBXn7GO9guZqoZtpYpo=
 github.com/vinyldns/go-vinyldns v0.9.16 h1:GZJStDkcCk1F1AcRc64LuuMh+ENL8pHA0CVd4ulRMcQ=
 github.com/vinyldns/go-vinyldns v0.9.16/go.mod h1:5qIJOdmzAnatKjurI+Tl4uTus7GJKJxb+zitufjHs3Q=
-github.com/volcengine/volc-sdk-golang v1.0.203 h1:y4zZEjKp6nz3UK8Tb/qdz9tvB915KLO6nc1WNME0Zb8=
-github.com/volcengine/volc-sdk-golang v1.0.203/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
 github.com/volcengine/volc-sdk-golang v1.0.204 h1:Njid6coReHV2gWc3bsqWMQf+K8jveauzW8zEX08CTzI=
 github.com/volcengine/volc-sdk-golang v1.0.204/go.mod h1:stZX+EPgv1vF4nZwOlEe8iGcriUPRBKX8zA19gXycOQ=
 github.com/vultr/govultr/v3 v3.19.1 h1:31rOP5Tz40AOc8h6Ws4ryzqAniUBffgRhy9uMG/EFvs=
@@ -1881,6 +1903,10 @@ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRND
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
 go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
 go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 h1:xJ2qHD0C1BeYVTLLR9sX12+Qb95kfeD/byKj6Ky1pXg=
+go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0/go.mod h1:u5BF1xyjstDowA1R5QAO9JHzqK+ublenEW/dyqTjBVk=
 go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
 go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
 go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
@@ -1892,6 +1918,8 @@ go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.opentelemetry.io/proto/otlp v0.15.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
 go.opentelemetry.io/proto/otlp v0.19.0/go.mod h1:H7XAot3MsfNsj7EXtrA2q5xSNQ10UqI405h3+duxN4U=
+go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
+go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=

+ 5 - 1
internal/config/save.go

@@ -45,7 +45,11 @@ func Save(absPath string, content string, cfg *model.Config) (err error) {
 		return
 	}
 
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		return
+	} 
+
 	if nginx.GetLogLevel(output) >= nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}

+ 22 - 0
internal/docker/docker.go

@@ -0,0 +1,22 @@
+package docker
+
+import (
+	"context"
+
+	"github.com/docker/docker/client"
+)
+
+// Initialize Docker client from environment variables
+func initClient() (cli *client.Client, err error) {
+	cli, err = client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
+	if err != nil {
+		return
+	}
+	// Optionally ping the server to ensure the connection is valid
+	_, err = cli.Ping(context.Background())
+	if err != nil {
+		return
+	}
+
+	return
+}

+ 15 - 0
internal/docker/errors.go

@@ -0,0 +1,15 @@
+package docker
+
+import "github.com/uozi-tech/cosy"
+
+var (
+	e                                    = cosy.NewErrorScope("docker")
+	ErrClientNotInitialized              = e.New(500001, "docker client not initialized")
+	ErrFailedToExec                      = e.New(500002, "failed to exec command: {0}")
+	ErrFailedToAttach                    = e.New(500003, "failed to attach to exec instance: {0}")
+	ErrReadOutput                        = e.New(500004, "failed to read output: {0}")
+	ErrExitUnexpected                    = e.New(500005, "command exited with unexpected exit code: {0}, error: {1}")
+	ErrContainerStatusUnknown            = e.New(500006, "container status unknown")
+	ErrInspectContainer                  = e.New(500007, "failed to inspect container: {0}")
+	ErrNginxNotRunningInAnotherContainer = e.New(500008, "nginx is not running in another container")
+)

+ 80 - 0
internal/docker/exec.go

@@ -0,0 +1,80 @@
+package docker
+
+import (
+	"bytes"
+	"context"
+	"io"
+	"strconv"
+
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/docker/pkg/stdcopy"
+	"github.com/uozi-tech/cosy"
+	"github.com/uozi-tech/cosy/logger"
+)
+
+// Exec executes a command in a specific container and returns the output.
+func Exec(ctx context.Context, command []string) (string, error) {
+	if !settings.NginxSettings.RunningInAnotherContainer() {
+		return "", ErrNginxNotRunningInAnotherContainer
+	}
+
+	cli, err := initClient()
+	if err != nil {
+		return "", cosy.WrapErrorWithParams(ErrClientNotInitialized, err.Error())
+	}
+	defer cli.Close()
+
+	execConfig := container.ExecOptions{
+		AttachStdout: true,
+		AttachStderr: true, // Also attach stderr to capture errors from the command
+		Cmd:          command,
+	}
+
+	// Create the exec instance
+	execCreateResp, err := cli.ContainerExecCreate(ctx, settings.NginxSettings.ContainerName, execConfig)
+	if err != nil {
+		return "", cosy.WrapErrorWithParams(ErrFailedToExec, err.Error())
+	}
+	execID := execCreateResp.ID
+
+	// Attach to the exec instance
+	hijackedResp, err := cli.ContainerExecAttach(ctx, execID, container.ExecAttachOptions{})
+	if err != nil {
+		return "", cosy.WrapErrorWithParams(ErrFailedToAttach, err.Error())
+	}
+	defer hijackedResp.Close()
+
+	// Read the output
+	var outBuf, errBuf bytes.Buffer
+	outputDone := make(chan error)
+
+	go func() {
+		// stdcopy.StdCopy demultiplexes the stream into two buffers
+		_, err = stdcopy.StdCopy(&outBuf, &errBuf, hijackedResp.Reader)
+		outputDone <- err
+	}()
+
+	select {
+	case err := <-outputDone:
+		if err != nil && err != io.EOF { // io.EOF is expected when the stream finishes
+			return "", cosy.WrapErrorWithParams(ErrReadOutput, err.Error())
+		}
+	case <-ctx.Done():
+		return "", cosy.WrapErrorWithParams(ErrReadOutput, ctx.Err().Error())
+	}
+
+	// Optionally inspect the exec process to check the exit code
+	execInspectResp, err := cli.ContainerExecInspect(ctx, execID)
+	logger.Debug("docker exec result", outBuf.String(), errBuf.String())
+
+	if err != nil {
+		return "", cosy.WrapErrorWithParams(ErrExitUnexpected, err.Error())
+	} else if execInspectResp.ExitCode != 0 {
+		// Command exited with a non-zero status code. Return stderr as part of the error.
+		return outBuf.String(), cosy.WrapErrorWithParams(ErrExitUnexpected, strconv.Itoa(execInspectResp.ExitCode), errBuf.String())
+	}
+
+	// Return stdout if successful
+	return outBuf.String(), nil
+}

+ 29 - 0
internal/docker/stat_path.go

@@ -0,0 +1,29 @@
+package docker
+
+import (
+	"context"
+
+	"github.com/0xJacky/Nginx-UI/settings"
+	"github.com/uozi-tech/cosy/logger"
+)
+
+// StatPath checks if a path exists in the container
+func StatPath(path string) bool {
+	if !settings.NginxSettings.RunningInAnotherContainer() {
+		return false
+	}
+
+	cli, err := initClient()
+	if err != nil {
+		return false
+	}
+	defer cli.Close()
+
+	_, err = cli.ContainerStatPath(context.Background(), settings.NginxSettings.ContainerName, path)
+	if err != nil {
+		logger.Error("Failed to stat path", "error", err)
+		return false
+	}
+
+	return true
+}

+ 58 - 0
internal/docker/status.go

@@ -0,0 +1,58 @@
+package docker
+
+import (
+	"context"
+
+	"github.com/docker/docker/client"
+	"github.com/uozi-tech/cosy"
+)
+
+type ContainerStatus int
+
+const (
+	ContainerStatusCreated ContainerStatus = iota
+	ContainerStatusRunning
+	ContainerStatusPaused
+	ContainerStatusRestarting
+	ContainerStatusRemoving
+	ContainerStatusExited
+	ContainerStatusDead
+	ContainerStatusUnknown
+	ContainerStatusNotFound
+)
+
+var (
+	containerStatusMap = map[string]ContainerStatus{
+		"created":    ContainerStatusCreated,
+		"running":    ContainerStatusRunning,
+		"paused":     ContainerStatusPaused,
+		"restarting": ContainerStatusRestarting,
+		"removing":   ContainerStatusRemoving,
+		"exited":     ContainerStatusExited,
+		"dead":       ContainerStatusDead,
+	}
+)
+
+// GetContainerStatus checks the status of a given container.
+func GetContainerStatus(ctx context.Context, containerID string) (ContainerStatus, error) {
+	cli, err := initClient()
+	if err != nil {
+		return ContainerStatusUnknown, cosy.WrapErrorWithParams(ErrClientNotInitialized, err.Error())
+	}
+	defer cli.Close()
+
+	containerJSON, err := cli.ContainerInspect(ctx, containerID)
+	if err != nil {
+		if client.IsErrNotFound(err) {
+			return ContainerStatusNotFound, nil // Container doesn't exist
+		}
+		return ContainerStatusUnknown, cosy.WrapErrorWithParams(ErrInspectContainer, err.Error())
+	}
+
+	// Can be one of "created", "running", "paused", "restarting", "removing", "exited", or "dead"
+	status, ok := containerStatusMap[containerJSON.State.Status]
+	if !ok {
+		return ContainerStatusUnknown, ErrContainerStatusUnknown
+	}
+	return status, nil
+}

+ 1 - 0
internal/nginx/errors.go

@@ -5,4 +5,5 @@ import "github.com/uozi-tech/cosy"
 var (
 	e             = cosy.NewErrorScope("nginx")
 	ErrBlockIsNil = e.New(50001, "block is nil")
+	ErrReloadFailed = e.New(50002, "reload nginx failed: {0}")
 )

+ 28 - 0
internal/nginx/exec.go

@@ -0,0 +1,28 @@
+package nginx
+
+import (
+	"context"
+	"os/exec"
+
+	"github.com/0xJacky/Nginx-UI/internal/docker"
+	"github.com/0xJacky/Nginx-UI/settings"
+)
+
+func execShell(cmd string) (stdOut string, stdErr error) {
+	return execCommand("/bin/sh", "-c", cmd)
+}
+
+func execCommand(name string, cmd ...string) (stdOut string, stdErr error) {
+	switch settings.NginxSettings.RunningInAnotherContainer() {
+	case true:
+		cmd = append([]string{name}, cmd...)
+		stdOut, stdErr = docker.Exec(context.Background(), cmd)
+	case false:
+		bytes, err := exec.Command(name, cmd...).CombinedOutput()
+		stdOut = string(bytes)
+		if err != nil {
+			stdErr = err
+		}
+	}
+	return
+}

+ 38 - 51
internal/nginx/nginx.go

@@ -2,46 +2,41 @@ package nginx
 
 import (
 	"os"
-	"os/exec"
 	"strings"
 	"sync"
 	"time"
 
+	"github.com/0xJacky/Nginx-UI/internal/docker"
 	"github.com/0xJacky/Nginx-UI/settings"
 )
 
 var (
 	mutex      sync.Mutex
-	lastOutput string
+	lastStdOut string
+	lastStdErr error
 )
 
-func TestConf() (out string) {
+// TestConfig tests the nginx config
+func TestConfig() (stdOut string, stdErr error) {
 	mutex.Lock()
 	defer mutex.Unlock()
 	if settings.NginxSettings.TestConfigCmd != "" {
-		out = execShell(settings.NginxSettings.TestConfigCmd)
-
-		return
+		return execShell(settings.NginxSettings.TestConfigCmd)
 	}
-
-	out = execCommand("nginx", "-t")
-
-	return
+	return execCommand("nginx", "-t")
 }
 
-func Reload() (out string) {
+// Reload reloads the nginx
+func Reload() (stdOut string, stdErr error) {
 	mutex.Lock()
 	defer mutex.Unlock()
 	if settings.NginxSettings.ReloadCmd != "" {
-		out = execShell(settings.NginxSettings.ReloadCmd)
-		return
+		return execShell(settings.NginxSettings.ReloadCmd)
 	}
-
-	out = execCommand("nginx", "-s", "reload")
-
-	return
+	return execCommand("nginx", "-s", "reload")
 }
 
+// Restart restarts the nginx
 func Restart() {
 	mutex.Lock()
 	defer mutex.Unlock()
@@ -50,41 +45,45 @@ func Restart() {
 	time.Sleep(500 * time.Millisecond)
 
 	if settings.NginxSettings.RestartCmd != "" {
-		lastOutput = execShell(settings.NginxSettings.RestartCmd)
-
+		lastStdOut, lastStdErr = execShell(settings.NginxSettings.RestartCmd)
 		return
 	}
 
 	pidPath := GetPIDPath()
 	daemon := GetSbinPath()
 
-	lastOutput = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
+	lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--stop", "--quiet", "--oknodo", "--retry=TERM/30/KILL/5", "--pidfile", pidPath)
+	if lastStdErr != nil {
+		return
+	}
 
 	if daemon == "" {
-		lastOutput += execCommand("nginx")
-
+		lastStdOut, lastStdErr = execCommand("nginx")
 		return
 	}
 
-	lastOutput += execCommand("start-stop-daemon", "--start", "--quiet", "--pidfile", pidPath, "--exec", daemon)
-
+	lastStdOut, lastStdErr = execCommand("start-stop-daemon", "--start", "--quiet", "--pidfile", pidPath, "--exec", daemon)
 	return
 }
 
-func GetLastOutput() string {
+// GetLastOutput returns the last output of the nginx command
+func GetLastOutput() (stdOut string, stdErr error) {
 	mutex.Lock()
 	defer mutex.Unlock()
-	return lastOutput
+	return lastStdOut, lastStdErr
 }
 
 // GetModulesPath returns the nginx modules path
 func GetModulesPath() string {
 	// First try to get from nginx -V output
-	output := execCommand("nginx", "-V")
-	if output != "" {
+	stdOut, stdErr := execCommand("nginx", "-V")
+	if stdErr != nil {
+		return ""
+	}
+	if stdOut != "" {
 		// Look for --modules-path in the output
-		if strings.Contains(output, "--modules-path=") {
-			parts := strings.Split(output, "--modules-path=")
+		if strings.Contains(stdOut, "--modules-path=") {
+			parts := strings.Split(stdOut, "--modules-path=")
 			if len(parts) > 1 {
 				// Extract the path
 				path := strings.Split(parts[1], " ")[0]
@@ -99,28 +98,16 @@ func GetModulesPath() string {
 	return "/usr/lib/nginx/modules"
 }
 
-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
-}
-
 func IsNginxRunning() bool {
 	pidPath := GetPIDPath()
-	if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 {
-		return false
+	switch settings.NginxSettings.RunningInAnotherContainer() {
+	case true:
+		return docker.StatPath(pidPath)
+	case false:
+		if fileInfo, err := os.Stat(pidPath); err != nil || fileInfo.Size() == 0 {
+			return false
+		}
+		return true
 	}
-	return true
+	return false
 }

+ 4 - 1
internal/site/disable.go

@@ -35,7 +35,10 @@ func Disable(name string) (err error) {
 		return
 	}
 
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}

+ 8 - 2
internal/site/enable.go

@@ -35,13 +35,19 @@ func Enable(name string) (err error) {
 	}
 
 	// Test nginx config, if not pass, then disable the site.
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		_ = os.Remove(enabledConfigFilePath)
 		return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 	}
 
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}

+ 16 - 4
internal/site/maintenance.go

@@ -76,7 +76,10 @@ func EnableMaintenance(name string) (err error) {
 	}
 
 	// Test nginx config, if not pass, then restore original configuration
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		// Configuration error, cleanup and revert
 		_ = os.Remove(maintenanceConfigPath)
@@ -87,7 +90,10 @@ func EnableMaintenance(name string) (err error) {
 	}
 
 	// Reload nginx
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}
@@ -132,7 +138,10 @@ func DisableMaintenance(name string) (err error) {
 	}
 
 	// Test nginx config, if not pass, then revert
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		// Configuration error, cleanup and revert
 		_ = os.Remove(enabledConfigFilePath)
@@ -141,7 +150,10 @@ func DisableMaintenance(name string) (err error) {
 	}
 
 	// Reload nginx
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return fmt.Errorf("%s", output)
 	}

+ 13 - 6
internal/site/rename.go

@@ -2,16 +2,17 @@ package site
 
 import (
 	"fmt"
+	"net/http"
+	"os"
+	"runtime"
+	"sync"
+
 	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/notification"
 	"github.com/0xJacky/Nginx-UI/query"
 	"github.com/go-resty/resty/v2"
 	"github.com/uozi-tech/cosy/logger"
-	"net/http"
-	"os"
-	"runtime"
-	"sync"
 )
 
 func Rename(oldName string, newName string) (err error) {
@@ -47,13 +48,19 @@ func Rename(oldName string, newName string) (err error) {
 	}
 
 	// test nginx configuration
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return fmt.Errorf("%s", output)
 	}
 
 	// reload nginx
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return fmt.Errorf("%s", output)
 	}

+ 9 - 2
internal/site/save.go

@@ -38,14 +38,21 @@ func Save(name string, content string, overwrite bool, envGroupId uint64, syncNo
 	enabledConfigFilePath := nginx.GetConfPath("sites-enabled", name)
 	if helper.FileExists(enabledConfigFilePath) {
 		// Test nginx configuration
-		output := nginx.TestConf()
+		var output string
+		output, err = nginx.TestConfig()
+		if err != nil {
+			return
+		}
 
 		if nginx.GetLogLevel(output) > nginx.Warn {
 			return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 		}
 
 		if postAction == model.PostSyncActionReloadNginx {
-			output = nginx.Reload()
+			output, err = nginx.Reload()
+			if err != nil {
+				return
+			}
 			if nginx.GetLogLevel(output) > nginx.Warn {
 				return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 			}

+ 4 - 1
internal/stream/disable.go

@@ -35,7 +35,10 @@ func Disable(name string) (err error) {
 		return
 	}
 
-	output := nginx.Reload()
+	output, err := nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}

+ 8 - 2
internal/stream/enable.go

@@ -35,13 +35,19 @@ func Enable(name string) (err error) {
 	}
 
 	// Test nginx config, if not pass, then disable the site.
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		_ = os.Remove(enabledConfigFilePath)
 		return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 	}
 
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}

+ 8 - 2
internal/stream/rename.go

@@ -49,13 +49,19 @@ func Rename(oldName string, newName string) (err error) {
 	}
 
 	// test nginx configuration
-	output := nginx.TestConf()
+	output, err := nginx.TestConfig()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 	}
 
 	// reload nginx
-	output = nginx.Reload()
+	output, err = nginx.Reload()
+	if err != nil {
+		return
+	}
 	if nginx.GetLogLevel(output) > nginx.Warn {
 		return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 	}

+ 9 - 2
internal/stream/save.go

@@ -37,15 +37,22 @@ func Save(name string, content string, overwrite bool, syncNodeIds []uint64, pos
 
 	enabledConfigFilePath := nginx.GetConfPath("streams-enabled", name)
 	if helper.FileExists(enabledConfigFilePath) {
+		var output string
 		// Test nginx configuration
-		output := nginx.TestConf()
+		output, err = nginx.TestConfig()
+		if err != nil {
+			return
+		}
 
 		if nginx.GetLogLevel(output) > nginx.Warn {
 			return cosy.WrapErrorWithParams(ErrNginxTestFailed, output)
 		}
 
 		if postAction == model.PostSyncActionReloadNginx {
-			output = nginx.Reload()
+			output, err = nginx.Reload()
+			if err != nil {
+				return
+			}
 			if nginx.GetLogLevel(output) > nginx.Warn {
 				return cosy.WrapErrorWithParams(ErrNginxReloadFailed, output)
 			}

+ 5 - 0
settings/nginx.go

@@ -11,6 +11,7 @@ type Nginx struct {
 	ReloadCmd       string   `json:"reload_cmd" protected:"true"`
 	RestartCmd      string   `json:"restart_cmd" protected:"true"`
 	StubStatusPort  uint     `json:"stub_status_port" binding:"omitempty,min=1,max=65535"`
+	ContainerName   string   `json:"container_name" protected:"true"`
 }
 
 var NginxSettings = &Nginx{}
@@ -21,3 +22,7 @@ func (n *Nginx) GetStubStatusPort() uint {
 	}
 	return n.StubStatusPort
 }
+
+func (n *Nginx) RunningInAnotherContainer() bool {
+	return n.ContainerName != ""
+}