mirror of https://github.com/halo-dev/halo
feat: add retry mechanism for saving posts on the UC end (#5578)
#### What type of PR is this? /area ui /kind improvement /milestone 2.14.x #### What this PR does / why we need it: 为 UC 端保存文章的操作添加重试机制,防止出现因为锁导致的保存失败问题。 #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/5474 #### Special notes for your reviewer: 需要多次尝试编辑文章,以及设置表单的保存功能。 #### Does this PR introduce a user-facing change? ```release-note 为 UC 端保存文章的操作添加重试机制,防止出现因为锁导致的保存失败问题。 ```pull/5464/head^2
parent
db0fa1e103
commit
78c00a28f3
|
@ -13,30 +13,27 @@ import {
|
|||
VSpace,
|
||||
} from "@halo-dev/components";
|
||||
import EditorProviderSelector from "@/components/dropdown-selector/EditorProviderSelector.vue";
|
||||
import { ref, toRef, watch } from "vue";
|
||||
import type { ComputedRef } from "vue";
|
||||
import { computed, nextTick, onMounted, provide, ref, toRef, watch } from "vue";
|
||||
import { useLocalStorage } from "@vueuse/core";
|
||||
import type { Post, Content, Snapshot } from "@halo-dev/api-client";
|
||||
import type { Content, Post, Snapshot } from "@halo-dev/api-client";
|
||||
import { randomUUID } from "@/utils/id";
|
||||
import { contentAnnotations } from "@/constants/annotations";
|
||||
import { useRouteQuery } from "@vueuse/router";
|
||||
import { onMounted } from "vue";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { nextTick } from "vue";
|
||||
import { useRouter } from "vue-router";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useMutation } from "@tanstack/vue-query";
|
||||
import { computed } from "vue";
|
||||
import { useSaveKeybinding } from "@console/composables/use-save-keybinding";
|
||||
import PostCreationModal from "./components/PostCreationModal.vue";
|
||||
import PostSettingEditModal from "./components/PostSettingEditModal.vue";
|
||||
import HasPermission from "@/components/permission/HasPermission.vue";
|
||||
import { provide } from "vue";
|
||||
import type { ComputedRef } from "vue";
|
||||
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
|
||||
import { usePermission } from "@/utils/permission";
|
||||
import type { AxiosRequestConfig } from "axios";
|
||||
import { useContentCache } from "@/composables/use-content-cache";
|
||||
import { useAutoSaveContent } from "@/composables/use-auto-save-content";
|
||||
import { usePostUpdateMutate } from "@uc/modules/contents/posts/composables/use-post-update-mutate";
|
||||
|
||||
const router = useRouter();
|
||||
const { t } = useI18n();
|
||||
|
@ -306,19 +303,20 @@ const isUpdateMode = computed(
|
|||
() => !!formState.value.metadata.creationTimestamp
|
||||
);
|
||||
|
||||
const { mutateAsync: postUpdateMutate } = usePostUpdateMutate();
|
||||
|
||||
const { mutateAsync: handleSave, isLoading: isSaving } = useMutation({
|
||||
mutationKey: ["save-post"],
|
||||
mutationKey: ["uc:save-post-content"],
|
||||
variables: {
|
||||
mute: false,
|
||||
},
|
||||
mutationFn: async () => {
|
||||
// Update title
|
||||
// TODO: needs retry
|
||||
if (isTitleChanged.value) {
|
||||
const { data: updatedPost } = await apiClient.uc.post.updateMyPost({
|
||||
name: formState.value.metadata.name,
|
||||
post: formState.value,
|
||||
const { data: updatedPost } = await postUpdateMutate({
|
||||
postToUpdate: formState.value,
|
||||
});
|
||||
|
||||
formState.value = updatedPost;
|
||||
isTitleChanged.value = false;
|
||||
}
|
||||
|
@ -379,7 +377,7 @@ function onPublishPostSuccess() {
|
|||
}
|
||||
|
||||
const { mutateAsync: handlePublish, isLoading: isPublishing } = useMutation({
|
||||
mutationKey: ["publish-post"],
|
||||
mutationKey: ["uc:publish-post"],
|
||||
mutationFn: async () => {
|
||||
await handleSave({ mute: true });
|
||||
|
||||
|
@ -403,7 +401,7 @@ const { mutateAsync: handlePublish, isLoading: isPublishing } = useMutation({
|
|||
const postSettingEditModal = ref(false);
|
||||
|
||||
async function handleOpenPostSettingEditModal() {
|
||||
handleSave({ mute: true });
|
||||
await handleSave({ mute: true });
|
||||
await getLatestPost();
|
||||
postSettingEditModal.value = true;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ const emit = defineEmits<{
|
|||
const modal = ref();
|
||||
|
||||
const { mutate, isLoading } = useMutation({
|
||||
mutationKey: ["create-post"],
|
||||
mutationKey: ["uc:create-post"],
|
||||
mutationFn: async ({ data }: { data: PostFormState }) => {
|
||||
const post: Post = {
|
||||
apiVersion: "content.halo.run/v1alpha1",
|
||||
|
|
|
@ -5,9 +5,8 @@ import type { PostFormState } from "../types";
|
|||
import type { Post } from "@halo-dev/api-client";
|
||||
import { ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { useMutation } from "@tanstack/vue-query";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { toDatetimeLocal } from "@/utils/date";
|
||||
import { usePostUpdateMutate } from "@uc/modules/contents/posts/composables/use-post-update-mutate";
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
|
@ -25,46 +24,34 @@ const emit = defineEmits<{
|
|||
|
||||
const modal = ref();
|
||||
|
||||
const { mutate, isLoading } = useMutation({
|
||||
mutationKey: ["edit-post"],
|
||||
mutationFn: async ({ data }: { data: PostFormState }) => {
|
||||
const postToUpdate: Post = {
|
||||
...props.post,
|
||||
spec: {
|
||||
...props.post.spec,
|
||||
allowComment: data.allowComment,
|
||||
categories: data.categories,
|
||||
cover: data.cover,
|
||||
excerpt: {
|
||||
autoGenerate: data.excerptAutoGenerate,
|
||||
raw: data.excerptRaw,
|
||||
},
|
||||
pinned: data.pinned,
|
||||
publishTime: data.publishTime,
|
||||
slug: data.slug,
|
||||
tags: data.tags,
|
||||
title: data.title,
|
||||
visible: data.visible,
|
||||
},
|
||||
};
|
||||
const { data: updatedPost } = await apiClient.uc.post.updateMyPost({
|
||||
name: props.post.metadata.name,
|
||||
post: postToUpdate,
|
||||
});
|
||||
return updatedPost;
|
||||
},
|
||||
onSuccess(data) {
|
||||
Toast.success(t("core.common.toast.save_success"));
|
||||
emit("success", data);
|
||||
modal.value.close();
|
||||
},
|
||||
onError() {
|
||||
Toast.error(t("core.common.toast.save_failed_and_retry"));
|
||||
},
|
||||
});
|
||||
const { mutateAsync, isLoading } = usePostUpdateMutate();
|
||||
|
||||
function onSubmit(data: PostFormState) {
|
||||
mutate({ data });
|
||||
async function onSubmit(data: PostFormState) {
|
||||
const postToUpdate: Post = {
|
||||
...props.post,
|
||||
spec: {
|
||||
...props.post.spec,
|
||||
allowComment: data.allowComment,
|
||||
categories: data.categories,
|
||||
cover: data.cover,
|
||||
excerpt: {
|
||||
autoGenerate: data.excerptAutoGenerate,
|
||||
raw: data.excerptRaw,
|
||||
},
|
||||
pinned: data.pinned,
|
||||
publishTime: data.publishTime,
|
||||
slug: data.slug,
|
||||
tags: data.tags,
|
||||
title: data.title,
|
||||
visible: data.visible,
|
||||
},
|
||||
};
|
||||
|
||||
const { data: newPost } = await mutateAsync({ postToUpdate });
|
||||
|
||||
Toast.success(t("core.common.toast.save_success"));
|
||||
emit("success", newPost);
|
||||
modal.value.close();
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
import { useMutation } from "@tanstack/vue-query";
|
||||
import type { Post } from "@halo-dev/api-client";
|
||||
import { apiClient } from "@/utils/api-client";
|
||||
import { Toast } from "@halo-dev/components";
|
||||
import { useI18n } from "vue-i18n";
|
||||
|
||||
export function usePostUpdateMutate() {
|
||||
const { t } = useI18n();
|
||||
|
||||
return useMutation({
|
||||
mutationKey: ["uc:update-post"],
|
||||
mutationFn: async ({ postToUpdate }: { postToUpdate: Post }) => {
|
||||
const { data: latestPost } = await apiClient.uc.post.getMyPost({
|
||||
name: postToUpdate.metadata.name,
|
||||
});
|
||||
|
||||
return await apiClient.uc.post.updateMyPost(
|
||||
{
|
||||
name: postToUpdate.metadata.name,
|
||||
post: {
|
||||
...latestPost,
|
||||
spec: {
|
||||
...latestPost.spec,
|
||||
...postToUpdate.spec,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
mute: true,
|
||||
}
|
||||
);
|
||||
},
|
||||
retry: 3,
|
||||
onError: () => {
|
||||
Toast.error(t("core.common.toast.save_failed_and_retry"));
|
||||
},
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue