Support batch enabling and disabling of users (#7631)

* Support batch enable and disable

* documentation update

* Update ui/src/locales/en.yaml

Co-authored-by: Ryan Wang <i@ryanc.cc>

* Update ui/src/locales/zh-CN.yaml

Co-authored-by: Ryan Wang <i@ryanc.cc>

* Update ui/src/locales/zh-CN.yaml

Co-authored-by: Ryan Wang <i@ryanc.cc>

* Update ui/src/locales/zh-TW.yaml

Co-authored-by: Ryan Wang <i@ryanc.cc>

* Update ui/src/locales/zh-TW.yaml

Co-authored-by: Ryan Wang <i@ryanc.cc>

* batch handling and code reuse

* 1.还原批量删除的分批请求修改
2.使判断当前user启停用状态时条件更加宽松,以解决新增用户后该属性undefined而被过滤的问题。(之前测试时用的数据是之前构建并使用过单独启\禁用的)

---------

Co-authored-by: Ryan Wang <i@ryanc.cc>
pull/7635/head
王炸 2025-07-18 17:32:46 +08:00 committed by GitHub
parent 859b7030c5
commit 5bb7b2826e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 102 additions and 2 deletions

View File

@ -24,6 +24,7 @@ import {
} from "@halo-dev/components";
import { useQuery } from "@tanstack/vue-query";
import { useRouteQuery } from "@vueuse/router";
import { chunk } from "lodash-es";
import { computed, onMounted, ref, watch } from "vue";
import { useI18n } from "vue-i18n";
import UserCreationModal from "./components/UserCreationModal.vue";
@ -137,6 +138,71 @@ const handleDeleteInBatch = async () => {
});
};
const handleUserBatchOperation = async ({
filterCondition,
apiMethod,
successMessageKey,
emptyMessageKey,
}) => {
const filteredUserNames = selectedUserNames.value.filter((name) => {
if (name === userStore.currentUser?.metadata.name) return false;
const user = users.value?.find((u) => u.user.metadata.name === name);
return user && filterCondition(user.user);
});
if (!filteredUserNames.length) {
Toast.info(t(emptyMessageKey));
return;
}
const chunks = chunk(filteredUserNames, 5);
for (const chunk of chunks) {
await Promise.all(chunk.map((name) => apiMethod(name)));
}
await refetch();
selectedUserNames.value.length = 0;
Toast.success(t(successMessageKey));
};
const handleEnableInBatch = async () => {
Dialog.warning({
title: t("core.user.operations.enable_in_batch.title"),
description: t("core.user.operations.enable_in_batch.description"),
confirmType: "primary",
confirmText: t("core.common.buttons.confirm"),
cancelText: t("core.common.buttons.cancel"),
onConfirm: async () => {
await handleUserBatchOperation({
filterCondition: (user) => !!user.spec.disabled,
apiMethod: (name) =>
consoleApiClient.user.enableUser({ username: name }),
successMessageKey: "core.common.toast.enable_success",
emptyMessageKey: "core.common.toast.no_users_to_enable",
});
},
});
};
const handleDisableInBatch = async () => {
Dialog.warning({
title: t("core.user.operations.disable_in_batch.title"),
description: t("core.user.operations.disable_in_batch.description"),
confirmType: "danger",
confirmText: t("core.common.buttons.confirm"),
cancelText: t("core.common.buttons.cancel"),
onConfirm: async () => {
await handleUserBatchOperation({
filterCondition: (user) => !user.spec.disabled,
apiMethod: (name) =>
consoleApiClient.user.disableUser({ username: name }),
successMessageKey: "core.common.toast.disable_success",
emptyMessageKey: "core.common.toast.no_users_to_disable",
});
},
});
};
watch(selectedUserNames, (newValue) => {
checkedAll.value =
newValue.length ===
@ -242,6 +308,12 @@ function onCreationModalClose() {
<div class="flex w-full flex-1 items-center sm:w-auto">
<SearchInput v-if="!selectedUserNames.length" v-model="keyword" />
<VSpace v-else>
<VButton type="secondary" @click="handleDisableInBatch">
{{ $t("core.common.buttons.disable") }}
</VButton>
<VButton type="secondary" @click="handleEnableInBatch">
{{ $t("core.common.buttons.enable") }}
</VButton>
<VButton type="danger" @click="handleDeleteInBatch">
{{ $t("core.common.buttons.delete") }}
</VButton>

View File

@ -1124,11 +1124,21 @@ core:
enable:
title: Enable
description: Are you sure you want to enable this user?
enable_in_batch:
title: Enable
description: >-
Are you sure you want to enable the selected users? They will be able
to log in again after being enabled.
disable:
title: Disable
description: >-
Are you sure you want to disable this user? This user will not be able
to log in after being disabled
disable_in_batch:
title: Disable
description: >-
Are you sure you want to disable the selected users? They will no longer
be able to log in after being disabled.
filters:
role:
label: Role
@ -1951,6 +1961,8 @@ core:
unknown_error: Unknown error
disable_success: Disabled successfully
enable_success: Enabled successfully
no_users_to_enable: All selected users are already enabled
no_users_to_disable: All selected users are already disabled
dialog:
titles:
tip: Tip

View File

@ -1055,9 +1055,15 @@ core:
enable:
title: 取消禁用
description: 确定取消禁用该用户吗?
enable_in_batch:
title: 启用
description: 确定要启用所选用户吗?启用后该用户将可以重新登录系统
disable:
title: 禁用
description: 确定禁用该用户吗?禁用之后该用户将无法登录系统
description: 确定禁用该用户吗?禁用后该用户将无法登录系统
disable_in_batch:
title: 禁用
description: 确定要禁用所选用户吗?禁用后这些用户将无法登录系统
filters:
role:
label: 角色
@ -1815,7 +1821,9 @@ core:
server_internal_error: 服务器内部错误
unknown_error: 未知错误
disable_success: 禁用成功
enable_success: 啟用成功
enable_success: 启用成功
no_users_to_enable: 所有选中的用户已启用
no_users_to_disable: 所有选中的用户已停用
dialog:
titles:
tip: 提示

View File

@ -1040,9 +1040,15 @@ core:
enable:
title: 取消停用
description: 確定要取消停用該用戶嗎?
enable_in_batch:
title: 启用
description: 確定要启用所選用戶嗎?啟用後該用戶將可以重新登入系統
disable:
title: 停用
description: 確定要停用該用戶嗎?停用後該用戶將無法登入系統
disable_in_batch:
title: 停用
description: 確定要停用所選用戶嗎?停用後這些用戶將無法登入系統
filters:
role:
label: 角色
@ -1801,6 +1807,8 @@ core:
unknown_error: 未知錯誤
disable_success: 禁用成功
enable_success: 啟用成功
no_users_to_enable: 所有選中的用戶都已啟用
no_users_to_disable: 所有選中的用戶都已停用
dialog:
titles:
tip: 提示