mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 00:09:16 +08:00
feat: 增加定时刷新组件
This commit is contained in:
parent
1d3738be39
commit
3f3d24648b
4
.gitignore
vendored
4
.gitignore
vendored
@ -5,10 +5,6 @@
|
|||||||
*.so
|
*.so
|
||||||
*.dylib
|
*.dylib
|
||||||
.idea
|
.idea
|
||||||
cmd/server/web/assets/
|
|
||||||
cmd/server/web/monacoeditorwork
|
|
||||||
cmd/server/web/favicon.ico
|
|
||||||
cmd/server/web/index.html
|
|
||||||
|
|
||||||
build
|
build
|
||||||
|
|
||||||
|
@ -38,12 +38,12 @@ func (b *BaseApi) CreateSnapshot(c *gin.Context) {
|
|||||||
// @Summary Page system snapshot
|
// @Summary Page system snapshot
|
||||||
// @Description 获取系统快照列表分页
|
// @Description 获取系统快照列表分页
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Param request body dto.PageInfo true "request"
|
// @Param request body dto.SearchWithPage true "request"
|
||||||
// @Success 200 {object} dto.PageResult
|
// @Success 200 {object} dto.PageResult
|
||||||
// @Security ApiKeyAuth
|
// @Security ApiKeyAuth
|
||||||
// @Router /settings/snapshot/search [post]
|
// @Router /settings/snapshot/search [post]
|
||||||
func (b *BaseApi) SearchSnapshot(c *gin.Context) {
|
func (b *BaseApi) SearchSnapshot(c *gin.Context) {
|
||||||
var req dto.PageInfo
|
var req dto.SearchWithPage
|
||||||
if err := c.ShouldBindJSON(&req); err != nil {
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||||
return
|
return
|
||||||
|
@ -25,7 +25,7 @@ type SnapshotService struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ISnapshotService interface {
|
type ISnapshotService interface {
|
||||||
SearchWithPage(req dto.PageInfo) (int64, interface{}, error)
|
SearchWithPage(req dto.SearchWithPage) (int64, interface{}, error)
|
||||||
SnapshotCreate(req dto.SnapshotCreate) error
|
SnapshotCreate(req dto.SnapshotCreate) error
|
||||||
SnapshotRecover(req dto.SnapshotRecover) error
|
SnapshotRecover(req dto.SnapshotRecover) error
|
||||||
SnapshotRollback(req dto.SnapshotRecover) error
|
SnapshotRollback(req dto.SnapshotRecover) error
|
||||||
@ -38,8 +38,8 @@ func NewISnapshotService() ISnapshotService {
|
|||||||
return &SnapshotService{}
|
return &SnapshotService{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *SnapshotService) SearchWithPage(req dto.PageInfo) (int64, interface{}, error) {
|
func (u *SnapshotService) SearchWithPage(req dto.SearchWithPage) (int64, interface{}, error) {
|
||||||
total, systemBackups, err := snapshotRepo.Page(req.Page, req.PageSize)
|
total, systemBackups, err := snapshotRepo.Page(req.Page, req.PageSize, commonRepo.WithLikeName(req.Info))
|
||||||
var dtoSnap []dto.SnapshotInfo
|
var dtoSnap []dto.SnapshotInfo
|
||||||
for _, systemBackup := range systemBackups {
|
for _, systemBackup := range systemBackups {
|
||||||
var item dto.SnapshotInfo
|
var item dto.SnapshotInfo
|
||||||
@ -90,7 +90,7 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
|||||||
Description: req.Description,
|
Description: req.Description,
|
||||||
From: req.From,
|
From: req.From,
|
||||||
Version: versionItem.Value,
|
Version: versionItem.Value,
|
||||||
Status: constant.StatusSuccess,
|
Status: constant.StatusWaiting,
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.Create(&snap)
|
_ = snapshotRepo.Create(&snap)
|
||||||
_ = settingRepo.Update("SystemStatus", "Snapshoting")
|
_ = settingRepo.Update("SystemStatus", "Snapshoting")
|
||||||
@ -134,11 +134,10 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := u.handlePanelDatas(fileOp, "snapshot", global.CONF.BaseDir+"/1panel", backupPanelDir, localDir, dockerDataDir); err != nil {
|
if err := u.handlePanelDatas(snap.ID, fileOp, "snapshot", global.CONF.BaseDir+"/1panel", backupPanelDir, localDir, dockerDataDir); err != nil {
|
||||||
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
|
updateSnapshotStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusWaiting})
|
|
||||||
|
|
||||||
snapJson := SnapshotJson{DockerDataDir: dockerDataDir, BackupDataDir: localDir, PanelDataDir: global.CONF.BaseDir + "/1panel", LiveRestoreEnabled: liveRestoreStatus}
|
snapJson := SnapshotJson{DockerDataDir: dockerDataDir, BackupDataDir: localDir, PanelDataDir: global.CONF.BaseDir + "/1panel", LiveRestoreEnabled: liveRestoreStatus}
|
||||||
if err := u.saveJson(snapJson, rootDir); err != nil {
|
if err := u.saveJson(snapJson, rootDir); err != nil {
|
||||||
@ -154,6 +153,7 @@ func (u *SnapshotService) SnapshotCreate(req dto.SnapshotCreate) error {
|
|||||||
_ = settingRepo.Update("SystemStatus", "Free")
|
_ = settingRepo.Update("SystemStatus", "Free")
|
||||||
|
|
||||||
global.LOG.Infof("start to upload snapshot to %s, please wait", backup.Type)
|
global.LOG.Infof("start to upload snapshot to %s, please wait", backup.Type)
|
||||||
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusUploading})
|
||||||
localPath := fmt.Sprintf("%s/system/1panel_snapshot_%s.tar.gz", localDir, timeNow)
|
localPath := fmt.Sprintf("%s/system/1panel_snapshot_%s.tar.gz", localDir, timeNow)
|
||||||
if ok, err := backupAccont.Upload(localPath, fmt.Sprintf("system_snapshot/1panel_snapshot_%s.tar.gz", timeNow)); err != nil || !ok {
|
if ok, err := backupAccont.Upload(localPath, fmt.Sprintf("system_snapshot/1panel_snapshot_%s.tar.gz", timeNow)); err != nil || !ok {
|
||||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"status": constant.StatusFailed, "message": err.Error()})
|
||||||
@ -311,7 +311,7 @@ func (u *SnapshotService) SnapshotRecover(req dto.SnapshotRecover) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !isReTry || snap.InterruptStep == "1PanelData" {
|
if !isReTry || snap.InterruptStep == "1PanelData" {
|
||||||
if err := u.handlePanelDatas(fileOp, operation, rootDir, snapJson.PanelDataDir, localDir, snapJson.OldDockerDataDir); err != nil {
|
if err := u.handlePanelDatas(snap.ID, fileOp, operation, rootDir, snapJson.PanelDataDir, localDir, snapJson.OldDockerDataDir); err != nil {
|
||||||
updateRecoverStatus(snap.ID, "1PanelData", constant.StatusFailed, err.Error())
|
updateRecoverStatus(snap.ID, "1PanelData", constant.StatusFailed, err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -344,89 +344,92 @@ func (u *SnapshotService) SnapshotRollback(req dto.SnapshotRecover) error {
|
|||||||
if _, err := os.Stat(u.OriginalPath); err != nil && os.IsNotExist(err) {
|
if _, err := os.Stat(u.OriginalPath); err != nil && os.IsNotExist(err) {
|
||||||
return fmt.Errorf("load original dir failed, err: %s", err)
|
return fmt.Errorf("load original dir failed, err: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = settingRepo.Update("SystemStatus", "Rollbacking")
|
||||||
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"rollback_status": constant.StatusWaiting})
|
_ = snapshotRepo.Update(snap.ID, map[string]interface{}{"rollback_status": constant.StatusWaiting})
|
||||||
snapJson, err := u.readFromJson(fmt.Sprintf("%s/snapshot.json", rootDir))
|
go func() {
|
||||||
if err != nil {
|
snapJson, err := u.readFromJson(fmt.Sprintf("%s/snapshot.json", rootDir))
|
||||||
updateRollbackStatus(snap.ID, constant.StatusFailed, fmt.Sprintf("decompress file failed, err: %v", err))
|
if err != nil {
|
||||||
return err
|
updateRollbackStatus(snap.ID, constant.StatusFailed, fmt.Sprintf("decompress file failed, err: %v", err))
|
||||||
}
|
return
|
||||||
|
|
||||||
_, _ = cmd.Exec("systemctl stop docker")
|
|
||||||
if err := u.handleDockerDatas(fileOp, "rollback", u.OriginalPath, snapJson.OldDockerDataDir); err != nil {
|
|
||||||
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if snap.InterruptStep == "DockerDir" {
|
|
||||||
_, _ = cmd.Exec("systemctl restart docker")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := u.handleDaemonJson(fileOp, "rollback", u.OriginalPath+"/daemon.json", ""); err != nil {
|
|
||||||
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if snap.InterruptStep == "DaemonJson" {
|
|
||||||
_, _ = cmd.Exec("systemctl restart docker")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
if snapJson.LiveRestoreEnabled {
|
|
||||||
if err := u.updateLiveRestore(true); err != nil {
|
|
||||||
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if snap.InterruptStep == "UpdateLiveRestore" {
|
|
||||||
_, _ = cmd.Exec("systemctl restart dockere")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := u.handlePanelBinary(fileOp, "rollback", u.OriginalPath+"/1panel", ""); err != nil {
|
_, _ = cmd.Exec("systemctl stop docker")
|
||||||
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
if err := u.handleDockerDatas(fileOp, "rollback", u.OriginalPath, snapJson.OldDockerDataDir); err != nil {
|
||||||
return err
|
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||||
}
|
return
|
||||||
if snap.InterruptStep == "1PanelBinary" {
|
}
|
||||||
return nil
|
if snap.InterruptStep == "DockerDir" {
|
||||||
}
|
_, _ = cmd.Exec("systemctl restart docker")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := u.handlePanelctlBinary(fileOp, "rollback", u.OriginalPath+"/1pctl", ""); err != nil {
|
if err := u.handleDaemonJson(fileOp, "rollback", u.OriginalPath+"/daemon.json", ""); err != nil {
|
||||||
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
if snap.InterruptStep == "1PctlBinary" {
|
if snap.InterruptStep == "DaemonJson" {
|
||||||
return nil
|
_, _ = cmd.Exec("systemctl restart docker")
|
||||||
}
|
return
|
||||||
|
}
|
||||||
|
if snapJson.LiveRestoreEnabled {
|
||||||
|
if err := u.updateLiveRestore(true); err != nil {
|
||||||
|
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if snap.InterruptStep == "UpdateLiveRestore" {
|
||||||
|
_, _ = cmd.Exec("systemctl restart dockere")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := u.handlePanelService(fileOp, "rollback", u.OriginalPath+"/1panel.service", ""); err != nil {
|
if err := u.handlePanelBinary(fileOp, "rollback", u.OriginalPath+"/1panel", ""); err != nil {
|
||||||
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||||
return err
|
return
|
||||||
}
|
}
|
||||||
if snap.InterruptStep == "1PanelService" {
|
if snap.InterruptStep == "1PanelBinary" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := u.handlePanelctlBinary(fileOp, "rollback", u.OriginalPath+"/1pctl", ""); err != nil {
|
||||||
|
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if snap.InterruptStep == "1PctlBinary" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := u.handlePanelService(fileOp, "rollback", u.OriginalPath+"/1panel.service", ""); err != nil {
|
||||||
|
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if snap.InterruptStep == "1PanelService" {
|
||||||
|
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := u.handleBackupDatas(fileOp, "rollback", u.OriginalPath, snapJson.OldBackupDataDir); err != nil {
|
||||||
|
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if snap.InterruptStep == "1PanelBackups" {
|
||||||
|
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := u.handlePanelDatas(snap.ID, fileOp, "rollback", u.OriginalPath, snapJson.OldPanelDataDir, "", ""); err != nil {
|
||||||
|
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if snap.InterruptStep == "1PanelData" {
|
||||||
|
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
_ = os.RemoveAll(rootDir)
|
||||||
|
global.LOG.Info("rollback successful")
|
||||||
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
||||||
return nil
|
}()
|
||||||
}
|
|
||||||
|
|
||||||
if err := u.handleBackupDatas(fileOp, "rollback", u.OriginalPath, snapJson.OldBackupDataDir); err != nil {
|
|
||||||
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if snap.InterruptStep == "1PanelBackups" {
|
|
||||||
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := u.handlePanelDatas(fileOp, "rollback", u.OriginalPath, snapJson.OldPanelDataDir, "", ""); err != nil {
|
|
||||||
updateRollbackStatus(snap.ID, constant.StatusFailed, err.Error())
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if snap.InterruptStep == "1PanelData" {
|
|
||||||
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = os.RemoveAll(rootDir)
|
|
||||||
global.LOG.Info("rollback successful")
|
|
||||||
_, _ = cmd.Exec("systemctl daemon-reload && systemctl restart 1panel.service")
|
|
||||||
updateRollbackStatus(snap.ID, constant.StatusSuccess, "")
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -604,7 +607,7 @@ func (u *SnapshotService) handleBackupDatas(fileOp files.FileOp, operation strin
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *SnapshotService) handlePanelDatas(fileOp files.FileOp, operation string, source, target, backupDir, dockerDir string) error {
|
func (u *SnapshotService) handlePanelDatas(snapID uint, fileOp files.FileOp, operation string, source, target, backupDir, dockerDir string) error {
|
||||||
switch operation {
|
switch operation {
|
||||||
case "snapshot":
|
case "snapshot":
|
||||||
exclusionRules := "./tmp;./cache;"
|
exclusionRules := "./tmp;./cache;"
|
||||||
@ -614,9 +617,12 @@ func (u *SnapshotService) handlePanelDatas(fileOp files.FileOp, operation string
|
|||||||
if strings.Contains(dockerDir, source) {
|
if strings.Contains(dockerDir, source) {
|
||||||
exclusionRules += ("." + strings.ReplaceAll(dockerDir, source, "") + ";")
|
exclusionRules += ("." + strings.ReplaceAll(dockerDir, source, "") + ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = snapshotRepo.Update(snapID, map[string]interface{}{"status": constant.StatusSuccess})
|
||||||
if err := u.handleTar(source, target, "1panel_data.tar.gz", exclusionRules); err != nil {
|
if err := u.handleTar(source, target, "1panel_data.tar.gz", exclusionRules); err != nil {
|
||||||
return fmt.Errorf("backup panel data failed, err: %v", err)
|
return fmt.Errorf("backup panel data failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
_ = snapshotRepo.Update(snapID, map[string]interface{}{"status": constant.StatusWaiting})
|
||||||
case "recover":
|
case "recover":
|
||||||
exclusionRules := "./tmp/;./cache;"
|
exclusionRules := "./tmp/;./cache;"
|
||||||
if strings.Contains(backupDir, target) {
|
if strings.Contains(backupDir, target) {
|
||||||
@ -625,9 +631,12 @@ func (u *SnapshotService) handlePanelDatas(fileOp files.FileOp, operation string
|
|||||||
if strings.Contains(dockerDir, target) {
|
if strings.Contains(dockerDir, target) {
|
||||||
exclusionRules += ("." + strings.ReplaceAll(dockerDir, target, "") + ";")
|
exclusionRules += ("." + strings.ReplaceAll(dockerDir, target, "") + ";")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_ = snapshotRepo.Update(snapID, map[string]interface{}{"recover_status": ""})
|
||||||
if err := u.handleTar(target, u.OriginalPath, "1panel_data.tar.gz", exclusionRules); err != nil {
|
if err := u.handleTar(target, u.OriginalPath, "1panel_data.tar.gz", exclusionRules); err != nil {
|
||||||
return fmt.Errorf("restore original panel data failed, err: %v", err)
|
return fmt.Errorf("restore original panel data failed, err: %v", err)
|
||||||
}
|
}
|
||||||
|
_ = snapshotRepo.Update(snapID, map[string]interface{}{"recover_status": constant.StatusWaiting})
|
||||||
|
|
||||||
if err := u.handleUnTar(source+"/1panel/1panel_data.tar.gz", target); err != nil {
|
if err := u.handleUnTar(source+"/1panel/1panel_data.tar.gz", target); err != nil {
|
||||||
return fmt.Errorf("recover panel data failed, err: %v", err)
|
return fmt.Errorf("recover panel data failed, err: %v", err)
|
||||||
@ -701,6 +710,7 @@ func updateRecoverStatus(id uint, interruptStep, status string, message string)
|
|||||||
_ = settingRepo.Update("SystemStatus", "Free")
|
_ = settingRepo.Update("SystemStatus", "Free")
|
||||||
}
|
}
|
||||||
func updateRollbackStatus(id uint, status string, message string) {
|
func updateRollbackStatus(id uint, status string, message string) {
|
||||||
|
_ = settingRepo.Update("SystemStatus", "Free")
|
||||||
if status == constant.StatusSuccess {
|
if status == constant.StatusSuccess {
|
||||||
if err := snapshotRepo.Update(id, map[string]interface{}{
|
if err := snapshotRepo.Update(id, map[string]interface{}{
|
||||||
"recover_status": "",
|
"recover_status": "",
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
package constant
|
package constant
|
||||||
|
|
||||||
const (
|
const (
|
||||||
StatusRunning = "Running"
|
StatusRunning = "Running"
|
||||||
StatusStoped = "Stoped"
|
StatusStoped = "Stoped"
|
||||||
StatusWaiting = "Waiting"
|
StatusWaiting = "Waiting"
|
||||||
StatusSuccess = "Success"
|
StatusSuccess = "Success"
|
||||||
StatusFailed = "Failed"
|
StatusFailed = "Failed"
|
||||||
StatusEnable = "Enable"
|
StatusUploading = "Uploading"
|
||||||
StatusDisable = "Disable"
|
StatusEnable = "Enable"
|
||||||
|
StatusDisable = "Disable"
|
||||||
)
|
)
|
||||||
|
@ -28,26 +28,26 @@ var doc = `{
|
|||||||
"host": "{{.Host}}",
|
"host": "{{.Host}}",
|
||||||
"basePath": "{{.BasePath}}",
|
"basePath": "{{.BasePath}}",
|
||||||
"paths": {
|
"paths": {
|
||||||
"/apps/:id": {
|
"/apps/:key": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"ApiKeyAuth": []
|
"ApiKeyAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "通过 id 获取应用信息",
|
"description": "通过 key 获取应用信息",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"App"
|
"App"
|
||||||
],
|
],
|
||||||
"summary": "Search app by id",
|
"summary": "Search app by key",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "string",
|
||||||
"description": "app id",
|
"description": "app key",
|
||||||
"name": "id",
|
"name": "key",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
@ -6489,7 +6489,7 @@ var doc = `{
|
|||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/dto.PageInfo"
|
"$ref": "#/definitions/dto.SearchWithPage"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -10668,6 +10668,9 @@ var doc = `{
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"recommend": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"required": {
|
"required": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -11105,6 +11108,9 @@ var doc = `{
|
|||||||
"pageSize": {
|
"pageSize": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"recommend": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@ -11985,6 +11991,9 @@ var doc = `{
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"recommend": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"required": {
|
"required": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -14,26 +14,26 @@
|
|||||||
"host": "localhost",
|
"host": "localhost",
|
||||||
"basePath": "/api/v1",
|
"basePath": "/api/v1",
|
||||||
"paths": {
|
"paths": {
|
||||||
"/apps/:id": {
|
"/apps/:key": {
|
||||||
"get": {
|
"get": {
|
||||||
"security": [
|
"security": [
|
||||||
{
|
{
|
||||||
"ApiKeyAuth": []
|
"ApiKeyAuth": []
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "通过 id 获取应用信息",
|
"description": "通过 key 获取应用信息",
|
||||||
"consumes": [
|
"consumes": [
|
||||||
"application/json"
|
"application/json"
|
||||||
],
|
],
|
||||||
"tags": [
|
"tags": [
|
||||||
"App"
|
"App"
|
||||||
],
|
],
|
||||||
"summary": "Search app by id",
|
"summary": "Search app by key",
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
"type": "integer",
|
"type": "string",
|
||||||
"description": "app id",
|
"description": "app key",
|
||||||
"name": "id",
|
"name": "key",
|
||||||
"in": "path",
|
"in": "path",
|
||||||
"required": true
|
"required": true
|
||||||
}
|
}
|
||||||
@ -6475,7 +6475,7 @@
|
|||||||
"in": "body",
|
"in": "body",
|
||||||
"required": true,
|
"required": true,
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/dto.PageInfo"
|
"$ref": "#/definitions/dto.SearchWithPage"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@ -10654,6 +10654,9 @@
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"recommend": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"required": {
|
"required": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
@ -11091,6 +11094,9 @@
|
|||||||
"pageSize": {
|
"pageSize": {
|
||||||
"type": "integer"
|
"type": "integer"
|
||||||
},
|
},
|
||||||
|
"recommend": {
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@ -11971,6 +11977,9 @@
|
|||||||
"name": {
|
"name": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"recommend": {
|
||||||
|
"type": "integer"
|
||||||
|
},
|
||||||
"required": {
|
"required": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -1496,6 +1496,8 @@ definitions:
|
|||||||
type: integer
|
type: integer
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
|
recommend:
|
||||||
|
type: integer
|
||||||
required:
|
required:
|
||||||
type: string
|
type: string
|
||||||
shortDesc:
|
shortDesc:
|
||||||
@ -1782,6 +1784,8 @@ definitions:
|
|||||||
type: integer
|
type: integer
|
||||||
pageSize:
|
pageSize:
|
||||||
type: integer
|
type: integer
|
||||||
|
recommend:
|
||||||
|
type: boolean
|
||||||
tags:
|
tags:
|
||||||
items:
|
items:
|
||||||
type: string
|
type: string
|
||||||
@ -2375,6 +2379,8 @@ definitions:
|
|||||||
type: integer
|
type: integer
|
||||||
name:
|
name:
|
||||||
type: string
|
type: string
|
||||||
|
recommend:
|
||||||
|
type: integer
|
||||||
required:
|
required:
|
||||||
type: string
|
type: string
|
||||||
shortDesc:
|
shortDesc:
|
||||||
@ -2629,17 +2635,17 @@ info:
|
|||||||
title: 1Panel
|
title: 1Panel
|
||||||
version: "1.0"
|
version: "1.0"
|
||||||
paths:
|
paths:
|
||||||
/apps/:id:
|
/apps/:key:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
- application/json
|
- application/json
|
||||||
description: 通过 id 获取应用信息
|
description: 通过 key 获取应用信息
|
||||||
parameters:
|
parameters:
|
||||||
- description: app id
|
- description: app key
|
||||||
in: path
|
in: path
|
||||||
name: id
|
name: key
|
||||||
required: true
|
required: true
|
||||||
type: integer
|
type: string
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
@ -2647,7 +2653,7 @@ paths:
|
|||||||
$ref: '#/definitions/response.AppDTO'
|
$ref: '#/definitions/response.AppDTO'
|
||||||
security:
|
security:
|
||||||
- ApiKeyAuth: []
|
- ApiKeyAuth: []
|
||||||
summary: Search app by id
|
summary: Search app by key
|
||||||
tags:
|
tags:
|
||||||
- App
|
- App
|
||||||
/apps/detail/:appId/:version:
|
/apps/detail/:appId/:version:
|
||||||
@ -6736,7 +6742,7 @@ paths:
|
|||||||
name: request
|
name: request
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/dto.PageInfo'
|
$ref: '#/definitions/dto.SearchWithPage'
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
|
2
frontend/components.d.ts
vendored
2
frontend/components.d.ts
vendored
@ -60,7 +60,6 @@ declare module 'vue' {
|
|||||||
ElRow: typeof import('element-plus/es')['ElRow']
|
ElRow: typeof import('element-plus/es')['ElRow']
|
||||||
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
ElScrollbar: typeof import('element-plus/es')['ElScrollbar']
|
||||||
ElSelect: typeof import('element-plus/es')['ElSelect']
|
ElSelect: typeof import('element-plus/es')['ElSelect']
|
||||||
ElSpan: typeof import('element-plus/es')['ElSpan']
|
|
||||||
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
ElSubMenu: typeof import('element-plus/es')['ElSubMenu']
|
||||||
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
ElSwitch: typeof import('element-plus/es')['ElSwitch']
|
||||||
ElTable: typeof import('element-plus/es')['ElTable']
|
ElTable: typeof import('element-plus/es')['ElTable']
|
||||||
@ -83,6 +82,7 @@ declare module 'vue' {
|
|||||||
Status: typeof import('./src/components/status/index.vue')['default']
|
Status: typeof import('./src/components/status/index.vue')['default']
|
||||||
SubItem: typeof import('./src/components/app-layout/menu/components/sub-item.vue')['default']
|
SubItem: typeof import('./src/components/app-layout/menu/components/sub-item.vue')['default']
|
||||||
SvgIcon: typeof import('./src/components/svg-icon/svg-icon.vue')['default']
|
SvgIcon: typeof import('./src/components/svg-icon/svg-icon.vue')['default']
|
||||||
|
TableSetting: typeof import('./src/components/table-setting/index.vue')['default']
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import http from '@/api';
|
import http from '@/api';
|
||||||
import { ReqPage, ResPage } from '../interface';
|
import { ResPage, SearchWithPage } from '../interface';
|
||||||
import { Setting } from '../interface/setting';
|
import { Setting } from '../interface/setting';
|
||||||
|
|
||||||
export const getSettingInfo = () => {
|
export const getSettingInfo = () => {
|
||||||
@ -62,7 +62,7 @@ export const snapshotRecover = (param: Setting.SnapshotRecover) => {
|
|||||||
export const snapshotRollback = (param: Setting.SnapshotRecover) => {
|
export const snapshotRollback = (param: Setting.SnapshotRecover) => {
|
||||||
return http.post(`/settings/snapshot/rollback`, param);
|
return http.post(`/settings/snapshot/rollback`, param);
|
||||||
};
|
};
|
||||||
export const searchSnapshotPage = (param: ReqPage) => {
|
export const searchSnapshotPage = (param: SearchWithPage) => {
|
||||||
return http.post<ResPage<Setting.SnapshotInfo>>(`/settings/snapshot/search`, param);
|
return http.post<ResPage<Setting.SnapshotInfo>>(`/settings/snapshot/search`, param);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ const loadStatus = async () => {
|
|||||||
clearInterval(Number(timer));
|
clearInterval(Number(timer));
|
||||||
timer = null;
|
timer = null;
|
||||||
});
|
});
|
||||||
}, 1000 * 5);
|
}, 1000 * 20);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
79
frontend/src/components/table-setting/index.vue
Normal file
79
frontend/src/components/table-setting/index.vue
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-popover placement="bottom-start" :width="200" trigger="click">
|
||||||
|
<template #reference>
|
||||||
|
<el-button round class="timer-button">{{ $t('commons.table.tableSetting') }}</el-button>
|
||||||
|
</template>
|
||||||
|
<div style="margin-left: 15px">
|
||||||
|
<div>
|
||||||
|
<span>{{ $t('commons.table.autoRefresh') }}</span>
|
||||||
|
<el-switch style="margin-left: 5px" v-model="autoRefresh" @change="changeRefresh"></el-switch>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<span>{{ $t('commons.table.refreshRate') }}</span>
|
||||||
|
<el-select style="margin-left: 5px; width: 80px" v-model="refreshRate" @change="changeRefresh">
|
||||||
|
<el-option label="5s" :value="5"></el-option>
|
||||||
|
<el-option label="10s" :value="10"></el-option>
|
||||||
|
<el-option label="30s" :value="30"></el-option>
|
||||||
|
<el-option label="1min" :value="60"></el-option>
|
||||||
|
<el-option label="2min" :value="120"></el-option>
|
||||||
|
<el-option label="5min" :value="300"></el-option>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</el-popover>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { onUnmounted, ref } from 'vue';
|
||||||
|
defineOptions({ name: 'TableSetting' });
|
||||||
|
|
||||||
|
const autoRefresh = ref<boolean>(false);
|
||||||
|
const refreshRate = ref<number>(10);
|
||||||
|
const emit = defineEmits(['search']);
|
||||||
|
|
||||||
|
let timer: NodeJS.Timer | null = null;
|
||||||
|
|
||||||
|
const changeRefresh = () => {
|
||||||
|
if (autoRefresh.value) {
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(Number(timer));
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
timer = setInterval(() => {
|
||||||
|
emit('search');
|
||||||
|
}, 1000 * refreshRate.value);
|
||||||
|
} else {
|
||||||
|
if (timer) {
|
||||||
|
clearInterval(Number(timer));
|
||||||
|
timer = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const startTimer = () => {
|
||||||
|
autoRefresh.value = true;
|
||||||
|
changeRefresh();
|
||||||
|
};
|
||||||
|
const endTimer = () => {
|
||||||
|
autoRefresh.value = false;
|
||||||
|
changeRefresh();
|
||||||
|
};
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(Number(timer));
|
||||||
|
timer = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
defineExpose({
|
||||||
|
startTimer,
|
||||||
|
endTimer,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.timer-button {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
</style>
|
@ -61,12 +61,16 @@ export default {
|
|||||||
description: 'Description',
|
description: 'Description',
|
||||||
interval: 'Interval',
|
interval: 'Interval',
|
||||||
title: 'Title',
|
title: 'Title',
|
||||||
|
tableSetting: 'Table setting',
|
||||||
|
autoRefresh: 'Auto refresh',
|
||||||
|
refreshRate: 'Refresh rate',
|
||||||
},
|
},
|
||||||
loadingText: {
|
loadingText: {
|
||||||
Upgrading: 'System upgrade, please wait...',
|
Upgrading: 'System upgrade, please wait...',
|
||||||
Restarting: 'System restart, please wait...',
|
Restarting: 'System restart, please wait...',
|
||||||
Snapshoting: 'Making snapshots, please wait...',
|
Snapshoting: 'Making snapshots, please wait...',
|
||||||
Recovering: 'Recovering from snapshot, please wait...',
|
Recovering: 'Recovering from snapshot, please wait...',
|
||||||
|
Rollbacking: 'Rollbacking from snapshot, please wait...',
|
||||||
},
|
},
|
||||||
msg: {
|
msg: {
|
||||||
delete: 'This operation cannot be rolled back. Do you want to continue',
|
delete: 'This operation cannot be rolled back. Do you want to continue',
|
||||||
@ -155,6 +159,7 @@ export default {
|
|||||||
error: 'error',
|
error: 'error',
|
||||||
created: 'created',
|
created: 'created',
|
||||||
restarting: 'restarting',
|
restarting: 'restarting',
|
||||||
|
uploading: 'uploading',
|
||||||
removing: 'removing',
|
removing: 'removing',
|
||||||
paused: 'paused',
|
paused: 'paused',
|
||||||
exited: 'exited',
|
exited: 'exited',
|
||||||
|
@ -64,12 +64,16 @@ export default {
|
|||||||
description: '描述信息',
|
description: '描述信息',
|
||||||
interval: '耗时',
|
interval: '耗时',
|
||||||
title: '标题',
|
title: '标题',
|
||||||
|
tableSetting: '列表设置',
|
||||||
|
autoRefresh: '定时刷新',
|
||||||
|
refreshRate: '刷新频率',
|
||||||
},
|
},
|
||||||
loadingText: {
|
loadingText: {
|
||||||
Upgrading: '系统升级中,请稍候...',
|
Upgrading: '系统升级中,请稍候...',
|
||||||
Restarting: '系统重启中,请稍候...',
|
Restarting: '系统重启中,请稍候...',
|
||||||
Snapshoting: '制作快照中,请稍候...',
|
Snapshoting: '制作快照中,请稍候...',
|
||||||
Recovering: '从快照恢复中,请稍候...',
|
Recovering: '从快照恢复中,请稍候...',
|
||||||
|
Rollbacking: '快照回滚中,请稍候...',
|
||||||
},
|
},
|
||||||
msg: {
|
msg: {
|
||||||
delete: '删除 操作不可回滚,是否继续',
|
delete: '删除 操作不可回滚,是否继续',
|
||||||
@ -165,6 +169,7 @@ export default {
|
|||||||
error: '失败',
|
error: '失败',
|
||||||
created: '已创建',
|
created: '已创建',
|
||||||
restarting: '重启中',
|
restarting: '重启中',
|
||||||
|
uploading: '上传中',
|
||||||
unhealthy: '异常',
|
unhealthy: '异常',
|
||||||
removing: '迁移中',
|
removing: '迁移中',
|
||||||
paused: '暂停',
|
paused: '暂停',
|
||||||
|
@ -19,12 +19,13 @@
|
|||||||
>
|
>
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" @click="onOpenDialog()">
|
<el-button type="primary" @click="onOpenDialog()">
|
||||||
{{ $t('container.createCompose') }}
|
{{ $t('container.createCompose') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchName"
|
v-model="searchName"
|
||||||
@ -88,6 +89,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import { reactive, onMounted, ref } from 'vue';
|
import { reactive, onMounted, ref } from 'vue';
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
import EditDialog from '@/views/container/compose/edit/index.vue';
|
import EditDialog from '@/views/container/compose/edit/index.vue';
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
>
|
>
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" @click="onCreate()">
|
<el-button type="primary" @click="onCreate()">
|
||||||
{{ $t('container.createContainer') }}
|
{{ $t('container.createContainer') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -42,7 +42,8 @@
|
|||||||
</el-button>
|
</el-button>
|
||||||
</el-button-group>
|
</el-button-group>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchName"
|
v-model="searchName"
|
||||||
@ -118,6 +119,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import ReNameDialog from '@/views/container/container/rename/index.vue';
|
import ReNameDialog from '@/views/container/container/rename/index.vue';
|
||||||
import CreateDialog from '@/views/container/container/create/index.vue';
|
import CreateDialog from '@/views/container/container/create/index.vue';
|
||||||
import MonitorDialog from '@/views/container/container/monitor/index.vue';
|
import MonitorDialog from '@/views/container/container/monitor/index.vue';
|
||||||
|
@ -47,6 +47,7 @@ interface DialogProps {
|
|||||||
tags: Array<string>;
|
tags: Array<string>;
|
||||||
}
|
}
|
||||||
const acceptParams = (params: DialogProps) => {
|
const acceptParams = (params: DialogProps) => {
|
||||||
|
isByID.value = false;
|
||||||
deleteVisiable.value = true;
|
deleteVisiable.value = true;
|
||||||
deleteForm.id = params.id.replaceAll('sha256:', '').substring(0, 12);
|
deleteForm.id = params.id.replaceAll('sha256:', '').substring(0, 12);
|
||||||
deleteForm.deleteTags = [];
|
deleteForm.deleteTags = [];
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<LayoutContent v-loading="loading" :title="$t('container.image')" :class="{ mask: dockerStatus != 'Running' }">
|
<LayoutContent v-loading="loading" :title="$t('container.image')" :class="{ mask: dockerStatus != 'Running' }">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" plain @click="onOpenPull">
|
<el-button type="primary" plain @click="onOpenPull">
|
||||||
{{ $t('container.imagePull') }}
|
{{ $t('container.imagePull') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -22,7 +22,8 @@
|
|||||||
{{ $t('container.build') }}
|
{{ $t('container.build') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchName"
|
v-model="searchName"
|
||||||
@ -75,6 +76,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import { reactive, onMounted, ref } from 'vue';
|
import { reactive, onMounted, ref } from 'vue';
|
||||||
import { dateFormatSimple } from '@/utils/util';
|
import { dateFormatSimple } from '@/utils/util';
|
||||||
import { Container } from '@/api/interface/container';
|
import { Container } from '@/api/interface/container';
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
>
|
>
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" @click="onCreate()">
|
<el-button type="primary" @click="onCreate()">
|
||||||
{{ $t('container.createNetwork') }}
|
{{ $t('container.createNetwork') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -23,7 +23,8 @@
|
|||||||
{{ $t('commons.button.delete') }}
|
{{ $t('commons.button.delete') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchName"
|
v-model="searchName"
|
||||||
@ -99,6 +100,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import CreateDialog from '@/views/container/network/create/index.vue';
|
import CreateDialog from '@/views/container/network/create/index.vue';
|
||||||
import CodemirrorDialog from '@/components/codemirror-dialog/codemirror.vue';
|
import CodemirrorDialog from '@/components/codemirror-dialog/codemirror.vue';
|
||||||
import { reactive, onMounted, ref } from 'vue';
|
import { reactive, onMounted, ref } from 'vue';
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<LayoutContent v-loading="loading" :title="$t('container.repo')" :class="{ mask: dockerStatus != 'Running' }">
|
<LayoutContent v-loading="loading" :title="$t('container.repo')" :class="{ mask: dockerStatus != 'Running' }">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" @click="onOpenDialog('create')">
|
<el-button type="primary" @click="onOpenDialog('create')">
|
||||||
{{ $t('container.createRepo') }}
|
{{ $t('container.createRepo') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -19,7 +19,8 @@
|
|||||||
{{ $t('commons.button.delete') }}
|
{{ $t('commons.button.delete') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchName"
|
v-model="searchName"
|
||||||
@ -78,6 +79,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import OperatorDialog from '@/views/container/repo/operator/index.vue';
|
import OperatorDialog from '@/views/container/repo/operator/index.vue';
|
||||||
import DeleteDialog from '@/views/container/repo/delete/index.vue';
|
import DeleteDialog from '@/views/container/repo/delete/index.vue';
|
||||||
import { reactive, onMounted, ref } from 'vue';
|
import { reactive, onMounted, ref } from 'vue';
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
>
|
>
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" @click="onOpenDialog('create')">
|
<el-button type="primary" @click="onOpenDialog('create')">
|
||||||
{{ $t('container.createComposeTemplate') }}
|
{{ $t('container.createComposeTemplate') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -23,7 +23,8 @@
|
|||||||
{{ $t('commons.button.delete') }}
|
{{ $t('commons.button.delete') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchName"
|
v-model="searchName"
|
||||||
@ -102,6 +103,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import { Codemirror } from 'vue-codemirror';
|
import { Codemirror } from 'vue-codemirror';
|
||||||
import { javascript } from '@codemirror/lang-javascript';
|
import { javascript } from '@codemirror/lang-javascript';
|
||||||
import { oneDark } from '@codemirror/theme-one-dark';
|
import { oneDark } from '@codemirror/theme-one-dark';
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<LayoutContent v-loading="loading" :title="$t('container.volume')" :class="{ mask: dockerStatus != 'Running' }">
|
<LayoutContent v-loading="loading" :title="$t('container.volume')" :class="{ mask: dockerStatus != 'Running' }">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" @click="onCreate()">
|
<el-button type="primary" @click="onCreate()">
|
||||||
{{ $t('container.createVolume') }}
|
{{ $t('container.createVolume') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -19,7 +19,8 @@
|
|||||||
{{ $t('commons.button.delete') }}
|
{{ $t('commons.button.delete') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchName"
|
v-model="searchName"
|
||||||
@ -84,6 +85,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import CreateDialog from '@/views/container/volume/create/index.vue';
|
import CreateDialog from '@/views/container/volume/create/index.vue';
|
||||||
import CodemirrorDialog from '@/components/codemirror-dialog/codemirror.vue';
|
import CodemirrorDialog from '@/components/codemirror-dialog/codemirror.vue';
|
||||||
import { reactive, onMounted, ref } from 'vue';
|
import { reactive, onMounted, ref } from 'vue';
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
<LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('cronjob.cronTask')">
|
<LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('cronjob.cronTask')">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" @click="onOpenDialog('create')">
|
<el-button type="primary" @click="onOpenDialog('create')">
|
||||||
{{ $t('commons.button.create') }}{{ $t('cronjob.cronTask') }}
|
{{ $t('commons.button.create') }}{{ $t('cronjob.cronTask') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
@ -19,7 +19,8 @@
|
|||||||
{{ $t('commons.button.delete') }}
|
{{ $t('commons.button.delete') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchName"
|
v-model="searchName"
|
||||||
@ -124,6 +125,7 @@
|
|||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import OperatrDialog from '@/views/cronjob/operate/index.vue';
|
import OperatrDialog from '@/views/cronjob/operate/index.vue';
|
||||||
import Records from '@/views/cronjob/record/index.vue';
|
import Records from '@/views/cronjob/record/index.vue';
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
<LayoutContent v-loading="loading" :title="$t('logs.login')">
|
<LayoutContent v-loading="loading" :title="$t('logs.login')">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" plain @click="onClean()">
|
<el-button type="primary" plain @click="onClean()">
|
||||||
{{ $t('logs.deleteLogs') }}
|
{{ $t('logs.deleteLogs') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchIP"
|
v-model="searchIP"
|
||||||
@ -64,6 +65,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
import { dateFormat } from '@/utils/util';
|
import { dateFormat } from '@/utils/util';
|
||||||
|
@ -3,12 +3,13 @@
|
|||||||
<LayoutContent v-loading="loading" :title="$t('logs.operation')">
|
<LayoutContent v-loading="loading" :title="$t('logs.operation')">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-row>
|
<el-row>
|
||||||
<el-col :span="20">
|
<el-col :span="16">
|
||||||
<el-button type="primary" plain @click="onClean()">
|
<el-button type="primary" plain @click="onClean()">
|
||||||
{{ $t('logs.deleteLogs') }}
|
{{ $t('logs.deleteLogs') }}
|
||||||
</el-button>
|
</el-button>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="4">
|
<el-col :span="8">
|
||||||
|
<TableSetting @search="search()" />
|
||||||
<div class="search-button">
|
<div class="search-button">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="searchName"
|
v-model="searchName"
|
||||||
@ -91,6 +92,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
import ConfirmDialog from '@/components/confirm-dialog/index.vue';
|
||||||
import { dateFormat } from '@/utils/util';
|
import { dateFormat } from '@/utils/util';
|
||||||
import LayoutContent from '@/layout/layout-content.vue';
|
import LayoutContent from '@/layout/layout-content.vue';
|
||||||
|
@ -2,12 +2,30 @@
|
|||||||
<div>
|
<div>
|
||||||
<LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('setting.snapshot')">
|
<LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('setting.snapshot')">
|
||||||
<template #toolbar>
|
<template #toolbar>
|
||||||
<el-button type="primary" @click="onCreate()">
|
<el-row>
|
||||||
{{ $t('setting.createSnapshot') }}
|
<el-col :span="16">
|
||||||
</el-button>
|
<el-button type="primary" @click="onCreate()">
|
||||||
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
|
{{ $t('setting.createSnapshot') }}
|
||||||
{{ $t('commons.button.delete') }}
|
</el-button>
|
||||||
</el-button>
|
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
|
||||||
|
{{ $t('commons.button.delete') }}
|
||||||
|
</el-button>
|
||||||
|
</el-col>
|
||||||
|
<el-col :span="8">
|
||||||
|
<TableSetting ref="timerRef" @search="search()" />
|
||||||
|
<div class="search-button">
|
||||||
|
<el-input
|
||||||
|
v-model="searchName"
|
||||||
|
clearable
|
||||||
|
@clear="search()"
|
||||||
|
suffix-icon="Search"
|
||||||
|
@keyup.enter="search()"
|
||||||
|
@blur="search()"
|
||||||
|
:placeholder="$t('commons.button.search')"
|
||||||
|
></el-input>
|
||||||
|
</div>
|
||||||
|
</el-col>
|
||||||
|
</el-row>
|
||||||
</template>
|
</template>
|
||||||
<template #main>
|
<template #main>
|
||||||
<ComplexTable
|
<ComplexTable
|
||||||
@ -40,6 +58,9 @@
|
|||||||
<el-tag v-if="row.status === 'Waiting'" type="info">
|
<el-tag v-if="row.status === 'Waiting'" type="info">
|
||||||
{{ $t('commons.table.statusWaiting') }}
|
{{ $t('commons.table.statusWaiting') }}
|
||||||
</el-tag>
|
</el-tag>
|
||||||
|
<el-tag v-if="row.status === 'Uploading'" type="info">
|
||||||
|
{{ $t('commons.status.uploading') }}...
|
||||||
|
</el-tag>
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
v-if="row.status === 'Failed'"
|
v-if="row.status === 'Failed'"
|
||||||
class="box-item"
|
class="box-item"
|
||||||
@ -67,7 +88,7 @@
|
|||||||
</ComplexTable>
|
</ComplexTable>
|
||||||
</template>
|
</template>
|
||||||
</LayoutContent>
|
</LayoutContent>
|
||||||
<RecoverStatus @search="search()" ref="recoverStatusRef"></RecoverStatus>
|
<RecoverStatus ref="recoverStatusRef" @search="search()"></RecoverStatus>
|
||||||
<el-drawer v-model="drawerVisiable" size="50%">
|
<el-drawer v-model="drawerVisiable" size="50%">
|
||||||
<template #header>
|
<template #header>
|
||||||
<DrawerHeader :header="$t('setting.createSnapshot')" :back="handleClose" />
|
<DrawerHeader :header="$t('setting.createSnapshot')" :back="handleClose" />
|
||||||
@ -117,6 +138,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import ComplexTable from '@/components/complex-table/index.vue';
|
import ComplexTable from '@/components/complex-table/index.vue';
|
||||||
|
import TableSetting from '@/components/table-setting/index.vue';
|
||||||
import { snapshotCreate, searchSnapshotPage, snapshotDelete } from '@/api/modules/setting';
|
import { snapshotCreate, searchSnapshotPage, snapshotDelete } from '@/api/modules/setting';
|
||||||
import { onMounted, reactive, ref } from 'vue';
|
import { onMounted, reactive, ref } from 'vue';
|
||||||
import { dateFormat } from '@/utils/util';
|
import { dateFormat } from '@/utils/util';
|
||||||
@ -139,6 +161,7 @@ const paginationConfig = reactive({
|
|||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
});
|
});
|
||||||
|
const searchName = ref();
|
||||||
|
|
||||||
const recoverStatusRef = ref();
|
const recoverStatusRef = ref();
|
||||||
const isRecordShow = ref();
|
const isRecordShow = ref();
|
||||||
@ -231,6 +254,7 @@ const buttons = [
|
|||||||
|
|
||||||
const search = async () => {
|
const search = async () => {
|
||||||
let params = {
|
let params = {
|
||||||
|
info: searchName.value,
|
||||||
page: paginationConfig.currentPage,
|
page: paginationConfig.currentPage,
|
||||||
pageSize: paginationConfig.pageSize,
|
pageSize: paginationConfig.pageSize,
|
||||||
};
|
};
|
||||||
|
@ -198,7 +198,7 @@ const acceptParams = (params: DialogProps): void => {
|
|||||||
snapInfo.value = params.snapInfo;
|
snapInfo.value = params.snapInfo;
|
||||||
drawerVisiable.value = true;
|
drawerVisiable.value = true;
|
||||||
};
|
};
|
||||||
const emit = defineEmits<{ (e: 'search'): void }>();
|
const emit = defineEmits(['search']);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
drawerVisiable.value = false;
|
drawerVisiable.value = false;
|
||||||
@ -211,6 +211,7 @@ const doRecover = async (isNew: boolean) => {
|
|||||||
emit('search');
|
emit('search');
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
dialogVisiable.value = false;
|
dialogVisiable.value = false;
|
||||||
|
drawerVisiable.value = false;
|
||||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
@ -240,6 +241,7 @@ const rollbackSnapshot = async () => {
|
|||||||
emit('search');
|
emit('search');
|
||||||
loading.value = false;
|
loading.value = false;
|
||||||
dialogVisiable.value = false;
|
dialogVisiable.value = false;
|
||||||
|
drawerVisiable.value = false;
|
||||||
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
ElMessage.success(i18n.global.t('commons.msg.operationSuccess'));
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user