2022-05-23 07:16:23 +00:00
|
|
|
<script lang="ts" setup>
|
2022-06-14 07:56:55 +00:00
|
|
|
import {
|
|
|
|
IconBookRead,
|
|
|
|
IconSave,
|
2022-11-10 16:24:10 +00:00
|
|
|
IconSettings,
|
|
|
|
IconSendPlaneFill,
|
2022-06-14 07:56:55 +00:00
|
|
|
VButton,
|
|
|
|
VPageHeader,
|
2022-08-23 04:08:10 +00:00
|
|
|
VSpace,
|
2022-11-18 13:16:23 +00:00
|
|
|
Toast,
|
2022-12-22 04:14:29 +00:00
|
|
|
Dialog,
|
2023-05-25 14:54:18 +00:00
|
|
|
IconEye,
|
2022-06-14 07:56:55 +00:00
|
|
|
} from "@halo-dev/components";
|
2022-08-23 04:08:10 +00:00
|
|
|
import PostSettingModal from "./components/PostSettingModal.vue";
|
2022-11-10 16:24:10 +00:00
|
|
|
import type { Post, PostRequest } from "@halo-dev/api-client";
|
2022-12-22 04:14:29 +00:00
|
|
|
import {
|
|
|
|
computed,
|
|
|
|
nextTick,
|
|
|
|
onMounted,
|
|
|
|
provide,
|
|
|
|
ref,
|
|
|
|
toRef,
|
|
|
|
type ComputedRef,
|
2024-03-18 04:38:07 +00:00
|
|
|
watch,
|
2022-12-22 04:14:29 +00:00
|
|
|
} from "vue";
|
2022-09-22 08:46:32 +00:00
|
|
|
import { apiClient } from "@/utils/api-client";
|
2022-08-23 04:08:10 +00:00
|
|
|
import { useRouteQuery } from "@vueuse/router";
|
2022-11-10 16:24:10 +00:00
|
|
|
import { useRouter } from "vue-router";
|
2022-11-18 06:00:23 +00:00
|
|
|
import { randomUUID } from "@/utils/id";
|
2024-01-29 09:32:25 +00:00
|
|
|
import { useContentCache } from "@/composables/use-content-cache";
|
2023-11-30 03:55:29 +00:00
|
|
|
import { useEditorExtensionPoints } from "@/composables/use-editor-extension-points";
|
2023-08-25 07:28:11 +00:00
|
|
|
import type { EditorProvider } from "@halo-dev/console-shared";
|
2022-12-29 13:46:34 +00:00
|
|
|
import { useLocalStorage } from "@vueuse/core";
|
|
|
|
import EditorProviderSelector from "@/components/dropdown-selector/EditorProviderSelector.vue";
|
2023-03-23 08:54:33 +00:00
|
|
|
import { useI18n } from "vue-i18n";
|
2023-05-25 14:54:18 +00:00
|
|
|
import UrlPreviewModal from "@/components/preview/UrlPreviewModal.vue";
|
2023-07-18 08:16:02 +00:00
|
|
|
import { usePostUpdateMutate } from "./composables/use-post-update-mutate";
|
|
|
|
import { contentAnnotations } from "@/constants/annotations";
|
2024-01-29 09:32:25 +00:00
|
|
|
import { useAutoSaveContent } from "@/composables/use-auto-save-content";
|
2023-11-09 06:56:06 +00:00
|
|
|
import { useContentSnapshot } from "@console/composables/use-content-snapshot";
|
|
|
|
import { useSaveKeybinding } from "@console/composables/use-save-keybinding";
|
2023-11-30 04:10:08 +00:00
|
|
|
import { useSessionKeepAlive } from "@/composables/use-session-keep-alive";
|
2023-12-01 02:14:09 +00:00
|
|
|
import { usePermission } from "@/utils/permission";
|
2024-01-19 09:39:06 +00:00
|
|
|
import type { AxiosRequestConfig } from "axios";
|
2022-11-10 16:24:10 +00:00
|
|
|
|
|
|
|
const router = useRouter();
|
2023-03-23 08:54:33 +00:00
|
|
|
const { t } = useI18n();
|
2023-07-18 08:16:02 +00:00
|
|
|
const { mutateAsync: postUpdateMutate } = usePostUpdateMutate();
|
2023-12-01 02:14:09 +00:00
|
|
|
const { currentUserHasPermission } = usePermission();
|
2022-08-23 04:08:10 +00:00
|
|
|
|
2022-12-29 13:46:34 +00:00
|
|
|
// Editor providers
|
2022-12-22 04:14:29 +00:00
|
|
|
const { editorProviders } = useEditorExtensionPoints();
|
|
|
|
const currentEditorProvider = ref<EditorProvider>();
|
2022-12-29 13:46:34 +00:00
|
|
|
const storedEditorProviderName = useLocalStorage("editor-provider-name", "");
|
|
|
|
|
2023-07-18 08:16:02 +00:00
|
|
|
const handleChangeEditorProvider = async (provider: EditorProvider) => {
|
2022-12-29 13:46:34 +00:00
|
|
|
currentEditorProvider.value = provider;
|
|
|
|
storedEditorProviderName.value = provider.name;
|
2023-07-18 08:16:02 +00:00
|
|
|
|
2022-12-29 13:46:34 +00:00
|
|
|
formState.value.post.metadata.annotations = {
|
2023-07-18 08:16:02 +00:00
|
|
|
...formState.value.post.metadata.annotations,
|
|
|
|
[contentAnnotations.PREFERRED_EDITOR]: provider.name,
|
2022-12-29 13:46:34 +00:00
|
|
|
};
|
2023-07-18 08:16:02 +00:00
|
|
|
|
2023-03-15 03:12:26 +00:00
|
|
|
formState.value.content.rawType = provider.rawType;
|
2023-07-18 08:16:02 +00:00
|
|
|
|
|
|
|
if (isUpdateMode.value) {
|
|
|
|
const { data } = await postUpdateMutate(formState.value.post);
|
|
|
|
formState.value.post = data;
|
|
|
|
}
|
2022-12-29 13:46:34 +00:00
|
|
|
};
|
2022-12-22 04:14:29 +00:00
|
|
|
|
2023-11-30 03:55:29 +00:00
|
|
|
// fixme: PostRequest type may be wrong
|
|
|
|
interface PostRequestWithContent extends PostRequest {
|
|
|
|
content: {
|
|
|
|
raw: string;
|
|
|
|
content: string;
|
|
|
|
rawType: string;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2022-12-29 13:46:34 +00:00
|
|
|
// Post form
|
2024-03-18 04:38:07 +00:00
|
|
|
const formState = ref<PostRequestWithContent>({
|
2022-08-23 04:08:10 +00:00
|
|
|
post: {
|
|
|
|
spec: {
|
|
|
|
title: "",
|
|
|
|
slug: "",
|
|
|
|
template: "",
|
|
|
|
cover: "",
|
|
|
|
deleted: false,
|
2022-11-10 16:24:10 +00:00
|
|
|
publish: false,
|
2023-04-03 03:12:14 +00:00
|
|
|
publishTime: undefined,
|
2022-08-23 04:08:10 +00:00
|
|
|
pinned: false,
|
|
|
|
allowComment: true,
|
|
|
|
visible: "PUBLIC",
|
|
|
|
priority: 0,
|
|
|
|
excerpt: {
|
|
|
|
autoGenerate: true,
|
|
|
|
raw: "",
|
|
|
|
},
|
|
|
|
categories: [],
|
|
|
|
tags: [],
|
|
|
|
htmlMetas: [],
|
|
|
|
},
|
|
|
|
apiVersion: "content.halo.run/v1alpha1",
|
|
|
|
kind: "Post",
|
|
|
|
metadata: {
|
2022-11-18 06:00:23 +00:00
|
|
|
name: randomUUID(),
|
2022-12-22 04:14:29 +00:00
|
|
|
annotations: {},
|
2022-08-23 04:08:10 +00:00
|
|
|
},
|
|
|
|
},
|
|
|
|
content: {
|
|
|
|
raw: "",
|
|
|
|
content: "",
|
|
|
|
rawType: "HTML",
|
|
|
|
},
|
2024-03-18 04:38:07 +00:00
|
|
|
});
|
2022-08-23 04:08:10 +00:00
|
|
|
const settingModal = ref(false);
|
|
|
|
const saving = ref(false);
|
2022-11-10 16:24:10 +00:00
|
|
|
const publishing = ref(false);
|
2022-08-23 04:08:10 +00:00
|
|
|
|
2024-03-18 04:38:07 +00:00
|
|
|
const isTitleChanged = ref(false);
|
|
|
|
watch(
|
|
|
|
() => formState.value.post.spec.title,
|
|
|
|
(newValue, oldValue) => {
|
|
|
|
isTitleChanged.value = newValue !== oldValue;
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
2022-08-23 04:08:10 +00:00
|
|
|
const isUpdateMode = computed(() => {
|
|
|
|
return !!formState.value.post.metadata.creationTimestamp;
|
|
|
|
});
|
|
|
|
|
2022-12-22 04:14:29 +00:00
|
|
|
// provide some data to editor
|
|
|
|
provide<ComputedRef<string | undefined>>(
|
|
|
|
"owner",
|
|
|
|
computed(() => formState.value.post.spec.owner)
|
|
|
|
);
|
|
|
|
provide<ComputedRef<string | undefined>>(
|
|
|
|
"publishTime",
|
|
|
|
computed(() => formState.value.post.spec.publishTime)
|
|
|
|
);
|
|
|
|
provide<ComputedRef<string | undefined>>(
|
|
|
|
"permalink",
|
|
|
|
computed(() => formState.value.post.status?.permalink)
|
|
|
|
);
|
|
|
|
|
2023-05-25 14:54:18 +00:00
|
|
|
const handleSave = async (options?: { mute?: boolean }) => {
|
2022-08-23 04:08:10 +00:00
|
|
|
try {
|
2023-05-25 14:54:18 +00:00
|
|
|
if (!options?.mute) {
|
|
|
|
saving.value = true;
|
|
|
|
}
|
2022-08-23 09:10:00 +00:00
|
|
|
|
2022-08-24 07:41:29 +00:00
|
|
|
// Set default title and slug
|
|
|
|
if (!formState.value.post.spec.title) {
|
2023-03-23 08:54:33 +00:00
|
|
|
formState.value.post.spec.title = t("core.post_editor.untitled");
|
2022-08-24 07:41:29 +00:00
|
|
|
}
|
2022-11-10 16:24:10 +00:00
|
|
|
|
2022-08-24 07:41:29 +00:00
|
|
|
if (!formState.value.post.spec.slug) {
|
2022-11-18 06:00:23 +00:00
|
|
|
formState.value.post.spec.slug = new Date().getTime().toString();
|
2022-08-24 07:41:29 +00:00
|
|
|
}
|
|
|
|
|
2022-08-23 04:08:10 +00:00
|
|
|
if (isUpdateMode.value) {
|
2024-03-18 04:38:07 +00:00
|
|
|
// Save post title
|
|
|
|
if (isTitleChanged.value) {
|
|
|
|
formState.value.post = (
|
|
|
|
await postUpdateMutate(formState.value.post)
|
|
|
|
).data;
|
|
|
|
}
|
|
|
|
|
2022-11-18 13:16:23 +00:00
|
|
|
const { data } = await apiClient.post.updatePostContent({
|
refactor: method parameters of api client (halo-dev/console#605)
<!-- Thanks for sending a pull request! Here are some tips for you:
1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。
1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>.
2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request.
3. 请确保你已经添加并运行了适当的测试。
3. Ensure you have added or ran the appropriate tests for your PR.
-->
#### What type of PR is this?
/kind improvement
/milestone 2.0
<!--
添加其中一个类别:
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind optimization
适当添加其中一个或多个类别(可选):
Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->
#### What this PR does / why we need it:
修改 api-client 的请求参数结构,改为所有参数由一个对象包裹,而不是将各个参数作为方法的参数,防止因为后端参数结构发生改变,或者生成 api-client 时参数顺序发生改变导致请求异常。如:
```diff
await apiClient.extension.storage.group.updatestorageHaloRunV1alpha1Group(
- formState.value.metadata.name,
- formState.value
+ {
+ name: formState.value.metadata.name,
+ group: formState.value,
+ }
);
```
#### Which issue(s) this PR fixes:
<!--
PR 合并时自动关闭 issue。
Automatically closes linked issue when PR is merged.
用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)`
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
None
#### Screenshots:
<!--
如果此 PR 有 UI 的改动,最好截图说明这个 PR 的改动。
If there are UI changes to this PR, it is best to take a screenshot to illustrate the changes to this PR.
eg.
Before:

After:

-->
None
#### Special notes for your reviewer:
/cc @halo-dev/sig-halo-admin
#### Does this PR introduce a user-facing change?
<!--
如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。
否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change),
Release Note 需要以 `action required` 开头。
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
None
```
2022-09-06 02:26:11 +00:00
|
|
|
name: formState.value.post.metadata.name,
|
2022-11-18 13:16:23 +00:00
|
|
|
content: formState.value.content,
|
refactor: method parameters of api client (halo-dev/console#605)
<!-- Thanks for sending a pull request! Here are some tips for you:
1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。
1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>.
2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request.
3. 请确保你已经添加并运行了适当的测试。
3. Ensure you have added or ran the appropriate tests for your PR.
-->
#### What type of PR is this?
/kind improvement
/milestone 2.0
<!--
添加其中一个类别:
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind optimization
适当添加其中一个或多个类别(可选):
Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->
#### What this PR does / why we need it:
修改 api-client 的请求参数结构,改为所有参数由一个对象包裹,而不是将各个参数作为方法的参数,防止因为后端参数结构发生改变,或者生成 api-client 时参数顺序发生改变导致请求异常。如:
```diff
await apiClient.extension.storage.group.updatestorageHaloRunV1alpha1Group(
- formState.value.metadata.name,
- formState.value
+ {
+ name: formState.value.metadata.name,
+ group: formState.value,
+ }
);
```
#### Which issue(s) this PR fixes:
<!--
PR 合并时自动关闭 issue。
Automatically closes linked issue when PR is merged.
用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)`
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
None
#### Screenshots:
<!--
如果此 PR 有 UI 的改动,最好截图说明这个 PR 的改动。
If there are UI changes to this PR, it is best to take a screenshot to illustrate the changes to this PR.
eg.
Before:

After:

-->
None
#### Special notes for your reviewer:
/cc @halo-dev/sig-halo-admin
#### Does this PR introduce a user-facing change?
<!--
如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。
否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change),
Release Note 需要以 `action required` 开头。
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
None
```
2022-09-06 02:26:11 +00:00
|
|
|
});
|
2022-11-10 16:24:10 +00:00
|
|
|
|
2022-08-23 04:08:10 +00:00
|
|
|
formState.value.post = data;
|
2024-03-18 04:38:07 +00:00
|
|
|
|
|
|
|
isTitleChanged.value = false;
|
2022-08-23 04:08:10 +00:00
|
|
|
} else {
|
2023-08-25 16:18:16 +00:00
|
|
|
// Clear new post content cache
|
|
|
|
handleClearCache();
|
2024-03-18 04:38:07 +00:00
|
|
|
|
refactor: method parameters of api client (halo-dev/console#605)
<!-- Thanks for sending a pull request! Here are some tips for you:
1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。
1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>.
2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request.
3. 请确保你已经添加并运行了适当的测试。
3. Ensure you have added or ran the appropriate tests for your PR.
-->
#### What type of PR is this?
/kind improvement
/milestone 2.0
<!--
添加其中一个类别:
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind optimization
适当添加其中一个或多个类别(可选):
Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->
#### What this PR does / why we need it:
修改 api-client 的请求参数结构,改为所有参数由一个对象包裹,而不是将各个参数作为方法的参数,防止因为后端参数结构发生改变,或者生成 api-client 时参数顺序发生改变导致请求异常。如:
```diff
await apiClient.extension.storage.group.updatestorageHaloRunV1alpha1Group(
- formState.value.metadata.name,
- formState.value
+ {
+ name: formState.value.metadata.name,
+ group: formState.value,
+ }
);
```
#### Which issue(s) this PR fixes:
<!--
PR 合并时自动关闭 issue。
Automatically closes linked issue when PR is merged.
用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)`
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
None
#### Screenshots:
<!--
如果此 PR 有 UI 的改动,最好截图说明这个 PR 的改动。
If there are UI changes to this PR, it is best to take a screenshot to illustrate the changes to this PR.
eg.
Before:

After:

-->
None
#### Special notes for your reviewer:
/cc @halo-dev/sig-halo-admin
#### Does this PR introduce a user-facing change?
<!--
如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。
否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change),
Release Note 需要以 `action required` 开头。
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
None
```
2022-09-06 02:26:11 +00:00
|
|
|
const { data } = await apiClient.post.draftPost({
|
|
|
|
postRequest: formState.value,
|
|
|
|
});
|
2022-08-23 04:08:10 +00:00
|
|
|
formState.value.post = data;
|
|
|
|
name.value = data.metadata.name;
|
|
|
|
}
|
2022-08-23 09:10:00 +00:00
|
|
|
|
2023-05-25 14:54:18 +00:00
|
|
|
if (!options?.mute) {
|
|
|
|
Toast.success(t("core.common.toast.save_success"));
|
|
|
|
}
|
2023-08-25 16:18:16 +00:00
|
|
|
handleClearCache(formState.value.post.metadata.name as string);
|
2022-08-23 09:10:00 +00:00
|
|
|
await handleFetchContent();
|
2023-08-25 16:18:16 +00:00
|
|
|
await handleFetchSnapshot();
|
2022-08-23 04:08:10 +00:00
|
|
|
} catch (e) {
|
|
|
|
console.error("Failed to save post", e);
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.error(t("core.common.toast.save_failed_and_retry"));
|
2022-08-23 04:08:10 +00:00
|
|
|
} finally {
|
|
|
|
saving.value = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-11-21 07:14:28 +00:00
|
|
|
const returnToView = useRouteQuery<string>("returnToView");
|
|
|
|
|
2022-11-10 16:24:10 +00:00
|
|
|
const handlePublish = async () => {
|
|
|
|
try {
|
|
|
|
publishing.value = true;
|
|
|
|
|
|
|
|
if (isUpdateMode.value) {
|
|
|
|
const { name: postName } = formState.value.post.metadata;
|
2022-11-21 07:14:28 +00:00
|
|
|
const { permalink } = formState.value.post.status || {};
|
2022-11-18 13:16:23 +00:00
|
|
|
|
2024-03-18 04:38:07 +00:00
|
|
|
if (isTitleChanged.value) {
|
|
|
|
formState.value.post = (
|
|
|
|
await postUpdateMutate(formState.value.post)
|
|
|
|
).data;
|
|
|
|
}
|
|
|
|
|
2022-11-18 13:16:23 +00:00
|
|
|
await apiClient.post.updatePostContent({
|
|
|
|
name: postName,
|
|
|
|
content: formState.value.content,
|
|
|
|
});
|
2022-11-10 16:24:10 +00:00
|
|
|
|
2022-11-11 16:10:12 +00:00
|
|
|
await apiClient.post.publishPost({
|
2022-11-10 16:24:10 +00:00
|
|
|
name: postName,
|
|
|
|
});
|
2022-11-21 07:14:28 +00:00
|
|
|
|
|
|
|
if (returnToView.value === "true" && permalink) {
|
|
|
|
window.location.href = permalink;
|
|
|
|
} else {
|
2023-07-19 11:46:17 +00:00
|
|
|
router.back();
|
2022-11-21 07:14:28 +00:00
|
|
|
}
|
2022-11-10 16:24:10 +00:00
|
|
|
} else {
|
2022-11-11 16:10:12 +00:00
|
|
|
const { data } = await apiClient.post.draftPost({
|
2022-11-10 16:24:10 +00:00
|
|
|
postRequest: formState.value,
|
|
|
|
});
|
2022-11-11 16:10:12 +00:00
|
|
|
|
|
|
|
await apiClient.post.publishPost({
|
|
|
|
name: data.metadata.name,
|
|
|
|
});
|
2022-11-24 14:59:06 +00:00
|
|
|
|
2023-07-28 03:09:09 +00:00
|
|
|
// Clear new post content cache
|
|
|
|
handleClearCache();
|
|
|
|
|
2022-11-24 14:59:06 +00:00
|
|
|
router.push({ name: "Posts" });
|
2022-11-10 16:24:10 +00:00
|
|
|
}
|
|
|
|
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.success(t("core.common.toast.publish_success"), {
|
|
|
|
duration: 2000,
|
|
|
|
});
|
2022-11-30 07:21:47 +00:00
|
|
|
handleClearCache(name.value as string);
|
2022-11-10 16:24:10 +00:00
|
|
|
} catch (error) {
|
|
|
|
console.error("Failed to publish post", error);
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.error(t("core.common.toast.publish_failed_and_retry"));
|
2022-11-10 16:24:10 +00:00
|
|
|
} finally {
|
|
|
|
publishing.value = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const handlePublishClick = () => {
|
|
|
|
if (isUpdateMode.value) {
|
|
|
|
handlePublish();
|
|
|
|
} else {
|
2024-03-18 04:38:07 +00:00
|
|
|
// Set editor title to post
|
2022-11-10 16:24:10 +00:00
|
|
|
settingModal.value = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-08-23 09:10:00 +00:00
|
|
|
const handleFetchContent = async () => {
|
|
|
|
if (!formState.value.post.spec.headSnapshot) {
|
|
|
|
return;
|
|
|
|
}
|
2022-11-10 16:24:10 +00:00
|
|
|
|
2023-01-31 02:52:09 +00:00
|
|
|
const { data } = await apiClient.post.fetchPostHeadContent({
|
|
|
|
name: formState.value.post.metadata.name,
|
refactor: method parameters of api client (halo-dev/console#605)
<!-- Thanks for sending a pull request! Here are some tips for you:
1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。
1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>.
2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request.
3. 请确保你已经添加并运行了适当的测试。
3. Ensure you have added or ran the appropriate tests for your PR.
-->
#### What type of PR is this?
/kind improvement
/milestone 2.0
<!--
添加其中一个类别:
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind optimization
适当添加其中一个或多个类别(可选):
Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->
#### What this PR does / why we need it:
修改 api-client 的请求参数结构,改为所有参数由一个对象包裹,而不是将各个参数作为方法的参数,防止因为后端参数结构发生改变,或者生成 api-client 时参数顺序发生改变导致请求异常。如:
```diff
await apiClient.extension.storage.group.updatestorageHaloRunV1alpha1Group(
- formState.value.metadata.name,
- formState.value
+ {
+ name: formState.value.metadata.name,
+ group: formState.value,
+ }
);
```
#### Which issue(s) this PR fixes:
<!--
PR 合并时自动关闭 issue。
Automatically closes linked issue when PR is merged.
用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)`
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
None
#### Screenshots:
<!--
如果此 PR 有 UI 的改动,最好截图说明这个 PR 的改动。
If there are UI changes to this PR, it is best to take a screenshot to illustrate the changes to this PR.
eg.
Before:

After:

-->
None
#### Special notes for your reviewer:
/cc @halo-dev/sig-halo-admin
#### Does this PR introduce a user-facing change?
<!--
如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。
否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change),
Release Note 需要以 `action required` 开头。
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
None
```
2022-09-06 02:26:11 +00:00
|
|
|
});
|
2022-08-23 09:10:00 +00:00
|
|
|
|
2023-03-08 02:50:11 +00:00
|
|
|
formState.value.content = Object.assign(formState.value.content, data);
|
|
|
|
|
2022-12-22 04:14:29 +00:00
|
|
|
// get editor provider
|
|
|
|
if (!currentEditorProvider.value) {
|
|
|
|
const preferredEditor = editorProviders.value.find(
|
|
|
|
(provider) =>
|
|
|
|
provider.name ===
|
|
|
|
formState.value.post.metadata.annotations?.[
|
2023-07-18 08:16:02 +00:00
|
|
|
contentAnnotations.PREFERRED_EDITOR
|
2022-12-22 04:14:29 +00:00
|
|
|
]
|
|
|
|
);
|
|
|
|
|
|
|
|
const provider =
|
|
|
|
preferredEditor ||
|
|
|
|
editorProviders.value.find(
|
|
|
|
(provider) => provider.rawType === data.rawType
|
|
|
|
);
|
|
|
|
|
|
|
|
if (provider) {
|
|
|
|
currentEditorProvider.value = provider;
|
|
|
|
|
|
|
|
formState.value.post.metadata.annotations = {
|
|
|
|
...formState.value.post.metadata.annotations,
|
2023-07-18 08:16:02 +00:00
|
|
|
[contentAnnotations.PREFERRED_EDITOR]: provider.name,
|
2022-12-22 04:14:29 +00:00
|
|
|
};
|
2022-12-29 13:42:34 +00:00
|
|
|
|
2023-07-18 08:16:02 +00:00
|
|
|
const { data } = await postUpdateMutate(formState.value.post);
|
2022-12-29 13:42:34 +00:00
|
|
|
|
|
|
|
formState.value.post = data;
|
2022-12-22 04:14:29 +00:00
|
|
|
} else {
|
|
|
|
Dialog.warning({
|
2023-03-23 08:54:33 +00:00
|
|
|
title: t("core.common.dialog.titles.warning"),
|
|
|
|
description: t("core.common.dialog.descriptions.editor_not_found", {
|
|
|
|
raw_type: data.rawType,
|
|
|
|
}),
|
|
|
|
confirmText: t("core.common.buttons.confirm"),
|
2023-07-26 06:42:19 +00:00
|
|
|
showCancel: false,
|
2022-12-22 04:14:29 +00:00
|
|
|
onConfirm: () => {
|
|
|
|
router.back();
|
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
}
|
2022-08-23 09:10:00 +00:00
|
|
|
};
|
|
|
|
|
2022-11-10 16:24:10 +00:00
|
|
|
const handleOpenSettingModal = async () => {
|
|
|
|
const { data: latestPost } =
|
|
|
|
await apiClient.extension.post.getcontentHaloRunV1alpha1Post({
|
|
|
|
name: formState.value.post.metadata.name,
|
|
|
|
});
|
|
|
|
formState.value.post = latestPost;
|
|
|
|
settingModal.value = true;
|
|
|
|
};
|
|
|
|
|
2022-12-29 13:46:34 +00:00
|
|
|
// Post settings
|
2022-11-10 16:24:10 +00:00
|
|
|
const onSettingSaved = (post: Post) => {
|
2022-08-23 09:10:00 +00:00
|
|
|
// Set route query parameter
|
|
|
|
if (!isUpdateMode.value) {
|
2022-11-10 16:24:10 +00:00
|
|
|
name.value = post.metadata.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
formState.value.post = post;
|
|
|
|
settingModal.value = false;
|
|
|
|
|
|
|
|
if (!isUpdateMode.value) {
|
|
|
|
handleSave();
|
2022-08-23 09:10:00 +00:00
|
|
|
}
|
2022-11-10 16:24:10 +00:00
|
|
|
};
|
2022-08-23 09:10:00 +00:00
|
|
|
|
2022-11-10 16:24:10 +00:00
|
|
|
const onSettingPublished = (post: Post) => {
|
|
|
|
formState.value.post = post;
|
2022-08-23 04:08:10 +00:00
|
|
|
settingModal.value = false;
|
2022-11-10 16:24:10 +00:00
|
|
|
handlePublish();
|
2022-08-23 04:08:10 +00:00
|
|
|
};
|
|
|
|
|
2022-08-23 09:10:00 +00:00
|
|
|
// Get post data when the route contains the name parameter
|
2023-03-23 13:52:36 +00:00
|
|
|
const name = useRouteQuery<string>("name");
|
2022-08-23 04:08:10 +00:00
|
|
|
onMounted(async () => {
|
|
|
|
if (name.value) {
|
|
|
|
// fetch post
|
|
|
|
const { data: post } =
|
refactor: method parameters of api client (halo-dev/console#605)
<!-- Thanks for sending a pull request! Here are some tips for you:
1. 如果这是你的第一次,请阅读我们的贡献指南:<https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>。
1. If this is your first time, please read our contributor guidelines: <https://github.com/halo-dev/halo/blob/master/CONTRIBUTING.md>.
2. 请根据你解决问题的类型为 Pull Request 添加合适的标签。
2. Please label this pull request according to what type of issue you are addressing, especially if this is a release targeted pull request.
3. 请确保你已经添加并运行了适当的测试。
3. Ensure you have added or ran the appropriate tests for your PR.
-->
#### What type of PR is this?
/kind improvement
/milestone 2.0
<!--
添加其中一个类别:
Add one of the following kinds:
/kind bug
/kind cleanup
/kind documentation
/kind feature
/kind optimization
适当添加其中一个或多个类别(可选):
Optionally add one or more of the following kinds if applicable:
/kind api-change
/kind deprecation
/kind failing-test
/kind flake
/kind regression
-->
#### What this PR does / why we need it:
修改 api-client 的请求参数结构,改为所有参数由一个对象包裹,而不是将各个参数作为方法的参数,防止因为后端参数结构发生改变,或者生成 api-client 时参数顺序发生改变导致请求异常。如:
```diff
await apiClient.extension.storage.group.updatestorageHaloRunV1alpha1Group(
- formState.value.metadata.name,
- formState.value
+ {
+ name: formState.value.metadata.name,
+ group: formState.value,
+ }
);
```
#### Which issue(s) this PR fixes:
<!--
PR 合并时自动关闭 issue。
Automatically closes linked issue when PR is merged.
用法:`Fixes #<issue 号>`,或者 `Fixes (粘贴 issue 完整链接)`
Usage: `Fixes #<issue number>`, or `Fixes (paste link of issue)`.
-->
None
#### Screenshots:
<!--
如果此 PR 有 UI 的改动,最好截图说明这个 PR 的改动。
If there are UI changes to this PR, it is best to take a screenshot to illustrate the changes to this PR.
eg.
Before:

After:

-->
None
#### Special notes for your reviewer:
/cc @halo-dev/sig-halo-admin
#### Does this PR introduce a user-facing change?
<!--
如果当前 Pull Request 的修改不会造成用户侧的任何变更,在 `release-note` 代码块儿中填写 `NONE`。
否则请填写用户侧能够理解的 Release Note。如果当前 Pull Request 包含破坏性更新(Break Change),
Release Note 需要以 `action required` 开头。
If no, just write "NONE" in the release-note block below.
If yes, a release note is required:
Enter your extended release note in the block below. If the PR requires additional action from users switching to the new release, include the string "action required".
-->
```release-note
None
```
2022-09-06 02:26:11 +00:00
|
|
|
await apiClient.extension.post.getcontentHaloRunV1alpha1Post({
|
|
|
|
name: name.value as string,
|
|
|
|
});
|
2022-08-23 04:08:10 +00:00
|
|
|
formState.value.post = post;
|
|
|
|
|
2022-08-23 09:10:00 +00:00
|
|
|
// fetch post content
|
|
|
|
await handleFetchContent();
|
2022-12-22 04:14:29 +00:00
|
|
|
} else {
|
|
|
|
// Set default editor
|
|
|
|
const provider =
|
|
|
|
editorProviders.value.find(
|
2022-12-29 13:46:34 +00:00
|
|
|
(provider) => provider.name === storedEditorProviderName.value
|
2022-12-22 04:14:29 +00:00
|
|
|
) || editorProviders.value[0];
|
|
|
|
|
|
|
|
if (provider) {
|
|
|
|
currentEditorProvider.value = provider;
|
|
|
|
formState.value.content.rawType = provider.rawType;
|
|
|
|
}
|
|
|
|
|
|
|
|
formState.value.post.metadata.annotations = {
|
2023-07-18 08:16:02 +00:00
|
|
|
[contentAnnotations.PREFERRED_EDITOR]: provider.name,
|
2022-12-22 04:14:29 +00:00
|
|
|
};
|
2022-08-23 04:08:10 +00:00
|
|
|
}
|
2022-11-30 07:21:47 +00:00
|
|
|
handleResetCache();
|
2022-08-23 04:08:10 +00:00
|
|
|
});
|
2022-11-30 07:21:47 +00:00
|
|
|
|
2023-08-25 16:18:16 +00:00
|
|
|
const headSnapshot = computed(() => {
|
|
|
|
return formState.value.post.spec.headSnapshot;
|
|
|
|
});
|
|
|
|
|
|
|
|
const { version, handleFetchSnapshot } = useContentSnapshot(headSnapshot);
|
|
|
|
|
2022-12-29 13:46:34 +00:00
|
|
|
// Post content cache
|
2023-08-25 16:18:16 +00:00
|
|
|
const {
|
|
|
|
currentCache,
|
|
|
|
handleSetContentCache,
|
|
|
|
handleResetCache,
|
|
|
|
handleClearCache,
|
|
|
|
} = useContentCache(
|
|
|
|
"post-content-cache",
|
|
|
|
name,
|
|
|
|
toRef(formState.value.content, "raw"),
|
|
|
|
version
|
|
|
|
);
|
|
|
|
|
|
|
|
useAutoSaveContent(currentCache, toRef(formState.value.content, "raw"), () => {
|
2023-09-07 07:20:10 +00:00
|
|
|
// Do not save when the setting modal is open
|
|
|
|
if (settingModal.value) {
|
|
|
|
return;
|
|
|
|
}
|
2023-08-25 16:18:16 +00:00
|
|
|
handleSave({ mute: true });
|
|
|
|
});
|
2023-05-25 14:54:18 +00:00
|
|
|
|
|
|
|
// Post preview
|
|
|
|
const previewModal = ref(false);
|
|
|
|
const previewPending = ref(false);
|
|
|
|
|
|
|
|
const handlePreview = async () => {
|
|
|
|
previewPending.value = true;
|
|
|
|
await handleSave({ mute: true });
|
|
|
|
previewModal.value = true;
|
|
|
|
previewPending.value = false;
|
|
|
|
};
|
2023-09-01 02:30:12 +00:00
|
|
|
|
|
|
|
useSaveKeybinding(handleSave);
|
2023-11-30 03:55:29 +00:00
|
|
|
|
2023-11-30 04:10:08 +00:00
|
|
|
// Keep session alive
|
|
|
|
useSessionKeepAlive();
|
|
|
|
|
2023-11-30 03:55:29 +00:00
|
|
|
// Upload image
|
2024-01-19 09:39:06 +00:00
|
|
|
async function handleUploadImage(file: File, options?: AxiosRequestConfig) {
|
2023-12-01 02:14:09 +00:00
|
|
|
if (!currentUserHasPermission(["uc:attachments:manage"])) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-11-30 03:55:29 +00:00
|
|
|
if (!isUpdateMode.value) {
|
|
|
|
await handleSave();
|
|
|
|
}
|
|
|
|
|
2024-01-19 09:39:06 +00:00
|
|
|
const { data } = await apiClient.uc.attachment.createAttachmentForPost(
|
|
|
|
{
|
|
|
|
file,
|
|
|
|
postName: formState.value.post.metadata.name,
|
|
|
|
waitForPermalink: true,
|
|
|
|
},
|
|
|
|
options
|
|
|
|
);
|
2023-11-30 03:55:29 +00:00
|
|
|
return data;
|
|
|
|
}
|
2022-05-23 07:16:23 +00:00
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2022-08-23 04:08:10 +00:00
|
|
|
<PostSettingModal
|
|
|
|
v-model:visible="settingModal"
|
2022-11-10 16:24:10 +00:00
|
|
|
:post="formState.post"
|
|
|
|
:publish-support="!isUpdateMode"
|
|
|
|
:only-emit="!isUpdateMode"
|
2022-08-23 04:08:10 +00:00
|
|
|
@saved="onSettingSaved"
|
2022-11-10 16:24:10 +00:00
|
|
|
@published="onSettingPublished"
|
2022-08-23 04:08:10 +00:00
|
|
|
/>
|
2023-05-25 14:54:18 +00:00
|
|
|
|
|
|
|
<UrlPreviewModal
|
|
|
|
v-if="isUpdateMode"
|
|
|
|
v-model:visible="previewModal"
|
|
|
|
:title="formState.post.spec.title"
|
|
|
|
:url="`/preview/posts/${formState.post.metadata.name}`"
|
|
|
|
/>
|
|
|
|
|
2023-03-23 08:54:33 +00:00
|
|
|
<VPageHeader :title="$t('core.post.title')">
|
2022-05-23 07:16:23 +00:00
|
|
|
<template #icon>
|
2022-05-29 15:55:06 +00:00
|
|
|
<IconBookRead class="mr-2 self-center" />
|
2022-05-23 07:16:23 +00:00
|
|
|
</template>
|
|
|
|
<template #actions>
|
2022-08-23 04:08:10 +00:00
|
|
|
<VSpace>
|
2022-12-29 13:46:34 +00:00
|
|
|
<EditorProviderSelector
|
2023-07-18 08:16:02 +00:00
|
|
|
v-if="editorProviders.length > 1"
|
2022-12-29 13:46:34 +00:00
|
|
|
:provider="currentEditorProvider"
|
2023-07-18 08:16:02 +00:00
|
|
|
:allow-forced-select="!isUpdateMode"
|
2022-12-29 13:46:34 +00:00
|
|
|
@select="handleChangeEditorProvider"
|
|
|
|
/>
|
2023-05-25 14:54:18 +00:00
|
|
|
<VButton
|
|
|
|
size="sm"
|
|
|
|
type="default"
|
|
|
|
:loading="previewPending"
|
|
|
|
@click="handlePreview"
|
|
|
|
>
|
|
|
|
<template #icon>
|
|
|
|
<IconEye class="h-full w-full" />
|
|
|
|
</template>
|
|
|
|
{{ $t("core.common.buttons.preview") }}
|
|
|
|
</VButton>
|
2022-08-23 09:10:00 +00:00
|
|
|
<VButton :loading="saving" size="sm" type="default" @click="handleSave">
|
2022-11-10 16:24:10 +00:00
|
|
|
<template #icon>
|
|
|
|
<IconSave class="h-full w-full" />
|
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.buttons.save") }}
|
2022-08-23 04:08:10 +00:00
|
|
|
</VButton>
|
2022-11-10 16:24:10 +00:00
|
|
|
<VButton
|
|
|
|
v-if="isUpdateMode"
|
|
|
|
size="sm"
|
|
|
|
type="default"
|
|
|
|
@click="handleOpenSettingModal"
|
|
|
|
>
|
|
|
|
<template #icon>
|
|
|
|
<IconSettings class="h-full w-full" />
|
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.buttons.setting") }}
|
2022-11-10 16:24:10 +00:00
|
|
|
</VButton>
|
|
|
|
<VButton
|
|
|
|
type="secondary"
|
|
|
|
:loading="publishing"
|
|
|
|
@click="handlePublishClick"
|
|
|
|
>
|
2022-08-23 04:08:10 +00:00
|
|
|
<template #icon>
|
2022-11-10 16:24:10 +00:00
|
|
|
<IconSendPlaneFill class="h-full w-full" />
|
2022-08-23 04:08:10 +00:00
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.buttons.publish") }}
|
2022-08-23 04:08:10 +00:00
|
|
|
</VButton>
|
|
|
|
</VSpace>
|
2022-05-23 07:16:23 +00:00
|
|
|
</template>
|
|
|
|
</VPageHeader>
|
2022-08-24 03:26:32 +00:00
|
|
|
<div class="editor border-t" style="height: calc(100vh - 3.5rem)">
|
2022-12-22 04:14:29 +00:00
|
|
|
<component
|
|
|
|
:is="currentEditorProvider.component"
|
|
|
|
v-if="currentEditorProvider"
|
|
|
|
v-model:raw="formState.content.raw"
|
|
|
|
v-model:content="formState.content.content"
|
2024-03-18 04:38:07 +00:00
|
|
|
v-model:title="formState.post.spec.title"
|
2023-11-30 03:55:29 +00:00
|
|
|
:upload-image="handleUploadImage"
|
2022-12-22 04:14:29 +00:00
|
|
|
class="h-full"
|
2022-11-30 07:21:47 +00:00
|
|
|
@update="handleSetContentCache"
|
2022-11-10 06:50:09 +00:00
|
|
|
/>
|
2022-05-23 07:16:23 +00:00
|
|
|
</div>
|
|
|
|
</template>
|