diff --git a/console/console-src/modules/system/users/UserDetail.vue b/console/console-src/modules/system/users/UserDetail.vue index f7f607b5a..2355ac07f 100644 --- a/console/console-src/modules/system/users/UserDetail.vue +++ b/console/console-src/modules/system/users/UserDetail.vue @@ -5,7 +5,6 @@ import { VTabbar, VDropdown, VDropdownItem, - VLoading, } from "@halo-dev/components"; import { computed, provide, ref, type Ref } from "vue"; import { useRoute } from "vue-router"; @@ -15,7 +14,6 @@ import UserPasswordChangeModal from "./components/UserPasswordChangeModal.vue"; import { usePermission } from "@/utils/permission"; import { useQuery } from "@tanstack/vue-query"; import { useI18n } from "vue-i18n"; -import { rbacAnnotations } from "@/constants/annotations"; import UserAvatar from "@/components/user-avatar/UserAvatar.vue"; import type { Raw } from "vue"; import type { Component } from "vue"; @@ -45,7 +43,6 @@ const { params } = useRoute(); const { data: user, - isFetching, isLoading, refetch, } = useQuery({ @@ -56,13 +53,6 @@ const { }); return data; }, - refetchInterval: (data) => { - const annotations = data?.user.metadata.annotations; - return annotations?.[rbacAnnotations.AVATAR_ATTACHMENT_NAME] !== - annotations?.[rbacAnnotations.LAST_AVATAR_ATTACHMENT_NAME] - ? 1000 - : false; - }, enabled: computed(() => !!params.name), }); @@ -105,8 +95,7 @@ function handleRouteToUC() {
- - +

diff --git a/console/src/components/user-avatar/UserAvatar.vue b/console/src/components/user-avatar/UserAvatar.vue index f15f41589..4d5b02447 100644 --- a/console/src/components/user-avatar/UserAvatar.vue +++ b/console/src/components/user-avatar/UserAvatar.vue @@ -11,21 +11,23 @@ import { VSpace, Toast, Dialog, + VLoading, } from "@halo-dev/components"; import { ref, defineAsyncComponent, type Ref } from "vue"; -import type { DetailedUser } from "@halo-dev/api-client"; import { usePermission } from "@/utils/permission"; -import { useQueryClient } from "@tanstack/vue-query"; +import { useQuery, useQueryClient } from "@tanstack/vue-query"; import { useI18n } from "vue-i18n"; import { useFileDialog } from "@vueuse/core"; -import { inject } from "vue"; import { computed } from "vue"; +import { rbacAnnotations } from "@/constants/annotations"; const props = withDefaults( defineProps<{ + name?: string; isCurrentUser?: boolean; }>(), { + name: "-", isCurrentUser: false, } ); @@ -34,6 +36,31 @@ const queryClient = useQueryClient(); const { currentUserHasPermission } = usePermission(); const { t } = useI18n(); +const { data: avatar, isFetching } = useQuery({ + queryKey: ["user-avatar", props.name, props.isCurrentUser], + queryFn: async () => { + const { data } = props.isCurrentUser + ? await apiClient.user.getCurrentUserDetail() + : await apiClient.user.getUserDetail({ + name: props.name, + }); + + const annotations = data?.user.metadata.annotations; + + // Check avatar has been updated. if not, we need retry. + if ( + annotations?.[rbacAnnotations.AVATAR_ATTACHMENT_NAME] !== + annotations?.[rbacAnnotations.LAST_AVATAR_ATTACHMENT_NAME] + ) { + throw new Error("Avatar is not updated"); + } + + return data.user.spec.avatar || ""; + }, + retry: 5, + retryDelay: 1000, +}); + const UserAvatarCropper = defineAsyncComponent( () => import("./UserAvatarCropper.vue") ); @@ -48,8 +75,6 @@ const { open, reset, onChange } = useFileDialog({ multiple: false, }); -const user = inject>("user"); - const userAvatarCropper = ref(); const visibleCropperModal = ref(false); const originalFile = ref() as Ref; @@ -67,18 +92,15 @@ onChange((files) => { const uploadSaving = ref(false); const handleUploadAvatar = () => { userAvatarCropper.value?.getCropperFile().then((file) => { - if (!user?.value) { - return; - } - uploadSaving.value = true; apiClient.user .uploadUserAvatar({ - name: props.isCurrentUser ? "-" : user.value.user.metadata.name, + name: props.isCurrentUser ? "-" : props.name, file: file, }) .then(() => { + queryClient.invalidateQueries({ queryKey: ["user-avatar"] }); queryClient.invalidateQueries({ queryKey: ["user-detail"] }); handleCloseCropperModal(); }) @@ -99,15 +121,12 @@ const handleRemoveCurrentAvatar = () => { confirmText: t("core.common.buttons.confirm"), cancelText: t("core.common.buttons.cancel"), onConfirm: async () => { - if (!user?.value) { - return; - } - apiClient.user .deleteUserAvatar({ - name: props.isCurrentUser ? "-" : user.value.user.metadata.name, + name: props.isCurrentUser ? "-" : props.name, }) .then(() => { + queryClient.invalidateQueries({ queryKey: ["user-avatar"] }); queryClient.invalidateQueries({ queryKey: ["user-detail"] }); }) .catch(() => { @@ -128,15 +147,16 @@ const changeUploadAvatar = () => { }; const hasAvatar = computed(() => { - return !!user?.value?.user.spec.avatar; + return !!avatar.value; });