From 833efb0136693bd6ae69faefd9592671c8abd4ec Mon Sep 17 00:00:00 2001 From: ssongliu <73214554+ssongliu@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:14:08 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E9=95=9C=E5=83=8F=E5=88=A0=E9=99=A4?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=AD=98=E5=9C=A8=E6=80=A7=E5=88=A4=E6=96=AD?= =?UTF-8?q?=20(#3114)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refs #3109 --- backend/app/dto/container.go | 1 + backend/app/service/image.go | 2 +- frontend/src/lang/modules/en.ts | 1 + frontend/src/lang/modules/tw.ts | 1 + frontend/src/lang/modules/zh.ts | 1 + .../views/container/image/delete/index.vue | 59 +++++++++++++++---- frontend/src/views/container/image/index.vue | 1 + 7 files changed, 54 insertions(+), 12 deletions(-) diff --git a/backend/app/dto/container.go b/backend/app/dto/container.go index b2364e1e1..66f55f498 100644 --- a/backend/app/dto/container.go +++ b/backend/app/dto/container.go @@ -168,6 +168,7 @@ type VolumeCreate struct { } type BatchDelete struct { + Force bool `json:"force"` Names []string `json:"names" validate:"required"` } diff --git a/backend/app/service/image.go b/backend/app/service/image.go index 3842febde..452231407 100644 --- a/backend/app/service/image.go +++ b/backend/app/service/image.go @@ -390,7 +390,7 @@ func (u *ImageService) ImageRemove(req dto.BatchDelete) error { return err } for _, id := range req.Names { - if _, err := client.ImageRemove(context.TODO(), id, types.ImageRemoveOptions{Force: true, PruneChildren: true}); err != nil { + if _, err := client.ImageRemove(context.TODO(), id, types.ImageRemoveOptions{Force: req.Force, PruneChildren: true}); err != nil { if strings.Contains(err.Error(), "image is being used") { if strings.Contains(id, "sha256:") { return buserr.New(constant.ErrObjectInUsed) diff --git a/frontend/src/lang/modules/en.ts b/frontend/src/lang/modules/en.ts index 3b2eddf1b..24d704727 100644 --- a/frontend/src/lang/modules/en.ts +++ b/frontend/src/lang/modules/en.ts @@ -524,6 +524,7 @@ const message = { unpause: 'Unpause', rename: 'Rename', remove: 'Remove', + removeAll: 'Remove All', containerPrune: 'Container prune', containerPruneHelper1: 'Cleaning containers will delete all containers that are in a stopped state.', containerPruneHelper2: diff --git a/frontend/src/lang/modules/tw.ts b/frontend/src/lang/modules/tw.ts index e5647c4da..b6eb5ded1 100644 --- a/frontend/src/lang/modules/tw.ts +++ b/frontend/src/lang/modules/tw.ts @@ -512,6 +512,7 @@ const message = { unpause: '恢復', rename: '重命名', remove: '刪除', + removeAll: '删除所有', containerPrune: '清理容器', containerPruneHelper1: '清理容器 將刪除所有處於停止狀態的容器。', containerPruneHelper2: diff --git a/frontend/src/lang/modules/zh.ts b/frontend/src/lang/modules/zh.ts index 751f5124f..bf37fc86f 100644 --- a/frontend/src/lang/modules/zh.ts +++ b/frontend/src/lang/modules/zh.ts @@ -513,6 +513,7 @@ const message = { unpause: '恢复', rename: '重命名', remove: '删除', + removeAll: '删除所有', containerPrune: '清理容器', containerPruneHelper1: '清理容器 将删除所有处于停止状态的容器。', containerPruneHelper2: diff --git a/frontend/src/views/container/image/delete/index.vue b/frontend/src/views/container/image/delete/index.vue index 068edfc47..870d73f6a 100644 --- a/frontend/src/views/container/image/delete/index.vue +++ b/frontend/src/views/container/image/delete/index.vue @@ -4,15 +4,24 @@ - + - +
+ + {{ $t('container.removeAll') }} + +
+
{{ $t('commons.button.cancel') }} - + {{ $t('commons.button.delete') }} @@ -45,20 +54,29 @@ import DrawerHeader from '@/components/drawer-header/index.vue'; import i18n from '@/lang'; const deleteVisible = ref(false); -const deleteForm = reactive({ +const form = reactive({ + id: '', + force: false, tags: [] as Array, deleteTags: [] as Array, }); +const deleteAll = ref(); +const isIndeterminate = ref(true); const opRef = ref(); interface DialogProps { + id: string; + isUsed: boolean; tags: Array; } const acceptParams = (params: DialogProps) => { + deleteAll.value = false; deleteVisible.value = true; - deleteForm.deleteTags = []; - deleteForm.tags = params.tags; + form.deleteTags = []; + form.id = params.id; + form.tags = params.tags; + form.force = !params.isUsed; }; const handleClose = () => { deleteVisible.value = false; @@ -69,20 +87,39 @@ const onSearch = () => { emit('search'); }; +const handleCheckAllChange = (val: boolean) => { + form.deleteTags = val ? form.tags : []; + isIndeterminate.value = false; +}; +const handleCheckedCitiesChange = (value: string[]) => { + const checkedCount = value.length; + deleteAll.value = checkedCount === form.tags.length; + isIndeterminate.value = checkedCount > 0 && checkedCount < form.tags.length; +}; + const batchDelete = async () => { let names = []; - for (const item of deleteForm.deleteTags) { - names.push(item); + let showNames = []; + if (deleteAll.value) { + names.push(form.id); + for (const item of form.deleteTags) { + showNames.push(item); + } + } else { + for (const item of form.deleteTags) { + names.push(item); + showNames.push(item); + } } opRef.value.acceptParams({ title: i18n.global.t('commons.button.delete'), - names: names, + names: showNames, msg: i18n.global.t('commons.msg.operatorHelper', [ i18n.global.t('container.image'), i18n.global.t('commons.button.delete'), ]), api: imageRemove, - params: { names: names }, + params: { names: names, force: form.force }, }); }; diff --git a/frontend/src/views/container/image/index.vue b/frontend/src/views/container/image/index.vue index 26f524a28..451dd1788 100644 --- a/frontend/src/views/container/image/index.vue +++ b/frontend/src/views/container/image/index.vue @@ -279,6 +279,7 @@ const buttons = [ } let params = { id: row.id, + isUsed: row.isUsed, tags: row.tags, }; dialogDeleteRef.value!.acceptParams(params);