feat: reload cluster node settings from settings file #169

This commit is contained in:
Jacky 2024-05-08 15:32:45 +08:00
parent 29f1b7db89
commit e0366f949f
No known key found for this signature in database
GPG key ID: 215C21B10DF38B4D
13 changed files with 110 additions and 34 deletions

View file

@ -3,9 +3,11 @@ package cluster
import ( import (
"github.com/0xJacky/Nginx-UI/api" "github.com/0xJacky/Nginx-UI/api"
"github.com/0xJacky/Nginx-UI/internal/analytic" "github.com/0xJacky/Nginx-UI/internal/analytic"
"github.com/0xJacky/Nginx-UI/internal/cluster"
"github.com/0xJacky/Nginx-UI/internal/cosy" "github.com/0xJacky/Nginx-UI/internal/cosy"
"github.com/0xJacky/Nginx-UI/model" "github.com/0xJacky/Nginx-UI/model"
"github.com/0xJacky/Nginx-UI/query" "github.com/0xJacky/Nginx-UI/query"
"github.com/0xJacky/Nginx-UI/settings"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/spf13/cast" "github.com/spf13/cast"
"net/http" "net/http"
@ -75,3 +77,19 @@ func DeleteEnvironment(c *gin.Context) {
c.JSON(http.StatusNoContent, nil) c.JSON(http.StatusNoContent, nil)
} }
func LoadEnvironmentFromSettings(c *gin.Context) {
err := settings.ReloadCluster()
if err != nil {
api.ErrHandler(c, err)
return
}
cluster.RegisterPredefinedNodes()
go analytic.RestartRetrieveNodesStatus()
c.JSON(http.StatusOK, gin.H{
"message": "ok",
})
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,6 +1,6 @@
<script setup lang="tsx"> <script setup lang="tsx">
import { h } from 'vue' import { h } from 'vue'
import { Badge, Tag } from 'ant-design-vue' import { Badge, Tag, message } from 'ant-design-vue'
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer' import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer' import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
import environment from '@/api/environment' import environment from '@/api/environment'
@ -130,14 +130,28 @@ const columns: Column[] = [{
dataIndex: 'action', dataIndex: 'action',
}] }]
const curd = ref()
function load_from_settings() {
environment.load_from_settings().then(() => {
curd.value.get_list()
message.success($gettext('Load successfully'))
}).catch(e => {
message.error(`${$gettext('Server error')} ${e?.message}`)
})
}
</script> </script>
<template> <template>
<StdCurd <StdCurd
ref="curd"
:title="$gettext('Environment')" :title="$gettext('Environment')"
:api="environment" :api="environment"
:columns="columns" :columns="columns"
/> >
<template #extra>
<a @click="load_from_settings">{{ $gettext('Load from settings') }}</a>
</template>
</StdCurd>
</template> </template>
<style lang="less" scoped> <style lang="less" scoped>

View file

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

View file

@ -1,4 +1,4 @@
package kernal package cluster
import ( import (
"github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/logger"
@ -10,7 +10,7 @@ import (
"strings" "strings"
) )
func registerPredefinedClusterNodes() { func RegisterPredefinedNodes() {
if len(settings.ClusterSettings.Node) == 0 { if len(settings.ClusterSettings.Node) == 0 {
return return
} }

View file

@ -1,4 +1,4 @@
package kernal package cluster
import ( import (
"github.com/0xJacky/Nginx-UI/settings" "github.com/0xJacky/Nginx-UI/settings"

View file

@ -3,6 +3,7 @@ package kernal
import ( import (
"github.com/0xJacky/Nginx-UI/internal/analytic" "github.com/0xJacky/Nginx-UI/internal/analytic"
"github.com/0xJacky/Nginx-UI/internal/cert" "github.com/0xJacky/Nginx-UI/internal/cert"
"github.com/0xJacky/Nginx-UI/internal/cluster"
"github.com/0xJacky/Nginx-UI/internal/logger" "github.com/0xJacky/Nginx-UI/internal/logger"
"github.com/0xJacky/Nginx-UI/internal/logrotate" "github.com/0xJacky/Nginx-UI/internal/logrotate"
"github.com/0xJacky/Nginx-UI/internal/validation" "github.com/0xJacky/Nginx-UI/internal/validation"
@ -44,7 +45,7 @@ func InitAfterDatabase() {
registerPredefinedUser, registerPredefinedUser,
cert.InitRegister, cert.InitRegister,
InitCronJobs, InitCronJobs,
registerPredefinedClusterNodes, cluster.RegisterPredefinedNodes,
analytic.RetrieveNodesStatus, analytic.RetrieveNodesStatus,
} }

View file

@ -7,3 +7,13 @@ type Cluster struct {
var ClusterSettings = Cluster{ var ClusterSettings = Cluster{
Node: []string{}, Node: []string{},
} }
func ReloadCluster() (err error) {
err = load()
if err != nil {
return err
}
return mapTo("cluster", &ClusterSettings)
}

View file

@ -39,13 +39,18 @@ func Init(confPath string) {
Setup() Setup()
} }
func Setup() { func load() (err error) {
var err error
Conf, err = ini.LoadSources(ini.LoadOptions{ Conf, err = ini.LoadSources(ini.LoadOptions{
Loose: true, Loose: true,
AllowShadows: true, AllowShadows: true,
}, ConfPath) }, ConfPath)
return
}
func Setup() {
err := load()
if err != nil { if err != nil {
log.Fatalf("settings.Setup: %v\n", err) log.Fatalf("settings.Setup: %v\n", err)
} }
@ -72,7 +77,11 @@ func Setup() {
func MapTo() { func MapTo() {
for k, v := range sections { for k, v := range sections {
mapTo(k, v) err := mapTo(k, v)
if err != nil {
log.Fatalf("Cfg.MapTo %s err: %v", k, err)
}
} }
} }
@ -101,11 +110,8 @@ func ProtectedFill(targetSettings interface{}, newSettings interface{}) {
} }
} }
func mapTo(section string, v interface{}) { func mapTo(section string, v interface{}) error {
err := Conf.Section(section).MapTo(v) return Conf.Section(section).MapTo(v)
if err != nil {
log.Fatalf("Cfg.MapTo %s err: %v", section, err)
}
} }
func reflectFrom(section string, v interface{}) { func reflectFrom(section string, v interface{}) {