mirror of https://github.com/halo-dev/halo-admin
perf: automatic refresh of the list of users and roles (#797)
#### What type of PR is this? /kind improvement /milestone 2.1.x #### What this PR does / why we need it: 优化用户和角色列表,如果包含正在删除的内容会自动刷新。 #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/3036 #### Special notes for your reviewer: 测试方式: 1. 创建若干角色和用户。 2. 测试删除之后是否会自动刷新列表。 #### Does this PR introduce a user-facing change? ```release-note 优化 Console 端的用户和角色列表,如果包含正在删除的内容会自动刷新。 ```pull/784/head^2
parent
f7ece9135a
commit
da06195d08
|
@ -137,6 +137,8 @@ const handleDelete = async (role: Role) => {
|
||||||
Toast.success("删除成功");
|
Toast.success("删除成功");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to delete role", e);
|
console.error("Failed to delete role", e);
|
||||||
|
} finally {
|
||||||
|
handleFetchRoles();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -296,11 +298,6 @@ const handleDelete = async (role: Role) => {
|
||||||
></VEntityField>
|
></VEntityField>
|
||||||
</template>
|
</template>
|
||||||
<template #end>
|
<template #end>
|
||||||
<VEntityField v-if="role.metadata.deletionTimestamp">
|
|
||||||
<template #description>
|
|
||||||
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
|
||||||
</template>
|
|
||||||
</VEntityField>
|
|
||||||
<!-- TODO: 支持显示用户数量 -->
|
<!-- TODO: 支持显示用户数量 -->
|
||||||
<VEntityField v-if="false" description="0 个用户" />
|
<VEntityField v-if="false" description="0 个用户" />
|
||||||
<VEntityField>
|
<VEntityField>
|
||||||
|
@ -310,6 +307,11 @@ const handleDelete = async (role: Role) => {
|
||||||
</VTag>
|
</VTag>
|
||||||
</template>
|
</template>
|
||||||
</VEntityField>
|
</VEntityField>
|
||||||
|
<VEntityField v-if="role.metadata.deletionTimestamp">
|
||||||
|
<template #description>
|
||||||
|
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
||||||
|
</template>
|
||||||
|
</VEntityField>
|
||||||
<VEntityField>
|
<VEntityField>
|
||||||
<template #description>
|
<template #description>
|
||||||
<span class="truncate text-xs tabular-nums text-gray-500">
|
<span class="truncate text-xs tabular-nums text-gray-500">
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type { Role } from "@halo-dev/api-client";
|
import type { Role } from "@halo-dev/api-client";
|
||||||
import type { ComputedRef, Ref } from "vue";
|
import { onUnmounted, type ComputedRef, type Ref } from "vue";
|
||||||
import { computed, onMounted, ref } from "vue";
|
import { computed, onMounted, ref } from "vue";
|
||||||
import { roleLabels } from "@/constants/labels";
|
import { roleLabels } from "@/constants/labels";
|
||||||
import { rbacAnnotations } from "@/constants/annotations";
|
import { rbacAnnotations } from "@/constants/annotations";
|
||||||
|
@ -55,16 +55,32 @@ interface useRoleTemplateSelectionReturn {
|
||||||
export function useFetchRole(): useFetchRoleReturn {
|
export function useFetchRole(): useFetchRoleReturn {
|
||||||
const roles = ref<Role[]>([]);
|
const roles = ref<Role[]>([]);
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
|
const refreshInterval = ref();
|
||||||
|
|
||||||
const handleFetchRoles = async () => {
|
const handleFetchRoles = async (options?: { mute?: boolean }) => {
|
||||||
try {
|
try {
|
||||||
|
clearInterval(refreshInterval.value);
|
||||||
|
|
||||||
|
if (!options?.mute) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
const { data } = await apiClient.extension.role.listv1alpha1Role({
|
const { data } = await apiClient.extension.role.listv1alpha1Role({
|
||||||
page: 0,
|
page: 0,
|
||||||
size: 0,
|
size: 0,
|
||||||
labelSelector: [`!${roleLabels.TEMPLATE}`],
|
labelSelector: [`!${roleLabels.TEMPLATE}`],
|
||||||
});
|
});
|
||||||
roles.value = data.items;
|
roles.value = data.items;
|
||||||
|
|
||||||
|
const deletedRoles = roles.value.filter(
|
||||||
|
(role) => !!role.metadata.deletionTimestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
if (deletedRoles.length) {
|
||||||
|
refreshInterval.value = setInterval(() => {
|
||||||
|
handleFetchRoles({ mute: true });
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to fetch roles", e);
|
console.error("Failed to fetch roles", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -74,6 +90,10 @@ export function useFetchRole(): useFetchRoleReturn {
|
||||||
|
|
||||||
onMounted(handleFetchRoles);
|
onMounted(handleFetchRoles);
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(refreshInterval.value);
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
roles,
|
roles,
|
||||||
loading,
|
loading,
|
||||||
|
|
|
@ -21,7 +21,7 @@ import {
|
||||||
import UserEditingModal from "./components/UserEditingModal.vue";
|
import UserEditingModal from "./components/UserEditingModal.vue";
|
||||||
import UserPasswordChangeModal from "./components/UserPasswordChangeModal.vue";
|
import UserPasswordChangeModal from "./components/UserPasswordChangeModal.vue";
|
||||||
import GrantPermissionModal from "./components/GrantPermissionModal.vue";
|
import GrantPermissionModal from "./components/GrantPermissionModal.vue";
|
||||||
import { computed, onMounted, ref, watch } from "vue";
|
import { computed, onMounted, onUnmounted, ref, watch } from "vue";
|
||||||
import { apiClient } from "@/utils/api-client";
|
import { apiClient } from "@/utils/api-client";
|
||||||
import type { User, UserList } from "@halo-dev/api-client";
|
import type { User, UserList } from "@halo-dev/api-client";
|
||||||
import { rbacAnnotations } from "@/constants/annotations";
|
import { rbacAnnotations } from "@/constants/annotations";
|
||||||
|
@ -52,14 +52,19 @@ const users = ref<UserList>({
|
||||||
const loading = ref(false);
|
const loading = ref(false);
|
||||||
const selectedUserNames = ref<string[]>([]);
|
const selectedUserNames = ref<string[]>([]);
|
||||||
const selectedUser = ref<User>();
|
const selectedUser = ref<User>();
|
||||||
|
const refreshInterval = ref();
|
||||||
|
|
||||||
const userStore = useUserStore();
|
const userStore = useUserStore();
|
||||||
|
|
||||||
let fuse: Fuse<User> | undefined = undefined;
|
let fuse: Fuse<User> | undefined = undefined;
|
||||||
|
|
||||||
const handleFetchUsers = async () => {
|
const handleFetchUsers = async (options?: { mute?: boolean }) => {
|
||||||
try {
|
try {
|
||||||
|
clearInterval(refreshInterval.value);
|
||||||
|
|
||||||
|
if (!options?.mute) {
|
||||||
loading.value = true;
|
loading.value = true;
|
||||||
|
}
|
||||||
|
|
||||||
const { data } = await apiClient.extension.user.listv1alpha1User({
|
const { data } = await apiClient.extension.user.listv1alpha1User({
|
||||||
page: users.value.page,
|
page: users.value.page,
|
||||||
|
@ -71,6 +76,16 @@ const handleFetchUsers = async () => {
|
||||||
keys: ["spec.displayName", "metadata.name", "spec.email"],
|
keys: ["spec.displayName", "metadata.name", "spec.email"],
|
||||||
useExtendedSearch: true,
|
useExtendedSearch: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const deletedUsers = users.value.items.filter(
|
||||||
|
(user) => !!user.metadata.deletionTimestamp
|
||||||
|
);
|
||||||
|
|
||||||
|
if (deletedUsers.length) {
|
||||||
|
refreshInterval.value = setInterval(() => {
|
||||||
|
handleFetchUsers({ mute: true });
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("Failed to fetch users", e);
|
console.error("Failed to fetch users", e);
|
||||||
} finally {
|
} finally {
|
||||||
|
@ -199,6 +214,10 @@ onMounted(() => {
|
||||||
handleFetchUsers();
|
handleFetchUsers();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
clearInterval(refreshInterval.value);
|
||||||
|
});
|
||||||
|
|
||||||
// Route query action
|
// Route query action
|
||||||
const routeQueryAction = useRouteQuery<string | undefined>("action");
|
const routeQueryAction = useRouteQuery<string | undefined>("action");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue