1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-19 00:09:16 +08:00

feat: merge code from dev (#7439)

This commit is contained in:
ssongliu 2024-12-19 22:21:00 +08:00 committed by GitHub
parent 7631c237e9
commit 7008774bb5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
39 changed files with 257 additions and 88 deletions

View File

@ -4,16 +4,17 @@ GOCLEAN=$(GOCMD) clean
GOARCH=$(shell go env GOARCH)
GOOS=$(shell go env GOOS )
BASE_PAH := $(shell pwd)
BUILD_PATH = $(BASE_PAH)/build
WEB_PATH=$(BASE_PAH)/frontend
ASSERT_PATH= $(BASE_PAH)/core/cmd/server/web/assets
BASE_PATH := $(shell pwd)
BUILD_PATH = $(BASE_PATH)/build
WEB_PATH=$(BASE_PATH)/frontend
ASSERT_PATH= $(BASE_PATH)/core/cmd/server/web/assets
CORE_MAIN= $(BASE_PAH)/cmd/server/main.go
CORE_PATH=$(BASE_PATH)/core
CORE_MAIN=$(CORE_PATH)/cmd/server/main.go
CORE_NAME=1panel-core
AGENT_PATH=$(BASE_PAH)/agent
AGENT_MAIN= $(AGENT_PATH)/cmd/server/main.go
AGENT_PATH=$(BASE_PATH)/agent
AGENT_MAIN=$(AGENT_PATH)/cmd/server/main.go
AGENT_NAME=1panel-agent
@ -28,14 +29,16 @@ build_frontend:
cd $(WEB_PATH) && npm install && npm run build:pro
build_core_on_linux:
GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(CORE_NAME) $(CORE_MAIN)
cd $(CORE_PATH) \
&& GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(CORE_NAME) $(CORE_MAIN)
build_agent_on_linux:
cd $(AGENT_PATH) \
&& GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(AGENT_NAME) $(AGENT_MAIN)
build_core_on_darwin:
GOOS=linux GOARCH=amd64 $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(CORE_NAME) $(CORE_MAIN)
cd $(CORE_PATH) \
&& GOOS=linux GOARCH=amd64 $(GOBUILD) -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(CORE_NAME) $(CORE_MAIN)
build_agent_on_darwin:
cd $(AGENT_PATH) \
@ -50,10 +53,12 @@ build_agent_xpack_on_linux:
&& GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -tags=xpack -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(AGENT_NAME) $(AGENT_MAIN)
build_core_xpack_on_darwin:
GOOS=linux GOARCH=amd64 $(GOBUILD) -tags=xpack -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(CORE_NAME) $(CORE_MAIN)
cd $(CORE_PATH) \
&& GOOS=linux GOARCH=amd64 $(GOBUILD) -tags=xpack -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(CORE_NAME) $(CORE_MAIN)
build_core_xpack_on_linux:
GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -tags=xpack -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(CORE_NAME) $(CORE_MAIN)
cd $(CORE_PATH) \
&& GOOS=$(GOOS) GOARCH=$(GOARCH) $(GOBUILD) -tags=xpack -trimpath -ldflags '-s -w' -o $(BUILD_PATH)/$(CORE_NAME) $(CORE_MAIN)
build_all: build_frontend build_core_on_linux build_agent_on_linux

View File

@ -16,6 +16,8 @@ type DashboardBase struct {
KernelArch string `json:"kernelArch"`
KernelVersion string `json:"kernelVersion"`
VirtualizationSystem string `json:"virtualizationSystem"`
IpV4Addr string `json:"ipV4Addr"`
SystemProxy string `json:"systemProxy"`
CPUCores int `json:"cpuCores"`
CPULogicalCores int `json:"cpuLogicalCores"`

View File

@ -3,7 +3,9 @@ package service
import (
"encoding/json"
"fmt"
network "net"
"net/http"
"os"
"sort"
"strings"
"sync"
@ -130,6 +132,15 @@ func (u *DashboardService) LoadBaseInfo(ioOption string, netOption string) (*dto
baseInfo.KernelVersion = hostInfo.KernelVersion
ss, _ := json.Marshal(hostInfo)
baseInfo.VirtualizationSystem = string(ss)
baseInfo.IpV4Addr = GetOutboundIP()
httpProxy := os.Getenv("http_proxy")
if httpProxy == "" {
httpProxy = os.Getenv("HTTP_PROXY")
}
if httpProxy != "" {
baseInfo.SystemProxy = httpProxy
}
baseInfo.SystemProxy = "noProxy"
appInstall, err := appInstallRepo.ListBy()
if err != nil {
@ -518,3 +529,15 @@ func loadXpuInfo() []dto.XPUInfo {
}
return data
}
func GetOutboundIP() string {
conn, err := network.Dial("udp", "8.8.8.8:80")
if err != nil {
return "IPNotFound"
}
defer conn.Close()
localAddr := conn.LocalAddr().(*network.UDPAddr)
return localAddr.IP.String()
}

View File

@ -308,21 +308,58 @@ func (u *FirewallService) OperateForwardRule(req dto.ForwardRuleOperate) error {
}
rules, _ := client.ListForward()
i := 0
for _, rule := range rules {
shouldKeep := true
for i := range req.Rules {
reqRule := &req.Rules[i]
if reqRule.TargetIP == "" {
reqRule.TargetIP = "127.0.0.1"
}
if reqRule.Operation == "remove" {
for _, proto := range strings.Split(reqRule.Protocol, "/") {
if reqRule.Port == rule.Port &&
reqRule.TargetPort == rule.TargetPort &&
reqRule.TargetIP == rule.TargetIP &&
proto == rule.Protocol {
shouldKeep = false
break
}
}
}
}
if shouldKeep {
rules[i] = rule
i++
}
}
rules = rules[:i]
for _, rule := range rules {
for _, reqRule := range req.Rules {
if reqRule.Operation == "remove" {
continue
}
if reqRule.TargetIP == "" {
reqRule.TargetIP = "127.0.0.1"
}
if reqRule.Port == rule.Port && reqRule.TargetPort == rule.TargetPort && reqRule.TargetIP == rule.TargetIP {
return constant.ErrRecordExist
for _, proto := range strings.Split(reqRule.Protocol, "/") {
if reqRule.Port == rule.Port &&
reqRule.TargetPort == rule.TargetPort &&
reqRule.TargetIP == rule.TargetIP &&
proto == rule.Protocol {
return constant.ErrRecordExist
}
}
}
}
sort.SliceStable(req.Rules, func(i, j int) bool {
if req.Rules[i].Operation == "remove" && req.Rules[j].Operation != "remove" {
return true
}
if req.Rules[i].Operation != "remove" && req.Rules[j].Operation == "remove" {
return false
}
n1, _ := strconv.Atoi(req.Rules[i].Num)
n2, _ := strconv.Atoi(req.Rules[j].Num)
return n1 > n2

View File

@ -33,11 +33,13 @@ func Init() {
createDir(fileOp, dir)
}
_ = docker.CreateDefaultDockerNetwork()
go func() {
_ = docker.CreateDefaultDockerNetwork()
if f, err := firewall.NewFirewallClient(); err == nil {
_ = f.EnableForward()
}
if f, err := firewall.NewFirewallClient(); err == nil {
_ = f.EnableForward()
}
}()
}
func createDir(fileOp files.FileOp, dirPath string) {

View File

@ -6,7 +6,6 @@ import (
"github.com/1Panel-dev/1Panel/agent/i18n"
"github.com/1Panel-dev/1Panel/agent/middleware"
rou "github.com/1Panel-dev/1Panel/agent/router"
"github.com/gin-contrib/gzip"
"github.com/gin-gonic/gin"
)
@ -18,11 +17,6 @@ func Routers() *gin.Engine {
Router = gin.Default()
Router.Use(i18n.UseI18n())
PublicGroup := Router.Group("")
{
PublicGroup.Use(gzip.Gzip(gzip.DefaultCompression))
PublicGroup.Static("/api/v2/images", "./uploads")
}
PrivateGroup := Router.Group("/api/v2")
if !global.IsMaster {
PrivateGroup.Use(middleware.Certificate())

View File

@ -4,16 +4,16 @@ import (
"fmt"
"log"
"os"
"path"
"time"
"github.com/1Panel-dev/1Panel/agent/global"
"github.com/glebarez/sqlite"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
func LoadDBConnByPath(fullPath, dbName string) *gorm.DB {
if _, err := CreateDirWhenNotExist(true, global.CONF.System.DbPath); err != nil {
if _, err := CreateDirWhenNotExist(true, path.Dir(fullPath)); err != nil {
panic(fmt.Errorf("init db dir failed, err: %v", err))
}
if _, err := os.Stat(fullPath); err != nil {
@ -32,7 +32,7 @@ func LoadDBConnByPath(fullPath, dbName string) *gorm.DB {
}
func LoadDBConnByPathWithErr(fullPath, dbName string) (*gorm.DB, error) {
if _, err := CreateDirWhenNotExist(true, global.CONF.System.DbPath); err != nil {
if _, err := CreateDirWhenNotExist(true, path.Dir(fullPath)); err != nil {
return nil, fmt.Errorf("init db dir failed, err: %v", err)
}
if _, err := os.Stat(fullPath); err != nil {

View File

@ -5,6 +5,7 @@ import (
"database/sql"
"errors"
"fmt"
"net/url"
"time"
"github.com/1Panel-dev/1Panel/agent/buserr"
@ -31,8 +32,9 @@ func NewPostgresqlClient(conn client.DBInfo) (PostgresqlClient, error) {
connArgs := []string{"exec", conn.Address, "psql", "-t", "-U", conn.Username, "-c"}
return client.NewLocal(connArgs, conn.Address, conn.Username, conn.Password, conn.Database), nil
}
connArgs := fmt.Sprintf("postgres://%s:%s@%s:%d/?sslmode=disable", conn.Username, conn.Password, conn.Address, conn.Port)
escapedUsername := url.QueryEscape(conn.Username)
escapedPassword := url.QueryEscape(conn.Password)
connArgs := fmt.Sprintf("postgres://%s:%s@%s:%d/?sslmode=disable", escapedUsername, escapedPassword, conn.Address, conn.Port)
db, err := sql.Open("pgx", connArgs)
if err != nil {
return nil, err

View File

@ -135,7 +135,7 @@ func (r *Remote) Backup(info BackupInfo) error {
}
fileNameItem := info.TargetDir + "/" + strings.TrimSuffix(info.FileName, ".gz")
backupCommand := exec.Command("bash", "-c",
fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c 'PGPASSWORD=%s pg_dump -h %s -p %d --no-owner -Fc -U %s %s' > %s",
fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c 'PGPASSWORD=\"%s\" pg_dump -h %s -p %d --no-owner -Fc -U %s %s' > %s",
imageTag, r.Password, r.Address, r.Port, r.User, info.Name, fileNameItem))
_ = backupCommand.Run()
b := make([]byte, 5)
@ -178,7 +178,7 @@ func (r *Remote) Recover(info RecoverInfo) error {
}()
}
recoverCommand := exec.Command("bash", "-c",
fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c 'PGPASSWORD=%s pg_restore -h %s -p %d --verbose --clean --no-privileges --no-owner -Fc -U %s -d %s --role=%s' < %s",
fmt.Sprintf("docker run --rm --net=host -i %s /bin/bash -c 'PGPASSWORD=\"%s\" pg_restore -h %s -p %d --verbose --clean --no-privileges --no-owner -Fc -U %s -d %s --role=%s' < %s",
imageTag, r.Password, r.Address, r.Port, r.User, info.Name, info.Username, fileName))
pipe, _ := recoverCommand.StdoutPipe()
stderrPipe, _ := recoverCommand.StderrPipe()

View File

@ -3,6 +3,7 @@ package cmd
import (
"fmt"
"os/user"
"path"
"strings"
"time"
@ -42,11 +43,7 @@ func loadDBConn() (*gorm.DB, error) {
if len(baseDir) == 0 {
return nil, fmt.Errorf("error `BASE_DIR` find in /usr/local/bin/1pctl \n")
}
if strings.HasSuffix(baseDir, "/") {
baseDir = baseDir[:strings.LastIndex(baseDir, "/")]
}
db, err := gorm.Open(sqlite.Open(baseDir+"/1panel/db/core.db"), &gorm.Config{})
db, err := gorm.Open(sqlite.Open(path.Join(baseDir, "/1panel/db/core.db")), &gorm.Config{})
if err != nil {
return nil, fmt.Errorf("init my db conn failed, err: %v \n", err)
}

View File

@ -2,12 +2,11 @@ package cmd
import (
"fmt"
"github.com/1Panel-dev/1Panel/core/configs"
"github.com/1Panel-dev/1Panel/core/cmd/server/conf"
"gopkg.in/yaml.v3"
"github.com/1Panel-dev/1Panel/core/configs"
"github.com/spf13/cobra"
"gopkg.in/yaml.v3"
)
func init() {

View File

@ -32,6 +32,7 @@ require (
github.com/robfig/cron/v3 v3.0.1
github.com/sirupsen/logrus v1.9.3
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
github.com/spf13/afero v1.11.0
github.com/spf13/cobra v1.8.1
github.com/spf13/viper v1.19.0
github.com/studio-b12/gowebdav v0.9.0
@ -43,6 +44,7 @@ require (
github.com/wader/gormstore/v2 v2.0.3
github.com/xlzd/gotp v0.1.0
golang.org/x/crypto v0.28.0
golang.org/x/net v0.30.0
golang.org/x/oauth2 v0.18.0
golang.org/x/sys v0.26.0
golang.org/x/term v0.25.0
@ -105,7 +107,6 @@ require (
github.com/sagikazarmark/locafero v0.4.0 // indirect
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
github.com/sourcegraph/conc v0.3.0 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/subosito/gotenv v1.6.0 // indirect
@ -116,7 +117,6 @@ require (
golang.org/x/arch v0.8.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/image v0.13.0 // indirect
golang.org/x/net v0.30.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/time v0.6.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect

View File

@ -1,4 +1,4 @@
package middleware
package router
import (
"context"
@ -26,7 +26,7 @@ func Proxy() gin.HandlerFunc {
}
currentNode := c.Request.Header.Get("CurrentNode")
if !strings.HasPrefix(c.Request.URL.Path, "/api/v2/core") && (currentNode == "local" || len(currentNode) == 0) {
if !strings.HasPrefix(c.Request.URL.Path, "/api/v2/core") && (currentNode == "local" || len(currentNode) == 0 || currentNode == "127.0.0.1") {
sockPath := "/etc/1panel/agent.sock"
if _, err := os.Stat(sockPath); err != nil {
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrProxy, err)
@ -53,6 +53,5 @@ func Proxy() gin.HandlerFunc {
}
xpack.Proxy(c, currentNode)
c.Abort()
return
}
}

View File

@ -58,10 +58,7 @@ func Routers() *gin.Engine {
if global.CONF.System.IsDemo {
Router.Use(middleware.DemoHandle())
}
Router.Use(middleware.JwtAuth())
Router.Use(middleware.SessionAuth())
Router.Use(middleware.PasswordExpired())
Router.Use(middleware.Proxy())
Router.Use(Proxy())
PrivateGroup := Router.Group("/api/v2/core")
PrivateGroup.Use(middleware.WhiteAllow())

View File

@ -13,7 +13,7 @@ import (
"time"
"github.com/1Panel-dev/1Panel/core/app/model"
"github.com/1Panel-dev/1Panel/core/app/service"
"github.com/1Panel-dev/1Panel/core/app/repo"
"github.com/1Panel-dev/1Panel/core/cmd/server/docs"
"github.com/1Panel-dev/1Panel/core/constant"
"github.com/1Panel-dev/1Panel/core/global"
@ -124,6 +124,7 @@ func OperationLog() gin.HandlerFunc {
c.Next()
datas := writer.body.Bytes()
logRepo := repo.NewILogRepo()
if c.Request.Header.Get("Content-Encoding") == "gzip" {
buf := bytes.NewReader(writer.body.Bytes())
reader, err := gzip.NewReader(buf)
@ -133,7 +134,7 @@ func OperationLog() gin.HandlerFunc {
latency := time.Since(now)
record.Latency = latency
if err := service.NewILogService().CreateOperationLog(record); err != nil {
if err := logRepo.CreateOperationLog(record); err != nil {
global.LOG.Errorf("create operation record failed, err: %v", err)
}
return
@ -153,7 +154,7 @@ func OperationLog() gin.HandlerFunc {
latency := time.Since(now)
record.Latency = latency
if err := service.NewILogService().CreateOperationLog(record); err != nil {
if err := logRepo.CreateOperationLog(record); err != nil {
global.LOG.Errorf("create operation record failed, err: %v", err)
}
}

View File

@ -2,13 +2,17 @@ package router
import (
v2 "github.com/1Panel-dev/1Panel/core/app/api/v2"
"github.com/1Panel-dev/1Panel/core/middleware"
"github.com/gin-gonic/gin"
)
type AppLauncherRouter struct{}
func (s *AppLauncherRouter) InitRouter(Router *gin.RouterGroup) {
launcherRouter := Router.Group("launcher")
launcherRouter := Router.Group("launcher").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v2.ApiGroupApp.BaseApi
{
launcherRouter.GET("/search", baseApi.SearchAppLauncher)

View File

@ -2,13 +2,17 @@ package router
import (
v2 "github.com/1Panel-dev/1Panel/core/app/api/v2"
"github.com/1Panel-dev/1Panel/core/middleware"
"github.com/gin-gonic/gin"
)
type CommandRouter struct{}
func (s *CommandRouter) InitRouter(Router *gin.RouterGroup) {
commandRouter := Router.Group("commands")
commandRouter := Router.Group("commands").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v2.ApiGroupApp.BaseApi
{
commandRouter.POST("/list", baseApi.ListCommand)

View File

@ -2,13 +2,17 @@ package router
import (
v2 "github.com/1Panel-dev/1Panel/core/app/api/v2"
"github.com/1Panel-dev/1Panel/core/middleware"
"github.com/gin-gonic/gin"
)
type BackupRouter struct{}
func (s *BackupRouter) InitRouter(Router *gin.RouterGroup) {
backupRouter := Router.Group("backup")
backupRouter := Router.Group("backup").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v2.ApiGroupApp.BaseApi
{
backupRouter.GET("/local", baseApi.GetLocalDir)

View File

@ -2,6 +2,7 @@ package router
import (
v2 "github.com/1Panel-dev/1Panel/core/app/api/v2"
"github.com/1Panel-dev/1Panel/core/middleware"
"github.com/gin-gonic/gin"
)
@ -9,7 +10,10 @@ type GroupRouter struct {
}
func (a *GroupRouter) InitRouter(Router *gin.RouterGroup) {
groupRouter := Router.Group("groups")
groupRouter := Router.Group("groups").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v2.ApiGroupApp.BaseApi
{

View File

@ -2,13 +2,17 @@ package router
import (
v2 "github.com/1Panel-dev/1Panel/core/app/api/v2"
"github.com/1Panel-dev/1Panel/core/middleware"
"github.com/gin-gonic/gin"
)
type HostRouter struct{}
func (s *HostRouter) InitRouter(Router *gin.RouterGroup) {
hostRouter := Router.Group("hosts")
hostRouter := Router.Group("hosts").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v2.ApiGroupApp.BaseApi
{
hostRouter.POST("", baseApi.CreateHost)

View File

@ -2,6 +2,7 @@ package router
import (
v2 "github.com/1Panel-dev/1Panel/core/app/api/v2"
"github.com/1Panel-dev/1Panel/core/middleware"
"github.com/gin-gonic/gin"
)
@ -9,7 +10,10 @@ import (
type LogRouter struct{}
func (s *LogRouter) InitRouter(Router *gin.RouterGroup) {
operationRouter := Router.Group("logs")
operationRouter := Router.Group("logs").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v2.ApiGroupApp.BaseApi
{
operationRouter.POST("/login", baseApi.GetLoginLogs)

View File

@ -2,18 +2,25 @@ package router
import (
v2 "github.com/1Panel-dev/1Panel/core/app/api/v2"
"github.com/1Panel-dev/1Panel/core/middleware"
"github.com/gin-gonic/gin"
)
type SettingRouter struct{}
func (s *SettingRouter) InitRouter(Router *gin.RouterGroup) {
settingRouter := Router.Group("settings")
router := Router.Group("settings").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth())
settingRouter := Router.Group("settings").
Use(middleware.JwtAuth()).
Use(middleware.SessionAuth()).
Use(middleware.PasswordExpired())
baseApi := v2.ApiGroupApp.BaseApi
{
settingRouter.POST("/search", baseApi.GetSettingInfo)
router.POST("/search", baseApi.GetSettingInfo)
router.POST("/expired/handle", baseApi.HandlePasswordExpired)
settingRouter.POST("/terminal/search", baseApi.GetTerminalSettingInfo)
settingRouter.POST("/expired/handle", baseApi.HandlePasswordExpired)
settingRouter.GET("/search/available", baseApi.GetSystemAvailable)
settingRouter.POST("/update", baseApi.UpdateSetting)
settingRouter.POST("/terminal/update", baseApi.UpdateTerminalSetting)

View File

@ -40,7 +40,6 @@ func ValidCode(code, intervalStr, secret string) bool {
}
totp := gotp.NewTOTP(secret, 6, interval, nil)
now := time.Now().Unix()
strInt64 := strconv.FormatInt(now, 10)
id16, _ := strconv.Atoi(strInt64)
return totp.Verify(code, int64(id16))
prevTime := now - int64(interval)
return totp.Verify(code, now) || totp.Verify(code, prevTime)
}

View File

@ -50,6 +50,8 @@ export namespace Dashboard {
kernelArch: string;
kernelVersion: string;
virtualizationSystem: string;
ipV4Addr: string;
httpProxy: string;
cpuCores: number;
cpuLogicalCores: number;

View File

@ -1,16 +1,14 @@
<template>
<div>
<body>
<div>
<el-row type="flex" justify="center">
<h1>{{ loadErrInfo() }}</h1>
</el-row>
</div>
<hr />
<div>
<el-row type="flex" justify="center"><span>nginx</span></el-row>
</div>
</body>
<div>
<el-row type="flex" justify="center">
<h1>{{ loadErrInfo() }}</h1>
</el-row>
</div>
<hr />
<div>
<el-row type="flex" justify="center"><span>nginx</span></el-row>
</div>
</div>
</template>

View File

@ -366,6 +366,8 @@ const message = {
kernelArch: 'Kernel arch',
network: 'Network',
io: 'Disk IO',
ip: 'Ip Addr',
proxy: 'System Proxy',
baseInfo: 'Base info',
totalSend: 'Total send',
totalRecv: 'Total recv',

View File

@ -359,6 +359,8 @@ const message = {
kernelArch: '系統類型',
network: '流量',
io: '磁盤 IO',
ip: '主機地址',
proxy: '系統代理',
baseInfo: '基本信息',
totalSend: '總發送',
totalRecv: '總接收',

View File

@ -359,6 +359,8 @@ const message = {
kernelArch: '系统类型',
network: '流量',
io: '磁盘 IO',
ip: '主机地址',
proxy: '系统代理',
baseInfo: '基本信息',
totalSend: '总发送',
totalRecv: '总接收',

View File

@ -1,7 +1,15 @@
<template>
<div>
<div v-if="showButton">
<RouterButton :buttons="buttons" />
<RouterButton :buttons="buttons">
<template #route-button>
<el-badge is-dot :hidden="!canUpdate" class="pr-5">
<el-button @click="sync" type="primary" plain :disabled="syncing">
{{ $t('app.syncAppList') }}
</el-button>
</el-badge>
</template>
</RouterButton>
</div>
<LayoutContent>
<router-view></router-view>
@ -12,9 +20,14 @@
<script lang="ts" setup>
import i18n from '@/lang';
import { onMounted, ref } from 'vue';
import { SearchAppInstalled } from '@/api/modules/app';
import { SearchAppInstalled, SyncApp } from '@/api/modules/app';
import bus from './bus';
import { MsgSuccess } from '@/utils/message';
import { newUUID } from '@/utils/util';
let showButton = ref(false);
const syncing = ref(false);
const canUpdate = ref(false);
const buttons = [
{
label: i18n.global.t('app.all'),
@ -35,6 +48,26 @@ const buttons = [
},
];
const sync = () => {
syncing.value = true;
const taskID = newUUID();
const syncReq = {
taskID: taskID,
};
SyncApp(syncReq)
.then((res) => {
if (res.message != '') {
MsgSuccess(res.message);
} else {
MsgSuccess(i18n.global.t('app.syncStart'));
}
canUpdate.value = false;
})
.finally(() => {
syncing.value = false;
});
};
const search = () => {
SearchAppInstalled({ update: true, page: 1, pageSize: 100 })
.then((res) => {

View File

@ -209,6 +209,25 @@
</template>
{{ baseInfo.kernelArch }}
</el-descriptions-item>
<el-descriptions-item class-name="system-content">
<template #label>
<span class="system-label">
{{ $t('home.ip') }}
</span>
</template>
{{ baseInfo.ipV4Addr }}
</el-descriptions-item>
<el-descriptions-item
v-if="baseInfo.httpProxy && baseInfo.httpProxy !== 'noProxy'"
class-name="system-content"
>
<template #label>
<span class="system-label">
{{ $t('home.proxy') }}
</span>
{{ baseInfo.httpProxy }}
</template>
</el-descriptions-item>
<el-descriptions-item class-name="system-content">
<template #label>
<span class="system-label">
@ -299,6 +318,8 @@ const baseInfo = ref<Dashboard.BaseInfo>({
kernelArch: '',
kernelVersion: '',
virtualizationSystem: '',
ipV4Addr: '',
httpProxy: '',
cpuCores: 0,
cpuLogicalCores: 0,

View File

@ -68,8 +68,8 @@ const acceptParams = (props: BatchRoleProps) => {
addForm.paths.push(file.path);
});
addForm.mode = Number.parseInt(String(props.files[0].mode), 8);
addForm.group = props.files[0].group;
addForm.user = props.files[0].user;
addForm.group = props.files[0].group || props.files[0].gid + '';
addForm.user = props.files[0].user || props.files[0].uid + '';
addForm.sub = true;
mode.value = String(props.files[0].mode);

View File

@ -10,7 +10,7 @@
@submit.enter.prevent
>
<el-form-item :label="$t('commons.table.name')" prop="name">
<el-input v-model.trim="addForm.name" />
<el-input v-model="addForm.name" />
</el-form-item>
<el-form-item v-if="!addForm.isDir">
<el-checkbox v-model="addForm.isLink" :label="$t('file.link')"></el-checkbox>
@ -88,9 +88,9 @@ const getMode = (val: number) => {
let getPath = computed(() => {
if (addForm.path.endsWith('/')) {
return addForm.path + addForm.name;
return addForm.path + addForm.name.trim();
} else {
return addForm.path + '/' + addForm.name;
return addForm.path + '/' + addForm.name.trim();
}
});
@ -116,6 +116,7 @@ const submit = async (formEl: FormInstance | undefined) => {
if (!setRole.value) {
addItem['mode'] = undefined;
}
addItem['name'] = addForm.name.trim();
CreateFile(addItem as File.FileCreate)
.then(() => {
MsgSuccess(i18n.global.t('commons.msg.createSuccess'));

View File

@ -532,6 +532,11 @@ const top = () => {
};
const jump = async (url: string) => {
const fileName = url.substring(url.lastIndexOf('/') + 1);
let filePath = url.substring(0, url.lastIndexOf('/') + 1);
if (!url.includes('.')) {
filePath = url;
}
history.splice(pointer + 1);
history.push(url);
pointer = history.length - 1;
@ -541,6 +546,7 @@ const jump = async (url: string) => {
// reset search params before exec jump
Object.assign(req, initData());
req.path = url;
req.path = filePath;
req.containSub = false;
req.search = '';
req.pageSize = oldPageSize;
@ -553,6 +559,14 @@ const jump = async (url: string) => {
MsgWarning(i18n.global.t('commons.res.notFound'));
return;
}
if (fileName && fileName.length > 1 && fileName.includes('.')) {
const fileData = searchResult.data.items.filter((item) => item.name === fileName);
if (fileData && fileData.length === 1) {
openView(fileData[0]);
} else {
MsgWarning(i18n.global.t('commons.res.notFound'));
}
}
handleSearchResult(searchResult);
getPaths(req.path);
nextTick(function () {
@ -1021,4 +1035,7 @@ onMounted(() => {
color: #726e6e;
}
}
.search-button {
width: 20vw;
}
</style>

View File

@ -48,6 +48,7 @@
prop="deleteTime"
:formatter="dateFormat"
show-overflow-tooltip
sortable
></el-table-column>
<fu-table-operations :buttons="buttons" :label="$t('commons.table.operate')" fix />
</ComplexTable>

View File

@ -187,7 +187,9 @@ const convertFileToUploadFile = (file: File, path: string): UploadFile => {
const traverseFileTree = async (item: any, path = '') => {
path = path || '';
if (!item) {
return;
}
if (item.isFile) {
if (tmpFiles.value.length > 1000) {
breakFlag.value = true;

View File

@ -119,7 +119,6 @@ const onClean = async () => {
submitInputInfo: i18n.global.t('logs.deleteLogs'),
};
confirmDialogRef.value!.acceptParams(params);
searchLog();
};
const onDownload = async () => {

View File

@ -41,8 +41,8 @@
<div class="login-form">
<el-form ref="loginFormRef" :model="loginForm" size="default" :rules="loginRules">
<div class="login-form-header">
<div class="title">{{ $t('commons.button.login') }}</div>
<div>
<div class="title cursor-pointer">{{ $t('commons.button.login') }}</div>
<div class="cursor-pointer">
<el-dropdown @command="handleCommand">
<span>
{{ dropdownText }}

View File

@ -55,6 +55,7 @@
:width="400"
trigger="hover"
:content="row.message"
popper-class="max-h-[300px] overflow-auto"
>
<template #reference>
<Status :key="row.status" :status="row.status"></Status>

View File

@ -98,7 +98,7 @@ export default defineConfig(({ mode }: ConfigEnv): UserConfig => {
pure: viteEnv.VITE_DROP_CONSOLE ? ['console.log', 'debugger'] : [],
},
build: {
outDir: '../cmd/server/web',
outDir: '../core/cmd/server/web',
minify: 'esbuild',
target: 'esnext',
rollupOptions: {