mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
fix: resolved all vue-tsc errors
This commit is contained in:
parent
d325dd7493
commit
ab1adcfa3d
64 changed files with 675 additions and 451 deletions
|
@ -2,7 +2,7 @@ package analytic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
analytic2 "github.com/0xJacky/Nginx-UI/internal/analytic"
|
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
||||||
"github.com/0xJacky/Nginx-UI/internal/logger"
|
"github.com/0xJacky/Nginx-UI/internal/logger"
|
||||||
"github.com/shirou/gopsutil/v3/cpu"
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
"github.com/shirou/gopsutil/v3/host"
|
"github.com/shirou/gopsutil/v3/host"
|
||||||
|
@ -17,22 +17,6 @@ import (
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CPUStat struct {
|
|
||||||
User float64 `json:"user"`
|
|
||||||
System float64 `json:"system"`
|
|
||||||
Idle float64 `json:"idle"`
|
|
||||||
Total float64 `json:"total"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type Stat struct {
|
|
||||||
Uptime uint64 `json:"uptime"`
|
|
||||||
LoadAvg *load.AvgStat `json:"loadavg"`
|
|
||||||
CPU CPUStat `json:"cpu"`
|
|
||||||
Memory analytic2.MemStat `json:"memory"`
|
|
||||||
Disk analytic2.DiskStat `json:"disk"`
|
|
||||||
Network net.IOCountersStat `json:"network"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func Analytic(c *gin.Context) {
|
func Analytic(c *gin.Context) {
|
||||||
var upGrader = websocket.Upgrader{
|
var upGrader = websocket.Upgrader{
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
@ -51,7 +35,7 @@ func Analytic(c *gin.Context) {
|
||||||
var stat Stat
|
var stat Stat
|
||||||
|
|
||||||
for {
|
for {
|
||||||
stat.Memory, err = analytic2.GetMemoryStat()
|
stat.Memory, err = analytic.GetMemoryStat()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
|
@ -76,7 +60,7 @@ func Analytic(c *gin.Context) {
|
||||||
|
|
||||||
stat.LoadAvg, _ = load.Avg()
|
stat.LoadAvg, _ = load.Avg()
|
||||||
|
|
||||||
stat.Disk, err = analytic2.GetDiskStat()
|
stat.Disk, err = analytic.GetDiskStat()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
|
@ -103,20 +87,24 @@ func Analytic(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAnalyticInit(c *gin.Context) {
|
func GetAnalyticInit(c *gin.Context) {
|
||||||
cpuInfo, _ := cpu.Info()
|
cpuInfo, err := cpu.Info()
|
||||||
network, _ := net.IOCounters(false)
|
|
||||||
memory, err := analytic2.GetMemoryStat()
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diskStat, err := analytic2.GetDiskStat()
|
network, err := net.IOCounters(false)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
memory, err := analytic.GetMemoryStat()
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
diskStat, err := analytic.GetDiskStat()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _net net.IOCountersStat
|
var _net net.IOCountersStat
|
||||||
|
@ -132,86 +120,30 @@ func GetAnalyticInit(c *gin.Context) {
|
||||||
hostInfo.Platform = "CentOS"
|
hostInfo.Platform = "CentOS"
|
||||||
}
|
}
|
||||||
|
|
||||||
loadAvg, _ := load.Avg()
|
loadAvg, err := load.Avg()
|
||||||
|
|
||||||
c.JSON(http.StatusOK, gin.H{
|
if err != nil {
|
||||||
"host": hostInfo,
|
logger.Error(err)
|
||||||
"cpu": gin.H{
|
}
|
||||||
"info": cpuInfo,
|
|
||||||
"user": analytic2.CpuUserRecord,
|
c.JSON(http.StatusOK, InitResp{
|
||||||
"total": analytic2.CpuTotalRecord,
|
Host: hostInfo,
|
||||||
|
CPU: CPURecords{
|
||||||
|
Info: cpuInfo,
|
||||||
|
User: analytic.CpuUserRecord,
|
||||||
|
Total: analytic.CpuTotalRecord,
|
||||||
},
|
},
|
||||||
"network": gin.H{
|
Network: NetworkRecords{
|
||||||
"init": _net,
|
Init: _net,
|
||||||
"bytesRecv": analytic2.NetRecvRecord,
|
BytesRecv: analytic.NetRecvRecord,
|
||||||
"bytesSent": analytic2.NetSentRecord,
|
BytesSent: analytic.NetSentRecord,
|
||||||
},
|
},
|
||||||
"disk_io": gin.H{
|
DiskIO: DiskIORecords{
|
||||||
"writes": analytic2.DiskWriteRecord,
|
Writes: analytic.DiskWriteRecord,
|
||||||
"reads": analytic2.DiskReadRecord,
|
Reads: analytic.DiskReadRecord,
|
||||||
},
|
},
|
||||||
"memory": memory,
|
Memory: memory,
|
||||||
"disk": diskStat,
|
Disk: diskStat,
|
||||||
"loadavg": loadAvg,
|
LoadAvg: loadAvg,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetNodeStat(c *gin.Context) {
|
|
||||||
var upGrader = websocket.Upgrader{
|
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// upgrade http to websocket
|
|
||||||
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer ws.Close()
|
|
||||||
|
|
||||||
for {
|
|
||||||
// write
|
|
||||||
err = ws.WriteJSON(analytic2.GetNodeStat())
|
|
||||||
if err != nil || websocket.IsUnexpectedCloseError(err,
|
|
||||||
websocket.CloseGoingAway,
|
|
||||||
websocket.CloseNoStatusReceived,
|
|
||||||
websocket.CloseNormalClosure) {
|
|
||||||
logger.Error(err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetNodesAnalytic(c *gin.Context) {
|
|
||||||
var upGrader = websocket.Upgrader{
|
|
||||||
CheckOrigin: func(r *http.Request) bool {
|
|
||||||
return true
|
|
||||||
},
|
|
||||||
}
|
|
||||||
// upgrade http to websocket
|
|
||||||
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
|
||||||
if err != nil {
|
|
||||||
logger.Error(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
defer ws.Close()
|
|
||||||
|
|
||||||
for {
|
|
||||||
// write
|
|
||||||
err = ws.WriteJSON(analytic2.NodeMap)
|
|
||||||
if err != nil || websocket.IsUnexpectedCloseError(err,
|
|
||||||
websocket.CloseGoingAway,
|
|
||||||
websocket.CloseNoStatusReceived,
|
|
||||||
websocket.CloseNormalClosure) {
|
|
||||||
logger.Error(err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
time.Sleep(10 * time.Second)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
70
api/analytic/nodes.go
Normal file
70
api/analytic/nodes.go
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
package analytic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
||||||
|
"github.com/0xJacky/Nginx-UI/internal/logger"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetNodeStat(c *gin.Context) {
|
||||||
|
var upGrader = websocket.Upgrader{
|
||||||
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// upgrade http to websocket
|
||||||
|
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer ws.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
// write
|
||||||
|
err = ws.WriteJSON(analytic.GetNodeStat())
|
||||||
|
if err != nil || websocket.IsUnexpectedCloseError(err,
|
||||||
|
websocket.CloseGoingAway,
|
||||||
|
websocket.CloseNoStatusReceived,
|
||||||
|
websocket.CloseNormalClosure) {
|
||||||
|
logger.Error(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNodesAnalytic(c *gin.Context) {
|
||||||
|
var upGrader = websocket.Upgrader{
|
||||||
|
CheckOrigin: func(r *http.Request) bool {
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
// upgrade http to websocket
|
||||||
|
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
|
if err != nil {
|
||||||
|
logger.Error(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
defer ws.Close()
|
||||||
|
|
||||||
|
for {
|
||||||
|
// write
|
||||||
|
err = ws.WriteJSON(analytic.NodeMap)
|
||||||
|
if err != nil || websocket.IsUnexpectedCloseError(err,
|
||||||
|
websocket.CloseGoingAway,
|
||||||
|
websocket.CloseNoStatusReceived,
|
||||||
|
websocket.CloseNormalClosure) {
|
||||||
|
logger.Error(err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
time.Sleep(10 * time.Second)
|
||||||
|
}
|
||||||
|
}
|
52
api/analytic/type.go
Normal file
52
api/analytic/type.go
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
package analytic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/0xJacky/Nginx-UI/internal/analytic"
|
||||||
|
"github.com/shirou/gopsutil/v3/cpu"
|
||||||
|
"github.com/shirou/gopsutil/v3/host"
|
||||||
|
"github.com/shirou/gopsutil/v3/load"
|
||||||
|
"github.com/shirou/gopsutil/v3/net"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CPUStat struct {
|
||||||
|
User float64 `json:"user"`
|
||||||
|
System float64 `json:"system"`
|
||||||
|
Idle float64 `json:"idle"`
|
||||||
|
Total float64 `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Stat struct {
|
||||||
|
Uptime uint64 `json:"uptime"`
|
||||||
|
LoadAvg *load.AvgStat `json:"loadavg"`
|
||||||
|
CPU CPUStat `json:"cpu"`
|
||||||
|
Memory analytic.MemStat `json:"memory"`
|
||||||
|
Disk analytic.DiskStat `json:"disk"`
|
||||||
|
Network net.IOCountersStat `json:"network"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CPURecords struct {
|
||||||
|
Info []cpu.InfoStat `json:"info"`
|
||||||
|
User []analytic.Usage[float64] `json:"user"`
|
||||||
|
Total []analytic.Usage[float64] `json:"total"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type NetworkRecords struct {
|
||||||
|
Init net.IOCountersStat `json:"init"`
|
||||||
|
BytesRecv []analytic.Usage[uint64] `json:"bytesRecv"`
|
||||||
|
BytesSent []analytic.Usage[uint64] `json:"bytesSent"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type DiskIORecords struct {
|
||||||
|
Writes []analytic.Usage[uint64] `json:"writes"`
|
||||||
|
Reads []analytic.Usage[uint64] `json:"reads"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type InitResp struct {
|
||||||
|
Host *host.InfoStat `json:"host"`
|
||||||
|
CPU CPURecords `json:"cpu"`
|
||||||
|
Network NetworkRecords `json:"network"`
|
||||||
|
DiskIO DiskIORecords `json:"disk_io"`
|
||||||
|
Memory analytic.MemStat `json:"memory"`
|
||||||
|
Disk analytic.DiskStat `json:"disk"`
|
||||||
|
LoadAvg *load.AvgStat `json:"loadavg"`
|
||||||
|
}
|
|
@ -3,7 +3,7 @@ package certificate
|
||||||
import (
|
import (
|
||||||
"github.com/0xJacky/Nginx-UI/api"
|
"github.com/0xJacky/Nginx-UI/api"
|
||||||
"github.com/0xJacky/Nginx-UI/internal/cert/dns"
|
"github.com/0xJacky/Nginx-UI/internal/cert/dns"
|
||||||
model2 "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/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/spf13/cast"
|
"github.com/spf13/cast"
|
||||||
|
@ -21,7 +21,7 @@ func GetDnsCredential(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
type apiDnsCredential struct {
|
type apiDnsCredential struct {
|
||||||
model2.Model
|
model.Model
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
dns.Config
|
dns.Config
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ func GetDnsCredential(c *gin.Context) {
|
||||||
func GetDnsCredentialList(c *gin.Context) {
|
func GetDnsCredentialList(c *gin.Context) {
|
||||||
d := query.DnsCredential
|
d := query.DnsCredential
|
||||||
provider := c.Query("provider")
|
provider := c.Query("provider")
|
||||||
var data []*model2.DnsCredential
|
var data []*model.DnsCredential
|
||||||
var err error
|
var err error
|
||||||
if provider != "" {
|
if provider != "" {
|
||||||
data, err = d.Where(d.Provider.Eq(provider)).Find()
|
data, err = d.Where(d.Provider.Eq(provider)).Find()
|
||||||
|
@ -65,7 +65,7 @@ func AddDnsCredential(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
json.Config.Name = json.Provider
|
json.Config.Name = json.Provider
|
||||||
dnsCredential := model2.DnsCredential{
|
dnsCredential := model.DnsCredential{
|
||||||
Name: json.Name,
|
Name: json.Name,
|
||||||
Config: &json.Config,
|
Config: &json.Config,
|
||||||
Provider: json.Provider,
|
Provider: json.Provider,
|
||||||
|
@ -99,7 +99,7 @@ func EditDnsCredential(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
json.Config.Name = json.Provider
|
json.Config.Name = json.Provider
|
||||||
_, err = d.Where(d.ID.Eq(dnsCredential.ID)).Updates(&model2.DnsCredential{
|
_, err = d.Where(d.ID.Eq(dnsCredential.ID)).Updates(&model.DnsCredential{
|
||||||
Name: json.Name,
|
Name: json.Name,
|
||||||
Config: &json.Config,
|
Config: &json.Config,
|
||||||
Provider: json.Provider,
|
Provider: json.Provider,
|
||||||
|
|
|
@ -1,9 +1,120 @@
|
||||||
import http from '@/lib/http'
|
import http from '@/lib/http'
|
||||||
|
import ws from '@/lib/websocket'
|
||||||
|
|
||||||
|
export interface CPUInfoStat {
|
||||||
|
cpu: number
|
||||||
|
vendorId: string
|
||||||
|
family: string
|
||||||
|
model: string
|
||||||
|
stepping: number
|
||||||
|
physicalId: string
|
||||||
|
coreId: string
|
||||||
|
cores: number
|
||||||
|
modelName: string
|
||||||
|
mhz: number
|
||||||
|
cacheSize: number
|
||||||
|
flags: string[]
|
||||||
|
microcode: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IOCountersStat {
|
||||||
|
name: string
|
||||||
|
bytesSent: number
|
||||||
|
bytesRecv: number
|
||||||
|
packetsSent: number
|
||||||
|
packetsRecv: number
|
||||||
|
errin: number
|
||||||
|
errout: number
|
||||||
|
dropin: number
|
||||||
|
dropout: number
|
||||||
|
fifoin: number
|
||||||
|
fifoout: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface HostInfoStat {
|
||||||
|
hostname: string
|
||||||
|
uptime: number
|
||||||
|
bootTime: number
|
||||||
|
procs: number
|
||||||
|
os: string
|
||||||
|
platform: string
|
||||||
|
platformFamily: string
|
||||||
|
platformVersion: string
|
||||||
|
kernelVersion: string
|
||||||
|
kernelArch: string
|
||||||
|
virtualizationSystem: string
|
||||||
|
virtualizationRole: string
|
||||||
|
hostId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MemStat {
|
||||||
|
total: string
|
||||||
|
used: string
|
||||||
|
cached: string
|
||||||
|
free: string
|
||||||
|
swap_used: string
|
||||||
|
swap_total: string
|
||||||
|
swap_cached: string
|
||||||
|
swap_percent: number
|
||||||
|
pressure: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiskStat {
|
||||||
|
total: string
|
||||||
|
used: string
|
||||||
|
percentage: number
|
||||||
|
writes: Usage
|
||||||
|
reads: Usage
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface LoadStat {
|
||||||
|
load1: number
|
||||||
|
load5: number
|
||||||
|
load15: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Usage {
|
||||||
|
x: string
|
||||||
|
y: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CPURecords {
|
||||||
|
info: CPUInfoStat[]
|
||||||
|
user: Usage[]
|
||||||
|
total: Usage[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface NetworkRecords {
|
||||||
|
init: IOCountersStat
|
||||||
|
bytesRecv: Usage[]
|
||||||
|
bytesSent: Usage[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DiskIORecords {
|
||||||
|
writes: Usage[]
|
||||||
|
reads: Usage[]
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AnalyticInit {
|
||||||
|
host: HostInfoStat
|
||||||
|
cpu: CPURecords
|
||||||
|
network: NetworkRecords
|
||||||
|
disk_io: DiskIORecords
|
||||||
|
disk: DiskStat
|
||||||
|
memory: MemStat
|
||||||
|
loadavg: LoadStat
|
||||||
|
}
|
||||||
|
|
||||||
const analytic = {
|
const analytic = {
|
||||||
init() {
|
init(): Promise<AnalyticInit> {
|
||||||
return http.get('/analytic/init')
|
return http.get('/analytic/init')
|
||||||
},
|
},
|
||||||
|
server() {
|
||||||
|
return ws('/api/analytic')
|
||||||
|
},
|
||||||
|
nodes() {
|
||||||
|
return ws('/api/analytic/nodes')
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
export default analytic
|
export default analytic
|
||||||
|
|
|
@ -16,7 +16,7 @@ const auth = {
|
||||||
login(r.token)
|
login(r.token)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
async casdoor_login(code: string, state: string) {
|
async casdoor_login(code?: string, state?: string) {
|
||||||
await http.post('/casdoor_callback', {
|
await http.post('/casdoor_callback', {
|
||||||
code,
|
code,
|
||||||
state,
|
state,
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import http from '@/lib/http'
|
import http from '@/lib/http'
|
||||||
|
|
||||||
export interface DNSProvider {
|
export interface DNSProvider {
|
||||||
name: string
|
name?: string
|
||||||
code: string
|
code: string
|
||||||
|
provider?: string
|
||||||
configuration: {
|
configuration: {
|
||||||
credentials: {
|
credentials: {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
|
@ -11,11 +12,15 @@ export interface DNSProvider {
|
||||||
[key: string]: string
|
[key: string]: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
links: {
|
links?: {
|
||||||
api: string
|
api: string
|
||||||
go_client: string
|
go_client: string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export interface DnsChallenge extends DNSProvider {
|
||||||
|
dns_credential_id: number
|
||||||
|
challenge_method: string
|
||||||
|
}
|
||||||
|
|
||||||
const auto_cert = {
|
const auto_cert = {
|
||||||
get_dns_providers(): Promise<DNSProvider[]> {
|
get_dns_providers(): Promise<DNSProvider[]> {
|
||||||
|
|
|
@ -5,8 +5,15 @@ export interface Environment extends ModelBase {
|
||||||
name: string
|
name: string
|
||||||
url: string
|
url: string
|
||||||
token: string
|
token: string
|
||||||
|
status?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Node {
|
||||||
|
id: number
|
||||||
|
name: string
|
||||||
|
token: string
|
||||||
|
response_at?: Date
|
||||||
|
}
|
||||||
const environment: Curd<Environment> = new Curd('/environment')
|
const environment: Curd<Environment> = new Curd('/environment')
|
||||||
|
|
||||||
export default environment
|
export default environment
|
||||||
|
|
|
@ -3,10 +3,10 @@ import http from '@/lib/http'
|
||||||
import type { NgxServer } from '@/api/ngx'
|
import type { NgxServer } from '@/api/ngx'
|
||||||
|
|
||||||
export interface Variable {
|
export interface Variable {
|
||||||
type: string
|
type?: string
|
||||||
name: { [key: string]: string }
|
name?: { [key: string]: string }
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
value: any
|
value?: any
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Template extends NgxServer {
|
export interface Template extends NgxServer {
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
import http from '@/lib/http'
|
import http from '@/lib/http'
|
||||||
|
|
||||||
|
export interface RuntimeInfo {
|
||||||
|
name: string
|
||||||
|
os: string
|
||||||
|
arch: string
|
||||||
|
ex_path: string
|
||||||
|
body: string
|
||||||
|
published_at: string
|
||||||
|
}
|
||||||
|
|
||||||
const upgrade = {
|
const upgrade = {
|
||||||
get_latest_release(channel: string) {
|
get_latest_release(channel: string) {
|
||||||
return http.get('/upgrade/release', {
|
return http.get('/upgrade/release', {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import type { Series } from '@/components/Chart/types'
|
||||||
|
|
||||||
const { series, centerText, colors, name, bottomText }
|
const { series, centerText, colors, name, bottomText }
|
||||||
= defineProps<{
|
= defineProps<{
|
||||||
series: Series[]
|
series: Series[] | number[]
|
||||||
centerText?: string
|
centerText?: string
|
||||||
colors?: string
|
colors?: string
|
||||||
name?: string
|
name?: string
|
||||||
|
|
4
app/src/components/Chart/types.d.ts
vendored
4
app/src/components/Chart/types.d.ts
vendored
|
@ -1,4 +1,6 @@
|
||||||
|
import type {Usage} from '@/api/analytic'
|
||||||
|
|
||||||
export interface Series {
|
export interface Series {
|
||||||
name: string
|
name: string
|
||||||
data: []
|
data: Usage[]
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
|
import type { Environment } from '@/api/environment'
|
||||||
import environment from '@/api/environment'
|
import environment from '@/api/environment'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
|
@ -12,13 +14,13 @@ const emit = defineEmits(['update:target', 'update:map'])
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const data = ref([])
|
const data = ref([]) as Ref<Environment[]>
|
||||||
const data_map = ref({})
|
const data_map = ref({}) as Ref<Record<number, Environment>>
|
||||||
|
|
||||||
environment.get_list().then(r => {
|
environment.get_list().then(r => {
|
||||||
data.value = r.data
|
data.value = r.data
|
||||||
r.data.forEach(node => {
|
r.data.forEach(node => {
|
||||||
data_map[node.id] = node
|
data_map.value[node.id] = node
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -30,7 +32,7 @@ const value = computed({
|
||||||
if (typeof props.map === 'object') {
|
if (typeof props.map === 'object') {
|
||||||
v.forEach(id => {
|
v.forEach(id => {
|
||||||
if (id !== 0)
|
if (id !== 0)
|
||||||
emit('update:map', { ...props.map, [id]: data_map[id].name })
|
emit('update:map', { ...props.map, [id]: data_map.value[id].name })
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
emit('update:target', v)
|
emit('update:target', v)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import type { Ref } from 'vue'
|
|
||||||
import Breadcrumb from '@/components/Breadcrumb/Breadcrumb.vue'
|
import Breadcrumb from '@/components/Breadcrumb/Breadcrumb.vue'
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
@ -9,10 +8,8 @@ const display = computed(() => {
|
||||||
return !route.meta.hiddenHeaderContent
|
return !route.meta.hiddenHeaderContent
|
||||||
})
|
})
|
||||||
|
|
||||||
const name = ref(route.name) as Ref<() => string>
|
const name = computed(() => {
|
||||||
|
return (route.name as never as () => string)()
|
||||||
watch(() => route.name, () => {
|
|
||||||
name.value = route.name as () => string
|
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -27,7 +24,7 @@ watch(() => route.name, () => {
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h1 class="title">
|
<h1 class="title">
|
||||||
{{ name() }}
|
{{ name }}
|
||||||
</h1>
|
</h1>
|
||||||
<div class="action">
|
<div class="action">
|
||||||
<slot name="action" />
|
<slot name="action" />
|
||||||
|
|
|
@ -28,7 +28,7 @@ watch(current, v => {
|
||||||
settings.set_language(v)
|
settings.set_language(v)
|
||||||
gettext.current = v
|
gettext.current = v
|
||||||
|
|
||||||
const name = route.name as () => string
|
const name = route.name as never as () => string
|
||||||
|
|
||||||
document.title = `${name()} | Nginx UI`
|
document.title = `${name()} | Nginx UI`
|
||||||
})
|
})
|
||||||
|
|
|
@ -15,7 +15,7 @@ export interface StdCurdProps {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
onClickEdit?: (id: number | string, record: any, index: number) => void
|
onClickEdit?: (id: number | string, record: any, index: number) => void
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
beforeSave?: (data: any) => void
|
beforeSave?: (data: any) => Promise<void>
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = defineProps<StdTableProps & StdCurdProps>()
|
const props = defineProps<StdTableProps & StdCurdProps>()
|
||||||
|
@ -24,14 +24,16 @@ const { $gettext } = gettext
|
||||||
|
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const update = ref(0)
|
const update = ref(0)
|
||||||
const data = reactive({ id: null })
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const data: any = reactive({ id: null })
|
||||||
|
|
||||||
provide('data', data)
|
provide('data', data)
|
||||||
|
|
||||||
const error = reactive({})
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const error: any = reactive({})
|
||||||
const selected = ref([])
|
const selected = ref([])
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function onSelect(keys) {
|
function onSelect(keys: any) {
|
||||||
selected.value = keys
|
selected.value = keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +88,7 @@ function cancel() {
|
||||||
clear_error()
|
clear_error()
|
||||||
}
|
}
|
||||||
|
|
||||||
function edit(id) {
|
function edit(id: number | string) {
|
||||||
props.api!.get(id).then(async r => {
|
props.api!.get(id).then(async r => {
|
||||||
Object.keys(data).forEach(k => {
|
Object.keys(data).forEach(k => {
|
||||||
delete data[k]
|
delete data[k]
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
import { HolderOutlined } from '@ant-design/icons-vue'
|
import { HolderOutlined } from '@ant-design/icons-vue'
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import type { ComputedRef } from 'vue'
|
import type { ComputedRef, Ref } from 'vue'
|
||||||
import type { SorterResult } from 'ant-design-vue/lib/table/interface'
|
import type { SorterResult } from 'ant-design-vue/lib/table/interface'
|
||||||
import StdPagination from './StdPagination.vue'
|
import StdPagination from './StdPagination.vue'
|
||||||
import StdDataEntry from '@/components/StdDesign/StdDataEntry'
|
import StdDataEntry from '@/components/StdDesign/StdDataEntry'
|
||||||
|
@ -46,9 +46,11 @@ const props = withDefaults(defineProps<StdTableProps>(), {
|
||||||
const emit = defineEmits(['onSelected', 'onSelectedRecord', 'clickEdit', 'update:selectedRowKeys', 'clickBatchModify'])
|
const emit = defineEmits(['onSelected', 'onSelectedRecord', 'clickEdit', 'update:selectedRowKeys', 'clickBatchModify'])
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const dataSource = ref([])
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const expandKeysList = ref([])
|
const dataSource: Ref<any[]> = ref([])
|
||||||
const rowsKeyIndexMap = ref({})
|
const expandKeysList: Ref<number[]> = ref([])
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
const rowsKeyIndexMap: Ref<Record<number, any>> = ref({})
|
||||||
const loading = ref(true)
|
const loading = ref(true)
|
||||||
|
|
||||||
// This can be useful if there are more than one StdTable in the same page.
|
// This can be useful if there are more than one StdTable in the same page.
|
||||||
|
@ -78,7 +80,7 @@ const selectedRowKeysBuffer = computed({
|
||||||
})
|
})
|
||||||
|
|
||||||
const searchColumns = computed(() => {
|
const searchColumns = computed(() => {
|
||||||
const _searchColumns = []
|
const _searchColumns: Column[] = []
|
||||||
|
|
||||||
props.columns?.forEach(column => {
|
props.columns?.forEach(column => {
|
||||||
if (column.search)
|
if (column.search)
|
||||||
|
@ -101,7 +103,7 @@ const pithyColumns = computed(() => {
|
||||||
}) as ComputedRef<Column[]>
|
}) as ComputedRef<Column[]>
|
||||||
|
|
||||||
const batchColumns = computed(() => {
|
const batchColumns = computed(() => {
|
||||||
const batch = []
|
const batch: Column[] = []
|
||||||
|
|
||||||
props.columns?.forEach(column => {
|
props.columns?.forEach(column => {
|
||||||
if (column.batch)
|
if (column.batch)
|
||||||
|
@ -125,7 +127,7 @@ defineExpose({
|
||||||
get_list,
|
get_list,
|
||||||
})
|
})
|
||||||
|
|
||||||
function destroy(id) {
|
function destroy(id: number | string) {
|
||||||
props.api!.destroy(id).then(() => {
|
props.api!.destroy(id).then(() => {
|
||||||
get_list()
|
get_list()
|
||||||
message.success($gettext('Deleted successfully'))
|
message.success($gettext('Deleted successfully'))
|
||||||
|
@ -155,9 +157,11 @@ function get_list(page_num = null, page_size = 20) {
|
||||||
message.error(e?.message ?? $gettext('Server error'))
|
message.error(e?.message ?? $gettext('Server error'))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function buildIndexMap(data, level: number = 0, index: number = 0, total: number[] = []) {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
function buildIndexMap(data: any, level: number = 0, index: number = 0, total: number[] = []) {
|
||||||
if (data && data.length > 0) {
|
if (data && data.length > 0) {
|
||||||
data.forEach(v => {
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
data.forEach((v: any) => {
|
||||||
v.level = level
|
v.level = level
|
||||||
|
|
||||||
const current_indexes = [...total, index++]
|
const current_indexes = [...total, index++]
|
||||||
|
@ -168,7 +172,7 @@ function buildIndexMap(data, level: number = 0, index: number = 0, total: number
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function orderPaginationChange(_pagination: Pagination, filters, sorter: SorterResult) {
|
function orderPaginationChange(_pagination: Pagination, filters: never, sorter: SorterResult) {
|
||||||
if (sorter) {
|
if (sorter) {
|
||||||
selectedRowKeysBuffer.value = []
|
selectedRowKeysBuffer.value = []
|
||||||
params.order_by = sorter.field
|
params.order_by = sorter.field
|
||||||
|
@ -189,19 +193,19 @@ function orderPaginationChange(_pagination: Pagination, filters, sorter: SorterR
|
||||||
selectedRowKeysBuffer.value = []
|
selectedRowKeysBuffer.value = []
|
||||||
}
|
}
|
||||||
|
|
||||||
function expandedTable(keys) {
|
function expandedTable(keys: number[]) {
|
||||||
expandKeysList.value = keys
|
expandKeysList.value = keys
|
||||||
}
|
}
|
||||||
|
|
||||||
const crossPageSelect = {}
|
const crossPageSelect: Record<string, number[]> = {}
|
||||||
|
|
||||||
async function onSelectChange(_selectedRowKeys) {
|
async function onSelectChange(_selectedRowKeys: number[]) {
|
||||||
const page = params.page || 1
|
const page = params.page || 1
|
||||||
|
|
||||||
crossPageSelect[page] = await _selectedRowKeys
|
crossPageSelect[page] = _selectedRowKeys
|
||||||
|
|
||||||
let t = []
|
let t: number[] = []
|
||||||
Object.keys(crossPageSelect).forEach(v => {
|
Object.keys(crossPageSelect).forEach((v: string) => {
|
||||||
t.push(...crossPageSelect[v])
|
t.push(...crossPageSelect[v])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -215,8 +219,8 @@ async function onSelectChange(_selectedRowKeys) {
|
||||||
selectedRowKeysBuffer.value = Array.from(set)
|
selectedRowKeysBuffer.value = Array.from(set)
|
||||||
emit('onSelected', selectedRowKeysBuffer.value)
|
emit('onSelected', selectedRowKeysBuffer.value)
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function onSelect(record) {
|
function onSelect(record: any) {
|
||||||
emit('onSelectedRecord', record)
|
emit('onSelectedRecord', record)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import type { StdTableProps } from '@/components/StdDesign/StdDataDisplay/StdTab
|
||||||
|
|
||||||
const { $gettext } = gettext
|
const { $gettext } = gettext
|
||||||
async function exportCsv(props: StdTableProps, pithyColumns: ComputedRef<Column[]>) {
|
async function exportCsv(props: StdTableProps, pithyColumns: ComputedRef<Column[]>) {
|
||||||
const header: { title?: string; key: string }[] = []
|
const header: { title?: string; key: string | string[] }[] = []
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const headerKeys: any[] = []
|
const headerKeys: any[] = []
|
||||||
const showColumnsMap: Record<string, Column> = {}
|
const showColumnsMap: Record<string, Column> = {}
|
||||||
|
@ -24,8 +24,8 @@ async function exportCsv(props: StdTableProps, pithyColumns: ComputedRef<Column[
|
||||||
title: t,
|
title: t,
|
||||||
key: column.dataIndex,
|
key: column.dataIndex,
|
||||||
})
|
})
|
||||||
headerKeys.push(column.dataIndex)
|
headerKeys.push(column.dataIndex.toString())
|
||||||
showColumnsMap[column.dataIndex] = column
|
showColumnsMap[column.dataIndex.toString()] = column
|
||||||
})
|
})
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
|
@ -59,7 +59,7 @@ async function exportCsv(props: StdTableProps, pithyColumns: ComputedRef<Column[
|
||||||
const c = showColumnsMap[key]
|
const c = showColumnsMap[key]
|
||||||
|
|
||||||
_data = c?.customRender?.({ text: _data }) ?? _data
|
_data = c?.customRender?.({ text: _data }) ?? _data
|
||||||
obj[c.dataIndex] = _data
|
_.set(obj, c.dataIndex, _data)
|
||||||
})
|
})
|
||||||
data.push(obj)
|
data.push(obj)
|
||||||
})
|
})
|
||||||
|
|
|
@ -8,12 +8,12 @@ const props = defineProps<{
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
dataSource: Record<string, any>
|
dataSource: Record<string, any>
|
||||||
errors?: Record<string, string>
|
errors?: Record<string, string>
|
||||||
layout?: 'horizontal' | 'vertical'
|
layout?: 'horizontal' | 'vertical' | 'inline'
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
'update:dataSource': (v: any[]) => void
|
'update:dataSource': [data: Record<string, any>]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const dataSource = computed({
|
const dataSource = computed({
|
||||||
|
|
|
@ -7,7 +7,7 @@ const props = defineProps<Props>()
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
dataIndex?: string
|
dataIndex?: string | string[]
|
||||||
label?: string
|
label?: string
|
||||||
extra?: string
|
extra?: string
|
||||||
error?: {
|
error?: {
|
||||||
|
@ -16,7 +16,7 @@ export interface Props {
|
||||||
}
|
}
|
||||||
|
|
||||||
const tag = computed(() => {
|
const tag = computed(() => {
|
||||||
return props.error?.[props.dataIndex] ?? ''
|
return props.error?.[props.dataIndex!.toString()] ?? ''
|
||||||
})
|
})
|
||||||
|
|
||||||
const valid_status = computed(() => {
|
const valid_status = computed(() => {
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { useGettext } from 'vue3-gettext'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
value: string
|
value: string
|
||||||
generate: boolean
|
generate?: boolean
|
||||||
placeholder: string
|
placeholder?: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits(['update:value'])
|
const emit = defineEmits(['update:value'])
|
||||||
|
|
|
@ -6,17 +6,16 @@ import type { Column } from '@/components/StdDesign/types'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
selectedKey: string | number
|
selectedKey: string | number
|
||||||
value: string | number
|
value?: string | number
|
||||||
recordValueIndex: string
|
recordValueIndex: string
|
||||||
selectionType: 'radio' | 'checkbox'
|
selectionType: 'radio' | 'checkbox'
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
api: Curd<any>
|
api: Curd<any>
|
||||||
columns: Column[]
|
columns: Column[]
|
||||||
dataKey: string
|
disableSearch?: boolean
|
||||||
disableSearch: boolean
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
getParams: any
|
getParams: any
|
||||||
description: string
|
description?: string
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits(['update:selectedKey', 'changeSelect'])
|
const emit = defineEmits(['update:selectedKey', 'changeSelect'])
|
||||||
|
@ -29,8 +28,8 @@ onMounted(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const selected = ref([])
|
const selected = ref([])
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const record = reactive({})
|
const record: any = reactive({})
|
||||||
|
|
||||||
function init() {
|
function init() {
|
||||||
if (props.selectedKey && !props.value && props.selectionType === 'radio') {
|
if (props.selectedKey && !props.value && props.selectionType === 'radio') {
|
||||||
|
@ -113,12 +112,11 @@ const _selectedKey = computed({
|
||||||
<StdTable
|
<StdTable
|
||||||
:api="api"
|
:api="api"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:data_key="dataKey"
|
:disable-search="disableSearch"
|
||||||
:disable_search="disableSearch"
|
|
||||||
pithy
|
pithy
|
||||||
:get_params="getParams"
|
:get-params="getParams"
|
||||||
:selection-type="selectionType"
|
:selection-type="selectionType"
|
||||||
disable_query_params
|
disable-query-params
|
||||||
@on-selected="onSelect"
|
@on-selected="onSelect"
|
||||||
@on-selected-record="onSelectedRecord"
|
@on-selected-record="onSelectedRecord"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -52,6 +52,7 @@ function textarea(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
|
||||||
function password(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
|
function password(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
|
||||||
return <StdPassword
|
return <StdPassword
|
||||||
v-model:value={dataSource[dataIndex]}
|
v-model:value={dataSource[dataIndex]}
|
||||||
|
value={dataSource[dataIndex]}
|
||||||
generate={edit.config?.generate}
|
generate={edit.config?.generate}
|
||||||
placeholder={placeholder_helper(edit)}
|
placeholder={placeholder_helper(edit)}
|
||||||
/>
|
/>
|
||||||
|
@ -60,19 +61,21 @@ function password(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
|
||||||
function select(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
|
function select(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
|
||||||
return <StdSelect
|
return <StdSelect
|
||||||
v-model:value={dataSource[dataIndex]}
|
v-model:value={dataSource[dataIndex]}
|
||||||
mask={edit.mask}
|
value={dataSource[dataIndex]}
|
||||||
|
mask={edit.mask as Record<string, () => string>}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
function selector(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
|
function selector(edit: StdDesignEdit, dataSource: any, dataIndex: any) {
|
||||||
return <StdSelector
|
return <StdSelector
|
||||||
v-model:selectedKey={dataSource[dataIndex]}
|
v-model:selectedKey={dataSource[dataIndex]}
|
||||||
|
selectedKey={dataSource[dataIndex]}
|
||||||
recordValueIndex={edit.selector?.recordValueIndex}
|
recordValueIndex={edit.selector?.recordValueIndex}
|
||||||
selectionType={edit.selector?.selectionType}
|
selectionType={edit.selector?.selectionType}
|
||||||
api={edit.selector?.api}
|
api={edit.selector?.api}
|
||||||
columns={edit.selector?.columns}
|
columns={edit.selector?.columns}
|
||||||
disableSearch={edit.selector?.disable_search}
|
disableSearch={edit.selector?.disableSearch}
|
||||||
getParams={edit.selector?.get_params}
|
getParams={edit.selector?.getParams}
|
||||||
description={edit.selector?.description}
|
description={edit.selector?.description}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
|
10
app/src/components/StdDesign/types.d.ts
vendored
10
app/src/components/StdDesign/types.d.ts
vendored
|
@ -8,20 +8,18 @@ export interface StdDesignEdit {
|
||||||
|
|
||||||
batch?: boolean // batch edit
|
batch?: boolean // batch edit
|
||||||
|
|
||||||
mask?: {
|
mask?: Record<string, () => string> // use for select-option
|
||||||
[key: string]: () => string
|
|
||||||
} // use for select-option
|
|
||||||
|
|
||||||
rules?: [] // validator rules
|
rules?: [] // validator rules
|
||||||
|
|
||||||
selector?: {
|
selector?: {
|
||||||
get_params?: {}
|
getParams?: {}
|
||||||
recordValueIndex: any // relative to api return
|
recordValueIndex: any // relative to api return
|
||||||
selectionType: any
|
selectionType: any
|
||||||
api: Curd,
|
api: Curd,
|
||||||
valueApi?: Curd,
|
valueApi?: Curd,
|
||||||
columns: any
|
columns: any
|
||||||
disable_search?: boolean
|
disableSearch?: boolean
|
||||||
description?: string
|
description?: string
|
||||||
bind?: any
|
bind?: any
|
||||||
itemKey?: any // default is id
|
itemKey?: any // default is id
|
||||||
|
@ -52,7 +50,7 @@ export interface Flex {
|
||||||
|
|
||||||
export interface Column {
|
export interface Column {
|
||||||
title?: string | (() => string);
|
title?: string | (() => string);
|
||||||
dataIndex: string;
|
dataIndex: string | string[];
|
||||||
edit?: StdDesignEdit;
|
edit?: StdDesignEdit;
|
||||||
customRender?: function;
|
customRender?: function;
|
||||||
extra?: string | (() => string);
|
extra?: string | (() => string);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import NginxControl from '@/components/NginxControl/NginxControl.vue'
|
||||||
import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.vue'
|
import SwitchAppearance from '@/components/SwitchAppearance/SwitchAppearance.vue'
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
clickUnFold: () => void
|
clickUnFold: [void]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const { $gettext } = gettext
|
const { $gettext } = gettext
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { useRoute } from 'vue-router'
|
||||||
import type { ComputedRef } from 'vue'
|
import type { ComputedRef } from 'vue'
|
||||||
import { computed, ref, watch } from 'vue'
|
import { computed, ref, watch } from 'vue'
|
||||||
import type { AntdIconType } from '@ant-design/icons-vue/lib/components/AntdIcon'
|
import type { AntdIconType } from '@ant-design/icons-vue/lib/components/AntdIcon'
|
||||||
|
import type { IconComponentProps } from '@ant-design/icons-vue/es/components/Icon'
|
||||||
import Logo from '@/components/Logo/Logo.vue'
|
import Logo from '@/components/Logo/Logo.vue'
|
||||||
import { routes } from '@/routes'
|
import { routes } from '@/routes'
|
||||||
import EnvIndicator from '@/components/EnvIndicator/EnvIndicator.vue'
|
import EnvIndicator from '@/components/EnvIndicator/EnvIndicator.vue'
|
||||||
|
@ -56,7 +57,7 @@ const visible: ComputedRef<sidebar[]> = computed(() => {
|
||||||
const t: sidebar = {
|
const t: sidebar = {
|
||||||
path: s.path,
|
path: s.path,
|
||||||
name: s.name,
|
name: s.name,
|
||||||
meta: s.meta as meta,
|
meta: s.meta as unknown as meta,
|
||||||
children: [],
|
children: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,7 +65,7 @@ const visible: ComputedRef<sidebar[]> = computed(() => {
|
||||||
if (c.meta && c.meta.hiddenInSidebar)
|
if (c.meta && c.meta.hiddenInSidebar)
|
||||||
return
|
return
|
||||||
|
|
||||||
t.children.push((c as sidebar))
|
t.children.push((c as unknown as sidebar))
|
||||||
})
|
})
|
||||||
res.push(t)
|
res.push(t)
|
||||||
})
|
})
|
||||||
|
@ -80,7 +81,6 @@ const visible: ComputedRef<sidebar[]> = computed(() => {
|
||||||
<AMenu
|
<AMenu
|
||||||
v-model:openKeys="openKeys"
|
v-model:openKeys="openKeys"
|
||||||
v-model:selectedKeys="selectedKey"
|
v-model:selectedKeys="selectedKey"
|
||||||
:open-keys="openKeys"
|
|
||||||
mode="inline"
|
mode="inline"
|
||||||
>
|
>
|
||||||
<EnvIndicator />
|
<EnvIndicator />
|
||||||
|
@ -91,7 +91,7 @@ const visible: ComputedRef<sidebar[]> = computed(() => {
|
||||||
:key="s.name"
|
:key="s.name"
|
||||||
@click="$router.push(`/${s.path}`).catch(() => {})"
|
@click="$router.push(`/${s.path}`).catch(() => {})"
|
||||||
>
|
>
|
||||||
<component :is="s.meta.icon" />
|
<Component :is="s.meta.icon as IconComponentProps" />
|
||||||
<span>{{ s.name() }}</span>
|
<span>{{ s.name() }}</span>
|
||||||
</AMenuItem>
|
</AMenuItem>
|
||||||
|
|
||||||
|
@ -100,7 +100,7 @@ const visible: ComputedRef<sidebar[]> = computed(() => {
|
||||||
:key="s.path"
|
:key="s.path"
|
||||||
>
|
>
|
||||||
<template #title>
|
<template #title>
|
||||||
<component :is="s.meta.icon" />
|
<Component :is="s.meta.icon as IconComponentProps" />
|
||||||
<span>{{ s.name() }}</span>
|
<span>{{ s.name() }}</span>
|
||||||
</template>
|
</template>
|
||||||
<AMenuItem
|
<AMenuItem
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { createRouter, createWebHashHistory } from 'vue-router'
|
import { createRouter, createWebHashHistory } from 'vue-router'
|
||||||
|
import type { AntDesignOutlinedIconType } from '@ant-design/icons-vue/lib/icons/AntDesignOutlined'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CloudOutlined,
|
CloudOutlined,
|
||||||
|
@ -13,7 +14,6 @@ import {
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
import NProgress from 'nprogress'
|
import NProgress from 'nprogress'
|
||||||
import type { AntDesignOutlinedIconType } from '@ant-design/icons-vue/lib/icons/AntDesignOutlined'
|
|
||||||
|
|
||||||
import gettext from '../gettext'
|
import gettext from '../gettext'
|
||||||
import { useUserStore } from '@/pinia'
|
import { useUserStore } from '@/pinia'
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"version":"2.0.0-beta.4","build_id":56,"total_build":260}
|
{"version":"2.0.0-beta.4","build_id":62,"total_build":266}
|
|
@ -9,13 +9,14 @@ import cert from '@/api/cert'
|
||||||
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
|
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
|
||||||
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
|
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
|
||||||
import CertInfo from '@/views/domain/cert/CertInfo.vue'
|
import CertInfo from '@/views/domain/cert/CertInfo.vue'
|
||||||
|
import type { Column } from '@/components/StdDesign/types'
|
||||||
|
|
||||||
const { $gettext, interpolate } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const columns = [{
|
const columns: Column[] = [{
|
||||||
title: () => $gettext('Name'),
|
title: () => $gettext('Name'),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
customRender: (args: customRender) => {
|
customRender: (args: customRender) => {
|
||||||
const { text, record } = args
|
const { text, record } = args
|
||||||
|
@ -31,7 +32,7 @@ const columns = [{
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('Config Name'),
|
title: () => $gettext('Config Name'),
|
||||||
dataIndex: 'filename',
|
dataIndex: 'filename',
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('Auto Cert'),
|
title: () => $gettext('Auto Cert'),
|
||||||
|
@ -50,7 +51,7 @@ const columns = [{
|
||||||
|
|
||||||
return h('div', template)
|
return h('div', template)
|
||||||
},
|
},
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('SSL Certificate Path'),
|
title: () => $gettext('SSL Certificate Path'),
|
||||||
|
@ -58,19 +59,19 @@ const columns = [{
|
||||||
edit: {
|
edit: {
|
||||||
type: input,
|
type: input,
|
||||||
},
|
},
|
||||||
display: false,
|
hidden: true,
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('SSL Certificate Key Path'),
|
title: () => $gettext('SSL Certificate Key Path'),
|
||||||
dataIndex: 'ssl_certificate_key_path',
|
dataIndex: 'ssl_certificate_key_path',
|
||||||
edit: {
|
edit: {
|
||||||
type: input,
|
type: input,
|
||||||
},
|
},
|
||||||
display: false,
|
hidden: true,
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('Updated at'),
|
title: () => $gettext('Updated at'),
|
||||||
dataIndex: 'updated_at',
|
dataIndex: 'updated_at',
|
||||||
customRender: datetime,
|
customRender: datetime,
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('Action'),
|
title: () => $gettext('Action'),
|
||||||
|
@ -83,7 +84,6 @@ const columns = [{
|
||||||
:title="$gettext('Certification')"
|
:title="$gettext('Certification')"
|
||||||
:api="cert"
|
:api="cert"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
row-key="name"
|
|
||||||
>
|
>
|
||||||
<template #beforeEdit="{ data }">
|
<template #beforeEdit="{ data }">
|
||||||
<template v-if="data.auto_cert === 1">
|
<template v-if="data.auto_cert === 1">
|
||||||
|
@ -109,7 +109,7 @@ const columns = [{
|
||||||
style="margin-bottom: 15px"
|
style="margin-bottom: 15px"
|
||||||
>
|
>
|
||||||
<AAlert
|
<AAlert
|
||||||
:message="interpolate($gettext('Domains list is empty, try to reopen auto-cert for %{config}'), { config: data.filename })"
|
:message="$gettext('Domains list is empty, try to reopen auto-cert for %{config}', { config: data.filename })"
|
||||||
type="error"
|
type="error"
|
||||||
show-icon
|
show-icon
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,12 +1,16 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import type { SelectProps } from 'ant-design-vue'
|
import type { SelectProps } from 'ant-design-vue'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
|
import type { DNSProvider } from '@/api/auto_cert'
|
||||||
import auto_cert from '@/api/auto_cert'
|
import auto_cert from '@/api/auto_cert'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
const providers = ref([])
|
const providers = ref([]) as Ref<DNSProvider[]>
|
||||||
|
|
||||||
const data = inject('data')
|
// This data is provided by the Top StdCurd component,
|
||||||
|
// is the object that you are trying to modify it
|
||||||
|
const data = inject('data') as DNSProvider
|
||||||
|
|
||||||
const code = computed(() => {
|
const code = computed(() => {
|
||||||
return data.code
|
return data.code
|
||||||
|
@ -14,9 +18,11 @@ const code = computed(() => {
|
||||||
|
|
||||||
const provider_idx = ref()
|
const provider_idx = ref()
|
||||||
function init() {
|
function init() {
|
||||||
data.configuration = {
|
if (!data.configuration) {
|
||||||
credentials: {},
|
data.configuration = {
|
||||||
additional: {},
|
credentials: {},
|
||||||
|
additional: {},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
providers.value?.forEach((v: { code: string }, k: number) => {
|
providers.value?.forEach((v: { code: string }, k: number) => {
|
||||||
if (v.code === code.value)
|
if (v.code === code.value)
|
||||||
|
@ -39,6 +45,7 @@ watch(code, init)
|
||||||
watch(current, () => {
|
watch(current, () => {
|
||||||
data.code = current.value.code
|
data.code = current.value.code
|
||||||
data.provider = current.value.name
|
data.provider = current.value.name
|
||||||
|
|
||||||
auto_cert.get_dns_provider(current.value.code).then(r => {
|
auto_cert.get_dns_provider(current.value.code).then(r => {
|
||||||
Object.assign(current.value, r)
|
Object.assign(current.value, r)
|
||||||
})
|
})
|
||||||
|
@ -47,7 +54,7 @@ watch(current, () => {
|
||||||
const options = computed<SelectProps['options']>(() => {
|
const options = computed<SelectProps['options']>(() => {
|
||||||
const list: SelectProps['options'] = []
|
const list: SelectProps['options'] = []
|
||||||
|
|
||||||
providers.value.forEach((v: { name: string }, k: number) => {
|
providers.value.forEach((v: DNSProvider, k: number) => {
|
||||||
list!.push({
|
list!.push({
|
||||||
value: k,
|
value: k,
|
||||||
label: v.name,
|
label: v.name,
|
||||||
|
|
|
@ -5,13 +5,14 @@ import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransfor
|
||||||
import dns_credential from '@/api/dns_credential'
|
import dns_credential from '@/api/dns_credential'
|
||||||
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
|
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
|
||||||
import { input } from '@/components/StdDesign/StdDataEntry'
|
import { input } from '@/components/StdDesign/StdDataEntry'
|
||||||
|
import type { Column } from '@/components/StdDesign/types'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const columns = [{
|
const columns: Column[] = [{
|
||||||
title: () => $gettext('Name'),
|
title: () => $gettext('Name'),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
edit: {
|
edit: {
|
||||||
type: input,
|
type: input,
|
||||||
|
@ -19,13 +20,13 @@ const columns = [{
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('Provider'),
|
title: () => $gettext('Provider'),
|
||||||
dataIndex: ['config', 'name'],
|
dataIndex: ['config', 'name'],
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('Updated at'),
|
title: () => $gettext('Updated at'),
|
||||||
dataIndex: 'updated_at',
|
dataIndex: 'updated_at',
|
||||||
customRender: datetime,
|
customRender: datetime,
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('Action'),
|
title: () => $gettext('Action'),
|
||||||
|
@ -38,7 +39,6 @@ const columns = [{
|
||||||
:title="$gettext('DNS Credentials')"
|
:title="$gettext('DNS Credentials')"
|
||||||
:api="dns_credential"
|
:api="dns_credential"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
row-key="name"
|
|
||||||
>
|
>
|
||||||
<template #beforeEdit>
|
<template #beforeEdit>
|
||||||
<AAlert
|
<AAlert
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { computed, ref } from 'vue'
|
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
import { formatDateTime } from '@/lib/helper'
|
import { formatDateTime } from '@/lib/helper'
|
||||||
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
|
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
|
||||||
import gettext from '@/gettext'
|
import gettext from '@/gettext'
|
||||||
|
@ -10,6 +10,7 @@ import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
|
||||||
import ngx from '@/api/ngx'
|
import ngx from '@/api/ngx'
|
||||||
import InspectConfig from '@/views/config/InspectConfig.vue'
|
import InspectConfig from '@/views/config/InspectConfig.vue'
|
||||||
import ChatGPT from '@/components/ChatGPT/ChatGPT.vue'
|
import ChatGPT from '@/components/ChatGPT/ChatGPT.vue'
|
||||||
|
import type { ChatComplicationMessage } from '@/api/openai'
|
||||||
|
|
||||||
const { $gettext, interpolate } = gettext
|
const { $gettext, interpolate } = gettext
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
@ -25,7 +26,7 @@ const name = computed(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const configText = ref('')
|
const configText = ref('')
|
||||||
const history_chatgpt_record = ref([])
|
const history_chatgpt_record = ref([]) as Ref<ChatComplicationMessage[]>
|
||||||
const file_path = ref('')
|
const file_path = ref('')
|
||||||
const active_key = ref(['1', '2'])
|
const active_key = ref(['1', '2'])
|
||||||
const modified_at = ref('')
|
const modified_at = ref('')
|
||||||
|
@ -52,7 +53,7 @@ init()
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
config.save(name.value, { content: configText.value }).then(r => {
|
config.save(name.value, { content: configText.value }).then(r => {
|
||||||
configText.value = r.config
|
configText.value = r.content
|
||||||
message.success($gettext('Saved successfully'))
|
message.success($gettext('Saved successfully'))
|
||||||
}).catch(r => {
|
}).catch(r => {
|
||||||
message.error(interpolate($gettext('Save error %{msg}'), { msg: r.message ?? '' }))
|
message.error(interpolate($gettext('Save error %{msg}'), { msg: r.message ?? '' }))
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import { computed, onMounted, onUnmounted, ref } from 'vue'
|
|
||||||
import Icon, { LinkOutlined, SendOutlined, ThunderboltOutlined } from '@ant-design/icons-vue'
|
import Icon, { LinkOutlined, SendOutlined, ThunderboltOutlined } from '@ant-design/icons-vue'
|
||||||
import type ReconnectingWebSocket from 'reconnecting-websocket'
|
import type ReconnectingWebSocket from 'reconnecting-websocket'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
import { useSettingsStore } from '@/pinia'
|
import { useSettingsStore } from '@/pinia'
|
||||||
|
import type { Node } from '@/api/environment'
|
||||||
import environment from '@/api/environment'
|
import environment from '@/api/environment'
|
||||||
import logo from '@/assets/img/logo.png'
|
import logo from '@/assets/img/logo.png'
|
||||||
import pulse from '@/assets/svg/pulse.svg'
|
import pulse from '@/assets/svg/pulse.svg'
|
||||||
import { formatDateTime } from '@/lib/helper'
|
import { formatDateTime } from '@/lib/helper'
|
||||||
import ws from '@/lib/websocket'
|
|
||||||
import NodeAnalyticItem from '@/views/dashboard/components/NodeAnalyticItem.vue'
|
import NodeAnalyticItem from '@/views/dashboard/components/NodeAnalyticItem.vue'
|
||||||
|
import analytic from '@/api/analytic'
|
||||||
|
|
||||||
const settingsStore = useSettingsStore()
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const data = ref([])
|
const data = ref([]) as Ref<Node[]>
|
||||||
|
|
||||||
const node_map = computed(() => {
|
const node_map = computed(() => {
|
||||||
const o = {}
|
const o = {} as Record<number, Node>
|
||||||
|
|
||||||
data.value.forEach(v => {
|
data.value.forEach(v => {
|
||||||
o[v.id] = v
|
o[v.id] = v
|
||||||
|
@ -32,16 +32,19 @@ onMounted(() => {
|
||||||
environment.get_list().then(r => {
|
environment.get_list().then(r => {
|
||||||
data.value = r.data
|
data.value = r.data
|
||||||
})
|
})
|
||||||
websocket = ws('/api/analytic/nodes')
|
websocket = analytic.nodes()
|
||||||
websocket.onmessage = m => {
|
websocket.onmessage = async m => {
|
||||||
const nodes = JSON.parse(m.data)
|
const nodes = JSON.parse(m.data)
|
||||||
for (const key in nodes) {
|
|
||||||
|
Object.keys(nodes).forEach((v: string) => {
|
||||||
|
const key = Number.parseInt(v)
|
||||||
|
|
||||||
// update node online status
|
// update node online status
|
||||||
if (node_map.value[key]) {
|
if (node_map.value[key]) {
|
||||||
Object.assign(node_map.value[key], nodes[key])
|
Object.assign(node_map.value[key], nodes[key])
|
||||||
node_map.value[key].response_at = new Date()
|
node_map.value[key].response_at = new Date()
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -49,13 +52,7 @@ onUnmounted(() => {
|
||||||
websocket.close()
|
websocket.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
export interface Node {
|
const { environment: env } = useSettingsStore()
|
||||||
id: number
|
|
||||||
name: string
|
|
||||||
token: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const { environment: env } = settingsStore
|
|
||||||
|
|
||||||
function link_start(node: Node) {
|
function link_start(node: Node) {
|
||||||
env.id = node.id
|
env.id = node.id
|
||||||
|
|
|
@ -3,9 +3,10 @@ import { useGettext } from 'vue3-gettext'
|
||||||
import type ReconnectingWebSocket from 'reconnecting-websocket'
|
import type ReconnectingWebSocket from 'reconnecting-websocket'
|
||||||
import AreaChart from '@/components/Chart/AreaChart.vue'
|
import AreaChart from '@/components/Chart/AreaChart.vue'
|
||||||
import RadialBarChart from '@/components/Chart/RadialBarChart.vue'
|
import RadialBarChart from '@/components/Chart/RadialBarChart.vue'
|
||||||
|
import type { CPUInfoStat, DiskStat, HostInfoStat, LoadStat, MemStat } from '@/api/analytic'
|
||||||
import analytic from '@/api/analytic'
|
import analytic from '@/api/analytic'
|
||||||
import ws from '@/lib/websocket'
|
|
||||||
import { bytesToSize } from '@/lib/helper'
|
import { bytesToSize } from '@/lib/helper'
|
||||||
|
import type { Series } from '@/components/Chart/types'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
|
@ -17,32 +18,42 @@ const host = reactive({
|
||||||
os: '',
|
os: '',
|
||||||
kernelVersion: '',
|
kernelVersion: '',
|
||||||
kernelArch: '',
|
kernelArch: '',
|
||||||
})
|
}) as HostInfoStat
|
||||||
|
|
||||||
const cpu = ref('0.0')
|
const cpu = ref('0.0')
|
||||||
const cpu_info = reactive([])
|
const cpu_info = reactive([]) as CPUInfoStat[]
|
||||||
const cpu_analytic_series = reactive([{ name: 'User', data: [] }, { name: 'Total', data: [] }])
|
const cpu_analytic_series = reactive([{ name: 'User', data: [] }, { name: 'Total', data: [] }]) as Series[]
|
||||||
|
|
||||||
const net_analytic = reactive([{ name: $gettext('Receive'), data: [] },
|
const net_analytic = reactive([{ name: $gettext('Receive'), data: [] },
|
||||||
{ name: $gettext('Send'), data: [] }])
|
{ name: $gettext('Send'), data: [] }]) as Series[]
|
||||||
|
|
||||||
const disk_io_analytic = reactive([{ name: $gettext('Writes'), data: [] },
|
const disk_io_analytic = reactive([{ name: $gettext('Writes'), data: [] },
|
||||||
{ name: $gettext('Reads'), data: [] }])
|
{ name: $gettext('Reads'), data: [] }]) as Series[]
|
||||||
|
|
||||||
const memory = reactive({ swap_used: '', swap_percent: '', swap_total: '' })
|
const memory = reactive({
|
||||||
const disk = reactive({ percentage: '', used: '' })
|
total: '',
|
||||||
|
used: '',
|
||||||
|
cached: '',
|
||||||
|
free: '',
|
||||||
|
swap_used: '',
|
||||||
|
swap_cached: '',
|
||||||
|
swap_percent: 0,
|
||||||
|
swap_total: '',
|
||||||
|
pressure: 0,
|
||||||
|
}) as MemStat
|
||||||
|
|
||||||
|
const disk = reactive({ percentage: 0, used: '', total: '', writes: { x: '', y: 0 }, reads: { x: '', y: 0 } }) as DiskStat
|
||||||
const disk_io = reactive({ writes: 0, reads: 0 })
|
const disk_io = reactive({ writes: 0, reads: 0 })
|
||||||
const uptime = ref('')
|
const uptime = ref('')
|
||||||
const loadavg = reactive({ load1: 0, load5: 0, load15: 0 })
|
const loadavg = reactive({ load1: 0, load5: 0, load15: 0 }) as LoadStat
|
||||||
const net = reactive({ recv: 0, sent: 0, last_recv: 0, last_sent: 0 })
|
const net = reactive({ recv: 0, sent: 0, last_recv: 0, last_sent: 0 })
|
||||||
|
|
||||||
const net_formatter = (bytes: number) => {
|
const net_formatter = (bytes: number) => {
|
||||||
return `${bytesToSize(bytes)}/s`
|
return `${bytesToSize(bytes)}/s`
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Usage {
|
const cpu_formatter = (usage: number) => {
|
||||||
x: number
|
return usage.toFixed(2)
|
||||||
y: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -60,22 +71,15 @@ onMounted(() => {
|
||||||
|
|
||||||
net.last_recv = r.network.init.bytesRecv
|
net.last_recv = r.network.init.bytesRecv
|
||||||
net.last_sent = r.network.init.bytesSent
|
net.last_sent = r.network.init.bytesSent
|
||||||
r.cpu.user.forEach((u: Usage) => {
|
|
||||||
cpu_analytic_series[0].data.push([u.x, u.y.toFixed(2)])
|
cpu_analytic_series[0].data = cpu_analytic_series[0].data.concat(r.cpu.user)
|
||||||
})
|
cpu_analytic_series[1].data = cpu_analytic_series[1].data.concat(r.cpu.total)
|
||||||
r.cpu.total.forEach((u: Usage) => {
|
net_analytic[0].data = net_analytic[0].data.concat(r.network.bytesRecv)
|
||||||
cpu_analytic_series[1].data.push([u.x, u.y.toFixed(2)])
|
net_analytic[1].data = net_analytic[1].data.concat(r.network.bytesSent)
|
||||||
})
|
|
||||||
r.network.bytesRecv.forEach((u: Usage) => {
|
|
||||||
net_analytic[0].data.push([u.x, u.y.toFixed(2)])
|
|
||||||
})
|
|
||||||
r.network.bytesSent.forEach((u: Usage) => {
|
|
||||||
net_analytic[1].data.push([u.x, u.y.toFixed(2)])
|
|
||||||
})
|
|
||||||
disk_io_analytic[0].data = disk_io_analytic[0].data.concat(r.disk_io.writes)
|
disk_io_analytic[0].data = disk_io_analytic[0].data.concat(r.disk_io.writes)
|
||||||
disk_io_analytic[1].data = disk_io_analytic[1].data.concat(r.disk_io.reads)
|
disk_io_analytic[1].data = disk_io_analytic[1].data.concat(r.disk_io.reads)
|
||||||
|
|
||||||
websocket = ws('/api/analytic')
|
websocket = analytic.server()
|
||||||
websocket.onmessage = wsOnMessage
|
websocket.onmessage = wsOnMessage
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -97,17 +101,17 @@ function handle_uptime(t: number) {
|
||||||
uptime.value = `${uptime_days}d ${uptime_hours}h ${Math.floor(_uptime / 60)}m`
|
uptime.value = `${uptime_days}d ${uptime_hours}h ${Math.floor(_uptime / 60)}m`
|
||||||
}
|
}
|
||||||
|
|
||||||
function wsOnMessage(m) {
|
function wsOnMessage(m: MessageEvent) {
|
||||||
const r = JSON.parse(m.data)
|
const r = JSON.parse(m.data)
|
||||||
|
|
||||||
const cpu_usage = r.cpu.system + r.cpu.user
|
const cpu_usage = Math.min(r.cpu.system + r.cpu.user, 100)
|
||||||
|
|
||||||
cpu.value = cpu_usage.toFixed(2)
|
cpu.value = cpu_usage.toFixed(2)
|
||||||
|
|
||||||
const time = new Date().getTime()
|
const time = new Date().toLocaleString()
|
||||||
|
|
||||||
cpu_analytic_series[0].data.push([time, r.cpu.user.toFixed(2)])
|
cpu_analytic_series[0].data.push({ x: time, y: r.cpu.user.toFixed(2) })
|
||||||
cpu_analytic_series[1].data.push([time, cpu.value])
|
cpu_analytic_series[1].data.push({ x: time, y: cpu_usage })
|
||||||
|
|
||||||
if (cpu_analytic_series[0].data.length > 100) {
|
if (cpu_analytic_series[0].data.length > 100) {
|
||||||
cpu_analytic_series[0].data.shift()
|
cpu_analytic_series[0].data.shift()
|
||||||
|
@ -135,8 +139,8 @@ function wsOnMessage(m) {
|
||||||
net.last_recv = r.network.bytesRecv
|
net.last_recv = r.network.bytesRecv
|
||||||
net.last_sent = r.network.bytesSent
|
net.last_sent = r.network.bytesSent
|
||||||
|
|
||||||
net_analytic[0].data.push([time, net.recv])
|
net_analytic[0].data.push({ x: time, y: net.recv })
|
||||||
net_analytic[1].data.push([time, net.sent])
|
net_analytic[1].data.push({ x: time, y: net.sent })
|
||||||
|
|
||||||
if (net_analytic[0].data.length > 100) {
|
if (net_analytic[0].data.length > 100) {
|
||||||
net_analytic[0].data.shift()
|
net_analytic[0].data.shift()
|
||||||
|
@ -302,6 +306,7 @@ function wsOnMessage(m) {
|
||||||
</AStatistic>
|
</AStatistic>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
:series="cpu_analytic_series"
|
:series="cpu_analytic_series"
|
||||||
|
:y-formatter="cpu_formatter"
|
||||||
:max="100"
|
:max="100"
|
||||||
/>
|
/>
|
||||||
</ACard>
|
</ACard>
|
||||||
|
|
|
@ -67,10 +67,10 @@ function create_another() {
|
||||||
|
|
||||||
const has_server_name = computed(() => {
|
const has_server_name = computed(() => {
|
||||||
const servers = ngx_config.servers
|
const servers = ngx_config.servers
|
||||||
for (const server_key in servers) {
|
|
||||||
for (const k in servers[server_key].directives) {
|
for (const server of Object.values(servers)) {
|
||||||
const v = servers[server_key].directives[k]
|
for (const directive of Object.values(server.directives!)) {
|
||||||
if (v.directive === 'server_name' && v.params.trim() !== '')
|
if (directive.directive === 'server_name' && directive.params.trim() !== '')
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,15 +2,19 @@
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
|
import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
|
||||||
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
|
import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
|
||||||
|
|
||||||
import NgxConfigEditor from '@/views/domain/ngx_conf/NgxConfigEditor.vue'
|
import NgxConfigEditor from '@/views/domain/ngx_conf/NgxConfigEditor.vue'
|
||||||
|
import type { Site } from '@/api/domain'
|
||||||
import domain from '@/api/domain'
|
import domain from '@/api/domain'
|
||||||
import type { NgxConfig } from '@/api/ngx'
|
import type { NgxConfig } from '@/api/ngx'
|
||||||
import ngx from '@/api/ngx'
|
import ngx from '@/api/ngx'
|
||||||
import config from '@/api/config'
|
import config from '@/api/config'
|
||||||
import RightSettings from '@/views/domain/components/RightSettings.vue'
|
import RightSettings from '@/views/domain/components/RightSettings.vue'
|
||||||
|
import type { CertificateInfo } from '@/api/cert'
|
||||||
|
import type { ChatComplicationMessage } from '@/api/openai'
|
||||||
|
|
||||||
const { $gettext, interpolate } = useGettext()
|
const { $gettext, interpolate } = useGettext()
|
||||||
|
|
||||||
|
@ -29,7 +33,7 @@ const ngx_config: NgxConfig = reactive({
|
||||||
servers: [],
|
servers: [],
|
||||||
})
|
})
|
||||||
|
|
||||||
const cert_info_map = reactive({})
|
const cert_info_map: Record<string, CertificateInfo> = reactive({})
|
||||||
|
|
||||||
const auto_cert = ref(false)
|
const auto_cert = ref(false)
|
||||||
const enabled = ref(false)
|
const enabled = ref(false)
|
||||||
|
@ -52,16 +56,16 @@ const advance_mode = computed({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const history_chatgpt_record = ref([])
|
const history_chatgpt_record = ref([]) as Ref<ChatComplicationMessage[]>
|
||||||
|
|
||||||
function handle_response(r) {
|
function handle_response(r: Site) {
|
||||||
if (r.advanced)
|
if (r.advanced)
|
||||||
advance_mode.value = true
|
advance_mode.value = true
|
||||||
|
|
||||||
if (r.advanced)
|
if (r.advanced)
|
||||||
advance_mode.value = true
|
advance_mode.value = true
|
||||||
|
|
||||||
Object.keys(cert_info_map).forEach(v => {
|
Object.keys(cert_info_map).forEach((v: string) => {
|
||||||
delete cert_info_map[v]
|
delete cert_info_map[v]
|
||||||
})
|
})
|
||||||
parse_error_status.value = false
|
parse_error_status.value = false
|
||||||
|
@ -87,13 +91,13 @@ function init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handle_parse_error(e) {
|
function handle_parse_error(e: { error?: string; message: string }) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
if (e?.error === 'nginx_config_syntax_error') {
|
if (e?.error === 'nginx_config_syntax_error') {
|
||||||
parse_error_status.value = true
|
parse_error_status.value = true
|
||||||
parse_error_message.value = e.message
|
parse_error_message.value = e.message
|
||||||
config.get(`sites-available/${name.value}`).then(r => {
|
config.get(`sites-available/${name.value}`).then(r => {
|
||||||
configText.value = r.config
|
configText.value = r.content
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -117,7 +121,7 @@ function on_mode_change(advanced: boolean) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function build_config() {
|
async function build_config() {
|
||||||
return ngx.build_config(ngx_config).then(r => {
|
return ngx.build_config(ngx_config).then(r => {
|
||||||
configText.value = r.content
|
configText.value = r.content
|
||||||
})
|
})
|
||||||
|
@ -316,10 +320,6 @@ provide('data', data)
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.location-block {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.directive-params-wrapper {
|
.directive-params-wrapper {
|
||||||
margin: 10px 0;
|
margin: 10px 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,13 +8,14 @@ import domain from '@/api/domain'
|
||||||
import { input } from '@/components/StdDesign/StdDataEntry'
|
import { input } from '@/components/StdDesign/StdDataEntry'
|
||||||
import SiteDuplicate from '@/views/domain/components/SiteDuplicate.vue'
|
import SiteDuplicate from '@/views/domain/components/SiteDuplicate.vue'
|
||||||
import InspectConfig from '@/views/config/InspectConfig.vue'
|
import InspectConfig from '@/views/config/InspectConfig.vue'
|
||||||
|
import type { Column } from '@/components/StdDesign/types'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const columns = [{
|
const columns: Column[] = [{
|
||||||
title: () => $gettext('Name'),
|
title: () => $gettext('Name'),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
edit: {
|
edit: {
|
||||||
type: input,
|
type: input,
|
||||||
|
@ -37,13 +38,13 @@ const columns = [{
|
||||||
|
|
||||||
return h('div', template)
|
return h('div', template)
|
||||||
},
|
},
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('Updated at'),
|
title: () => $gettext('Updated at'),
|
||||||
dataIndex: 'modified_at',
|
dataIndex: 'modified_at',
|
||||||
customRender: datetime,
|
customRender: datetime,
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
}, {
|
}, {
|
||||||
title: () => $gettext('Action'),
|
title: () => $gettext('Action'),
|
||||||
|
@ -52,7 +53,7 @@ const columns = [{
|
||||||
|
|
||||||
const table = ref()
|
const table = ref()
|
||||||
|
|
||||||
function enable(name) {
|
function enable(name: string) {
|
||||||
domain.enable(name).then(() => {
|
domain.enable(name).then(() => {
|
||||||
message.success($gettext('Enabled successfully'))
|
message.success($gettext('Enabled successfully'))
|
||||||
table.value?.get_list()
|
table.value?.get_list()
|
||||||
|
@ -61,7 +62,7 @@ function enable(name) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function disable(name) {
|
function disable(name: string) {
|
||||||
domain.disable(name).then(() => {
|
domain.disable(name).then(() => {
|
||||||
message.success($gettext('Disabled successfully'))
|
message.success($gettext('Disabled successfully'))
|
||||||
table.value?.get_list()
|
table.value?.get_list()
|
||||||
|
@ -70,7 +71,7 @@ function disable(name) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function destroy(site_name) {
|
function destroy(site_name: string) {
|
||||||
domain.destroy(site_name).then(() => {
|
domain.destroy(site_name).then(() => {
|
||||||
table.value.get_list()
|
table.value.get_list()
|
||||||
message.success($gettext('Delete site: %{site_name}', { site_name }))
|
message.success($gettext('Delete site: %{site_name}', { site_name }))
|
||||||
|
|
|
@ -37,7 +37,7 @@ const now = computed(() => new Date().toISOString())
|
||||||
</template>
|
</template>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<CheckCircleOutlined class="text-green-500" />
|
<CheckCircleOutlined class="text-green-500" />
|
||||||
<span class="ml-2">{{ $gettext('Certificate is valid<') }}</span>
|
<span class="ml-2">{{ $gettext('Certificate is valid') }}</span>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,23 +1,26 @@
|
||||||
<script setup lang="tsx">
|
<script setup lang="tsx">
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import { Badge } from 'ant-design-vue'
|
import { Badge } from 'ant-design-vue'
|
||||||
|
import type { ComputedRef, Ref } from 'vue'
|
||||||
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
|
import StdTable from '@/components/StdDesign/StdDataDisplay/StdTable.vue'
|
||||||
|
import type { Cert } from '@/api/cert'
|
||||||
import cert from '@/api/cert'
|
import cert from '@/api/cert'
|
||||||
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
import type { customRender } from '@/components/StdDesign/StdDataDisplay/StdTableTransformer'
|
||||||
import { input } from '@/components/StdDesign/StdDataEntry'
|
import { input } from '@/components/StdDesign/StdDataEntry'
|
||||||
import type { NgxDirective } from '@/api/ngx'
|
import type { NgxDirective } from '@/api/ngx'
|
||||||
|
import type { Column } from '@/components/StdDesign/types'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const current_server_directives = inject('current_server_directives')
|
const current_server_directives = inject('current_server_directives') as ComputedRef<NgxDirective[]>
|
||||||
const directivesMap = inject('directivesMap') as Record<string, NgxDirective[]>
|
const directivesMap = inject('directivesMap') as Ref<Record<string, NgxDirective[]>>
|
||||||
const visible = ref(false)
|
const visible = ref(false)
|
||||||
const record = ref({})
|
const record = ref({}) as Ref<Cert>
|
||||||
|
|
||||||
const columns = [{
|
const columns: Column[] = [{
|
||||||
title: () => $gettext('Name'),
|
title: () => $gettext('Name'),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
customRender: (args: customRender) => {
|
customRender: (args: customRender) => {
|
||||||
const { text, record: r } = args
|
const { text, record: r } = args
|
||||||
|
@ -47,7 +50,7 @@ const columns = [{
|
||||||
|
|
||||||
return h('div', template)
|
return h('div', template)
|
||||||
},
|
},
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
@ -55,13 +58,13 @@ function open() {
|
||||||
visible.value = true
|
visible.value = true
|
||||||
}
|
}
|
||||||
|
|
||||||
function onSelectedRecord(r) {
|
function onSelectedRecord(r: Cert) {
|
||||||
record.value = r
|
record.value = r
|
||||||
}
|
}
|
||||||
|
|
||||||
function ok() {
|
function ok() {
|
||||||
if (directivesMap.ssl_certificate?.[0]) {
|
if (directivesMap.value.ssl_certificate?.[0]) {
|
||||||
directivesMap.ssl_certificate[0].params = record.value.ssl_certificate_path
|
directivesMap.value.ssl_certificate[0].params = record.value.ssl_certificate_path
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
current_server_directives?.value.push({
|
current_server_directives?.value.push({
|
||||||
|
@ -69,8 +72,8 @@ function ok() {
|
||||||
params: record.value.ssl_certificate_path,
|
params: record.value.ssl_certificate_path,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if (directivesMap.ssl_certificate_key?.[0]) {
|
if (directivesMap.value.ssl_certificate_key?.[0]) {
|
||||||
directivesMap.ssl_certificate_key[0].params = record.value.ssl_certificate_key_path
|
directivesMap.value.ssl_certificate_key[0].params = record.value.ssl_certificate_key_path
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
current_server_directives?.value.push({
|
current_server_directives?.value.push({
|
||||||
|
|
|
@ -3,16 +3,19 @@ import { useGettext } from 'vue3-gettext'
|
||||||
import ObtainCert from '@/views/domain/cert/components/ObtainCert.vue'
|
import ObtainCert from '@/views/domain/cert/components/ObtainCert.vue'
|
||||||
import type { NgxDirective } from '@/api/ngx'
|
import type { NgxDirective } from '@/api/ngx'
|
||||||
|
|
||||||
const props = defineProps<{
|
export interface Props {
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
}>()
|
configName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = defineProps<Props>()
|
||||||
|
|
||||||
const emit = defineEmits(['callback', 'update:enabled'])
|
const emit = defineEmits(['callback', 'update:enabled'])
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
const issuing_cert = ref(false)
|
const issuing_cert = ref(false)
|
||||||
const obtain_cert = ref()
|
const obtain_cert = ref()
|
||||||
const directivesMap = inject('directivesMap') as Record<string, NgxDirective[]>
|
const directivesMap = inject('directivesMap') as Ref<Record<string, NgxDirective[]>>
|
||||||
|
|
||||||
const enabled = computed({
|
const enabled = computed({
|
||||||
get() {
|
get() {
|
||||||
|
@ -24,10 +27,10 @@ const enabled = computed({
|
||||||
})
|
})
|
||||||
|
|
||||||
const no_server_name = computed(() => {
|
const no_server_name = computed(() => {
|
||||||
if (!directivesMap.server_name)
|
if (!directivesMap.value.server_name)
|
||||||
return true
|
return true
|
||||||
|
|
||||||
return directivesMap.server_name.length === 0
|
return directivesMap.value.server_name.length === 0
|
||||||
})
|
})
|
||||||
|
|
||||||
provide('no_server_name', no_server_name)
|
provide('no_server_name', no_server_name)
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { inject } from 'vue'
|
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
|
import type { DnsChallenge } from '@/api/auto_cert'
|
||||||
import DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue'
|
import DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
const no_server_name = inject('no_server_name')
|
const no_server_name = inject('no_server_name')
|
||||||
const data = inject('data')
|
|
||||||
|
// Provide by ObtainCert.vue
|
||||||
|
const data = inject('data') as DnsChallenge
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -30,28 +32,23 @@ const data = inject('data')
|
||||||
:message="$gettext('Note')"
|
:message="$gettext('Note')"
|
||||||
>
|
>
|
||||||
<template #description>
|
<template #description>
|
||||||
<p v-translate>
|
<p>
|
||||||
The server_name
|
{{ $gettext('The server_name'
|
||||||
in the current configuration must be the domain name you need to get the certificate, support
|
+ 'in the current configuration must be the domain name you need to get the certificate, support'
|
||||||
multiple domains.
|
+ 'multiple domains.') }}
|
||||||
</p>
|
</p>
|
||||||
<p v-translate>
|
<p>
|
||||||
The certificate for the domain will be checked every hour,
|
{{ $gettext('The certificate for the domain will be checked 5 minutes,'
|
||||||
and will be renewed if it has been more than 1 week since it was last issued.
|
+ 'and will be renewed if it has been more than 1 week since it was last issued.') }}
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p v-if="data.challenge_method === 'http01'">
|
||||||
v-if="data.challenge_method === 'http01'"
|
{{ $gettext('Make sure you have configured a reverse proxy for .well-known '
|
||||||
v-translate
|
+ 'directory to HTTPChallengePort before obtaining the certificate.') }}
|
||||||
>
|
|
||||||
Make sure you have configured a reverse proxy for .well-known
|
|
||||||
directory to HTTPChallengePort before obtaining the certificate.
|
|
||||||
</p>
|
</p>
|
||||||
<p
|
<p v-else-if="data.challenge_method === 'dns01'">
|
||||||
v-else-if="data.challenge_method === 'dns01'"
|
{{ $gettext('Please first add credentials in Certification > DNS Credentials, '
|
||||||
v-translate
|
+ 'and then select one of the credentials'
|
||||||
>
|
+ 'below to request the API of the DNS provider.') }}
|
||||||
Please first add credentials in Certification > DNS Credentials, and then select one of the credentials
|
|
||||||
below to request the API of the DNS provider.
|
|
||||||
</p>
|
</p>
|
||||||
</template>
|
</template>
|
||||||
</AAlert>
|
</AAlert>
|
||||||
|
|
|
@ -1,14 +1,20 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import type { SelectProps } from 'ant-design-vue'
|
import type { SelectProps } from 'ant-design-vue'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
|
import type { DNSProvider } from '@/api/auto_cert'
|
||||||
import auto_cert from '@/api/auto_cert'
|
import auto_cert from '@/api/auto_cert'
|
||||||
import dns_credential from '@/api/dns_credential'
|
import dns_credential from '@/api/dns_credential'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
const providers = ref([])
|
const providers = ref([]) as Ref<DNSProvider[]>
|
||||||
const credentials = ref([])
|
const credentials = ref<SelectProps['options']>([])
|
||||||
|
|
||||||
const data = inject('data')
|
// This data is provided by the Top StdCurd component,
|
||||||
|
// is the object that you are trying to modify it
|
||||||
|
// we externalize the dns_credential_id to the parent component,
|
||||||
|
// this is used to tell the backend which dns_credential to use
|
||||||
|
const data = inject('data') as DNSProvider & { dns_credential_id: number | null }
|
||||||
|
|
||||||
const code = computed(() => {
|
const code = computed(() => {
|
||||||
return data.code
|
return data.code
|
||||||
|
@ -16,7 +22,7 @@ const code = computed(() => {
|
||||||
|
|
||||||
const provider_idx = ref()
|
const provider_idx = ref()
|
||||||
function init() {
|
function init() {
|
||||||
providers.value?.forEach((v, k: number) => {
|
providers.value?.forEach((v: DNSProvider, k: number) => {
|
||||||
if (v.code === code.value)
|
if (v.code === code.value)
|
||||||
provider_idx.value = k
|
provider_idx.value = k
|
||||||
})
|
})
|
||||||
|
@ -42,7 +48,7 @@ watch(current, () => {
|
||||||
|
|
||||||
dns_credential.get_list({ provider: data.provider }).then(r => {
|
dns_credential.get_list({ provider: data.provider }).then(r => {
|
||||||
r.data.forEach(v => {
|
r.data.forEach(v => {
|
||||||
credentials.value.push({
|
credentials.value?.push({
|
||||||
value: v.id,
|
value: v.id,
|
||||||
label: v.name,
|
label: v.name,
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,12 +2,14 @@
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import Modal from 'ant-design-vue/lib/modal'
|
import Modal from 'ant-design-vue/lib/modal'
|
||||||
import { message } from 'ant-design-vue'
|
import { message } from 'ant-design-vue'
|
||||||
|
import type { Ref } from 'vue'
|
||||||
import websocket from '@/lib/websocket'
|
import websocket from '@/lib/websocket'
|
||||||
import template from '@/api/template'
|
import template from '@/api/template'
|
||||||
import domain from '@/api/domain'
|
import domain from '@/api/domain'
|
||||||
import AutoCertStepOne from '@/views/domain/cert/components/AutoCertStepOne.vue'
|
import AutoCertStepOne from '@/views/domain/cert/components/AutoCertStepOne.vue'
|
||||||
import type DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue'
|
import type { NgxConfig, NgxDirective } from '@/api/ngx'
|
||||||
import type { NgxDirective } from '@/api/ngx'
|
import type { Props } from '@/views/domain/cert/IssueCert.vue'
|
||||||
|
import type { DnsChallenge } from '@/api/auto_cert'
|
||||||
|
|
||||||
const emit = defineEmits(['update:auto_cert'])
|
const emit = defineEmits(['update:auto_cert'])
|
||||||
|
|
||||||
|
@ -15,14 +17,14 @@ const { $gettext, interpolate } = useGettext()
|
||||||
|
|
||||||
const modalVisible = ref(false)
|
const modalVisible = ref(false)
|
||||||
const step = ref(1)
|
const step = ref(1)
|
||||||
const directivesMap = inject('directivesMap') as Record<string, NgxDirective[]>
|
const directivesMap = inject('directivesMap') as Ref<Record<string, NgxDirective[]>>
|
||||||
|
|
||||||
const progressStrokeColor = {
|
const progressStrokeColor = {
|
||||||
from: '#108ee9',
|
from: '#108ee9',
|
||||||
to: '#87d068',
|
to: '#87d068',
|
||||||
}
|
}
|
||||||
|
|
||||||
const data: DNSChallenge = reactive({
|
const data: DnsChallenge = reactive({
|
||||||
dns_credential_id: 0,
|
dns_credential_id: 0,
|
||||||
challenge_method: 'http01',
|
challenge_method: 'http01',
|
||||||
code: '',
|
code: '',
|
||||||
|
@ -40,15 +42,15 @@ provide('data', data)
|
||||||
|
|
||||||
const logContainer = ref()
|
const logContainer = ref()
|
||||||
|
|
||||||
const save_site_config = inject('save_site_config')
|
const save_site_config = inject('save_site_config') as () => Promise<void>
|
||||||
const no_server_name = inject('no_server_name')
|
const no_server_name = inject('no_server_name') as Ref<boolean>
|
||||||
const props = inject('props')
|
const props = inject('props') as Props
|
||||||
const issuing_cert = inject('issuing_cert')
|
const issuing_cert = inject('issuing_cert') as Ref<boolean>
|
||||||
const ngx_config = inject('ngx_config')
|
const ngx_config = inject('ngx_config') as NgxConfig
|
||||||
const current_server_directives = inject('current_server_directives')
|
const current_server_directives = inject('current_server_directives') as NgxDirective[]
|
||||||
|
|
||||||
const name = computed(() => {
|
const name = computed(() => {
|
||||||
return directivesMap.server_name[0].params.trim()
|
return directivesMap.value.server_name[0].params.trim()
|
||||||
})
|
})
|
||||||
|
|
||||||
const issue_cert = async (config_name: string, server_name: string) => {
|
const issue_cert = async (config_name: string, server_name: string) => {
|
||||||
|
@ -101,9 +103,9 @@ const issue_cert = async (config_name: string, server_name: string) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function callback(ssl_certificate: string, ssl_certificate_key: string) {
|
async function callback(ssl_certificate: string, ssl_certificate_key: string) {
|
||||||
directivesMap.ssl_certificate[0].params = ssl_certificate
|
directivesMap.value.ssl_certificate[0].params = ssl_certificate
|
||||||
directivesMap.ssl_certificate_key[0].params = ssl_certificate_key
|
directivesMap.value.ssl_certificate_key[0].params = ssl_certificate_key
|
||||||
save_site_config()
|
await save_site_config()
|
||||||
}
|
}
|
||||||
|
|
||||||
function change_auto_cert(status: boolean) {
|
function change_auto_cert(status: boolean) {
|
||||||
|
@ -119,7 +121,7 @@ function change_auto_cert(status: boolean) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
domain.remove_auto_cert(props.config_name).then(() => {
|
domain.remove_auto_cert(props.configName).then(() => {
|
||||||
message.success(interpolate($gettext('Auto-renewal disabled for %{name}'), { name: name.value }))
|
message.success(interpolate($gettext('Auto-renewal disabled for %{name}'), { name: name.value }))
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
message.error(e.message ?? interpolate($gettext('Disable auto-renewal failed for %{name}'), { name: name.value }))
|
message.error(e.message ?? interpolate($gettext('Disable auto-renewal failed for %{name}'), { name: name.value }))
|
||||||
|
@ -131,23 +133,23 @@ async function onchange(status: boolean) {
|
||||||
if (status) {
|
if (status) {
|
||||||
await template.get_block('letsencrypt.conf').then(r => {
|
await template.get_block('letsencrypt.conf').then(r => {
|
||||||
ngx_config.servers.forEach(async v => {
|
ngx_config.servers.forEach(async v => {
|
||||||
v.locations = v.locations.filter(l => l.path !== '/.well-known/acme-challenge')
|
v.locations = v?.locations?.filter(l => l.path !== '/.well-known/acme-challenge')
|
||||||
|
|
||||||
v.locations.push(...r.locations)
|
v.locations?.push(...r.locations)
|
||||||
})
|
})
|
||||||
}).then(async () => {
|
}).then(async () => {
|
||||||
// if ssl_certificate is empty, do not save, just use the config from last step.
|
// if ssl_certificate is empty, do not save, just use the config from last step.
|
||||||
if (directivesMap.ssl_certificate?.[0])
|
if (directivesMap.value.ssl_certificate?.[0])
|
||||||
await save_site_config()
|
await save_site_config()
|
||||||
|
|
||||||
job()
|
job()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
await ngx_config.servers.forEach(v => {
|
ngx_config.servers.forEach(v => {
|
||||||
v.locations = v.locations.filter(l => l.path !== '/.well-known/acme-challenge')
|
v.locations = v?.locations?.filter(l => l.path !== '/.well-known/acme-challenge')
|
||||||
})
|
})
|
||||||
save_site_config()
|
await save_site_config()
|
||||||
change_auto_cert(status)
|
change_auto_cert(status)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,26 +167,26 @@ function job() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const server_name = directivesMap.server_name[0]
|
const server_name_idx = directivesMap.value.server_name[0]?.idx ?? 0
|
||||||
|
|
||||||
if (!directivesMap.ssl_certificate) {
|
if (!directivesMap.value.ssl_certificate) {
|
||||||
current_server_directives.splice(server_name.idx + 1, 0, {
|
current_server_directives.splice(server_name_idx + 1, 0, {
|
||||||
directive: 'ssl_certificate',
|
directive: 'ssl_certificate',
|
||||||
params: '',
|
params: '',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
if (!directivesMap.ssl_certificate_key) {
|
if (!directivesMap.value.ssl_certificate_key) {
|
||||||
const ssl_certificate = directivesMap.ssl_certificate[0]
|
const ssl_certificate_idx = directivesMap.value.ssl_certificate[0]?.idx ?? 0
|
||||||
|
|
||||||
current_server_directives.splice(ssl_certificate.idx + 1, 0, {
|
current_server_directives.splice(ssl_certificate_idx + 1, 0, {
|
||||||
directive: 'ssl_certificate_key',
|
directive: 'ssl_certificate_key',
|
||||||
params: '',
|
params: '',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
issue_cert(props.config_name, name.value)
|
issue_cert(props.configName, name.value)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ const node_map = reactive({})
|
||||||
const target = ref([])
|
const target = ref([])
|
||||||
const overwrite = ref(false)
|
const overwrite = ref(false)
|
||||||
const enabled = ref(false)
|
const enabled = ref(false)
|
||||||
const name = inject('name')
|
const name = inject('name') as Ref<string>
|
||||||
|
|
||||||
function deploy() {
|
function deploy() {
|
||||||
Modal.confirm({
|
Modal.confirm({
|
||||||
|
|
|
@ -9,14 +9,16 @@ import ChatGPT from '@/components/ChatGPT/ChatGPT.vue'
|
||||||
import { formatDateTime } from '@/lib/helper'
|
import { formatDateTime } from '@/lib/helper'
|
||||||
import Deploy from '@/views/domain/components/Deploy.vue'
|
import Deploy from '@/views/domain/components/Deploy.vue'
|
||||||
import { useSettingsStore } from '@/pinia'
|
import { useSettingsStore } from '@/pinia'
|
||||||
|
import type { ChatComplicationMessage } from '@/api/openai'
|
||||||
|
import type { NgxConfig } from '@/api/ngx'
|
||||||
|
|
||||||
const settings = useSettingsStore()
|
const settings = useSettingsStore()
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
const configText = inject('configText')
|
const configText = inject('configText') as Ref<string>
|
||||||
const ngx_config = inject('ngx_config')
|
const ngx_config = inject('ngx_config') as Ref<NgxConfig>
|
||||||
const enabled = inject('enabled')
|
const enabled = inject('enabled') as Ref<boolean>
|
||||||
const name = inject('name')
|
const name = inject('name') as Ref<string>
|
||||||
const history_chatgpt_record = inject('history_chatgpt_record')
|
const history_chatgpt_record = inject('history_chatgpt_record') as Ref<ChatComplicationMessage[]>
|
||||||
const filename = inject('filename')
|
const filename = inject('filename')
|
||||||
const data: Ref<Site> = inject('data') as Ref<Site>
|
const data: Ref<Site> = inject('data') as Ref<Site>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { computed, nextTick, reactive, ref, watch } from 'vue'
|
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import { Form, message, notification } from 'ant-design-vue'
|
import { Form, message, notification } from 'ant-design-vue'
|
||||||
import gettext from '@/gettext'
|
import gettext from '@/gettext'
|
||||||
|
@ -27,7 +26,12 @@ const show = computed({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const modelRef = reactive({ name: '', target: [] })
|
interface Model {
|
||||||
|
name: string // site name
|
||||||
|
target: number[] // ids of deploy targets
|
||||||
|
}
|
||||||
|
|
||||||
|
const modelRef: Model = reactive({ name: '', target: [] })
|
||||||
|
|
||||||
const rulesRef = reactive({
|
const rulesRef = reactive({
|
||||||
name: [
|
name: [
|
||||||
|
@ -49,7 +53,7 @@ const { validate, validateInfos, clearValidate } = Form.useForm(modelRef, rulesR
|
||||||
|
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
|
|
||||||
const node_map = reactive({})
|
const node_map: Record<number, string> = reactive({})
|
||||||
|
|
||||||
function onSubmit() {
|
function onSubmit() {
|
||||||
validate().then(async () => {
|
validate().then(async () => {
|
||||||
|
|
|
@ -33,13 +33,13 @@ function add() {
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
adding.value = false
|
adding.value = false
|
||||||
ngx_config.servers[props.currentServerIndex].locations?.push({
|
ngx_config.servers[props.currentServerIndex!].locations?.push({
|
||||||
...location,
|
...location,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function remove(index: number) {
|
function remove(index: number) {
|
||||||
ngx_config.servers[props.currentServerIndex].locations?.splice(index, 1)
|
ngx_config.servers[props.currentServerIndex!].locations?.splice(index, 1)
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ const errorIdx = ref()
|
||||||
|
|
||||||
const hasAccessLog = computed(() => {
|
const hasAccessLog = computed(() => {
|
||||||
let flag = false
|
let flag = false
|
||||||
props.ngxConfig.servers[props.currentServerIdx].directives.forEach((v, k) => {
|
props.ngxConfig?.servers[props.currentServerIdx].directives?.forEach((v, k) => {
|
||||||
if (v.directive === 'access_log') {
|
if (v.directive === 'access_log') {
|
||||||
flag = true
|
flag = true
|
||||||
accessIdx.value = k
|
accessIdx.value = k
|
||||||
|
@ -29,7 +29,7 @@ const hasAccessLog = computed(() => {
|
||||||
|
|
||||||
const hasErrorLog = computed(() => {
|
const hasErrorLog = computed(() => {
|
||||||
let flag = false
|
let flag = false
|
||||||
props.ngxConfig.servers[props.currentServerIdx].directives.forEach((v, k) => {
|
props.ngxConfig?.servers[props.currentServerIdx].directives?.forEach((v, k) => {
|
||||||
if (v.directive === 'error_log') {
|
if (v.directive === 'error_log') {
|
||||||
flag = true
|
flag = true
|
||||||
errorIdx.value = k
|
errorIdx.value = k
|
||||||
|
|
|
@ -27,7 +27,7 @@ const emit = defineEmits(['callback', 'update:auto_cert'])
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const save_site_config = inject('save_site_config')!
|
const save_site_config = inject('save_site_config') as () => Promise<void>
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
|
@ -68,7 +68,7 @@ const current_server_directives = computed(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
const directivesMap: ComputedRef<Record<string, NgxDirective[]>> = computed(() => {
|
const directivesMap: ComputedRef<Record<string, NgxDirective[]>> = computed(() => {
|
||||||
const map = {}
|
const map: Record<string, NgxDirective[]> = {}
|
||||||
|
|
||||||
current_server_directives.value?.forEach((v, k) => {
|
current_server_directives.value?.forEach((v, k) => {
|
||||||
v.idx = k
|
v.idx = k
|
||||||
|
@ -81,6 +81,7 @@ const directivesMap: ComputedRef<Record<string, NgxDirective[]>> = computed(() =
|
||||||
return map
|
return map
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// eslint-disable-next-line sonarjs/cognitive-complexity
|
||||||
function change_tls(status: boolean) {
|
function change_tls(status: boolean) {
|
||||||
if (status) {
|
if (status) {
|
||||||
// deep copy servers[0] to servers[1]
|
// deep copy servers[0] to servers[1]
|
||||||
|
@ -93,15 +94,15 @@ function change_tls(status: boolean) {
|
||||||
const servers = ngx_config.servers
|
const servers = ngx_config.servers
|
||||||
|
|
||||||
let i = 0
|
let i = 0
|
||||||
while (i < servers[1].directives.length) {
|
while (i < (servers?.[1].directives?.length ?? 0)) {
|
||||||
const v = servers[1].directives[i]
|
const v = servers?.[1]?.directives?.[i]
|
||||||
if (v.directive === 'listen')
|
if (v?.directive === 'listen')
|
||||||
servers[1].directives.splice(i, 1)
|
servers[1]?.directives?.splice(i, 1)
|
||||||
else
|
else
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
|
|
||||||
servers[1].directives.splice(0, 0, {
|
servers?.[1]?.directives?.splice(0, 0, {
|
||||||
directive: 'listen',
|
directive: 'listen',
|
||||||
params: '443 ssl',
|
params: '443 ssl',
|
||||||
}, {
|
}, {
|
||||||
|
@ -112,10 +113,10 @@ function change_tls(status: boolean) {
|
||||||
params: 'on',
|
params: 'on',
|
||||||
})
|
})
|
||||||
|
|
||||||
const server_name = directivesMap.value.server_name[0]
|
const server_name_idx = directivesMap.value?.server_name?.[0].idx ?? 0
|
||||||
|
|
||||||
if (!directivesMap.value.ssl_certificate) {
|
if (!directivesMap.value.ssl_certificate) {
|
||||||
servers[1].directives.splice(server_name.idx + 1, 0, {
|
servers?.[1]?.directives?.splice(server_name_idx + 1, 0, {
|
||||||
directive: 'ssl_certificate',
|
directive: 'ssl_certificate',
|
||||||
params: '',
|
params: '',
|
||||||
})
|
})
|
||||||
|
@ -123,7 +124,7 @@ function change_tls(status: boolean) {
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (!directivesMap.value.ssl_certificate_key) {
|
if (!directivesMap.value.ssl_certificate_key) {
|
||||||
servers[1].directives.splice(server_name.idx + 2, 0, {
|
servers?.[1]?.directives?.splice(server_name_idx + 2, 0, {
|
||||||
directive: 'ssl_certificate_key',
|
directive: 'ssl_certificate_key',
|
||||||
params: '',
|
params: '',
|
||||||
})
|
})
|
||||||
|
@ -144,8 +145,8 @@ const support_ssl = computed(() => {
|
||||||
const servers = ngx_config.servers
|
const servers = ngx_config.servers
|
||||||
for (const server_key in servers) {
|
for (const server_key in servers) {
|
||||||
for (const k in servers[server_key].directives) {
|
for (const k in servers[server_key].directives) {
|
||||||
const v = servers[server_key].directives[k]
|
const v = servers?.[server_key]?.directives?.[Number.parseInt(k)]
|
||||||
if (v.directive === 'listen' && v.params.indexOf('ssl') > 0)
|
if (v?.directive === 'listen' && v?.params?.indexOf('ssl') > 0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,10 +52,10 @@ async function add() {
|
||||||
ngx_config.custom = ngx_config.custom?.trim()
|
ngx_config.custom = ngx_config.custom?.trim()
|
||||||
|
|
||||||
if (data.value.locations)
|
if (data.value.locations)
|
||||||
ngx_config.servers[props.currentServerIndex].locations.push(...data.value.locations)
|
ngx_config?.servers?.[props.currentServerIndex]?.locations?.push(...data.value.locations)
|
||||||
|
|
||||||
if (data.value.directives)
|
if (data.value.directives)
|
||||||
ngx_config.servers[props.currentServerIndex].directives.push(...data.value.directives)
|
ngx_config?.servers?.[props.currentServerIndex]?.directives?.push(...data.value.directives)
|
||||||
|
|
||||||
visible.value = false
|
visible.value = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,9 +9,9 @@ const props = defineProps<{
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
'update:data': (data: {
|
'update:data': [data: {
|
||||||
[key: string]: Variable
|
[key: string]: Variable
|
||||||
}) => void
|
}]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const data = computed({
|
const data = computed({
|
||||||
|
@ -30,7 +30,7 @@ const data = computed({
|
||||||
v-for="(_, k) in data"
|
v-for="(_, k) in data"
|
||||||
:key="k"
|
:key="k"
|
||||||
v-model:data="data[k]"
|
v-model:data="data[k]"
|
||||||
:name="k"
|
:name="k.toString()"
|
||||||
/>
|
/>
|
||||||
</AForm>
|
</AForm>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -10,7 +10,7 @@ const props = defineProps<{
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const emit = defineEmits<{
|
const emit = defineEmits<{
|
||||||
'update:data': (data: Variable) => void
|
'update:data': [data: Variable]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const data = computed({
|
const data = computed({
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { reactive, ref } from 'vue'
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import { DeleteOutlined } from '@ant-design/icons-vue'
|
import { DeleteOutlined } from '@ant-design/icons-vue'
|
||||||
import CodeEditor from '@/components/CodeEditor'
|
import CodeEditor from '@/components/CodeEditor'
|
||||||
|
import type { NgxDirective } from '@/api/ngx'
|
||||||
|
|
||||||
const props = defineProps<{
|
const props = defineProps<{
|
||||||
idx?: number
|
idx?: number
|
||||||
|
@ -12,7 +13,7 @@ const emit = defineEmits(['save'])
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const ngx_directives = inject('ngx_directives')
|
const ngx_directives = inject('ngx_directives') as NgxDirective[]
|
||||||
const directive = reactive({ directive: '', params: '' })
|
const directive = reactive({ directive: '', params: '' })
|
||||||
const adding = ref(false)
|
const adding = ref(false)
|
||||||
const mode = ref('default')
|
const mode = ref('default')
|
||||||
|
|
|
@ -26,7 +26,7 @@ const content = ref('')
|
||||||
function init() {
|
function init() {
|
||||||
if (ngx_directives[props.index].directive === 'include') {
|
if (ngx_directives[props.index].directive === 'include') {
|
||||||
config.get(ngx_directives[props.index].params).then(r => {
|
config.get(ngx_directives[props.index].params).then(r => {
|
||||||
content.value = r.config
|
content.value = r.content
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ watch(props, init)
|
||||||
|
|
||||||
function save() {
|
function save() {
|
||||||
config.save(ngx_directives[props.index].params, { content: content.value }).then(r => {
|
config.save(ngx_directives[props.index].params, { content: content.value }).then(r => {
|
||||||
content.value = r.config
|
content.value = r.content
|
||||||
message.success($gettext('Saved successfully'))
|
message.success($gettext('Saved successfully'))
|
||||||
}).catch(r => {
|
}).catch(r => {
|
||||||
message.error(interpolate($gettext('Save error %{msg}'), { msg: r.message ?? '' }))
|
message.error(interpolate($gettext('Save error %{msg}'), { msg: r.message ?? '' }))
|
||||||
|
|
|
@ -7,13 +7,14 @@ import { datetime } from '@/components/StdDesign/StdDataDisplay/StdTableTransfor
|
||||||
import environment from '@/api/environment'
|
import environment from '@/api/environment'
|
||||||
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
|
import StdCurd from '@/components/StdDesign/StdDataDisplay/StdCurd.vue'
|
||||||
import { input } from '@/components/StdDesign/StdDataEntry'
|
import { input } from '@/components/StdDesign/StdDataEntry'
|
||||||
|
import type { Column } from '@/components/StdDesign/types'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const columns = [{
|
const columns: Column[] = [{
|
||||||
title: () => $gettext('Name'),
|
title: () => $gettext('Name'),
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
edit: {
|
edit: {
|
||||||
type: input,
|
type: input,
|
||||||
|
@ -22,18 +23,20 @@ const columns = [{
|
||||||
{
|
{
|
||||||
title: () => $gettext('URL'),
|
title: () => $gettext('URL'),
|
||||||
dataIndex: 'url',
|
dataIndex: 'url',
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
edit: {
|
edit: {
|
||||||
type: input,
|
type: input,
|
||||||
placeholder: () => 'https://10.0.0.1:9000',
|
config: {
|
||||||
|
placeholder: () => 'https://10.0.0.1:9000',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: () => 'NodeSecret',
|
title: () => 'NodeSecret',
|
||||||
dataIndex: 'token',
|
dataIndex: 'token',
|
||||||
sorter: true,
|
sortable: true,
|
||||||
display: false,
|
hidden: true,
|
||||||
edit: {
|
edit: {
|
||||||
type: input,
|
type: input,
|
||||||
},
|
},
|
||||||
|
@ -88,14 +91,14 @@ const columns = [{
|
||||||
|
|
||||||
return h('div', template)
|
return h('div', template)
|
||||||
},
|
},
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: () => $gettext('Updated at'),
|
title: () => $gettext('Updated at'),
|
||||||
dataIndex: 'updated_at',
|
dataIndex: 'updated_at',
|
||||||
customRender: datetime,
|
customRender: datetime,
|
||||||
sorter: true,
|
sortable: true,
|
||||||
pithy: true,
|
pithy: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
import type { Ref, UnwrapNestedRefs } from 'vue'
|
|
||||||
import { computed, nextTick, onMounted, onUnmounted, reactive, ref, watch } from 'vue'
|
|
||||||
import type ReconnectingWebSocket from 'reconnecting-websocket'
|
import type ReconnectingWebSocket from 'reconnecting-websocket'
|
||||||
import { useRoute, useRouter } from 'vue-router'
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
import { debounce } from 'lodash'
|
import { debounce } from 'lodash'
|
||||||
|
@ -11,7 +9,7 @@ import nginx_log from '@/api/nginx_log'
|
||||||
import ws from '@/lib/websocket'
|
import ws from '@/lib/websocket'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
const logContainer: Ref<Element> = ref()!
|
const logContainer = ref()
|
||||||
let websocket: ReconnectingWebSocket | WebSocket
|
let websocket: ReconnectingWebSocket | WebSocket
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const buffer = ref('')
|
const buffer = ref('')
|
||||||
|
@ -21,7 +19,7 @@ const router = useRouter()
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const filter = ref('')
|
const filter = ref('')
|
||||||
|
|
||||||
const control: UnwrapNestedRefs<INginxLogData> = reactive({
|
const control: INginxLogData = reactive({
|
||||||
type: logType(),
|
type: logType(),
|
||||||
conf_name: route.query.conf_name as string,
|
conf_name: route.query.conf_name as string,
|
||||||
server_idx: Number.parseInt(route.query.server_idx as string),
|
server_idx: Number.parseInt(route.query.server_idx as string),
|
||||||
|
@ -53,10 +51,8 @@ function addLog(data: string, prepend: boolean = false) {
|
||||||
buffer.value += data
|
buffer.value += data
|
||||||
|
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
const elem = (logContainer.value as Element)
|
logContainer.value?.scroll({
|
||||||
|
top: logContainer.value.scrollHeight,
|
||||||
elem?.scroll({
|
|
||||||
top: elem.scrollHeight,
|
|
||||||
left: 0,
|
left: 0,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,6 +2,17 @@
|
||||||
import { useGettext } from 'vue3-gettext'
|
import { useGettext } from 'vue3-gettext'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
|
const info = computed(() => {
|
||||||
|
if (typeof route.meta.error === 'function')
|
||||||
|
return route.meta.error()
|
||||||
|
else if (typeof route.meta.error === 'string')
|
||||||
|
return route.meta.error
|
||||||
|
else
|
||||||
|
return $gettext('File Not Found')
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
@ -9,7 +20,7 @@ const { $gettext } = useGettext()
|
||||||
<h1 class="title">
|
<h1 class="title">
|
||||||
{{ $route.meta.status_code || 404 }}
|
{{ $route.meta.status_code || 404 }}
|
||||||
</h1>
|
</h1>
|
||||||
<p>{{ $route.meta.error?.() ?? $gettext('File Not Found') }}</p>
|
<p>{{ info }}</p>
|
||||||
<AButton
|
<AButton
|
||||||
type="primary"
|
type="primary"
|
||||||
@click="$router.push('/')"
|
@click="$router.push('/')"
|
||||||
|
|
|
@ -95,7 +95,7 @@ const loginWithCasdoor = () => {
|
||||||
|
|
||||||
if (route.query?.code !== undefined && route.query?.state !== undefined) {
|
if (route.query?.code !== undefined && route.query?.state !== undefined) {
|
||||||
loading.value = true
|
loading.value = true
|
||||||
auth.casdoor_login(route.query.code.toString(), route.query.state.toString()).then(async () => {
|
auth.casdoor_login(route.query?.code?.toString(), route.query?.state?.toString()).then(async () => {
|
||||||
message.success($gettext('Login successful'), 1)
|
message.success($gettext('Login successful'), 1)
|
||||||
|
|
||||||
const next = (route.query?.next || '').toString() || '/'
|
const next = (route.query?.next || '').toString() || '/'
|
||||||
|
|
|
@ -10,7 +10,7 @@ import ws from '@/lib/websocket'
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
let term: Terminal | null
|
let term: Terminal | null
|
||||||
let ping: NodeJS.Timer | null
|
let ping: number
|
||||||
|
|
||||||
const websocket = ws('/api/pty')
|
const websocket = ws('/api/pty')
|
||||||
|
|
||||||
|
@ -83,9 +83,9 @@ function wsOnOpen() {
|
||||||
|
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
window.removeEventListener('resize', fit)
|
window.removeEventListener('resize', fit)
|
||||||
clearInterval(ping as number)
|
clearInterval(ping)
|
||||||
term?.dispose()
|
term?.dispose()
|
||||||
ping = null
|
ping = 0
|
||||||
websocket.close()
|
websocket.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -8,22 +8,13 @@ import { message } from 'ant-design-vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import websocket from '@/lib/websocket'
|
import websocket from '@/lib/websocket'
|
||||||
import version from '@/version.json'
|
import version from '@/version.json'
|
||||||
|
import type { RuntimeInfo } from '@/api/upgrade'
|
||||||
import upgrade from '@/api/upgrade'
|
import upgrade from '@/api/upgrade'
|
||||||
|
|
||||||
const { $gettext } = useGettext()
|
const { $gettext } = useGettext()
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
const data = ref({}) as Ref<RuntimeInfo>
|
||||||
interface APIData {
|
|
||||||
name: string
|
|
||||||
os: string
|
|
||||||
arch: string
|
|
||||||
ex_path: string
|
|
||||||
body: string
|
|
||||||
published_at: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const data: Ref<APIData> = ref({})
|
|
||||||
const last_check = ref('')
|
const last_check = ref('')
|
||||||
const loading = ref(false)
|
const loading = ref(false)
|
||||||
const channel = ref('stable')
|
const channel = ref('stable')
|
||||||
|
@ -65,16 +56,16 @@ const is_latest_ver = computed(() => {
|
||||||
return data.value.name === `v${version.version}`
|
return data.value.name === `v${version.version}`
|
||||||
})
|
})
|
||||||
|
|
||||||
const logContainer = ref(null)
|
const logContainer = ref()
|
||||||
|
|
||||||
function log(msg: string) {
|
function log(msg: string) {
|
||||||
const para = document.createElement('p')
|
const para = document.createElement('p')
|
||||||
|
|
||||||
para.appendChild(document.createTextNode($gettext(msg)));
|
para.appendChild(document.createTextNode($gettext(msg)))
|
||||||
|
|
||||||
(logContainer.value as Element).appendChild(para);
|
logContainer.value.appendChild(para)
|
||||||
|
|
||||||
(logContainer.value as Element).scroll({ top: 320, left: 0, behavior: 'smooth' })
|
logContainer.value.scroll({ top: 320, left: 0, behavior: 'smooth' })
|
||||||
}
|
}
|
||||||
|
|
||||||
const dry_run = computed(() => {
|
const dry_run = computed(() => {
|
||||||
|
@ -85,8 +76,8 @@ async function perform_upgrade() {
|
||||||
progressStatus.value = 'active'
|
progressStatus.value = 'active'
|
||||||
modalClosable.value = false
|
modalClosable.value = false
|
||||||
modalVisible.value = true
|
modalVisible.value = true
|
||||||
progressPercent.value = 0;
|
progressPercent.value = 0
|
||||||
(logContainer.value as Element).innerHTML = ''
|
logContainer.value.innerHTML = ''
|
||||||
|
|
||||||
log($gettext('Upgrading Nginx UI, please wait...'))
|
log($gettext('Upgrading Nginx UI, please wait...'))
|
||||||
|
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"version":"2.0.0-beta.4","build_id":56,"total_build":260}
|
{"version":"2.0.0-beta.4","build_id":62,"total_build":266}
|
|
@ -6,18 +6,18 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Usage struct {
|
type Usage[T uint64 | float64] struct {
|
||||||
Time time.Time `json:"x"`
|
Time time.Time `json:"x"`
|
||||||
Usage interface{} `json:"y"`
|
Usage T `json:"y"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
CpuUserRecord []Usage
|
CpuUserRecord []Usage[float64]
|
||||||
CpuTotalRecord []Usage
|
CpuTotalRecord []Usage[float64]
|
||||||
NetRecvRecord []Usage
|
NetRecvRecord []Usage[uint64]
|
||||||
NetSentRecord []Usage
|
NetSentRecord []Usage[uint64]
|
||||||
DiskWriteRecord []Usage
|
DiskWriteRecord []Usage[uint64]
|
||||||
DiskReadRecord []Usage
|
DiskReadRecord []Usage[uint64]
|
||||||
LastDiskWrites uint64
|
LastDiskWrites uint64
|
||||||
LastDiskReads uint64
|
LastDiskReads uint64
|
||||||
LastNetSent uint64
|
LastNetSent uint64
|
||||||
|
@ -37,9 +37,10 @@ func init() {
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
// init record slices
|
// init record slices
|
||||||
for i := 100; i > 0; i-- {
|
for i := 100; i > 0; i-- {
|
||||||
u := Usage{Time: now.Add(time.Duration(-i) * time.Second), Usage: 0}
|
uf := Usage[float64]{Time: now.Add(time.Duration(-i) * time.Second), Usage: 0}
|
||||||
CpuUserRecord = append(CpuUserRecord, u)
|
CpuUserRecord = append(CpuUserRecord, uf)
|
||||||
CpuTotalRecord = append(CpuTotalRecord, u)
|
CpuTotalRecord = append(CpuTotalRecord, uf)
|
||||||
|
u := Usage[uint64]{Time: now.Add(time.Duration(-i) * time.Second), Usage: 0}
|
||||||
NetRecvRecord = append(NetRecvRecord, u)
|
NetRecvRecord = append(NetRecvRecord, u)
|
||||||
NetSentRecord = append(NetSentRecord, u)
|
NetSentRecord = append(NetSentRecord, u)
|
||||||
DiskWriteRecord = append(DiskWriteRecord, u)
|
DiskWriteRecord = append(DiskWriteRecord, u)
|
||||||
|
|
|
@ -41,14 +41,14 @@ func recordCpu(now time.Time) {
|
||||||
cpuSystemUsage := (cpuTimesAfter[0].System - cpuTimesBefore[0].System) / (float64(1000*threadNum) / 1000)
|
cpuSystemUsage := (cpuTimesAfter[0].System - cpuTimesBefore[0].System) / (float64(1000*threadNum) / 1000)
|
||||||
cpuSystemUsage *= 100
|
cpuSystemUsage *= 100
|
||||||
|
|
||||||
u := Usage{
|
u := Usage[float64]{
|
||||||
Time: now,
|
Time: now,
|
||||||
Usage: cpuUserUsage,
|
Usage: cpuUserUsage,
|
||||||
}
|
}
|
||||||
|
|
||||||
CpuUserRecord = append(CpuUserRecord, u)
|
CpuUserRecord = append(CpuUserRecord, u)
|
||||||
|
|
||||||
s := Usage{
|
s := Usage[float64]{
|
||||||
Time: now,
|
Time: now,
|
||||||
Usage: cpuUserUsage + cpuSystemUsage,
|
Usage: cpuUserUsage + cpuSystemUsage,
|
||||||
}
|
}
|
||||||
|
@ -75,11 +75,11 @@ func recordNetwork(now time.Time) {
|
||||||
if len(network) == 0 {
|
if len(network) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
NetRecvRecord = append(NetRecvRecord, Usage{
|
NetRecvRecord = append(NetRecvRecord, Usage[uint64]{
|
||||||
Time: now,
|
Time: now,
|
||||||
Usage: network[0].BytesRecv - LastNetRecv,
|
Usage: network[0].BytesRecv - LastNetRecv,
|
||||||
})
|
})
|
||||||
NetSentRecord = append(NetSentRecord, Usage{
|
NetSentRecord = append(NetSentRecord, Usage[uint64]{
|
||||||
Time: now,
|
Time: now,
|
||||||
Usage: network[0].BytesSent - LastNetSent,
|
Usage: network[0].BytesSent - LastNetSent,
|
||||||
})
|
})
|
||||||
|
@ -96,11 +96,11 @@ func recordNetwork(now time.Time) {
|
||||||
func recordDiskIO(now time.Time) {
|
func recordDiskIO(now time.Time) {
|
||||||
readCount, writeCount := getTotalDiskIO()
|
readCount, writeCount := getTotalDiskIO()
|
||||||
|
|
||||||
DiskReadRecord = append(DiskReadRecord, Usage{
|
DiskReadRecord = append(DiskReadRecord, Usage[uint64]{
|
||||||
Time: now,
|
Time: now,
|
||||||
Usage: readCount - LastDiskReads,
|
Usage: readCount - LastDiskReads,
|
||||||
})
|
})
|
||||||
DiskWriteRecord = append(DiskWriteRecord, Usage{
|
DiskWriteRecord = append(DiskWriteRecord, Usage[uint64]{
|
||||||
Time: now,
|
Time: now,
|
||||||
Usage: writeCount - LastDiskWrites,
|
Usage: writeCount - LastDiskWrites,
|
||||||
})
|
})
|
||||||
|
|
|
@ -23,11 +23,11 @@ type MemStat struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiskStat struct {
|
type DiskStat struct {
|
||||||
Total string `json:"total"`
|
Total string `json:"total"`
|
||||||
Used string `json:"used"`
|
Used string `json:"used"`
|
||||||
Percentage float64 `json:"percentage"`
|
Percentage float64 `json:"percentage"`
|
||||||
Writes Usage `json:"writes"`
|
Writes Usage[uint64] `json:"writes"`
|
||||||
Reads Usage `json:"reads"`
|
Reads Usage[uint64] `json:"reads"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetMemoryStat() (MemStat, error) {
|
func GetMemoryStat() (MemStat, error) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue