mirror of https://github.com/halo-dev/halo-admin
refactor: use tanstack query to refactor attachments-related fetching (#878)
#### What type of PR is this? /kind improvement #### What this PR does / why we need it: 使用 [TanStack Query](https://github.com/TanStack/query) 重构附件相关数据请求的相关逻辑。 #### Which issue(s) this PR fixes: Ref https://github.com/halo-dev/halo/issues/3360 #### Special notes for your reviewer: 测试方式: 1. 测试附件管理页面的筛选、存储策略、分组等业务。 2. 测试附件选择模态框组件。 #### Does this PR introduce a user-facing change? ```release-note None ```pull/879/head
parent
43c5effcd0
commit
0f8e5fad80
|
@ -339,7 +339,7 @@ const editor = useEditor({
|
|||
});
|
||||
|
||||
// image drag and paste upload
|
||||
const { policies } = useFetchAttachmentPolicy({ fetchOnMounted: true });
|
||||
const { policies } = useFetchAttachmentPolicy();
|
||||
|
||||
type Task = {
|
||||
file: File;
|
||||
|
@ -349,7 +349,7 @@ type Task = {
|
|||
const uploadQueue: queueAsPromised<Task> = fastq.promise(asyncWorker, 1);
|
||||
|
||||
async function asyncWorker(arg: Task): Promise<void> {
|
||||
if (!policies.value.length) {
|
||||
if (!policies.value?.length) {
|
||||
Toast.warning("目前没有可用的存储策略");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -51,10 +51,8 @@ const policyVisible = ref(false);
|
|||
const uploadVisible = ref(false);
|
||||
const detailVisible = ref(false);
|
||||
|
||||
const { policies } = useFetchAttachmentPolicy({ fetchOnMounted: true });
|
||||
const { groups, handleFetchGroups } = useFetchAttachmentGroup({
|
||||
fetchOnMounted: true,
|
||||
});
|
||||
const { policies } = useFetchAttachmentPolicy();
|
||||
const { groups, handleFetchGroups } = useFetchAttachmentGroup();
|
||||
|
||||
const selectedGroup = ref<Group>();
|
||||
|
||||
|
@ -85,26 +83,24 @@ const SortItems: SortItem[] = [
|
|||
|
||||
const selectedPolicy = ref<Policy>();
|
||||
const selectedUser = ref<User>();
|
||||
const keyword = ref<string>("");
|
||||
const selectedSortItem = ref<SortItem>();
|
||||
|
||||
const selectedSortItemValue = computed(() => {
|
||||
return selectedSortItem.value?.value;
|
||||
});
|
||||
|
||||
function handleSelectPolicy(policy: Policy | undefined) {
|
||||
selectedPolicy.value = policy;
|
||||
handleFetchAttachments({ page: 1 });
|
||||
page.value = 1;
|
||||
}
|
||||
|
||||
function handleSelectUser(user: User | undefined) {
|
||||
selectedUser.value = user;
|
||||
handleFetchAttachments({ page: 1 });
|
||||
page.value = 1;
|
||||
}
|
||||
|
||||
function handleSortItemChange(sortItem?: SortItem) {
|
||||
selectedSortItem.value = sortItem;
|
||||
handleFetchAttachments({ page: 1 });
|
||||
page.value = 1;
|
||||
}
|
||||
|
||||
function handleKeywordChange() {
|
||||
|
@ -112,12 +108,12 @@ function handleKeywordChange() {
|
|||
if (keywordNode) {
|
||||
keyword.value = keywordNode._value as string;
|
||||
}
|
||||
handleFetchAttachments({ page: 1 });
|
||||
page.value = 1;
|
||||
}
|
||||
|
||||
function handleClearKeyword() {
|
||||
keyword.value = "";
|
||||
handleFetchAttachments({ page: 1 });
|
||||
page.value = 1;
|
||||
}
|
||||
|
||||
const hasFilters = computed(() => {
|
||||
|
@ -134,19 +130,24 @@ function handleClearFilters() {
|
|||
selectedUser.value = undefined;
|
||||
selectedSortItem.value = undefined;
|
||||
keyword.value = "";
|
||||
handleFetchAttachments({ page: 1 });
|
||||
page.value = 1;
|
||||
}
|
||||
|
||||
const keyword = ref<string>("");
|
||||
const page = ref<number>(1);
|
||||
const size = ref<number>(20);
|
||||
|
||||
const {
|
||||
attachments,
|
||||
selectedAttachment,
|
||||
selectedAttachments,
|
||||
checkedAll,
|
||||
loading,
|
||||
isLoading,
|
||||
isFetching,
|
||||
total,
|
||||
handleFetchAttachments,
|
||||
handleSelectNext,
|
||||
handleSelectPrevious,
|
||||
handlePaginationChange,
|
||||
handleDelete,
|
||||
handleDeleteInBatch,
|
||||
handleCheckAll,
|
||||
|
@ -159,6 +160,8 @@ const {
|
|||
user: selectedUser,
|
||||
keyword: keyword,
|
||||
sort: selectedSortItemValue,
|
||||
page: page,
|
||||
size: size,
|
||||
});
|
||||
|
||||
const handleMove = async (group: Group) => {
|
||||
|
@ -209,21 +212,16 @@ const onDetailModalClose = () => {
|
|||
selectedAttachment.value = undefined;
|
||||
nameQuery.value = undefined;
|
||||
nameQueryAttachment.value = undefined;
|
||||
handleFetchAttachments({ mute: true });
|
||||
handleFetchAttachments();
|
||||
};
|
||||
|
||||
const onUploadModalClose = () => {
|
||||
routeQueryAction.value = undefined;
|
||||
handleFetchAttachments({ mute: true });
|
||||
};
|
||||
|
||||
const onGroupChange = () => {
|
||||
handleReset();
|
||||
handleFetchAttachments();
|
||||
};
|
||||
|
||||
const getPolicyName = (name: string | undefined) => {
|
||||
const policy = policies.value.find((p) => p.metadata.name === name);
|
||||
const policy = policies.value?.find((p) => p.metadata.name === name);
|
||||
return policy?.spec.displayName;
|
||||
};
|
||||
|
||||
|
@ -548,7 +546,7 @@ onMounted(() => {
|
|||
>
|
||||
<IconRefreshLine
|
||||
v-tooltip="`刷新`"
|
||||
:class="{ 'animate-spin text-gray-900': loading }"
|
||||
:class="{ 'animate-spin text-gray-900': isFetching }"
|
||||
class="h-4 w-4 text-gray-600 group-hover:text-gray-900"
|
||||
/>
|
||||
</div>
|
||||
|
@ -562,15 +560,15 @@ onMounted(() => {
|
|||
<div :style="`${viewType === 'list' ? 'padding:12px 16px 0' : ''}`">
|
||||
<AttachmentGroupList
|
||||
v-model:selected-group="selectedGroup"
|
||||
@select="onGroupChange"
|
||||
@select="handleReset"
|
||||
@update="handleFetchGroups"
|
||||
@reload-attachments="handleFetchAttachments"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<VLoading v-if="loading" />
|
||||
<VLoading v-if="isLoading" />
|
||||
|
||||
<Transition v-else-if="!attachments.total" appear name="fade">
|
||||
<Transition v-else-if="!attachments?.length" appear name="fade">
|
||||
<VEmpty
|
||||
message="当前分组没有附件,你可以尝试刷新或者上传附件"
|
||||
title="当前分组没有附件"
|
||||
|
@ -600,7 +598,7 @@ onMounted(() => {
|
|||
role="list"
|
||||
>
|
||||
<VCard
|
||||
v-for="(attachment, index) in attachments.items"
|
||||
v-for="(attachment, index) in attachments"
|
||||
:key="index"
|
||||
:body-class="['!p-0']"
|
||||
:class="{
|
||||
|
@ -680,10 +678,7 @@ onMounted(() => {
|
|||
class="box-border h-full w-full divide-y divide-gray-100"
|
||||
role="list"
|
||||
>
|
||||
<li
|
||||
v-for="(attachment, index) in attachments.items"
|
||||
:key="index"
|
||||
>
|
||||
<li v-for="(attachment, index) in attachments" :key="index">
|
||||
<VEntity :is-selected="isChecked(attachment)">
|
||||
<template
|
||||
v-if="
|
||||
|
@ -797,11 +792,10 @@ onMounted(() => {
|
|||
<template #footer>
|
||||
<div class="bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
:page="attachments.page"
|
||||
:size="attachments.size"
|
||||
:total="attachments.total"
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:total="total"
|
||||
:size-options="[60, 120, 200]"
|
||||
@change="handlePaginationChange"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
<script lang="ts" setup>
|
||||
import { VButton, VModal, VSpace, VTag } from "@halo-dev/components";
|
||||
import LazyImage from "@/components/image/LazyImage.vue";
|
||||
import type { Attachment, Policy } from "@halo-dev/api-client";
|
||||
import type { Attachment } from "@halo-dev/api-client";
|
||||
import prettyBytes from "pretty-bytes";
|
||||
import { ref, watch, watchEffect } from "vue";
|
||||
import { computed, ref } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { isImage } from "@/utils/image";
|
||||
import { formatDatetime } from "@/utils/date";
|
||||
import { useFetchAttachmentGroup } from "../composables/use-attachment-group";
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
|
@ -27,43 +28,40 @@ const emit = defineEmits<{
|
|||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const { groups, handleFetchGroups } = useFetchAttachmentGroup();
|
||||
const { groups } = useFetchAttachmentGroup();
|
||||
|
||||
const policy = ref<Policy>();
|
||||
const onlyPreview = ref(false);
|
||||
|
||||
watchEffect(async () => {
|
||||
if (props.attachment) {
|
||||
const { policyName } = props.attachment.spec;
|
||||
if (!policyName) {
|
||||
return;
|
||||
}
|
||||
const { data } =
|
||||
await apiClient.extension.storage.policy.getstorageHaloRunV1alpha1Policy({
|
||||
name: policyName,
|
||||
});
|
||||
policy.value = data;
|
||||
}
|
||||
const policyName = computed(() => {
|
||||
return props.attachment?.spec.policyName;
|
||||
});
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
handleFetchGroups();
|
||||
const { data: policy } = useQuery({
|
||||
queryKey: ["attachment-policy", policyName],
|
||||
queryFn: async () => {
|
||||
if (!policyName.value) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
const { data } =
|
||||
await apiClient.extension.storage.policy.getstorageHaloRunV1alpha1Policy({
|
||||
name: policyName.value,
|
||||
});
|
||||
|
||||
return data;
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
enabled: computed(() => !!policyName.value),
|
||||
});
|
||||
|
||||
const getGroupName = (name: string | undefined) => {
|
||||
const group = groups.value.find((group) => group.metadata.name === name);
|
||||
const group = groups.value?.find((group) => group.metadata.name === name);
|
||||
return group?.spec.displayName || name;
|
||||
};
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
emit("update:visible", visible);
|
||||
if (!visible) {
|
||||
policy.value = undefined;
|
||||
onlyPreview.value = false;
|
||||
emit("close");
|
||||
}
|
||||
|
|
|
@ -163,9 +163,9 @@ const handleDeleteWithAttachments = (group: Group) => {
|
|||
};
|
||||
|
||||
watch(
|
||||
() => groups.value.length,
|
||||
() => groups.value?.length,
|
||||
() => {
|
||||
const allGroups = [...defaultGroups, ...groups.value];
|
||||
const allGroups = [...defaultGroups, ...(groups.value || [])];
|
||||
const groupIndex = allGroups.findIndex(
|
||||
(group) => group.metadata.name === routeQuery.value
|
||||
);
|
||||
|
@ -178,9 +178,8 @@ watch(
|
|||
|
||||
onMounted(async () => {
|
||||
await handleFetchGroups();
|
||||
|
||||
if (routeQuery.value && !props.readonly) {
|
||||
const allGroups = [...defaultGroups, ...groups.value];
|
||||
const allGroups = [...defaultGroups, ...(groups.value || [])];
|
||||
const group = allGroups.find(
|
||||
(group) => group.metadata.name === routeQuery.value
|
||||
);
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
Toast,
|
||||
} from "@halo-dev/components";
|
||||
import AttachmentPolicyEditingModal from "./AttachmentPolicyEditingModal.vue";
|
||||
import { ref, watch } from "vue";
|
||||
import { ref } from "vue";
|
||||
import type { Policy, PolicyTemplate } from "@halo-dev/api-client";
|
||||
import { formatDatetime } from "@/utils/date";
|
||||
import {
|
||||
|
@ -21,7 +21,7 @@ import {
|
|||
} from "../composables/use-attachment-policy";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
|
||||
const props = withDefaults(
|
||||
withDefaults(
|
||||
defineProps<{
|
||||
visible: boolean;
|
||||
}>(),
|
||||
|
@ -35,11 +35,8 @@ const emit = defineEmits<{
|
|||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const { policies, loading, handleFetchPolicies } = useFetchAttachmentPolicy();
|
||||
const { policyTemplates, handleFetchPolicyTemplates } =
|
||||
useFetchAttachmentPolicyTemplate({
|
||||
fetchOnMounted: false,
|
||||
});
|
||||
const { policies, isLoading, handleFetchPolicies } = useFetchAttachmentPolicy();
|
||||
const { policyTemplates } = useFetchAttachmentPolicyTemplate();
|
||||
|
||||
const selectedPolicy = ref<Policy>();
|
||||
|
||||
|
@ -105,16 +102,6 @@ const onEditingModalClose = () => {
|
|||
selectedPolicy.value = undefined;
|
||||
handleFetchPolicies();
|
||||
};
|
||||
|
||||
watch(
|
||||
() => props.visible,
|
||||
(visible) => {
|
||||
if (visible) {
|
||||
handleFetchPolicyTemplates();
|
||||
handleFetchPolicies();
|
||||
}
|
||||
}
|
||||
);
|
||||
</script>
|
||||
<template>
|
||||
<VModal
|
||||
|
@ -150,7 +137,7 @@ watch(
|
|||
</FloatingDropdown>
|
||||
</template>
|
||||
<VEmpty
|
||||
v-if="!policies.length && !loading"
|
||||
v-if="!policies?.length && !isLoading"
|
||||
message="当前没有可用的存储策略,你可以尝试刷新或者新建策略"
|
||||
title="当前没有可用的存储策略"
|
||||
>
|
||||
|
|
|
@ -25,14 +25,9 @@ const emit = defineEmits<{
|
|||
(event: "close"): void;
|
||||
}>();
|
||||
|
||||
const { groups, handleFetchGroups } = useFetchAttachmentGroup({
|
||||
fetchOnMounted: false,
|
||||
});
|
||||
const { policies, handleFetchPolicies } = useFetchAttachmentPolicy({
|
||||
fetchOnMounted: false,
|
||||
});
|
||||
const { policyTemplates, handleFetchPolicyTemplates } =
|
||||
useFetchAttachmentPolicyTemplate();
|
||||
const { groups } = useFetchAttachmentGroup();
|
||||
const { policies, handleFetchPolicies } = useFetchAttachmentPolicy();
|
||||
const { policyTemplates } = useFetchAttachmentPolicyTemplate();
|
||||
|
||||
const selectedGroupName = useLocalStorage("attachment-upload-group", "");
|
||||
const selectedPolicyName = useLocalStorage("attachment-upload-policy", "");
|
||||
|
@ -45,12 +40,13 @@ watch(
|
|||
() => {
|
||||
if (selectedGroupName.value === "") return;
|
||||
|
||||
const group = groups.value.find(
|
||||
const group = groups.value?.find(
|
||||
(group) => group.metadata.name === selectedGroupName.value
|
||||
);
|
||||
if (!group) {
|
||||
selectedGroupName.value =
|
||||
groups.value.length > 0 ? groups.value[0].metadata.name : "";
|
||||
selectedGroupName.value = groups.value?.length
|
||||
? groups.value[0].metadata.name
|
||||
: "";
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -58,12 +54,13 @@ watch(
|
|||
watch(
|
||||
() => policies.value,
|
||||
() => {
|
||||
const policy = policies.value.find(
|
||||
const policy = policies.value?.find(
|
||||
(policy) => policy.metadata.name === selectedPolicyName.value
|
||||
);
|
||||
if (!policy) {
|
||||
selectedPolicyName.value =
|
||||
policies.value.length > 0 ? policies.value[0].metadata.name : "";
|
||||
selectedPolicyName.value = policies.value?.length
|
||||
? policies.value[0].metadata.name
|
||||
: "";
|
||||
}
|
||||
}
|
||||
);
|
||||
|
@ -87,7 +84,7 @@ const handleOpenCreateNewPolicyModal = (policyTemplate: PolicyTemplate) => {
|
|||
|
||||
const onEditingModalClose = async () => {
|
||||
await handleFetchPolicies();
|
||||
policyToCreate.value = policies.value[0];
|
||||
policyToCreate.value = policies.value?.[0];
|
||||
};
|
||||
|
||||
const onVisibleChange = (visible: boolean) => {
|
||||
|
@ -102,9 +99,6 @@ watch(
|
|||
() => props.visible,
|
||||
(newValue) => {
|
||||
if (newValue) {
|
||||
handleFetchGroups();
|
||||
handleFetchPolicies();
|
||||
handleFetchPolicyTemplates();
|
||||
uploadVisible.value = true;
|
||||
} else {
|
||||
const uploadVisibleTimer = setTimeout(() => {
|
||||
|
@ -131,7 +125,7 @@ watch(
|
|||
<div
|
||||
v-for="(group, index) in [
|
||||
{ metadata: { name: '' }, spec: { displayName: '未分组' } },
|
||||
...groups,
|
||||
...(groups || []),
|
||||
]"
|
||||
:key="index"
|
||||
:class="{
|
||||
|
@ -200,7 +194,7 @@ watch(
|
|||
</template>
|
||||
</FloatingDropdown>
|
||||
</div>
|
||||
<div v-if="policies.length <= 0" class="mb-3">
|
||||
<div v-if="!policies?.length" class="mb-3">
|
||||
<VAlert
|
||||
title="没有存储策略"
|
||||
description="在上传之前,需要新建一个存储策略"
|
||||
|
|
|
@ -38,20 +38,22 @@ const emit = defineEmits<{
|
|||
}>();
|
||||
|
||||
const selectedGroup = ref<Group>();
|
||||
const page = ref(1);
|
||||
const size = ref(60);
|
||||
|
||||
const {
|
||||
attachments,
|
||||
loading,
|
||||
isLoading,
|
||||
total,
|
||||
selectedAttachment,
|
||||
selectedAttachments,
|
||||
handleFetchAttachments,
|
||||
handlePaginationChange,
|
||||
handleSelect,
|
||||
handleSelectPrevious,
|
||||
handleSelectNext,
|
||||
handleReset,
|
||||
isChecked,
|
||||
} = useAttachmentControl({ group: selectedGroup });
|
||||
} = useAttachmentControl({ group: selectedGroup, page, size });
|
||||
|
||||
const uploadVisible = ref(false);
|
||||
const detailVisible = ref(false);
|
||||
|
@ -64,21 +66,14 @@ const handleOpenDetail = (attachment: Attachment) => {
|
|||
selectedAttachment.value = attachment;
|
||||
detailVisible.value = true;
|
||||
};
|
||||
|
||||
const onGroupChange = () => {
|
||||
handleReset();
|
||||
handleFetchAttachments();
|
||||
};
|
||||
|
||||
await handleFetchAttachments();
|
||||
</script>
|
||||
<template>
|
||||
<AttachmentGroupList
|
||||
v-model:selected-group="selectedGroup"
|
||||
readonly
|
||||
@select="onGroupChange"
|
||||
@select="handleReset"
|
||||
/>
|
||||
<div v-if="attachments.total > 0" class="mb-5">
|
||||
<div v-if="attachments?.length" class="mb-5">
|
||||
<VButton @click="uploadVisible = true">
|
||||
<template #icon>
|
||||
<IconUpload class="h-full w-full" />
|
||||
|
@ -87,7 +82,7 @@ await handleFetchAttachments();
|
|||
</VButton>
|
||||
</div>
|
||||
<VEmpty
|
||||
v-if="!attachments.total && !loading"
|
||||
v-if="!attachments?.length && !isLoading"
|
||||
message="当前没有附件,你可以尝试刷新或者上传附件"
|
||||
title="当前没有附件"
|
||||
>
|
||||
|
@ -109,7 +104,7 @@ await handleFetchAttachments();
|
|||
role="list"
|
||||
>
|
||||
<VCard
|
||||
v-for="(attachment, index) in attachments.items"
|
||||
v-for="(attachment, index) in attachments"
|
||||
:key="index"
|
||||
:body-class="['!p-0']"
|
||||
:class="{
|
||||
|
@ -171,11 +166,10 @@ await handleFetchAttachments();
|
|||
</div>
|
||||
<div class="mt-4 bg-white sm:flex sm:items-center sm:justify-end">
|
||||
<VPagination
|
||||
:page="attachments.page"
|
||||
:size="attachments.size"
|
||||
:total="attachments.total"
|
||||
v-model:page="page"
|
||||
v-model:size="size"
|
||||
:total="total"
|
||||
:size-options="[60, 120, 200]"
|
||||
@change="handlePaginationChange"
|
||||
/>
|
||||
</div>
|
||||
<AttachmentUploadModal
|
||||
|
|
|
@ -1,58 +1,35 @@
|
|||
import { onMounted, onUnmounted, ref, type Ref } from "vue";
|
||||
import type { Ref } from "vue";
|
||||
import type { Group } from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
|
||||
interface useFetchAttachmentGroupReturn {
|
||||
groups: Ref<Group[]>;
|
||||
loading: Ref<boolean>;
|
||||
groups: Ref<Group[] | undefined>;
|
||||
isLoading: Ref<boolean>;
|
||||
handleFetchGroups: () => void;
|
||||
}
|
||||
|
||||
export function useFetchAttachmentGroup(options?: {
|
||||
fetchOnMounted: boolean;
|
||||
}): useFetchAttachmentGroupReturn {
|
||||
const { fetchOnMounted } = options || {};
|
||||
|
||||
const groups = ref<Group[]>([] as Group[]);
|
||||
const loading = ref<boolean>(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchGroups = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
export function useFetchAttachmentGroup(): useFetchAttachmentGroupReturn {
|
||||
const { data, isLoading, refetch } = useQuery<Group[]>({
|
||||
queryKey: ["attachment-groups"],
|
||||
queryFn: async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.storage.group.liststorageHaloRunV1alpha1Group();
|
||||
groups.value = data.items;
|
||||
|
||||
const deletedGroups = groups.value.filter(
|
||||
return data.items;
|
||||
},
|
||||
refetchInterval(data) {
|
||||
const deletingGroups = data?.filter(
|
||||
(group) => !!group.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedGroups.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchGroups();
|
||||
}, 1000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch attachment groups", e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchOnMounted && handleFetchGroups();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
return deletingGroups?.length ? 1000 : false;
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
return {
|
||||
groups,
|
||||
loading,
|
||||
handleFetchGroups,
|
||||
groups: data,
|
||||
isLoading,
|
||||
handleFetchGroups: refetch,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,97 +1,58 @@
|
|||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
import type { Ref } from "vue";
|
||||
import type { Policy, PolicyTemplate } from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
|
||||
interface useFetchAttachmentPolicyReturn {
|
||||
policies: Ref<Policy[]>;
|
||||
loading: Ref<boolean>;
|
||||
policies: Ref<Policy[] | undefined>;
|
||||
isLoading: Ref<boolean>;
|
||||
handleFetchPolicies: () => void;
|
||||
}
|
||||
|
||||
interface useFetchAttachmentPolicyTemplatesReturn {
|
||||
policyTemplates: Ref<PolicyTemplate[]>;
|
||||
loading: Ref<boolean>;
|
||||
policyTemplates: Ref<PolicyTemplate[] | undefined>;
|
||||
isLoading: Ref<boolean>;
|
||||
handleFetchPolicyTemplates: () => void;
|
||||
}
|
||||
|
||||
export function useFetchAttachmentPolicy(options?: {
|
||||
fetchOnMounted: boolean;
|
||||
}): useFetchAttachmentPolicyReturn {
|
||||
const { fetchOnMounted } = options || {};
|
||||
|
||||
const policies = ref<Policy[]>([] as Policy[]);
|
||||
const loading = ref<boolean>(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchPolicies = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
export function useFetchAttachmentPolicy(): useFetchAttachmentPolicyReturn {
|
||||
const { data, isLoading, refetch } = useQuery<Policy[]>({
|
||||
queryKey: ["attachment-policies"],
|
||||
queryFn: async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.storage.policy.liststorageHaloRunV1alpha1Policy();
|
||||
policies.value = data.items;
|
||||
|
||||
const deletedPolicies = policies.value.filter(
|
||||
return data.items;
|
||||
},
|
||||
refetchInterval(data) {
|
||||
const deletingPolicies = data?.filter(
|
||||
(policy) => !!policy.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedPolicies.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchPolicies();
|
||||
}, 1000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch attachment policies", e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchOnMounted && handleFetchPolicies();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
return deletingPolicies?.length ? 1000 : false;
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
return {
|
||||
policies,
|
||||
loading,
|
||||
handleFetchPolicies,
|
||||
policies: data,
|
||||
isLoading,
|
||||
handleFetchPolicies: refetch,
|
||||
};
|
||||
}
|
||||
|
||||
export function useFetchAttachmentPolicyTemplate(options?: {
|
||||
fetchOnMounted: boolean;
|
||||
}): useFetchAttachmentPolicyTemplatesReturn {
|
||||
const { fetchOnMounted } = options || {};
|
||||
|
||||
const policyTemplates = ref<PolicyTemplate[]>([] as PolicyTemplate[]);
|
||||
const loading = ref<boolean>(false);
|
||||
|
||||
const handleFetchPolicyTemplates = async () => {
|
||||
try {
|
||||
loading.value = true;
|
||||
export function useFetchAttachmentPolicyTemplate(): useFetchAttachmentPolicyTemplatesReturn {
|
||||
const { data, isLoading, refetch } = useQuery<PolicyTemplate[]>({
|
||||
queryKey: ["attachment-policy-templates"],
|
||||
queryFn: async () => {
|
||||
const { data } =
|
||||
await apiClient.extension.storage.policyTemplate.liststorageHaloRunV1alpha1PolicyTemplate();
|
||||
policyTemplates.value = data.items;
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch attachment policy templates", e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
fetchOnMounted && handleFetchPolicyTemplates();
|
||||
return data.items;
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
return {
|
||||
policyTemplates,
|
||||
loading,
|
||||
handleFetchPolicyTemplates,
|
||||
policyTemplates: data,
|
||||
isLoading,
|
||||
handleFetchPolicyTemplates: refetch,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,32 +1,21 @@
|
|||
import type {
|
||||
Attachment,
|
||||
AttachmentList,
|
||||
Group,
|
||||
Policy,
|
||||
User,
|
||||
} from "@halo-dev/api-client";
|
||||
import type { Attachment, Group, Policy, User } from "@halo-dev/api-client";
|
||||
import type { Ref } from "vue";
|
||||
import { ref, watch } from "vue";
|
||||
import type { AttachmentLike } from "@halo-dev/console-shared";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { Dialog, Toast } from "@halo-dev/components";
|
||||
import type { Content, Editor } from "@halo-dev/richtext-editor";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
import { useQuery } from "@tanstack/vue-query";
|
||||
|
||||
interface useAttachmentControlReturn {
|
||||
attachments: Ref<AttachmentList>;
|
||||
loading: Ref<boolean>;
|
||||
attachments: Ref<Attachment[] | undefined>;
|
||||
isLoading: Ref<boolean>;
|
||||
isFetching: Ref<boolean>;
|
||||
selectedAttachment: Ref<Attachment | undefined>;
|
||||
selectedAttachments: Ref<Set<Attachment>>;
|
||||
checkedAll: Ref<boolean>;
|
||||
handleFetchAttachments: (options?: { mute?: boolean; page?: number }) => void;
|
||||
handlePaginationChange: ({
|
||||
page,
|
||||
size,
|
||||
}: {
|
||||
page: number;
|
||||
size: number;
|
||||
}) => void;
|
||||
total: Ref<number>;
|
||||
handleFetchAttachments: () => void;
|
||||
handleSelectPrevious: () => void;
|
||||
handleSelectNext: () => void;
|
||||
handleDelete: (attachment: Attachment) => void;
|
||||
|
@ -41,124 +30,95 @@ interface useAttachmentSelectReturn {
|
|||
onAttachmentSelect: (attachments: AttachmentLike[]) => void;
|
||||
}
|
||||
|
||||
export function useAttachmentControl(filterOptions?: {
|
||||
export function useAttachmentControl(filterOptions: {
|
||||
policy?: Ref<Policy | undefined>;
|
||||
group?: Ref<Group | undefined>;
|
||||
user?: Ref<User | undefined>;
|
||||
keyword?: Ref<string | undefined>;
|
||||
sort?: Ref<string | undefined>;
|
||||
page: Ref<number>;
|
||||
size: Ref<number>;
|
||||
}): useAttachmentControlReturn {
|
||||
const { user, policy, group, keyword, sort } = filterOptions || {};
|
||||
|
||||
const attachments = ref<AttachmentList>({
|
||||
page: 1,
|
||||
size: 60,
|
||||
total: 0,
|
||||
items: [],
|
||||
first: true,
|
||||
last: false,
|
||||
hasNext: false,
|
||||
hasPrevious: false,
|
||||
totalPages: 0,
|
||||
});
|
||||
const loading = ref<boolean>(false);
|
||||
const { user, policy, group, keyword, sort, page, size } = filterOptions;
|
||||
|
||||
const selectedAttachment = ref<Attachment>();
|
||||
const selectedAttachments = ref<Set<Attachment>>(new Set<Attachment>());
|
||||
const checkedAll = ref(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchAttachments = async (options?: {
|
||||
mute?: boolean;
|
||||
page?: number;
|
||||
}) => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
if (!options?.mute) {
|
||||
loading.value = true;
|
||||
}
|
||||
|
||||
if (options?.page) {
|
||||
attachments.value.page = options.page;
|
||||
}
|
||||
const total = ref(0);
|
||||
const hasPrevious = ref(false);
|
||||
const hasNext = ref(false);
|
||||
|
||||
const { data, isLoading, isFetching, refetch } = useQuery<Attachment[]>({
|
||||
queryKey: ["attachments", policy, keyword, group, user, page, size, sort],
|
||||
queryFn: async () => {
|
||||
const { data } = await apiClient.attachment.searchAttachments({
|
||||
policy: policy?.value?.metadata.name,
|
||||
displayName: keyword?.value,
|
||||
group: group?.value?.metadata.name,
|
||||
ungrouped: group?.value?.metadata.name === "ungrouped",
|
||||
uploadedBy: user?.value?.metadata.name,
|
||||
page: attachments.value.page,
|
||||
size: attachments.value.size,
|
||||
page: page?.value,
|
||||
size: size?.value,
|
||||
sort: [sort?.value as string].filter(Boolean),
|
||||
});
|
||||
attachments.value = data;
|
||||
|
||||
const deletedAttachments = attachments.value.items.filter(
|
||||
total.value = data.total;
|
||||
hasPrevious.value = data.hasPrevious;
|
||||
hasNext.value = data.hasNext;
|
||||
|
||||
return data.items;
|
||||
},
|
||||
refetchInterval(data) {
|
||||
const deletingAttachments = data?.filter(
|
||||
(attachment) => !!attachment.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedAttachments.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchAttachments({ mute: true });
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch attachments", e);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
};
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
return deletingAttachments?.length ? 3000 : false;
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
});
|
||||
|
||||
const handlePaginationChange = async ({
|
||||
page,
|
||||
size,
|
||||
}: {
|
||||
page: number;
|
||||
size: number;
|
||||
}) => {
|
||||
attachments.value.page = page;
|
||||
attachments.value.size = size;
|
||||
await handleFetchAttachments();
|
||||
};
|
||||
|
||||
const handleSelectPrevious = async () => {
|
||||
const { items, hasPrevious } = attachments.value;
|
||||
const index = items.findIndex(
|
||||
if (!data.value) return;
|
||||
|
||||
const index = data.value?.findIndex(
|
||||
(attachment) =>
|
||||
attachment.metadata.name === selectedAttachment.value?.metadata.name
|
||||
);
|
||||
|
||||
if (index === undefined) return;
|
||||
|
||||
if (index > 0) {
|
||||
selectedAttachment.value = items[index - 1];
|
||||
selectedAttachment.value = data.value[index - 1];
|
||||
return;
|
||||
}
|
||||
|
||||
if (index === 0 && hasPrevious) {
|
||||
attachments.value.page--;
|
||||
await handleFetchAttachments();
|
||||
selectedAttachment.value =
|
||||
attachments.value.items[attachments.value.items.length - 1];
|
||||
page.value--;
|
||||
await refetch();
|
||||
selectedAttachment.value = data.value[data.value.length - 1];
|
||||
}
|
||||
};
|
||||
|
||||
const handleSelectNext = async () => {
|
||||
const { items, hasNext } = attachments.value;
|
||||
const index = items.findIndex(
|
||||
if (!data.value) return;
|
||||
|
||||
const index = data.value?.findIndex(
|
||||
(attachment) =>
|
||||
attachment.metadata.name === selectedAttachment.value?.metadata.name
|
||||
);
|
||||
if (index < items.length - 1) {
|
||||
selectedAttachment.value = items[index + 1];
|
||||
|
||||
if (index === undefined) return;
|
||||
|
||||
if (index < data.value?.length - 1) {
|
||||
selectedAttachment.value = data.value[index + 1];
|
||||
return;
|
||||
}
|
||||
if (index === items.length - 1 && hasNext) {
|
||||
attachments.value.page++;
|
||||
await handleFetchAttachments();
|
||||
selectedAttachment.value = attachments.value.items[0];
|
||||
|
||||
if (index === data.value.length - 1 && hasNext) {
|
||||
page.value++;
|
||||
await refetch();
|
||||
selectedAttachment.value = data.value[0];
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -185,7 +145,7 @@ export function useAttachmentControl(filterOptions?: {
|
|||
} catch (e) {
|
||||
console.error("Failed to delete attachment", e);
|
||||
} finally {
|
||||
await handleFetchAttachments();
|
||||
await refetch();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -214,7 +174,7 @@ export function useAttachmentControl(filterOptions?: {
|
|||
} catch (e) {
|
||||
console.error("Failed to delete attachments", e);
|
||||
} finally {
|
||||
await handleFetchAttachments();
|
||||
await refetch();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
@ -222,7 +182,7 @@ export function useAttachmentControl(filterOptions?: {
|
|||
|
||||
const handleCheckAll = (checkAll: boolean) => {
|
||||
if (checkAll) {
|
||||
attachments.value.items.forEach((attachment) => {
|
||||
data.value?.forEach((attachment) => {
|
||||
selectedAttachments.value.add(attachment);
|
||||
});
|
||||
} else {
|
||||
|
@ -242,7 +202,7 @@ export function useAttachmentControl(filterOptions?: {
|
|||
watch(
|
||||
() => selectedAttachments.value.size,
|
||||
(newValue) => {
|
||||
checkedAll.value = newValue === attachments.value.items?.length;
|
||||
checkedAll.value = newValue === data.value?.length;
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -256,20 +216,21 @@ export function useAttachmentControl(filterOptions?: {
|
|||
};
|
||||
|
||||
const handleReset = () => {
|
||||
attachments.value.page = 1;
|
||||
page.value = 1;
|
||||
selectedAttachment.value = undefined;
|
||||
selectedAttachments.value.clear();
|
||||
checkedAll.value = false;
|
||||
};
|
||||
|
||||
return {
|
||||
attachments,
|
||||
loading,
|
||||
attachments: data,
|
||||
isLoading,
|
||||
isFetching,
|
||||
selectedAttachment,
|
||||
selectedAttachments,
|
||||
checkedAll,
|
||||
handleFetchAttachments,
|
||||
handlePaginationChange,
|
||||
total,
|
||||
handleFetchAttachments: refetch,
|
||||
handleSelectPrevious,
|
||||
handleSelectNext,
|
||||
handleDelete,
|
||||
|
|
Loading…
Reference in New Issue