浏览代码

feat: customize local environment name #313

Jacky 1 年之前
父节点
当前提交
1e9de6f21b

+ 1 - 0
api/system/router.go

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

+ 10 - 18
api/system/settings.go

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

+ 1 - 0
app.example.ini

@@ -15,6 +15,7 @@ HttpHost             = 0.0.0.0
 CertRenewalInterval  = 7
 RecursiveNameservers = 
 SkipInstallation     = false
+Name                 = 
 
 [nginx]
 AccessLogPath = /var/log/nginx/access.log

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

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

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

@@ -4,6 +4,7 @@ import { storeToRefs } from 'pinia'
 import { useRouter } from 'vue-router'
 import { computed, watch } from 'vue'
 import { useSettingsStore } from '@/pinia'
+import settings from '@/api/settings'
 
 const settingsStore = useSettingsStore()
 
@@ -25,6 +26,12 @@ watch(node_id, async () => {
   await router.push('/dashboard')
   location.reload()
 })
+
+const { server_name } = storeToRefs(useSettingsStore())
+
+settings.get_server_name().then(r => {
+  server_name.value = r.name
+})
 </script>
 
 <template>
@@ -35,7 +42,7 @@ watch(node_id, async () => {
         v-if="is_local"
         class="env-name"
       >
-        {{ $gettext('Local') }}
+        {{ server_name || $gettext('Local') }}
       </span>
       <span
         v-else

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

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

+ 3 - 0
app/src/views/preference/BasicSettings.vue

@@ -113,6 +113,9 @@ const errors: Record<string, Record<string, string>> = inject('errors') as Recor
         </template>
       </Draggable>
     </AFormItem>
+    <AFormItem :label="$gettext('Server Name')">
+      <AInput v-model:value="data.server.name" />
+    </AFormItem>
   </AForm>
 </template>
 

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

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

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

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

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

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

+ 2 - 1
settings/server.go

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

+ 31 - 13
settings/settings.go

@@ -6,7 +6,8 @@ import (
 	"gopkg.in/ini.v1"
 	"log"
 	"os"
-	"strings"
+    "reflect"
+    "strings"
 	"time"
 )
 
@@ -69,19 +70,7 @@ func MapTo() {
 	}
 }
 
-func mapTo(section string, v interface{}) {
-	err := Conf.Section(section).MapTo(v)
-	if err != nil {
-		log.Fatalf("Cfg.MapTo %s err: %v", section, err)
-	}
-}
 
-func reflectFrom(section string, v interface{}) {
-	err := Conf.Section(section).ReflectFrom(v)
-	if err != nil {
-		log.Fatalf("Cfg.ReflectFrom %s err: %v", section, err)
-	}
-}
 
 func Save() (err error) {
 	for k, v := range sections {
@@ -95,6 +84,33 @@ func Save() (err error) {
 	return
 }
 
+func ProtectedFill(targetSettings interface{}, newSettings interface{}) {
+    s := reflect.TypeOf(targetSettings).Elem()
+    vt := reflect.ValueOf(targetSettings).Elem()
+    vn := reflect.ValueOf(newSettings).Elem()
+
+    // copy the values from new to target settings if it is not protected
+    for i := 0; i < s.NumField(); i++ {
+        if s.Field(i).Tag.Get("protected") != "true" {
+            vt.Field(i).Set(vn.Field(i))
+        }
+    }
+}
+
+func mapTo(section string, v interface{}) {
+    err := Conf.Section(section).MapTo(v)
+    if err != nil {
+        log.Fatalf("Cfg.MapTo %s err: %v", section, err)
+    }
+}
+
+func reflectFrom(section string, v interface{}) {
+    err := Conf.Section(section).ReflectFrom(v)
+    if err != nil {
+        log.Fatalf("Cfg.ReflectFrom %s err: %v", section, err)
+    }
+}
+
 func parseEnv(ptr interface{}, prefix string) {
 	err := env.ParseWithOptions(ptr, env.Options{
 		Prefix:                EnvPrefix + prefix,
@@ -105,3 +121,5 @@ func parseEnv(ptr interface{}, prefix string) {
 		log.Fatalf("settings.parseEnv: %v\n", err)
 	}
 }
+
+

+ 2 - 0
settings/settings_test.go

@@ -26,6 +26,7 @@ func TestSetup(t *testing.T) {
 	_ = os.Setenv("NGINX_UI_SERVER_CERT_RENEWAL_INTERVAL", "14")
 	_ = os.Setenv("NGINX_UI_SERVER_RECURSIVE_NAMESERVERS", "8.8.8.8")
 	_ = os.Setenv("NGINX_UI_SERVER_SKIP_INSTALLATION", "true")
+	_ = os.Setenv("NGINX_UI_SERVER_NAME", "test")
 
 	_ = os.Setenv("NGINX_UI_NGINX_ACCESS_LOG_PATH", "/tmp/nginx/access.log")
 	_ = os.Setenv("NGINX_UI_NGINX_ERROR_LOG_PATH", "/tmp/nginx/error.log")
@@ -70,6 +71,7 @@ func TestSetup(t *testing.T) {
 	assert.Equal(t, 14, ServerSettings.CertRenewalInterval)
 	assert.Equal(t, []string{"8.8.8.8"}, ServerSettings.RecursiveNameservers)
 	assert.Equal(t, true, ServerSettings.SkipInstallation)
+	assert.Equal(t, "test", ServerSettings.Name)
 
 	assert.Equal(t, "/tmp/nginx/access.log", NginxSettings.AccessLogPath)
 	assert.Equal(t, "/tmp/nginx/error.log", NginxSettings.ErrorLogPath)