From 8857d97dd76ace2cb4a6b6e30c5dc5ed55d48d7a Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Thu, 26 Oct 2023 18:20:16 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E7=BB=9F=E4=B8=80=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E6=8F=90=E7=A4=BA=E4=BF=A1=E6=81=AF=E5=8F=8A=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=20(#2690)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/app/api/v1/container.go | 28 +++- backend/app/dto/container.go | 10 +- backend/app/service/container.go | 53 ++++--- backend/router/ro_container.go | 1 + cmd/server/docs/docs.go | 79 ++++++++-- cmd/server/docs/swagger.json | 79 ++++++++-- cmd/server/docs/swagger.yaml | 55 +++++-- frontend/src/api/interface/container.ts | 5 +- frontend/src/api/interface/cronjob.ts | 4 + frontend/src/api/modules/container.ts | 3 + frontend/src/api/modules/cronjob.ts | 4 +- frontend/src/components/del-dialog/index.vue | 91 +++++++++++ frontend/src/lang/modules/en.ts | 5 +- frontend/src/lang/modules/tw.ts | 5 +- frontend/src/lang/modules/zh.ts | 5 +- .../views/container/compose/detail/index.vue | 27 ++-- .../container/container/handle/index.vue | 87 ----------- .../src/views/container/container/index.vue | 45 +++--- .../container/container/rename/index.vue | 5 +- .../views/container/image/delete/index.vue | 92 +++++++----- frontend/src/views/container/image/index.vue | 23 ++- .../src/views/container/network/index.vue | 17 ++- frontend/src/views/container/repo/index.vue | 22 ++- .../src/views/container/template/index.vue | 21 ++- frontend/src/views/container/volume/index.vue | 26 +++- frontend/src/views/cronjob/index.vue | 142 ++++++------------ frontend/src/views/host/firewall/ip/index.vue | 62 ++++---- .../src/views/host/firewall/port/index.vue | 65 ++++---- .../src/views/host/terminal/command/index.vue | 29 +++- .../src/views/host/terminal/host/index.vue | 24 ++- frontend/src/views/setting/snapshot/index.vue | 29 +++- 31 files changed, 720 insertions(+), 423 deletions(-) create mode 100644 frontend/src/components/del-dialog/index.vue delete mode 100644 frontend/src/views/container/container/handle/index.vue diff --git a/backend/app/api/v1/container.go b/backend/app/api/v1/container.go index aab30afdc..73d20ece9 100644 --- a/backend/app/api/v1/container.go +++ b/backend/app/api/v1/container.go @@ -373,6 +373,32 @@ func (b *BaseApi) LoadContainerLog(c *gin.Context) { helper.SuccessWithData(c, content) } +// @Tags Container +// @Summary Rename Container +// @Description 容器重命名 +// @Accept json +// @Param request body dto.ContainerRename true "request" +// @Success 200 +// @Security ApiKeyAuth +// @Router /containers/rename [post] +// @x-panel-log {"bodyKeys":["name","newName"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"容器重命名 [name] => [newName]","formatEN":"rename container [name] => [newName]"} +func (b *BaseApi) ContainerRename(c *gin.Context) { + var req dto.ContainerRename + if err := c.ShouldBindJSON(&req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := global.VALID.Struct(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err) + return + } + if err := containerService.ContainerRename(req); err != nil { + helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err) + return + } + helper.SuccessWithData(c, nil) +} + // @Tags Container // @Summary Operate Container // @Description 容器操作 @@ -381,7 +407,7 @@ func (b *BaseApi) LoadContainerLog(c *gin.Context) { // @Success 200 // @Security ApiKeyAuth // @Router /containers/operate [post] -// @x-panel-log {"bodyKeys":["name","operation","newName"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"容器 [name] 执行 [operation] [newName]","formatEN":"container [operation] [name] [newName]"} +// @x-panel-log {"bodyKeys":["names","operation"],"paramKeys":[],"BeforeFunctions":[],"formatZH":"容器 [names] 执行 [operation]","formatEN":"container [operation] [names]"} func (b *BaseApi) ContainerOperation(c *gin.Context) { var req dto.ContainerOperation if err := c.ShouldBindJSON(&req); err != nil { diff --git a/backend/app/dto/container.go b/backend/app/dto/container.go index 1a6851a88..99a8e2bbe 100644 --- a/backend/app/dto/container.go +++ b/backend/app/dto/container.go @@ -104,9 +104,13 @@ type PortHelper struct { } type ContainerOperation struct { - Name string `json:"name" validate:"required"` - Operation string `json:"operation" validate:"required,oneof=start stop restart kill pause unpause rename remove"` - NewName string `json:"newName"` + Names []string `json:"names" validate:"required"` + Operation string `json:"operation" validate:"required,oneof=start stop restart kill pause unpause remove"` +} + +type ContainerRename struct { + Name string `json:"name" validate:"required"` + NewName string `json:"newName"` } type ContainerPrune struct { diff --git a/backend/app/service/container.go b/backend/app/service/container.go index 58f915d9b..1649063cf 100644 --- a/backend/app/service/container.go +++ b/backend/app/service/container.go @@ -52,6 +52,7 @@ type IContainerService interface { ContainerInfo(req dto.OperationWithName) (*dto.ContainerOperate, error) ContainerListStats() ([]dto.ContainerListStats, error) LoadResourceLimit() (*dto.ResourceLimit, error) + ContainerRename(req dto.ContainerRename) error ContainerLogClean(req dto.OperationWithName) error ContainerOperation(req dto.ContainerOperation) error ContainerLogs(wsConn *websocket.Conn, container, since, tail string, follow bool) error @@ -514,6 +515,20 @@ func (u *ContainerService) ContainerUpgrade(req dto.ContainerUpgrade) error { return nil } +func (u *ContainerService) ContainerRename(req dto.ContainerRename) error { + ctx := context.Background() + client, err := docker.NewDockerClient() + if err != nil { + return err + } + + newContainer, _ := client.ContainerInspect(ctx, req.NewName) + if newContainer.ContainerJSONBase != nil { + return buserr.New(constant.ErrContainerName) + } + return client.ContainerRename(ctx, req.Name, req.NewName) +} + func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error { var err error ctx := context.Background() @@ -521,28 +536,24 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error if err != nil { return err } - global.LOG.Infof("start container %s operation %s", req.Name, req.Operation) - switch req.Operation { - case constant.ContainerOpStart: - err = client.ContainerStart(ctx, req.Name, types.ContainerStartOptions{}) - case constant.ContainerOpStop: - err = client.ContainerStop(ctx, req.Name, container.StopOptions{}) - case constant.ContainerOpRestart: - err = client.ContainerRestart(ctx, req.Name, container.StopOptions{}) - case constant.ContainerOpKill: - err = client.ContainerKill(ctx, req.Name, "SIGKILL") - case constant.ContainerOpPause: - err = client.ContainerPause(ctx, req.Name) - case constant.ContainerOpUnpause: - err = client.ContainerUnpause(ctx, req.Name) - case constant.ContainerOpRename: - newContainer, _ := client.ContainerInspect(ctx, req.NewName) - if newContainer.ContainerJSONBase != nil { - return buserr.New(constant.ErrContainerName) + for _, item := range req.Names { + global.LOG.Infof("start container %s operation %s", item, req.Operation) + switch req.Operation { + case constant.ContainerOpStart: + err = client.ContainerStart(ctx, item, types.ContainerStartOptions{}) + case constant.ContainerOpStop: + err = client.ContainerStop(ctx, item, container.StopOptions{}) + case constant.ContainerOpRestart: + err = client.ContainerRestart(ctx, item, container.StopOptions{}) + case constant.ContainerOpKill: + err = client.ContainerKill(ctx, item, "SIGKILL") + case constant.ContainerOpPause: + err = client.ContainerPause(ctx, item) + case constant.ContainerOpUnpause: + err = client.ContainerUnpause(ctx, item) + case constant.ContainerOpRemove: + err = client.ContainerRemove(ctx, item, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true}) } - err = client.ContainerRename(ctx, req.Name, req.NewName) - case constant.ContainerOpRemove: - err = client.ContainerRemove(ctx, req.Name, types.ContainerRemoveOptions{RemoveVolumes: true, Force: true}) } return err } diff --git a/backend/router/ro_container.go b/backend/router/ro_container.go index 7bbc130a7..cf89deae2 100644 --- a/backend/router/ro_container.go +++ b/backend/router/ro_container.go @@ -30,6 +30,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) { baRouter.POST("/clean/log", baseApi.CleanContainerLog) baRouter.POST("/load/log", baseApi.LoadContainerLog) baRouter.POST("/inspect", baseApi.Inspect) + baRouter.POST("/rename", baseApi.ContainerRename) baRouter.POST("/operate", baseApi.ContainerOperation) baRouter.POST("/prune", baseApi.ContainerPrune) diff --git a/cmd/server/docs/docs.go b/cmd/server/docs/docs.go index 97ed1396a..853423973 100644 --- a/cmd/server/docs/docs.go +++ b/cmd/server/docs/docs.go @@ -2314,12 +2314,11 @@ const docTemplate = `{ "x-panel-log": { "BeforeFunctions": [], "bodyKeys": [ - "name", - "operation", - "newName" + "names", + "operation" ], - "formatEN": "container [operation] [name] [newName]", - "formatZH": "容器 [name] 执行 [operation] [newName]", + "formatEN": "container [operation] [names]", + "formatZH": "容器 [names] 执行 [operation]", "paramKeys": [] } } @@ -2369,6 +2368,49 @@ const docTemplate = `{ } } }, + "/containers/rename": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "容器重命名", + "consumes": [ + "application/json" + ], + "tags": [ + "Container" + ], + "summary": "Rename Container", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.ContainerRename" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "name", + "newName" + ], + "formatEN": "rename container [name] =\u003e [newName]", + "formatZH": "容器重命名 [name] =\u003e [newName]", + "paramKeys": [] + } + } + }, "/containers/repo": { "get": { "security": [ @@ -13022,15 +13064,15 @@ const docTemplate = `{ "dto.ContainerOperation": { "type": "object", "required": [ - "name", + "names", "operation" ], "properties": { - "name": { - "type": "string" - }, - "newName": { - "type": "string" + "names": { + "type": "array", + "items": { + "type": "string" + } }, "operation": { "type": "string", @@ -13041,7 +13083,6 @@ const docTemplate = `{ "kill", "pause", "unpause", - "rename", "remove" ] } @@ -13078,6 +13119,20 @@ const docTemplate = `{ } } }, + "dto.ContainerRename": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "newName": { + "type": "string" + } + } + }, "dto.ContainerStats": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.json b/cmd/server/docs/swagger.json index 4391b1d9e..44b4b7549 100644 --- a/cmd/server/docs/swagger.json +++ b/cmd/server/docs/swagger.json @@ -2307,12 +2307,11 @@ "x-panel-log": { "BeforeFunctions": [], "bodyKeys": [ - "name", - "operation", - "newName" + "names", + "operation" ], - "formatEN": "container [operation] [name] [newName]", - "formatZH": "容器 [name] 执行 [operation] [newName]", + "formatEN": "container [operation] [names]", + "formatZH": "容器 [names] 执行 [operation]", "paramKeys": [] } } @@ -2362,6 +2361,49 @@ } } }, + "/containers/rename": { + "post": { + "security": [ + { + "ApiKeyAuth": [] + } + ], + "description": "容器重命名", + "consumes": [ + "application/json" + ], + "tags": [ + "Container" + ], + "summary": "Rename Container", + "parameters": [ + { + "description": "request", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/dto.ContainerRename" + } + } + ], + "responses": { + "200": { + "description": "OK" + } + }, + "x-panel-log": { + "BeforeFunctions": [], + "bodyKeys": [ + "name", + "newName" + ], + "formatEN": "rename container [name] =\u003e [newName]", + "formatZH": "容器重命名 [name] =\u003e [newName]", + "paramKeys": [] + } + } + }, "/containers/repo": { "get": { "security": [ @@ -13015,15 +13057,15 @@ "dto.ContainerOperation": { "type": "object", "required": [ - "name", + "names", "operation" ], "properties": { - "name": { - "type": "string" - }, - "newName": { - "type": "string" + "names": { + "type": "array", + "items": { + "type": "string" + } }, "operation": { "type": "string", @@ -13034,7 +13076,6 @@ "kill", "pause", "unpause", - "rename", "remove" ] } @@ -13071,6 +13112,20 @@ } } }, + "dto.ContainerRename": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "newName": { + "type": "string" + } + } + }, "dto.ContainerStats": { "type": "object", "properties": { diff --git a/cmd/server/docs/swagger.yaml b/cmd/server/docs/swagger.yaml index b48b35689..8ba2ad0dd 100644 --- a/cmd/server/docs/swagger.yaml +++ b/cmd/server/docs/swagger.yaml @@ -431,10 +431,10 @@ definitions: type: object dto.ContainerOperation: properties: - name: - type: string - newName: - type: string + names: + items: + type: string + type: array operation: enum: - start @@ -443,11 +443,10 @@ definitions: - kill - pause - unpause - - rename - remove type: string required: - - name + - names - operation type: object dto.ContainerPrune: @@ -471,6 +470,15 @@ definitions: spaceReclaimed: type: integer type: object + dto.ContainerRename: + properties: + name: + type: string + newName: + type: string + required: + - name + type: object dto.ContainerStats: properties: cache: @@ -5704,11 +5712,10 @@ paths: x-panel-log: BeforeFunctions: [] bodyKeys: - - name + - names - operation - - newName - formatEN: container [operation] [name] [newName] - formatZH: 容器 [name] 执行 [operation] [newName] + formatEN: container [operation] [names] + formatZH: 容器 [names] 执行 [operation] paramKeys: [] /containers/prune: post: @@ -5739,6 +5746,34 @@ paths: formatEN: clean container [pruneType] formatZH: 清理容器 [pruneType] paramKeys: [] + /containers/rename: + post: + consumes: + - application/json + description: 容器重命名 + parameters: + - description: request + in: body + name: request + required: true + schema: + $ref: '#/definitions/dto.ContainerRename' + responses: + "200": + description: OK + security: + - ApiKeyAuth: [] + summary: Rename Container + tags: + - Container + x-panel-log: + BeforeFunctions: [] + bodyKeys: + - name + - newName + formatEN: rename container [name] => [newName] + formatZH: 容器重命名 [name] => [newName] + paramKeys: [] /containers/repo: get: description: 获取镜像仓库列表 diff --git a/frontend/src/api/interface/container.ts b/frontend/src/api/interface/container.ts index 7061aaf92..3c19baf83 100644 --- a/frontend/src/api/interface/container.ts +++ b/frontend/src/api/interface/container.ts @@ -2,8 +2,11 @@ import { ReqPage } from '.'; export namespace Container { export interface ContainerOperate { - name: string; + names: Array; operation: string; + } + export interface ContainerRename { + name: string; newName: string; } export interface ContainerSearch extends ReqPage { diff --git a/frontend/src/api/interface/cronjob.ts b/frontend/src/api/interface/cronjob.ts index 5a4f32a3a..5d4bbd5d5 100644 --- a/frontend/src/api/interface/cronjob.ts +++ b/frontend/src/api/interface/cronjob.ts @@ -66,6 +66,10 @@ export namespace Cronjob { targetDirID: number; retainCopies: number; } + export interface CronjobDelete { + ids: Array; + cleanData: boolean; + } export interface UpdateStatus { id: number; status: string; diff --git a/frontend/src/api/modules/container.ts b/frontend/src/api/modules/container.ts index 90308f8c8..a02277ffd 100644 --- a/frontend/src/api/modules/container.ts +++ b/frontend/src/api/modules/container.ts @@ -36,6 +36,9 @@ export const containerListStats = () => { export const containerStats = (id: string) => { return http.get(`/containers/stats/${id}`); }; +export const containerRename = (params: Container.ContainerRename) => { + return http.post(`/containers/rename`, params); +}; export const containerOperator = (params: Container.ContainerOperate) => { return http.post(`/containers/operate`, params); }; diff --git a/frontend/src/api/modules/cronjob.ts b/frontend/src/api/modules/cronjob.ts index 67674b539..25ba7c972 100644 --- a/frontend/src/api/modules/cronjob.ts +++ b/frontend/src/api/modules/cronjob.ts @@ -19,8 +19,8 @@ export const editCronjob = (params: Cronjob.CronjobUpdate) => { return http.post(`/cronjobs/update`, params); }; -export const deleteCronjob = (ids: number[], cleanData: boolean) => { - return http.post(`/cronjobs/del`, { ids: ids, cleanData: cleanData }); +export const deleteCronjob = (params: Cronjob.CronjobDelete) => { + return http.post(`/cronjobs/del`, params); }; export const searchRecords = (params: Cronjob.SearchRecord) => { diff --git a/frontend/src/components/del-dialog/index.vue b/frontend/src/components/del-dialog/index.vue new file mode 100644 index 000000000..745a3f145 --- /dev/null +++ b/frontend/src/components/del-dialog/index.vue @@ -0,0 +1,91 @@ + + + diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 8a6451f15..a5f8e3a62 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -114,6 +114,7 @@ const message = { operateConfirm: 'If you are sure about the operation, please input it manually', inputOrSelect: 'Please select or enter', copyFailed: 'Copy failed', + operatorHelper: 'Would you like to continue performing {1} operation on {0}?', notFound: 'Sorry, the page you requested does not exist.', unSupportType: 'Current file type is not supported!', unSupportSize: 'The uploaded file exceeds {0}M, please confirm!', @@ -502,7 +503,7 @@ const message = { containerList: 'Container list', operatorHelper: '{0} will be performed on the following container, Do you want to continue?', operatorAppHelper: - 'The {0} operation will be performed on the following containers, some of which are from the App Store. This operation may affect the normal use of the service, Do you want to continue?', + 'The {0} operation will be performed on the following containers,\n some of which are from the App Store. This operation may affect the normal use of the service. \nDo you want to continue?', start: 'Start', stop: 'Stop', restart: 'Restart', @@ -845,7 +846,7 @@ const message = { quickCommand: 'Quick command', quickCommandHelper: 'Frequently used command list for quick selection at the bottom of the terminal interface', groupDeleteHelper: - 'After the group is removed, all connections in the group will be migrated to the default group. Confirm the information', + 'After the group is removed, all connections in the group will be migrated to the default group. Do you want to continue?', command: 'Command', quickCmd: 'Quick command', addHost: 'Add Host', diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index 8e241ca9d..cd9a58755 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -114,6 +114,7 @@ const message = { operateConfirm: '如果確認操作,請手動輸入', inputOrSelect: '請選擇或輸入', copyFailed: '復製失敗', + operatorHelper: '將對以下{0}進行{1}操作,是否繼續?', backupSuccess: '備份成功', restoreSuccess: '備份成功', notFound: '抱歉,您訪問的頁面不存在', @@ -489,7 +490,7 @@ const message = { containerList: '容器列表', operatorHelper: '將對以下容器進行 {0} 操作,是否繼續?', operatorAppHelper: - '將對以下容器進行 {0} 操作,其中部分來源於應用商店,該操作可能會影響到該服務的正常使用,是否確認?', + '將對以下容器進行 {0} 操作,\n其中部分來源於應用商店,該操作可能會影響到該服務的正常使用。\n是否確認?', start: '啟動', stop: '停止', restart: '重啟', @@ -809,7 +810,7 @@ const message = { batchInput: '批量輸入', quickCommand: '快速命令', quickCommandHelper: '常用命令列表,用於在終端界面底部快速選擇', - groupDeleteHelper: '移除組後,組內所有連接將遷移到 default 組內,是否確認', + groupDeleteHelper: '移除組後,組內所有連接將遷移到 default 組內,是否繼續?', command: '命令', addHost: '添加主機', localhost: '本地服務器', diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 70e80459e..9b7a9d86b 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -114,6 +114,7 @@ const message = { operateConfirm: '如果确认操作,请手动输入', inputOrSelect: '请选择或输入', copyFailed: '复制失败', + operatorHelper: '将对以下{0}进行 {1} 操作,是否继续?', backupSuccess: '备份成功', restoreSuccess: '备份成功', notFound: '抱歉,您访问的页面不存在', @@ -489,7 +490,7 @@ const message = { containerList: '容器列表', operatorHelper: '将对以下容器进行 {0} 操作,是否继续?', operatorAppHelper: - '将对以下容器进行 {0} 操作,其中部分来源于应用商店,该操作可能会影响到该服务的正常使用,是否确认?', + '将对以下容器进行 {0} 操作,\n其中部分来源于应用商店,该操作可能会影响到该服务的正常使用。\n是否继续?', dead: '', start: '启动', stop: '停止', @@ -810,7 +811,7 @@ const message = { batchInput: '批量输入', quickCommand: '快速命令', quickCommandHelper: '常用命令列表,用于在终端界面底部快速选择', - groupDeleteHelper: '移除组后,组内所有连接将迁移到 default 组内,是否确认', + groupDeleteHelper: '移除组后,组内所有连接将迁移到 default 组内,是否继续?', command: '命令', addHost: '添加主机', localhost: '本地服务器', diff --git a/frontend/src/views/container/compose/detail/index.vue b/frontend/src/views/container/compose/detail/index.vue index e2705f945..d8653044c 100644 --- a/frontend/src/views/container/compose/detail/index.vue +++ b/frontend/src/views/container/compose/detail/index.vue @@ -102,11 +102,11 @@ + - @@ -115,14 +115,14 @@ - - diff --git a/frontend/src/views/container/container/index.vue b/frontend/src/views/container/container/index.vue index 8d175d246..49336246d 100644 --- a/frontend/src/views/container/container/index.vue +++ b/frontend/src/views/container/container/index.vue @@ -15,7 +15,7 @@ {{ $t('container.containerPrune') }} - + {{ $t('container.start') }} @@ -241,10 +241,12 @@ - + + + - + @@ -252,27 +254,27 @@ -