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"; } from "@halo-dev/components";
import { useQuery } from "@tanstack/vue-query"; import { useQuery } from "@tanstack/vue-query";
import { useRouteQuery } from "@vueuse/router"; import { useRouteQuery } from "@vueuse/router";
import { chunk } from "lodash-es";
import { computed, onMounted, ref, watch } from "vue"; import { computed, onMounted, ref, watch } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import UserCreationModal from "./components/UserCreationModal.vue"; 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) => { watch(selectedUserNames, (newValue) => {
checkedAll.value = checkedAll.value =
newValue.length === newValue.length ===
@ -242,6 +308,12 @@ function onCreationModalClose() {
<div class="flex w-full flex-1 items-center sm:w-auto"> <div class="flex w-full flex-1 items-center sm:w-auto">
<SearchInput v-if="!selectedUserNames.length" v-model="keyword" /> <SearchInput v-if="!selectedUserNames.length" v-model="keyword" />
<VSpace v-else> <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"> <VButton type="danger" @click="handleDeleteInBatch">
{{ $t("core.common.buttons.delete") }} {{ $t("core.common.buttons.delete") }}
</VButton> </VButton>

View File

@ -1124,11 +1124,21 @@ core:
enable: enable:
title: Enable title: Enable
description: Are you sure you want to enable this user? 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: disable:
title: Disable title: Disable
description: >- description: >-
Are you sure you want to disable this user? This user will not be able Are you sure you want to disable this user? This user will not be able
to log in after being disabled 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: filters:
role: role:
label: Role label: Role
@ -1951,6 +1961,8 @@ core:
unknown_error: Unknown error unknown_error: Unknown error
disable_success: Disabled successfully disable_success: Disabled successfully
enable_success: Enabled 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: dialog:
titles: titles:
tip: Tip tip: Tip

View File

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

View File

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