From db9fcb8e2ca191e85547fbfdebe9a05de70684d8 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Wed, 15 Mar 2023 12:02:27 +0800 Subject: [PATCH] perf: add supports for force updating of post and single page settings (#907) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit > **Warning** > > 此 PR 的改动来自: > 因为目前 Console 仓库已经合并到 Halo 主仓库,但主仓库的 release-2.3 分支不包含 Console,所以如果需要发布 2.3.x 的 patch 版本,依旧需要在此仓库修改。 #### What type of PR is this? /kind improvement /milestone 2.3.2 #### What this PR does / why we need it: 支持强制保存文章和单页面的设置,绕开后端 version 锁的机制,因为目前发现在后端 Reconcile 处理文章较慢时会影响文章的保存。 需要注意的是,这是一个不太合理的处理方式,但目前别无选择。 #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/3339 #### Special notes for your reviewer: 测试方式: 1. 同时打开多个同文章的编辑页面的窗口。 2. 编辑任意一个窗口的文章设置。 3. 然后再去其他窗口保存,观察是否有异常。 #### Does this PR introduce a user-facing change? ```release-note 支持强制保存文章和页面的设置,避免因为 Version 锁的机制导致保存失败。 ``` --- .../components/SinglePageSettingModal.vue | 44 +++++++++++++++---- .../posts/components/PostSettingModal.vue | 40 +++++++++++++++-- .../__tests__/PostSettingModal.spec.ts | 18 +++++--- 3 files changed, 85 insertions(+), 17 deletions(-) diff --git a/src/modules/contents/pages/components/SinglePageSettingModal.vue b/src/modules/contents/pages/components/SinglePageSettingModal.vue index 67ce50c8..cd670636 100644 --- a/src/modules/contents/pages/components/SinglePageSettingModal.vue +++ b/src/modules/contents/pages/components/SinglePageSettingModal.vue @@ -17,6 +17,7 @@ import { toDatetimeLocal, toISOString } from "@/utils/date"; import { submitForm } from "@formkit/core"; import AnnotationsForm from "@/components/form/AnnotationsForm.vue"; import useSlugify from "@/composables/use-slugify"; +import { useMutation } from "@tanstack/vue-query"; const initialFormState: SinglePage = { spec: { @@ -110,6 +111,40 @@ const handlePublishClick = () => { }); }; +// Fix me: +// Force update post settings, +// because currently there may be errors caused by changes in version due to asynchronous processing. +const { mutateAsync: singlePageUpdateMutate } = useMutation({ + mutationKey: ["singlePage-update"], + mutationFn: async (page: SinglePage) => { + const { data: latestSinglePage } = + await apiClient.extension.singlePage.getcontentHaloRunV1alpha1SinglePage({ + name: page.metadata.name, + }); + return apiClient.extension.singlePage.updatecontentHaloRunV1alpha1SinglePage( + { + name: page.metadata.name, + singlePage: { + ...latestSinglePage, + spec: page.spec, + metadata: { + ...latestSinglePage.metadata, + annotations: page.metadata.annotations, + }, + }, + }, + { + mute: true, + } + ); + }, + retry: 3, + onError: (error) => { + console.error("Failed to update post", error); + Toast.error(`服务器内部错误`); + }, +}); + const handleSave = async () => { annotationsFormRef.value?.handleSubmit(); await nextTick(); @@ -133,15 +168,8 @@ const handleSave = async () => { try { saving.value = true; - saving.value = true; - const { data } = isUpdateMode.value - ? await apiClient.extension.singlePage.updatecontentHaloRunV1alpha1SinglePage( - { - name: formState.value.metadata.name, - singlePage: formState.value, - } - ) + ? await singlePageUpdateMutate(formState.value) : await apiClient.extension.singlePage.createcontentHaloRunV1alpha1SinglePage( { singlePage: formState.value, diff --git a/src/modules/contents/posts/components/PostSettingModal.vue b/src/modules/contents/posts/components/PostSettingModal.vue index 8affc3ea..89d3fa2d 100644 --- a/src/modules/contents/posts/components/PostSettingModal.vue +++ b/src/modules/contents/posts/components/PostSettingModal.vue @@ -17,6 +17,7 @@ import { toDatetimeLocal, toISOString } from "@/utils/date"; import AnnotationsForm from "@/components/form/AnnotationsForm.vue"; import { submitForm } from "@formkit/core"; import useSlugify from "@/composables/use-slugify"; +import { useMutation } from "@tanstack/vue-query"; const initialFormState: Post = { spec: { @@ -114,6 +115,40 @@ const handlePublishClick = () => { }); }; +// Fix me: +// Force update post settings, +// because currently there may be errors caused by changes in version due to asynchronous processing. +const { mutateAsync: postUpdateMutate } = useMutation({ + mutationKey: ["post-update"], + mutationFn: async (post: Post) => { + const { data: latestPost } = + await apiClient.extension.post.getcontentHaloRunV1alpha1Post({ + name: post.metadata.name, + }); + return apiClient.extension.post.updatecontentHaloRunV1alpha1Post( + { + name: post.metadata.name, + post: { + ...latestPost, + spec: post.spec, + metadata: { + ...latestPost.metadata, + annotations: post.metadata.annotations, + }, + }, + }, + { + mute: true, + } + ); + }, + retry: 3, + onError: (error) => { + console.error("Failed to update post", error); + Toast.error(`服务器内部错误`); + }, +}); + const handleSave = async () => { annotationsFormRef.value?.handleSubmit(); await nextTick(); @@ -139,10 +174,7 @@ const handleSave = async () => { saving.value = true; const { data } = isUpdateMode.value - ? await apiClient.extension.post.updatecontentHaloRunV1alpha1Post({ - name: formState.value.metadata.name, - post: formState.value, - }) + ? await postUpdateMutate(formState.value) : await apiClient.extension.post.createcontentHaloRunV1alpha1Post({ post: formState.value, }); diff --git a/src/modules/contents/posts/components/__tests__/PostSettingModal.spec.ts b/src/modules/contents/posts/components/__tests__/PostSettingModal.spec.ts index 781930aa..1fba561b 100644 --- a/src/modules/contents/posts/components/__tests__/PostSettingModal.spec.ts +++ b/src/modules/contents/posts/components/__tests__/PostSettingModal.spec.ts @@ -2,6 +2,7 @@ import { beforeEach, describe, expect, it } from "vitest"; import { mount } from "@vue/test-utils"; import PostSettingModal from "../PostSettingModal.vue"; import { createPinia, setActivePinia } from "pinia"; +import { VueQueryPlugin } from "@tanstack/vue-query"; describe("PostSettingModal", () => { beforeEach(() => { @@ -9,12 +10,19 @@ describe("PostSettingModal", () => { }); it("should render", () => { - const wrapper = mount({ - components: { - PostSettingModal, + const wrapper = mount( + { + components: { + PostSettingModal, + }, + template: ``, }, - template: ``, - }); + { + global: { + plugins: [VueQueryPlugin], + }, + } + ); expect(wrapper).toBeDefined(); }); });