mirror of https://github.com/halo-dev/halo
feat: automatically refresh the list when it has data that is being deleted (halo-dev/console#661)
#### What type of PR is this? /kind feature /milestone 2.0 #### What this PR does / why we need it: 优化部分数据列表的逻辑,支持在检测出有正在删除的数据时,自动定时刷新列表。 #### Special notes for your reviewer: /cc @halo-dev/sig-halo-console 测试方式: 1. 进入任意一个数据列表,比如文章。 2. 删除一个文章,观察是否有自动刷新列表。 3. 切换路由,检查自动刷新是否停止。 #### Does this PR introduce a user-facing change? ```release-note 优化部分数据列表的逻辑,支持在检测出有正在删除的数据时,自动定时刷新列表。 ```pull/3445/head
parent
9d91adc590
commit
2e60eaee00
|
@ -11,6 +11,7 @@ import type { AttachmentLike } from "@halo-dev/console-shared";
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import { Dialog } from "@halo-dev/components";
|
||||
import type { Content, Editor } from "@halo-dev/richtext-editor";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
interface useAttachmentControlReturn {
|
||||
attachments: Ref<AttachmentList>;
|
||||
|
@ -63,9 +64,12 @@ export function useAttachmentControl(filterOptions?: {
|
|||
const selectedAttachment = ref<Attachment>();
|
||||
const selectedAttachments = ref<Set<Attachment>>(new Set<Attachment>());
|
||||
const checkedAll = ref(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchAttachments = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
const { data } = await apiClient.attachment.searchAttachments({
|
||||
policy: policy?.value?.metadata.name,
|
||||
|
@ -76,6 +80,16 @@ export function useAttachmentControl(filterOptions?: {
|
|||
size: attachments.value.size,
|
||||
});
|
||||
attachments.value = data;
|
||||
|
||||
const deletedAttachments = attachments.value.items.filter(
|
||||
(attachment) => !!attachment.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedAttachments.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchAttachments();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch attachments", e);
|
||||
} finally {
|
||||
|
@ -83,6 +97,10 @@ export function useAttachmentControl(filterOptions?: {
|
|||
}
|
||||
};
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
const handlePaginationChange = async ({
|
||||
page,
|
||||
size,
|
||||
|
|
|
@ -21,6 +21,7 @@ import type {
|
|||
} from "@halo-dev/api-client";
|
||||
import { onMounted, ref, watch } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
const comments = ref<ListedCommentList>({
|
||||
page: 1,
|
||||
|
@ -37,9 +38,12 @@ const checkAll = ref(false);
|
|||
const selectedComment = ref<ListedComment>();
|
||||
const selectedCommentNames = ref<string[]>([]);
|
||||
const keyword = ref("");
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchComments = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
const { data } = await apiClient.comment.listComments({
|
||||
page: comments.value.page,
|
||||
|
@ -47,10 +51,19 @@ const handleFetchComments = async () => {
|
|||
approved: selectedApprovedFilterItem.value.value,
|
||||
sort: selectedSortFilterItem.value.value,
|
||||
keyword: keyword.value,
|
||||
ownerKind: "User",
|
||||
ownerName: selectedUser.value?.metadata.name,
|
||||
});
|
||||
comments.value = data;
|
||||
|
||||
const deletedComments = comments.value.items.filter(
|
||||
(comment) => !!comment.comment.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedComments.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchComments();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.log("Failed to fetch comments", error);
|
||||
} finally {
|
||||
|
@ -58,6 +71,10 @@ const handleFetchComments = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
const handlePaginationChange = ({
|
||||
page,
|
||||
size,
|
||||
|
|
|
@ -20,10 +20,10 @@ import type {
|
|||
SinglePage,
|
||||
} from "@halo-dev/api-client";
|
||||
import { formatDatetime } from "@/utils/date";
|
||||
import { computed, provide, ref, watch, type Ref } from "vue";
|
||||
import { computed, onMounted, provide, ref, watch, type Ref } from "vue";
|
||||
import ReplyListItem from "./ReplyListItem.vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { RouteLocationRaw } from "vue-router";
|
||||
import { onBeforeRouteLeave, type RouteLocationRaw } from "vue-router";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import { usePermission } from "@/utils/permission";
|
||||
|
||||
|
@ -50,6 +50,7 @@ const hoveredReply = ref<ListedReply>();
|
|||
const loading = ref(false);
|
||||
const showReplies = ref(false);
|
||||
const replyModal = ref(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
provide<Ref<ListedReply | undefined>>("hoveredReply", hoveredReply);
|
||||
|
||||
|
@ -115,11 +116,23 @@ const handleApprove = async () => {
|
|||
|
||||
const handleFetchReplies = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
const { data } = await apiClient.reply.listReplies({
|
||||
commentName: props.comment.comment.metadata.name,
|
||||
});
|
||||
replies.value = data.items;
|
||||
|
||||
const deletedReplies = replies.value.filter(
|
||||
(reply) => !!reply.reply.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedReplies.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchReplies();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch comment replies", error);
|
||||
} finally {
|
||||
|
@ -127,6 +140,14 @@ const handleFetchReplies = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => showReplies.value,
|
||||
(newValue) => {
|
||||
|
|
|
@ -31,7 +31,7 @@ import type {
|
|||
} from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { formatDatetime } from "@/utils/date";
|
||||
import { RouterLink } from "vue-router";
|
||||
import { onBeforeRouteLeave, RouterLink } from "vue-router";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
import { usePermission } from "@/utils/permission";
|
||||
|
||||
|
@ -58,9 +58,12 @@ const settingModal = ref(false);
|
|||
const selectedSinglePage = ref<SinglePage>();
|
||||
const selectedSinglePageWithContent = ref<SinglePageRequest>();
|
||||
const checkAll = ref(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchSinglePages = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
|
||||
let contributors: string[] | undefined;
|
||||
|
@ -80,6 +83,16 @@ const handleFetchSinglePages = async () => {
|
|||
contributor: contributors,
|
||||
});
|
||||
singlePages.value = data;
|
||||
|
||||
const deletedSinglePages = singlePages.value.items.filter(
|
||||
(singlePage) => !!singlePage.page.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedSinglePages.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchSinglePages();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to fetch single pages", error);
|
||||
} finally {
|
||||
|
@ -87,6 +100,10 @@ const handleFetchSinglePages = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
const handlePaginationChange = ({
|
||||
page,
|
||||
size,
|
||||
|
|
|
@ -39,6 +39,7 @@ import { formatDatetime } from "@/utils/date";
|
|||
import { usePostCategory } from "@/modules/contents/posts/categories/composables/use-post-category";
|
||||
import { usePostTag } from "@/modules/contents/posts/tags/composables/use-post-tag";
|
||||
import { usePermission } from "@/utils/permission";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
const { currentUserHasPermission } = usePermission();
|
||||
|
||||
|
@ -64,9 +65,12 @@ const selectedPost = ref<Post | null>(null);
|
|||
const selectedPostWithContent = ref<PostRequest | null>(null);
|
||||
const checkedAll = ref(false);
|
||||
const selectedPostNames = ref<string[]>([]);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchPosts = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
|
||||
let categories: string[] | undefined;
|
||||
|
@ -101,6 +105,16 @@ const handleFetchPosts = async () => {
|
|||
contributor: contributors,
|
||||
});
|
||||
posts.value = data;
|
||||
|
||||
const deletedPosts = posts.value.items.filter(
|
||||
(post) => !!post.post.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedPosts.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchPosts();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch posts", e);
|
||||
} finally {
|
||||
|
@ -108,6 +122,10 @@ const handleFetchPosts = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
const handlePaginationChange = ({
|
||||
page,
|
||||
size,
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { Category } from "@halo-dev/api-client";
|
||||
import type { Ref } from "vue";
|
||||
import { onUnmounted, type Ref } from "vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
import type { CategoryTree } from "@/modules/contents/posts/categories/utils";
|
||||
import { buildCategoriesTree } from "@/modules/contents/posts/categories/utils";
|
||||
import { Dialog } from "@halo-dev/components";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
interface usePostCategoryReturn {
|
||||
categories: Ref<Category[]>;
|
||||
|
@ -22,9 +23,12 @@ export function usePostCategory(options?: {
|
|||
const categories = ref<Category[]>([] as Category[]);
|
||||
const categoriesTree = ref<CategoryTree[]>([] as CategoryTree[]);
|
||||
const loading = ref(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchCategories = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
const { data } =
|
||||
await apiClient.extension.category.listcontentHaloRunV1alpha1Category({
|
||||
|
@ -33,6 +37,16 @@ export function usePostCategory(options?: {
|
|||
});
|
||||
categories.value = data.items;
|
||||
categoriesTree.value = buildCategoriesTree(data.items);
|
||||
|
||||
const deletedCategories = categories.value.filter(
|
||||
(category) => !!category.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedCategories.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchCategories();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch categories", e);
|
||||
} finally {
|
||||
|
@ -40,6 +54,14 @@ export function usePostCategory(options?: {
|
|||
}
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
const handleDelete = async (category: CategoryTree) => {
|
||||
Dialog.warning({
|
||||
title: "确定要删除该分类吗?",
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { Tag } from "@halo-dev/api-client";
|
||||
import type { Ref } from "vue";
|
||||
import { onUnmounted, type Ref } from "vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { Dialog } from "@halo-dev/components";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
interface usePostTagReturn {
|
||||
tags: Ref<Tag[]>;
|
||||
|
@ -18,9 +19,12 @@ export function usePostTag(options?: {
|
|||
|
||||
const tags = ref<Tag[]>([] as Tag[]);
|
||||
const loading = ref(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchTags = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
const { data } =
|
||||
await apiClient.extension.tag.listcontentHaloRunV1alpha1Tag({
|
||||
|
@ -29,6 +33,16 @@ export function usePostTag(options?: {
|
|||
});
|
||||
|
||||
tags.value = data.items;
|
||||
|
||||
const deletedTags = tags.value.filter(
|
||||
(tag) => !!tag.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedTags.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchTags();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch tags", e);
|
||||
} finally {
|
||||
|
@ -36,6 +50,14 @@ export function usePostTag(options?: {
|
|||
}
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
const handleDelete = async (tag: Tag) => {
|
||||
Dialog.warning({
|
||||
title: "确定要删除该标签吗?",
|
||||
|
|
|
@ -12,7 +12,7 @@ import {
|
|||
import MenuItemEditingModal from "./components/MenuItemEditingModal.vue";
|
||||
import MenuItemListItem from "./components/MenuItemListItem.vue";
|
||||
import MenuList from "./components/MenuList.vue";
|
||||
import { ref } from "vue";
|
||||
import { onUnmounted, ref } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import type { Menu, MenuItem } from "@halo-dev/api-client";
|
||||
import cloneDeep from "lodash.clonedeep";
|
||||
|
@ -25,6 +25,7 @@ import {
|
|||
resetMenuItemsTreePriority,
|
||||
} from "./utils";
|
||||
import { useDebounceFn } from "@vueuse/core";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
const menuItems = ref<MenuItem[]>([] as MenuItem[]);
|
||||
const menuTreeItems = ref<MenuTreeItem[]>([] as MenuTreeItem[]);
|
||||
|
@ -34,9 +35,12 @@ const selectedParentMenuItem = ref<MenuItem>();
|
|||
const loading = ref(false);
|
||||
const menuListRef = ref();
|
||||
const menuItemEditingModal = ref();
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchMenuItems = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
|
||||
if (!selectedMenu.value?.spec.menuItems) {
|
||||
|
@ -53,6 +57,16 @@ const handleFetchMenuItems = async () => {
|
|||
menuItems.value = data.items;
|
||||
// Build the menu tree
|
||||
menuTreeItems.value = buildMenuItemsTree(data.items);
|
||||
|
||||
const deletedMenuItems = menuItems.value.filter(
|
||||
(menuItem) => !!menuItem.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedMenuItems.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchMenuItems();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch menu items", e);
|
||||
} finally {
|
||||
|
@ -60,6 +74,14 @@ const handleFetchMenuItems = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
const handleOpenEditingModal = (menuItem: MenuTreeItem) => {
|
||||
selectedMenuItem.value = convertMenuTreeItemToMenuItem(menuItem);
|
||||
menuItemEditingModal.value = true;
|
||||
|
|
|
@ -10,11 +10,12 @@ import {
|
|||
VEntityField,
|
||||
} from "@halo-dev/components";
|
||||
import MenuEditingModal from "./MenuEditingModal.vue";
|
||||
import { onMounted, ref } from "vue";
|
||||
import { onMounted, onUnmounted, ref } from "vue";
|
||||
import type { Menu } from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { useRouteQuery } from "@vueuse/router";
|
||||
import { usePermission } from "@/utils/permission";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
const { currentUserHasPermission } = usePermission();
|
||||
|
||||
|
@ -36,10 +37,13 @@ const menus = ref<Menu[]>([] as Menu[]);
|
|||
const loading = ref(false);
|
||||
const selectedMenuToUpdate = ref<Menu>();
|
||||
const menuEditingModal = ref<boolean>(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchMenus = async () => {
|
||||
selectedMenuToUpdate.value = undefined;
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
|
||||
const { data } = await apiClient.extension.menu.listv1alpha1Menu();
|
||||
|
@ -54,6 +58,16 @@ const handleFetchMenus = async () => {
|
|||
emit("update:selectedMenu", updatedMenu);
|
||||
}
|
||||
}
|
||||
|
||||
const deletedMenus = menus.value.filter(
|
||||
(menu) => !!menu.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedMenus.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchMenus();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch menus", e);
|
||||
} finally {
|
||||
|
@ -61,6 +75,14 @@ const handleFetchMenus = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
onUnmounted(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
const menuQuery = useRouteQuery("menu");
|
||||
const handleSelect = (menu: Menu) => {
|
||||
emit("update:selectedMenu", menu);
|
||||
|
|
|
@ -23,6 +23,7 @@ import { computed, ref, watch } from "vue";
|
|||
import type { Theme } from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { usePermission } from "@/utils/permission";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
const { currentUserHasPermission } = usePermission();
|
||||
|
||||
|
@ -51,6 +52,7 @@ const themes = ref<Theme[]>([] as Theme[]);
|
|||
const loading = ref(false);
|
||||
const themeInstall = ref(false);
|
||||
const creating = ref(false);
|
||||
const refreshInterval = ref();
|
||||
|
||||
const modalTitle = computed(() => {
|
||||
return activeTab.value === "installed" ? "已安装的主题" : "未安装的主题";
|
||||
|
@ -58,13 +60,31 @@ const modalTitle = computed(() => {
|
|||
|
||||
const handleFetchThemes = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
const { data } = await apiClient.theme.listThemes({
|
||||
page: 0,
|
||||
size: 0,
|
||||
uninstalled: activeTab.value !== "installed",
|
||||
page: 0,
|
||||
size: 0,
|
||||
});
|
||||
themes.value = data.items;
|
||||
|
||||
if (activeTab.value !== "installed") {
|
||||
return;
|
||||
}
|
||||
|
||||
const deletedThemes = themes.value.filter(
|
||||
(theme) => !!theme.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedThemes.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchThemes();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch themes", e);
|
||||
} finally {
|
||||
|
@ -72,6 +92,10 @@ const handleFetchThemes = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
watch(
|
||||
() => activeTab.value,
|
||||
() => {
|
||||
|
@ -159,6 +183,8 @@ watch(
|
|||
(visible) => {
|
||||
if (visible) {
|
||||
handleFetchThemes();
|
||||
} else {
|
||||
clearInterval(refreshInterval.value);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -18,6 +18,7 @@ import { onMounted, ref } from "vue";
|
|||
import { apiClient } from "@/utils/api-client";
|
||||
import type { PluginList } from "@halo-dev/api-client";
|
||||
import { usePermission } from "@/utils/permission";
|
||||
import { onBeforeRouteLeave } from "vue-router";
|
||||
|
||||
const { currentUserHasPermission } = usePermission();
|
||||
|
||||
|
@ -34,9 +35,12 @@ const plugins = ref<PluginList>({
|
|||
const loading = ref(false);
|
||||
const pluginInstall = ref(false);
|
||||
const keyword = ref("");
|
||||
const refreshInterval = ref();
|
||||
|
||||
const handleFetchPlugins = async () => {
|
||||
try {
|
||||
clearInterval(refreshInterval.value);
|
||||
|
||||
loading.value = true;
|
||||
|
||||
const { data } = await apiClient.plugin.listPlugins({
|
||||
|
@ -50,6 +54,16 @@ const handleFetchPlugins = async () => {
|
|||
});
|
||||
|
||||
plugins.value = data;
|
||||
|
||||
const deletedPlugins = plugins.value.items.filter(
|
||||
(plugin) => !!plugin.metadata.deletionTimestamp
|
||||
);
|
||||
|
||||
if (deletedPlugins.length) {
|
||||
refreshInterval.value = setInterval(() => {
|
||||
handleFetchPlugins();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Failed to fetch plugins", e);
|
||||
} finally {
|
||||
|
@ -57,6 +71,10 @@ const handleFetchPlugins = async () => {
|
|||
}
|
||||
};
|
||||
|
||||
onBeforeRouteLeave(() => {
|
||||
clearInterval(refreshInterval.value);
|
||||
});
|
||||
|
||||
const handlePaginationChange = ({
|
||||
page,
|
||||
size,
|
||||
|
|
|
@ -69,6 +69,11 @@ const { isStarted, changeStatus, uninstall } = usePluginLifeCycle(plugin);
|
|||
/>
|
||||
</template>
|
||||
</VEntityField>
|
||||
<VEntityField v-if="plugin?.metadata.deletionTimestamp">
|
||||
<template #description>
|
||||
<VStatusDot v-tooltip="`删除中`" state="warning" animate />
|
||||
</template>
|
||||
</VEntityField>
|
||||
<VEntityField>
|
||||
<template #description>
|
||||
<a
|
||||
|
|
Loading…
Reference in New Issue