mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-27 09:15:55 +08:00
feat: 文件管理增加用户/用户组设置 (#803)
This commit is contained in:
parent
db2aa35b2f
commit
7887bf96de
19 changed files with 701 additions and 14 deletions
|
|
@ -186,7 +186,29 @@ func (b *BaseApi) ChangeFileMode(c *gin.Context) {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
helper.SuccessWithData(c, nil)
|
helper.SuccessWithOutData(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// @Tags File
|
||||||
|
// @Summary Change file owner
|
||||||
|
// @Description 修改文件用户/组
|
||||||
|
// @Accept json
|
||||||
|
// @Param request body request.FileRoleUpdate true "request"
|
||||||
|
// @Success 200
|
||||||
|
// @Security ApiKeyAuth
|
||||||
|
// @Router /files/owner [post]
|
||||||
|
// @x-panel-log {"bodyKeys":["path","user","group"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改用户/组 [paths] => [user]/[group]","formatEN":"Change owner [paths] => [user]/[group]"}
|
||||||
|
func (b *BaseApi) ChangeFileOwner(c *gin.Context) {
|
||||||
|
var req request.FileRoleUpdate
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if err := fileService.ChangeOwner(req); err != nil {
|
||||||
|
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
helper.SuccessWithOutData(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
// @Tags File
|
// @Tags File
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ func (b *BaseApi) UpdatePassword(c *gin.Context) {
|
||||||
// @Success 200
|
// @Success 200
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /settings/ssl/update [post]
|
// @Router /settings/ssl/update [post]
|
||||||
// @x-panel-log {"bodyKeys":[ssl],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统 ssl => [ssl]","formatEN":"update system ssl => [ssl]"}
|
// @x-panel-log {"bodyKeys":["ssl"],"paramKeys":[],"BeforeFuntions":[],"formatZH":"修改系统 ssl => [ssl]","formatEN":"update system ssl => [ssl]"}
|
||||||
func (b *BaseApi) UpdateSSL(c *gin.Context) {
|
func (b *BaseApi) UpdateSSL(c *gin.Context) {
|
||||||
var req dto.SSLUpdate
|
var req dto.SSLUpdate
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -88,3 +88,10 @@ type DirSizeReq struct {
|
||||||
type FileProcessReq struct {
|
type FileProcessReq struct {
|
||||||
Key string `json:"key"`
|
Key string `json:"key"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FileRoleUpdate struct {
|
||||||
|
Path string `json:"path" validate:"required"`
|
||||||
|
User string `json:"user" validate:"required"`
|
||||||
|
Group string `json:"group" validate:"required"`
|
||||||
|
Sub bool `json:"sub" validate:"required"`
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ type IFileService interface {
|
||||||
ChangeName(req request.FileRename) error
|
ChangeName(req request.FileRename) error
|
||||||
Wget(w request.FileWget) (string, error)
|
Wget(w request.FileWget) (string, error)
|
||||||
MvFile(m request.FileMove) error
|
MvFile(m request.FileMove) error
|
||||||
|
ChangeOwner(req request.FileRoleUpdate) error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewIFileService() IFileService {
|
func NewIFileService() IFileService {
|
||||||
|
|
@ -162,6 +163,11 @@ func (f *FileService) ChangeMode(op request.FileCreate) error {
|
||||||
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
return fo.Chmod(op.Path, fs.FileMode(op.Mode))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *FileService) ChangeOwner(req request.FileRoleUpdate) error {
|
||||||
|
fo := files.NewFileOp()
|
||||||
|
return fo.ChownR(req.Path, req.User, req.Group, req.Sub)
|
||||||
|
}
|
||||||
|
|
||||||
func (f *FileService) Compress(c request.FileCompress) error {
|
func (f *FileService) Compress(c request.FileCompress) error {
|
||||||
fo := files.NewFileOp()
|
fo := files.NewFileOp()
|
||||||
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
|
if !c.Replace && fo.Stat(filepath.Join(c.Dst, c.Name)) {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ func (f *FileRouter) InitFileRouter(Router *gin.RouterGroup) {
|
||||||
fileRouter.POST("/del", baseApi.DeleteFile)
|
fileRouter.POST("/del", baseApi.DeleteFile)
|
||||||
fileRouter.POST("/batch/del", baseApi.BatchDeleteFile)
|
fileRouter.POST("/batch/del", baseApi.BatchDeleteFile)
|
||||||
fileRouter.POST("/mode", baseApi.ChangeFileMode)
|
fileRouter.POST("/mode", baseApi.ChangeFileMode)
|
||||||
|
fileRouter.POST("/owner", baseApi.ChangeFileOwner)
|
||||||
fileRouter.POST("/compress", baseApi.CompressFile)
|
fileRouter.POST("/compress", baseApi.CompressFile)
|
||||||
fileRouter.POST("/decompress", baseApi.DeCompressFile)
|
fileRouter.POST("/decompress", baseApi.DeCompressFile)
|
||||||
fileRouter.POST("/content", baseApi.GetContent)
|
fileRouter.POST("/content", baseApi.GetContent)
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/1Panel-dev/1Panel/backend/utils/cmd"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
@ -106,7 +107,7 @@ func (f FileOp) SaveFile(dst string, content string, mode fs.FileMode) error {
|
||||||
}
|
}
|
||||||
defer file.Close()
|
defer file.Close()
|
||||||
write := bufio.NewWriter(file)
|
write := bufio.NewWriter(file)
|
||||||
_, _ = write.WriteString(string(content))
|
_, _ = write.WriteString(content)
|
||||||
write.Flush()
|
write.Flush()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -119,6 +120,34 @@ func (f FileOp) Chown(dst string, uid int, gid int) error {
|
||||||
return f.Fs.Chown(dst, uid, gid)
|
return f.Fs.Chown(dst, uid, gid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f FileOp) ChownR(dst string, uid string, gid string, sub bool) error {
|
||||||
|
cmdStr := fmt.Sprintf("sudo chown %s:%s %s", uid, gid, dst)
|
||||||
|
if sub {
|
||||||
|
cmdStr = fmt.Sprintf("sudo chown -R %s:%s %s", uid, gid, dst)
|
||||||
|
}
|
||||||
|
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
|
||||||
|
if msg != "" {
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (f FileOp) ChmodR(dst string, mode fs.FileMode) error {
|
||||||
|
cmdStr := fmt.Sprintf("chmod -R %v %s", mode, dst)
|
||||||
|
if cmd.HasNoPasswordSudo() {
|
||||||
|
cmdStr = fmt.Sprintf("sudo %s", cmdStr)
|
||||||
|
}
|
||||||
|
if msg, err := cmd.ExecWithTimeOut(cmdStr, 2*time.Second); err != nil {
|
||||||
|
if msg != "" {
|
||||||
|
return errors.New(msg)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (f FileOp) Rename(oldName string, newName string) error {
|
func (f FileOp) Rename(oldName string, newName string) error {
|
||||||
return f.Fs.Rename(oldName, newName)
|
return f.Fs.Rename(oldName, newName)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
|
@ -73,6 +74,8 @@ func NewFileInfo(op FileOption) (*FileInfo, error) {
|
||||||
Extension: filepath.Ext(info.Name()),
|
Extension: filepath.Ext(info.Name()),
|
||||||
IsHidden: IsHidden(op.Path),
|
IsHidden: IsHidden(op.Path),
|
||||||
Mode: fmt.Sprintf("%04o", info.Mode().Perm()),
|
Mode: fmt.Sprintf("%04o", info.Mode().Perm()),
|
||||||
|
User: GetUsername(info.Sys().(*syscall.Stat_t).Uid),
|
||||||
|
Group: GetGroup(info.Sys().(*syscall.Stat_t).Gid),
|
||||||
MimeType: GetMimeType(op.Path),
|
MimeType: GetMimeType(op.Path),
|
||||||
}
|
}
|
||||||
if file.IsSymlink {
|
if file.IsSymlink {
|
||||||
|
|
@ -202,6 +205,8 @@ func (f *FileInfo) listChildren(dir, showHidden, containSub bool, search string,
|
||||||
Path: fPath,
|
Path: fPath,
|
||||||
Mode: fmt.Sprintf("%04o", df.Mode().Perm()),
|
Mode: fmt.Sprintf("%04o", df.Mode().Perm()),
|
||||||
MimeType: GetMimeType(fPath),
|
MimeType: GetMimeType(fPath),
|
||||||
|
User: GetUsername(df.Sys().(*syscall.Stat_t).Uid),
|
||||||
|
Group: GetGroup(df.Sys().(*syscall.Stat_t).Gid),
|
||||||
}
|
}
|
||||||
|
|
||||||
if isSymlink {
|
if isSymlink {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ import (
|
||||||
"github.com/gabriel-vasile/mimetype"
|
"github.com/gabriel-vasile/mimetype"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"os"
|
"os"
|
||||||
|
"os/user"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -28,6 +30,22 @@ func GetSymlink(path string) string {
|
||||||
return linkPath
|
return linkPath
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetUsername(uid uint32) string {
|
||||||
|
usr, err := user.LookupId(strconv.Itoa(int(uid)))
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return usr.Username
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetGroup(gid uint32) string {
|
||||||
|
usr, err := user.LookupGroupId(strconv.Itoa(int(gid)))
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return usr.Name
|
||||||
|
}
|
||||||
|
|
||||||
func ScanDir(fs afero.Fs, path string, dirMap *sync.Map, wg *sync.WaitGroup) {
|
func ScanDir(fs afero.Fs, path string, dirMap *sync.Map, wg *sync.WaitGroup) {
|
||||||
afs := &afero.Afero{Fs: fs}
|
afs := &afero.Afero{Fs: fs}
|
||||||
files, _ := afs.ReadDir(path)
|
files, _ := afs.ReadDir(path)
|
||||||
|
|
|
||||||
|
|
@ -4529,6 +4529,50 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/files/owner": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "修改文件用户/组",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"File"
|
||||||
|
],
|
||||||
|
"summary": "Change file owner",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.FileRoleUpdate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFuntions": [],
|
||||||
|
"bodyKeys": [
|
||||||
|
"path",
|
||||||
|
"user",
|
||||||
|
"group"
|
||||||
|
],
|
||||||
|
"formatEN": "Change owner [paths] =\u003e [user]/[group]",
|
||||||
|
"formatZH": "修改用户/组 [paths] =\u003e [user]/[group]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/files/rename": {
|
"/files/rename": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -7431,6 +7475,70 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/settings/ssl/info": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "获取证书信息",
|
||||||
|
"tags": [
|
||||||
|
"System Setting"
|
||||||
|
],
|
||||||
|
"summary": "Load system cert info",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.SettingInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/settings/ssl/update": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "修改系统 ssl 登录",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"System Setting"
|
||||||
|
],
|
||||||
|
"summary": "Update system ssl",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.SSLUpdate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFuntions": [],
|
||||||
|
"bodyKeys": [
|
||||||
|
"ssl"
|
||||||
|
],
|
||||||
|
"formatEN": "update system ssl =\u003e [ssl]",
|
||||||
|
"formatZH": "修改系统 ssl =\u003e [ssl]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/settings/time/sync": {
|
"/settings/time/sync": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -11440,10 +11548,16 @@ const docTemplate = `{
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"containerPort": {
|
"containerPort": {
|
||||||
"type": "integer"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"hostIP": {
|
||||||
|
"type": "string"
|
||||||
},
|
},
|
||||||
"hostPort": {
|
"hostPort": {
|
||||||
"type": "integer"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"protocol": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -11669,6 +11783,36 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.SSLUpdate": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"ssl"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cert": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"domain": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ssl": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"enable",
|
||||||
|
"disable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sslID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"sslType": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dto.SearchForTree": {
|
"dto.SearchForTree": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -11851,6 +11995,12 @@ const docTemplate = `{
|
||||||
"sessionTimeout": {
|
"sessionTimeout": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"ssl": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sslType": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"systemVersion": {
|
"systemVersion": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -12796,6 +12946,29 @@ const docTemplate = `{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"request.FileRoleUpdate": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"group",
|
||||||
|
"path",
|
||||||
|
"sub",
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"group": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sub": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"request.FileWget": {
|
"request.FileWget": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -4522,6 +4522,50 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/files/owner": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "修改文件用户/组",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"File"
|
||||||
|
],
|
||||||
|
"summary": "Change file owner",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/request.FileRoleUpdate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFuntions": [],
|
||||||
|
"bodyKeys": [
|
||||||
|
"path",
|
||||||
|
"user",
|
||||||
|
"group"
|
||||||
|
],
|
||||||
|
"formatEN": "Change owner [paths] =\u003e [user]/[group]",
|
||||||
|
"formatZH": "修改用户/组 [paths] =\u003e [user]/[group]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/files/rename": {
|
"/files/rename": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -7424,6 +7468,70 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/settings/ssl/info": {
|
||||||
|
"get": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "获取证书信息",
|
||||||
|
"tags": [
|
||||||
|
"System Setting"
|
||||||
|
],
|
||||||
|
"summary": "Load system cert info",
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.SettingInfo"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/settings/ssl/update": {
|
||||||
|
"post": {
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"ApiKeyAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"description": "修改系统 ssl 登录",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"System Setting"
|
||||||
|
],
|
||||||
|
"summary": "Update system ssl",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/dto.SSLUpdate"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-panel-log": {
|
||||||
|
"BeforeFuntions": [],
|
||||||
|
"bodyKeys": [
|
||||||
|
"ssl"
|
||||||
|
],
|
||||||
|
"formatEN": "update system ssl =\u003e [ssl]",
|
||||||
|
"formatZH": "修改系统 ssl =\u003e [ssl]",
|
||||||
|
"paramKeys": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"/settings/time/sync": {
|
"/settings/time/sync": {
|
||||||
"post": {
|
"post": {
|
||||||
"security": [
|
"security": [
|
||||||
|
|
@ -11433,10 +11541,16 @@
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"containerPort": {
|
"containerPort": {
|
||||||
"type": "integer"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"hostIP": {
|
||||||
|
"type": "string"
|
||||||
},
|
},
|
||||||
"hostPort": {
|
"hostPort": {
|
||||||
"type": "integer"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"protocol": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
@ -11662,6 +11776,36 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dto.SSLUpdate": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"ssl"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"cert": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"domain": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"key": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"ssl": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"enable",
|
||||||
|
"disable"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"sslID": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
|
"sslType": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"dto.SearchForTree": {
|
"dto.SearchForTree": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|
@ -11844,6 +11988,12 @@
|
||||||
"sessionTimeout": {
|
"sessionTimeout": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"ssl": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sslType": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"systemVersion": {
|
"systemVersion": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
|
@ -12789,6 +12939,29 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"request.FileRoleUpdate": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"group",
|
||||||
|
"path",
|
||||||
|
"sub",
|
||||||
|
"user"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"group": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"sub": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"request.FileWget": {
|
"request.FileWget": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
||||||
|
|
@ -1201,9 +1201,13 @@ definitions:
|
||||||
dto.PortHelper:
|
dto.PortHelper:
|
||||||
properties:
|
properties:
|
||||||
containerPort:
|
containerPort:
|
||||||
type: integer
|
type: string
|
||||||
|
hostIP:
|
||||||
|
type: string
|
||||||
hostPort:
|
hostPort:
|
||||||
type: integer
|
type: string
|
||||||
|
protocol:
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
dto.PortRuleOperate:
|
dto.PortRuleOperate:
|
||||||
properties:
|
properties:
|
||||||
|
|
@ -1354,6 +1358,26 @@ definitions:
|
||||||
used_memory_rss:
|
used_memory_rss:
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
dto.SSLUpdate:
|
||||||
|
properties:
|
||||||
|
cert:
|
||||||
|
type: string
|
||||||
|
domain:
|
||||||
|
type: string
|
||||||
|
key:
|
||||||
|
type: string
|
||||||
|
ssl:
|
||||||
|
enum:
|
||||||
|
- enable
|
||||||
|
- disable
|
||||||
|
type: string
|
||||||
|
sslID:
|
||||||
|
type: integer
|
||||||
|
sslType:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- ssl
|
||||||
|
type: object
|
||||||
dto.SearchForTree:
|
dto.SearchForTree:
|
||||||
properties:
|
properties:
|
||||||
info:
|
info:
|
||||||
|
|
@ -1475,6 +1499,10 @@ definitions:
|
||||||
type: string
|
type: string
|
||||||
sessionTimeout:
|
sessionTimeout:
|
||||||
type: string
|
type: string
|
||||||
|
ssl:
|
||||||
|
type: string
|
||||||
|
sslType:
|
||||||
|
type: string
|
||||||
systemVersion:
|
systemVersion:
|
||||||
type: string
|
type: string
|
||||||
theme:
|
theme:
|
||||||
|
|
@ -2101,6 +2129,22 @@ definitions:
|
||||||
- newName
|
- newName
|
||||||
- oldName
|
- oldName
|
||||||
type: object
|
type: object
|
||||||
|
request.FileRoleUpdate:
|
||||||
|
properties:
|
||||||
|
group:
|
||||||
|
type: string
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
sub:
|
||||||
|
type: boolean
|
||||||
|
user:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- group
|
||||||
|
- path
|
||||||
|
- sub
|
||||||
|
- user
|
||||||
|
type: object
|
||||||
request.FileWget:
|
request.FileWget:
|
||||||
properties:
|
properties:
|
||||||
name:
|
name:
|
||||||
|
|
@ -5899,6 +5943,35 @@ paths:
|
||||||
formatEN: Move [oldPaths] => [newPath]
|
formatEN: Move [oldPaths] => [newPath]
|
||||||
formatZH: 移动文件 [oldPaths] => [newPath]
|
formatZH: 移动文件 [oldPaths] => [newPath]
|
||||||
paramKeys: []
|
paramKeys: []
|
||||||
|
/files/owner:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 修改文件用户/组
|
||||||
|
parameters:
|
||||||
|
- description: request
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/request.FileRoleUpdate'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: Change file owner
|
||||||
|
tags:
|
||||||
|
- File
|
||||||
|
x-panel-log:
|
||||||
|
BeforeFuntions: []
|
||||||
|
bodyKeys:
|
||||||
|
- path
|
||||||
|
- user
|
||||||
|
- group
|
||||||
|
formatEN: Change owner [paths] => [user]/[group]
|
||||||
|
formatZH: 修改用户/组 [paths] => [user]/[group]
|
||||||
|
paramKeys: []
|
||||||
/files/rename:
|
/files/rename:
|
||||||
post:
|
post:
|
||||||
consumes:
|
consumes:
|
||||||
|
|
@ -7742,6 +7815,46 @@ paths:
|
||||||
summary: Page system snapshot
|
summary: Page system snapshot
|
||||||
tags:
|
tags:
|
||||||
- System Setting
|
- System Setting
|
||||||
|
/settings/ssl/info:
|
||||||
|
get:
|
||||||
|
description: 获取证书信息
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/dto.SettingInfo'
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: Load system cert info
|
||||||
|
tags:
|
||||||
|
- System Setting
|
||||||
|
/settings/ssl/update:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: 修改系统 ssl 登录
|
||||||
|
parameters:
|
||||||
|
- description: request
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/dto.SSLUpdate'
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
security:
|
||||||
|
- ApiKeyAuth: []
|
||||||
|
summary: Update system ssl
|
||||||
|
tags:
|
||||||
|
- System Setting
|
||||||
|
x-panel-log:
|
||||||
|
BeforeFuntions: []
|
||||||
|
bodyKeys:
|
||||||
|
- ssl
|
||||||
|
formatEN: update system ssl => [ssl]
|
||||||
|
formatZH: 修改系统 ssl => [ssl]
|
||||||
|
paramKeys: []
|
||||||
/settings/time/sync:
|
/settings/time/sync:
|
||||||
post:
|
post:
|
||||||
description: 系统时间同步
|
description: 系统时间同步
|
||||||
|
|
|
||||||
2
frontend/package-lock.json
generated
2
frontend/package-lock.json
generated
|
|
@ -17,7 +17,7 @@
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"echarts": "^5.3.0",
|
"echarts": "^5.3.0",
|
||||||
"echarts-liquidfill": "^3.1.0",
|
"echarts-liquidfill": "^3.1.0",
|
||||||
"element-plus": "^2.2.32",
|
"element-plus": "^2.3.4",
|
||||||
"fit2cloud-ui-plus": "^1.0.7",
|
"fit2cloud-ui-plus": "^1.0.7",
|
||||||
"js-base64": "^3.7.2",
|
"js-base64": "^3.7.2",
|
||||||
"js-md5": "^0.7.3",
|
"js-md5": "^0.7.3",
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@
|
||||||
"axios": "^0.27.2",
|
"axios": "^0.27.2",
|
||||||
"echarts": "^5.3.0",
|
"echarts": "^5.3.0",
|
||||||
"echarts-liquidfill": "^3.1.0",
|
"echarts-liquidfill": "^3.1.0",
|
||||||
"element-plus": "^2.2.32",
|
"element-plus": "^2.3.4",
|
||||||
"fit2cloud-ui-plus": "^1.0.7",
|
"fit2cloud-ui-plus": "^1.0.7",
|
||||||
"js-base64": "^3.7.2",
|
"js-base64": "^3.7.2",
|
||||||
"js-md5": "^0.7.3",
|
"js-md5": "^0.7.3",
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,13 @@ export namespace File {
|
||||||
newName: string;
|
newName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface FileOwner {
|
||||||
|
path: string;
|
||||||
|
user: string;
|
||||||
|
group: string;
|
||||||
|
sub: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface FileWget {
|
export interface FileWget {
|
||||||
path: string;
|
path: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,10 @@ export const RenameRile = (params: File.FileRename) => {
|
||||||
return http.post<File.File>('files/rename', params);
|
return http.post<File.File>('files/rename', params);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ChangeOwner = (params: File.FileOwner) => {
|
||||||
|
return http.post<File.File>('files/owner', params);
|
||||||
|
};
|
||||||
|
|
||||||
export const WgetFile = (params: File.FileWget) => {
|
export const WgetFile = (params: File.FileWget) => {
|
||||||
return http.post<File.FileWgetRes>('files/wget', params);
|
return http.post<File.FileWgetRes>('files/wget', params);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -800,6 +800,10 @@ const message = {
|
||||||
copyDir: 'Copy Dir',
|
copyDir: 'Copy Dir',
|
||||||
paste: 'Paste',
|
paste: 'Paste',
|
||||||
cancel: 'Cancel',
|
cancel: 'Cancel',
|
||||||
|
changeOwner: 'Modify user and user group',
|
||||||
|
containSub: 'Modify sub-file attributes at the same time',
|
||||||
|
ownerHelper:
|
||||||
|
'The default user of the PHP operating environment: the user group is 1000:1000, it is normal that the users inside and outside the container show inconsistencies',
|
||||||
},
|
},
|
||||||
setting: {
|
setting: {
|
||||||
all: 'All',
|
all: 'All',
|
||||||
|
|
|
||||||
|
|
@ -807,6 +807,9 @@ const message = {
|
||||||
copyDir: '复制路径',
|
copyDir: '复制路径',
|
||||||
paste: '粘贴',
|
paste: '粘贴',
|
||||||
cancel: '取消',
|
cancel: '取消',
|
||||||
|
changeOwner: '修改用户和用户组',
|
||||||
|
containSub: '同时修改子文件属性',
|
||||||
|
ownerHelper: 'PHP 运行环境默认用户:用户组为 1000:1000, 容器内外用户显示不一致为正常现象',
|
||||||
},
|
},
|
||||||
setting: {
|
setting: {
|
||||||
all: '全部',
|
all: '全部',
|
||||||
|
|
|
||||||
108
frontend/src/views/host/file-management/chown/index.vue
Normal file
108
frontend/src/views/host/file-management/chown/index.vue
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
<template>
|
||||||
|
<el-drawer v-model="open" size="40%">
|
||||||
|
<template #header>
|
||||||
|
<DrawerHeader :header="$t('file.changeOwner')" :back="handleClose" />
|
||||||
|
</template>
|
||||||
|
<el-row>
|
||||||
|
<el-col :span="22" :offset="1">
|
||||||
|
<el-form
|
||||||
|
ref="fileForm"
|
||||||
|
label-position="top"
|
||||||
|
:model="addForm"
|
||||||
|
label-width="100px"
|
||||||
|
:rules="rules"
|
||||||
|
v-loading="loading"
|
||||||
|
>
|
||||||
|
<el-form-item :label="$t('file.user')" prop="user">
|
||||||
|
<el-input v-model.trim="addForm.user" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item :label="$t('file.group')" prop="group">
|
||||||
|
<el-input v-model.trim="addForm.group" />
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item v-if="isDir">
|
||||||
|
<el-checkbox v-model="addForm.sub">{{ $t('file.containSub') }}</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<el-alert :title="$t('file.ownerHelper')" type="info" :closable="false" />
|
||||||
|
</el-form-item>
|
||||||
|
</el-form>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
|
<template #footer>
|
||||||
|
<span class="dialog-footer">
|
||||||
|
<el-button @click="handleClose">{{ $t('commons.button.cancel') }}</el-button>
|
||||||
|
<el-button type="primary" @click="submit(fileForm)">{{ $t('commons.button.confirm') }}</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</el-drawer>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import { ChangeOwner } from '@/api/modules/files';
|
||||||
|
import { Rules } from '@/global/form-rules';
|
||||||
|
import { FormInstance, FormRules } from 'element-plus';
|
||||||
|
import { reactive, ref } from 'vue';
|
||||||
|
import i18n from '@/lang';
|
||||||
|
import { MsgSuccess } from '@/utils/message';
|
||||||
|
|
||||||
|
interface OwnerProps {
|
||||||
|
path: string;
|
||||||
|
user: string;
|
||||||
|
group: string;
|
||||||
|
isDir: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileForm = ref<FormInstance>();
|
||||||
|
const loading = ref(false);
|
||||||
|
const open = ref(false);
|
||||||
|
const isDir = ref(false);
|
||||||
|
|
||||||
|
const addForm = reactive({
|
||||||
|
path: '',
|
||||||
|
user: '',
|
||||||
|
group: '',
|
||||||
|
sub: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const rules = reactive<FormRules>({
|
||||||
|
user: [Rules.requiredInput],
|
||||||
|
group: [Rules.requiredInput],
|
||||||
|
});
|
||||||
|
|
||||||
|
const em = defineEmits(['close']);
|
||||||
|
const handleClose = () => {
|
||||||
|
open.value = false;
|
||||||
|
if (fileForm.value) {
|
||||||
|
fileForm.value.resetFields();
|
||||||
|
}
|
||||||
|
em('close', false);
|
||||||
|
};
|
||||||
|
|
||||||
|
const submit = async (formEl: FormInstance | undefined) => {
|
||||||
|
if (!formEl) return;
|
||||||
|
await formEl.validate((valid) => {
|
||||||
|
if (!valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
loading.value = true;
|
||||||
|
ChangeOwner(addForm)
|
||||||
|
.then(() => {
|
||||||
|
MsgSuccess(i18n.global.t('commons.msg.updateSuccess'));
|
||||||
|
handleClose();
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
loading.value = false;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const acceptParams = (props: OwnerProps) => {
|
||||||
|
addForm.user = props.user;
|
||||||
|
addForm.path = props.path;
|
||||||
|
addForm.group = props.group;
|
||||||
|
isDir.value = props.isDir;
|
||||||
|
open.value = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
defineExpose({ acceptParams });
|
||||||
|
</script>
|
||||||
|
|
@ -123,8 +123,16 @@
|
||||||
<el-link :underline="false" @click="openMode(row)" type="primary">{{ row.mode }}</el-link>
|
<el-link :underline="false" @click="openMode(row)" type="primary">{{ row.mode }}</el-link>
|
||||||
</template>
|
</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<!-- <el-table-column :label="$t('file.user')" prop="user" show-overflow-tooltip></el-table-column>
|
<el-table-column :label="$t('file.user')" prop="user" show-overflow-tooltip>
|
||||||
<el-table-column :label="$t('file.group')" prop="group"></el-table-column> -->
|
<template #default="{ row }">
|
||||||
|
<el-link :underline="false" @click="openChown(row)" type="primary">{{ row.user }}</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :label="$t('file.group')" prop="group">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-link :underline="false" @click="openChown(row)" type="primary">{{ row.group }}</el-link>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
<el-table-column :label="$t('file.size')" prop="size" max-width="50">
|
<el-table-column :label="$t('file.size')" prop="size" max-width="50">
|
||||||
<template #default="{ row }">
|
<template #default="{ row }">
|
||||||
<span v-if="row.isDir">
|
<span v-if="row.isDir">
|
||||||
|
|
@ -167,6 +175,7 @@
|
||||||
<Move ref="moveRef" @close="closeMovePage" />
|
<Move ref="moveRef" @close="closeMovePage" />
|
||||||
<Download ref="downloadRef" @close="search" />
|
<Download ref="downloadRef" @close="search" />
|
||||||
<Process :open="processPage.open" @close="closeProcess" />
|
<Process :open="processPage.open" @close="closeProcess" />
|
||||||
|
<Owner ref="chownRef" @close="search"></Owner>
|
||||||
<!-- <Detail ref="detailRef" /> -->
|
<!-- <Detail ref="detailRef" /> -->
|
||||||
</LayoutContent>
|
</LayoutContent>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -191,6 +200,7 @@ import CodeEditor from './code-editor/index.vue';
|
||||||
import Wget from './wget/index.vue';
|
import Wget from './wget/index.vue';
|
||||||
import Move from './move/index.vue';
|
import Move from './move/index.vue';
|
||||||
import Download from './download/index.vue';
|
import Download from './download/index.vue';
|
||||||
|
import Owner from './chown/index.vue';
|
||||||
import { Mimetypes, Languages } from '@/global/mimetype';
|
import { Mimetypes, Languages } from '@/global/mimetype';
|
||||||
import Process from './process/index.vue';
|
import Process from './process/index.vue';
|
||||||
// import Detail from './detail/index.vue';
|
// import Detail from './detail/index.vue';
|
||||||
|
|
@ -251,7 +261,7 @@ const moveRef = ref();
|
||||||
const downloadRef = ref();
|
const downloadRef = ref();
|
||||||
const pathRef = ref();
|
const pathRef = ref();
|
||||||
const breadCrumbRef = ref();
|
const breadCrumbRef = ref();
|
||||||
|
const chownRef = ref();
|
||||||
const moveOpen = ref(false);
|
const moveOpen = ref(false);
|
||||||
|
|
||||||
// editablePath
|
// editablePath
|
||||||
|
|
@ -443,6 +453,10 @@ const openMode = (item: File.File) => {
|
||||||
roleRef.value.acceptParams(item);
|
roleRef.value.acceptParams(item);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const openChown = (item: File.File) => {
|
||||||
|
chownRef.value.acceptParams(item);
|
||||||
|
};
|
||||||
|
|
||||||
const openCompress = (items: File.File[]) => {
|
const openCompress = (items: File.File[]) => {
|
||||||
const paths = [];
|
const paths = [];
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue