2022-09-19 09:26:50 +00:00
|
|
|
<script lang="ts" setup>
|
|
|
|
import {
|
2022-10-18 01:58:09 +00:00
|
|
|
Dialog,
|
2024-05-23 02:56:50 +00:00
|
|
|
IconAddCircle,
|
|
|
|
IconExternalLinkLine,
|
|
|
|
Toast,
|
2022-09-19 09:26:50 +00:00
|
|
|
VAvatar,
|
|
|
|
VButton,
|
2024-05-23 02:56:50 +00:00
|
|
|
VDropdownItem,
|
|
|
|
VEmpty,
|
2022-09-19 09:26:50 +00:00
|
|
|
VEntity,
|
|
|
|
VEntityField,
|
2022-11-24 14:51:07 +00:00
|
|
|
VLoading,
|
2024-05-23 02:56:50 +00:00
|
|
|
VSpace,
|
|
|
|
VStatusDot,
|
2023-03-23 14:04:34 +00:00
|
|
|
VTag,
|
2022-09-19 09:26:50 +00:00
|
|
|
} from "@halo-dev/components";
|
|
|
|
import ReplyCreationModal from "./ReplyCreationModal.vue";
|
|
|
|
import type {
|
|
|
|
Extension,
|
|
|
|
ListedComment,
|
|
|
|
ListedReply,
|
|
|
|
Post,
|
|
|
|
SinglePage,
|
|
|
|
} from "@halo-dev/api-client";
|
|
|
|
import { formatDatetime } from "@/utils/date";
|
2024-05-23 02:56:50 +00:00
|
|
|
import { computed, onMounted, provide, ref, type Ref } from "vue";
|
2022-09-19 09:26:50 +00:00
|
|
|
import ReplyListItem from "./ReplyListItem.vue";
|
2022-09-22 08:46:32 +00:00
|
|
|
import { apiClient } from "@/utils/api-client";
|
2023-12-28 09:13:38 +00:00
|
|
|
import { cloneDeep } from "lodash-es";
|
2022-09-30 09:48:19 +00:00
|
|
|
import { usePermission } from "@/utils/permission";
|
2023-07-28 02:35:09 +00:00
|
|
|
import { useQuery, useQueryClient } from "@tanstack/vue-query";
|
2023-03-23 08:54:33 +00:00
|
|
|
import { useI18n } from "vue-i18n";
|
2023-08-25 07:28:11 +00:00
|
|
|
import { usePluginModuleStore } from "@/stores/plugin";
|
feat: make comment subject ref provider extensible (#4039)
#### What type of PR is this?
/area console
/kind feature
#### What this PR does / why we need it:
让评论来源的显示支持通过插件扩展,目前如 [瞬间](https://github.com/halo-sigs/plugin-moments) 这类的插件如果使用了评论模块,那么在评论管理是无法显示具体来源的:
<img width="627" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/0df354dc-ed42-4217-abbd-5bce67329e0d">
此 PR 为 Console 端提供了拓展方法,使用方式如下:
```ts
import { definePlugin } from "@halo-dev/console-shared";
import type { CommentSubjectRefResult } from "@halo-dev/console-shared";
import type { Extension } from "@halo-dev/api-client";
import type { Moment } from "./types";
export default definePlugin({
components: {},
extensionPoints: {
"comment:subject-ref:create": () => {
return [
{
kind: "Moment",
group: "moment.halo.run",
resolve: (subject: Extension): CommentSubjectRefResult => {
const moment = subject as Moment;
return {
label: "瞬间",
title: determineMomentTitle(moment),
externalUrl: `/moments/${moment.metadata.name}`,
route: {
name: "Moments",
},
};
},
},
];
},
},
});
```
#### Which issue(s) this PR fixes:
Fixes #3554
#### Special notes for your reviewer:
#### Does this PR introduce a user-facing change?
```release-note
Console 端的评论来源显示支持通过插件扩展
```
2023-06-26 04:20:18 +00:00
|
|
|
import type {
|
|
|
|
CommentSubjectRefProvider,
|
|
|
|
CommentSubjectRefResult,
|
2024-05-23 02:56:50 +00:00
|
|
|
PluginModule,
|
2023-09-01 03:02:12 +00:00
|
|
|
} from "@halo-dev/console-shared";
|
2022-09-30 09:48:19 +00:00
|
|
|
|
|
|
|
const { currentUserHasPermission } = usePermission();
|
2023-03-23 08:54:33 +00:00
|
|
|
const { t } = useI18n();
|
2023-07-28 02:35:09 +00:00
|
|
|
const queryClient = useQueryClient();
|
2022-09-19 09:26:50 +00:00
|
|
|
|
|
|
|
const props = withDefaults(
|
|
|
|
defineProps<{
|
2022-11-17 02:38:22 +00:00
|
|
|
comment: ListedComment;
|
2022-09-19 09:26:50 +00:00
|
|
|
isSelected?: boolean;
|
|
|
|
}>(),
|
|
|
|
{
|
|
|
|
isSelected: false,
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
const hoveredReply = ref<ListedReply>();
|
|
|
|
const showReplies = ref(false);
|
|
|
|
const replyModal = ref(false);
|
|
|
|
|
|
|
|
provide<Ref<ListedReply | undefined>>("hoveredReply", hoveredReply);
|
|
|
|
|
|
|
|
const handleDelete = async () => {
|
2022-10-18 01:58:09 +00:00
|
|
|
Dialog.warning({
|
2023-03-23 08:54:33 +00:00
|
|
|
title: t("core.comment.operations.delete_comment.title"),
|
|
|
|
description: t("core.comment.operations.delete_comment.description"),
|
2022-09-19 09:26:50 +00:00
|
|
|
confirmType: "danger",
|
2023-03-23 08:54:33 +00:00
|
|
|
confirmText: t("core.common.buttons.confirm"),
|
|
|
|
cancelText: t("core.common.buttons.cancel"),
|
2022-09-19 09:26:50 +00:00
|
|
|
onConfirm: async () => {
|
|
|
|
try {
|
2024-05-24 04:04:50 +00:00
|
|
|
await apiClient.extension.comment.deleteContentHaloRunV1alpha1Comment({
|
2022-09-19 09:26:50 +00:00
|
|
|
name: props.comment?.comment?.metadata.name as string,
|
|
|
|
});
|
2022-12-20 11:04:29 +00:00
|
|
|
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.success(t("core.common.toast.delete_success"));
|
2022-09-19 09:26:50 +00:00
|
|
|
} catch (error) {
|
2023-02-17 06:36:15 +00:00
|
|
|
console.error("Failed to delete comment", error);
|
2022-09-19 09:26:50 +00:00
|
|
|
} finally {
|
2023-07-28 02:35:09 +00:00
|
|
|
queryClient.invalidateQueries({ queryKey: ["comments"] });
|
2022-09-19 09:26:50 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleApproveReplyInBatch = async () => {
|
2022-10-18 01:58:09 +00:00
|
|
|
Dialog.warning({
|
2023-03-23 08:54:33 +00:00
|
|
|
title: t("core.comment.operations.approve_applies_in_batch.title"),
|
|
|
|
confirmText: t("core.common.buttons.confirm"),
|
|
|
|
cancelText: t("core.common.buttons.cancel"),
|
2022-09-19 09:26:50 +00:00
|
|
|
onConfirm: async () => {
|
|
|
|
try {
|
2023-02-28 15:46:18 +00:00
|
|
|
const repliesToUpdate = replies.value?.filter((reply) => {
|
2022-09-19 09:26:50 +00:00
|
|
|
return !reply.reply.spec.approved;
|
|
|
|
});
|
2023-02-28 15:46:18 +00:00
|
|
|
const promises = repliesToUpdate?.map((reply) => {
|
2024-05-24 04:04:50 +00:00
|
|
|
return apiClient.extension.reply.updateContentHaloRunV1alpha1Reply({
|
2023-02-28 15:46:18 +00:00
|
|
|
name: reply.reply.metadata.name,
|
|
|
|
reply: {
|
|
|
|
...reply.reply,
|
|
|
|
spec: {
|
|
|
|
...reply.reply.spec,
|
|
|
|
approved: true,
|
|
|
|
// TODO: 暂时由前端设置发布时间。see https://github.com/halo-dev/halo/pull/2746
|
|
|
|
approvedTime: new Date().toISOString(),
|
|
|
|
},
|
|
|
|
},
|
2022-09-19 09:26:50 +00:00
|
|
|
});
|
|
|
|
});
|
2023-02-28 15:46:18 +00:00
|
|
|
await Promise.all(promises || []);
|
2022-12-20 11:04:29 +00:00
|
|
|
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.success(t("core.common.toast.operation_success"));
|
2022-09-19 09:26:50 +00:00
|
|
|
} catch (e) {
|
|
|
|
console.error("Failed to approve comment replies in batch", e);
|
|
|
|
} finally {
|
2023-02-28 15:46:18 +00:00
|
|
|
await refetch();
|
2022-09-19 09:26:50 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleApprove = async () => {
|
|
|
|
try {
|
|
|
|
const commentToUpdate = cloneDeep(props.comment.comment);
|
|
|
|
commentToUpdate.spec.approved = true;
|
2022-11-28 13:28:18 +00:00
|
|
|
// TODO: 暂时由前端设置发布时间。see https://github.com/halo-dev/halo/pull/2746
|
|
|
|
commentToUpdate.spec.approvedTime = new Date().toISOString();
|
2024-05-24 04:04:50 +00:00
|
|
|
await apiClient.extension.comment.updateContentHaloRunV1alpha1Comment({
|
2022-09-19 09:26:50 +00:00
|
|
|
name: commentToUpdate.metadata.name,
|
|
|
|
comment: commentToUpdate,
|
|
|
|
});
|
2022-12-20 11:04:29 +00:00
|
|
|
|
2023-03-23 08:54:33 +00:00
|
|
|
Toast.success(t("core.common.toast.operation_success"));
|
2022-09-19 09:26:50 +00:00
|
|
|
} catch (error) {
|
|
|
|
console.error("Failed to approve comment", error);
|
|
|
|
} finally {
|
2023-07-28 02:35:09 +00:00
|
|
|
queryClient.invalidateQueries({ queryKey: ["comments"] });
|
2022-09-19 09:26:50 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2023-02-28 15:46:18 +00:00
|
|
|
const {
|
|
|
|
data: replies,
|
|
|
|
isLoading,
|
|
|
|
refetch,
|
|
|
|
} = useQuery<ListedReply[]>({
|
|
|
|
queryKey: [
|
|
|
|
"comment-replies",
|
|
|
|
props.comment.comment.metadata.name,
|
|
|
|
showReplies,
|
|
|
|
],
|
|
|
|
queryFn: async () => {
|
2022-09-19 09:26:50 +00:00
|
|
|
const { data } = await apiClient.reply.listReplies({
|
|
|
|
commentName: props.comment.comment.metadata.name,
|
2022-11-24 14:51:07 +00:00
|
|
|
page: 0,
|
|
|
|
size: 0,
|
2022-09-19 09:26:50 +00:00
|
|
|
});
|
2023-02-28 15:46:18 +00:00
|
|
|
return data.items;
|
|
|
|
},
|
|
|
|
refetchInterval(data) {
|
|
|
|
const deletingReplies = data?.filter(
|
2022-10-24 14:10:10 +00:00
|
|
|
(reply) => !!reply.reply.metadata.deletionTimestamp
|
|
|
|
);
|
2023-07-19 03:44:12 +00:00
|
|
|
return deletingReplies?.length ? 1000 : false;
|
2023-02-28 15:46:18 +00:00
|
|
|
},
|
|
|
|
enabled: computed(() => showReplies.value),
|
2022-10-24 14:10:10 +00:00
|
|
|
});
|
|
|
|
|
2022-09-19 09:26:50 +00:00
|
|
|
const handleToggleShowReplies = async () => {
|
|
|
|
showReplies.value = !showReplies.value;
|
|
|
|
if (showReplies.value) {
|
|
|
|
// update last read time
|
2023-02-28 15:46:18 +00:00
|
|
|
if (props.comment.comment.status?.unreadReplyCount) {
|
|
|
|
const commentToUpdate = cloneDeep(props.comment.comment);
|
|
|
|
commentToUpdate.spec.lastReadTime = new Date().toISOString();
|
2024-05-24 04:04:50 +00:00
|
|
|
await apiClient.extension.comment.updateContentHaloRunV1alpha1Comment({
|
2023-02-28 15:46:18 +00:00
|
|
|
name: commentToUpdate.metadata.name,
|
|
|
|
comment: commentToUpdate,
|
|
|
|
});
|
|
|
|
}
|
2022-09-19 09:26:50 +00:00
|
|
|
} else {
|
2023-07-28 02:35:09 +00:00
|
|
|
queryClient.invalidateQueries({ queryKey: ["comments"] });
|
2022-09-19 09:26:50 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const onReplyCreationModalClose = () => {
|
2023-07-28 02:35:09 +00:00
|
|
|
queryClient.invalidateQueries({ queryKey: ["comments"] });
|
|
|
|
|
|
|
|
if (showReplies.value) {
|
|
|
|
refetch();
|
|
|
|
}
|
2024-05-23 02:56:50 +00:00
|
|
|
|
|
|
|
replyModal.value = false;
|
2022-09-19 09:26:50 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// Subject ref processing
|
feat: make comment subject ref provider extensible (#4039)
#### What type of PR is this?
/area console
/kind feature
#### What this PR does / why we need it:
让评论来源的显示支持通过插件扩展,目前如 [瞬间](https://github.com/halo-sigs/plugin-moments) 这类的插件如果使用了评论模块,那么在评论管理是无法显示具体来源的:
<img width="627" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/0df354dc-ed42-4217-abbd-5bce67329e0d">
此 PR 为 Console 端提供了拓展方法,使用方式如下:
```ts
import { definePlugin } from "@halo-dev/console-shared";
import type { CommentSubjectRefResult } from "@halo-dev/console-shared";
import type { Extension } from "@halo-dev/api-client";
import type { Moment } from "./types";
export default definePlugin({
components: {},
extensionPoints: {
"comment:subject-ref:create": () => {
return [
{
kind: "Moment",
group: "moment.halo.run",
resolve: (subject: Extension): CommentSubjectRefResult => {
const moment = subject as Moment;
return {
label: "瞬间",
title: determineMomentTitle(moment),
externalUrl: `/moments/${moment.metadata.name}`,
route: {
name: "Moments",
},
};
},
},
];
},
},
});
```
#### Which issue(s) this PR fixes:
Fixes #3554
#### Special notes for your reviewer:
#### Does this PR introduce a user-facing change?
```release-note
Console 端的评论来源显示支持通过插件扩展
```
2023-06-26 04:20:18 +00:00
|
|
|
const SubjectRefProviders = ref<CommentSubjectRefProvider[]>([
|
2022-09-19 09:26:50 +00:00
|
|
|
{
|
feat: make comment subject ref provider extensible (#4039)
#### What type of PR is this?
/area console
/kind feature
#### What this PR does / why we need it:
让评论来源的显示支持通过插件扩展,目前如 [瞬间](https://github.com/halo-sigs/plugin-moments) 这类的插件如果使用了评论模块,那么在评论管理是无法显示具体来源的:
<img width="627" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/0df354dc-ed42-4217-abbd-5bce67329e0d">
此 PR 为 Console 端提供了拓展方法,使用方式如下:
```ts
import { definePlugin } from "@halo-dev/console-shared";
import type { CommentSubjectRefResult } from "@halo-dev/console-shared";
import type { Extension } from "@halo-dev/api-client";
import type { Moment } from "./types";
export default definePlugin({
components: {},
extensionPoints: {
"comment:subject-ref:create": () => {
return [
{
kind: "Moment",
group: "moment.halo.run",
resolve: (subject: Extension): CommentSubjectRefResult => {
const moment = subject as Moment;
return {
label: "瞬间",
title: determineMomentTitle(moment),
externalUrl: `/moments/${moment.metadata.name}`,
route: {
name: "Moments",
},
};
},
},
];
},
},
});
```
#### Which issue(s) this PR fixes:
Fixes #3554
#### Special notes for your reviewer:
#### Does this PR introduce a user-facing change?
```release-note
Console 端的评论来源显示支持通过插件扩展
```
2023-06-26 04:20:18 +00:00
|
|
|
kind: "Post",
|
|
|
|
group: "content.halo.run",
|
|
|
|
resolve: (subject: Extension): CommentSubjectRefResult => {
|
2022-09-19 09:26:50 +00:00
|
|
|
const post = subject as Post;
|
|
|
|
return {
|
2023-03-23 08:54:33 +00:00
|
|
|
label: t("core.comment.subject_refs.post"),
|
2022-09-19 09:26:50 +00:00
|
|
|
title: post.spec.title,
|
|
|
|
externalUrl: post.status?.permalink,
|
|
|
|
route: {
|
|
|
|
name: "PostEditor",
|
|
|
|
query: {
|
|
|
|
name: post.metadata.name,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
feat: make comment subject ref provider extensible (#4039)
#### What type of PR is this?
/area console
/kind feature
#### What this PR does / why we need it:
让评论来源的显示支持通过插件扩展,目前如 [瞬间](https://github.com/halo-sigs/plugin-moments) 这类的插件如果使用了评论模块,那么在评论管理是无法显示具体来源的:
<img width="627" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/0df354dc-ed42-4217-abbd-5bce67329e0d">
此 PR 为 Console 端提供了拓展方法,使用方式如下:
```ts
import { definePlugin } from "@halo-dev/console-shared";
import type { CommentSubjectRefResult } from "@halo-dev/console-shared";
import type { Extension } from "@halo-dev/api-client";
import type { Moment } from "./types";
export default definePlugin({
components: {},
extensionPoints: {
"comment:subject-ref:create": () => {
return [
{
kind: "Moment",
group: "moment.halo.run",
resolve: (subject: Extension): CommentSubjectRefResult => {
const moment = subject as Moment;
return {
label: "瞬间",
title: determineMomentTitle(moment),
externalUrl: `/moments/${moment.metadata.name}`,
route: {
name: "Moments",
},
};
},
},
];
},
},
});
```
#### Which issue(s) this PR fixes:
Fixes #3554
#### Special notes for your reviewer:
#### Does this PR introduce a user-facing change?
```release-note
Console 端的评论来源显示支持通过插件扩展
```
2023-06-26 04:20:18 +00:00
|
|
|
kind: "SinglePage",
|
|
|
|
group: "content.halo.run",
|
|
|
|
resolve: (subject: Extension): CommentSubjectRefResult => {
|
2022-09-19 09:26:50 +00:00
|
|
|
const singlePage = subject as SinglePage;
|
|
|
|
return {
|
2023-03-23 08:54:33 +00:00
|
|
|
label: t("core.comment.subject_refs.page"),
|
2022-09-19 09:26:50 +00:00
|
|
|
title: singlePage.spec.title,
|
|
|
|
externalUrl: singlePage.status?.permalink,
|
|
|
|
route: {
|
|
|
|
name: "SinglePageEditor",
|
|
|
|
query: {
|
|
|
|
name: singlePage.metadata.name,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
},
|
|
|
|
},
|
|
|
|
]);
|
|
|
|
|
feat: make comment subject ref provider extensible (#4039)
#### What type of PR is this?
/area console
/kind feature
#### What this PR does / why we need it:
让评论来源的显示支持通过插件扩展,目前如 [瞬间](https://github.com/halo-sigs/plugin-moments) 这类的插件如果使用了评论模块,那么在评论管理是无法显示具体来源的:
<img width="627" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/0df354dc-ed42-4217-abbd-5bce67329e0d">
此 PR 为 Console 端提供了拓展方法,使用方式如下:
```ts
import { definePlugin } from "@halo-dev/console-shared";
import type { CommentSubjectRefResult } from "@halo-dev/console-shared";
import type { Extension } from "@halo-dev/api-client";
import type { Moment } from "./types";
export default definePlugin({
components: {},
extensionPoints: {
"comment:subject-ref:create": () => {
return [
{
kind: "Moment",
group: "moment.halo.run",
resolve: (subject: Extension): CommentSubjectRefResult => {
const moment = subject as Moment;
return {
label: "瞬间",
title: determineMomentTitle(moment),
externalUrl: `/moments/${moment.metadata.name}`,
route: {
name: "Moments",
},
};
},
},
];
},
},
});
```
#### Which issue(s) this PR fixes:
Fixes #3554
#### Special notes for your reviewer:
#### Does this PR introduce a user-facing change?
```release-note
Console 端的评论来源显示支持通过插件扩展
```
2023-06-26 04:20:18 +00:00
|
|
|
onMounted(() => {
|
|
|
|
const { pluginModules } = usePluginModuleStore();
|
|
|
|
|
|
|
|
pluginModules.forEach((pluginModule: PluginModule) => {
|
|
|
|
const { extensionPoints } = pluginModule;
|
|
|
|
if (!extensionPoints?.["comment:subject-ref:create"]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
const providers = extensionPoints[
|
|
|
|
"comment:subject-ref:create"
|
|
|
|
]() as CommentSubjectRefProvider[];
|
|
|
|
|
|
|
|
if (providers) {
|
|
|
|
providers.forEach((provider) => {
|
|
|
|
SubjectRefProviders.value.push(provider);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-09-19 09:26:50 +00:00
|
|
|
const subjectRefResult = computed(() => {
|
|
|
|
const { subject } = props.comment;
|
|
|
|
if (!subject) {
|
|
|
|
return {
|
2023-03-23 08:54:33 +00:00
|
|
|
label: t("core.comment.subject_refs.unknown"),
|
|
|
|
title: t("core.comment.subject_refs.unknown"),
|
2022-09-19 09:26:50 +00:00
|
|
|
};
|
|
|
|
}
|
feat: make comment subject ref provider extensible (#4039)
#### What type of PR is this?
/area console
/kind feature
#### What this PR does / why we need it:
让评论来源的显示支持通过插件扩展,目前如 [瞬间](https://github.com/halo-sigs/plugin-moments) 这类的插件如果使用了评论模块,那么在评论管理是无法显示具体来源的:
<img width="627" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/0df354dc-ed42-4217-abbd-5bce67329e0d">
此 PR 为 Console 端提供了拓展方法,使用方式如下:
```ts
import { definePlugin } from "@halo-dev/console-shared";
import type { CommentSubjectRefResult } from "@halo-dev/console-shared";
import type { Extension } from "@halo-dev/api-client";
import type { Moment } from "./types";
export default definePlugin({
components: {},
extensionPoints: {
"comment:subject-ref:create": () => {
return [
{
kind: "Moment",
group: "moment.halo.run",
resolve: (subject: Extension): CommentSubjectRefResult => {
const moment = subject as Moment;
return {
label: "瞬间",
title: determineMomentTitle(moment),
externalUrl: `/moments/${moment.metadata.name}`,
route: {
name: "Moments",
},
};
},
},
];
},
},
});
```
#### Which issue(s) this PR fixes:
Fixes #3554
#### Special notes for your reviewer:
#### Does this PR introduce a user-facing change?
```release-note
Console 端的评论来源显示支持通过插件扩展
```
2023-06-26 04:20:18 +00:00
|
|
|
const subjectRef = SubjectRefProviders.value.find(
|
|
|
|
(provider) =>
|
|
|
|
provider.kind === subject.kind &&
|
|
|
|
subject.apiVersion.startsWith(provider.group)
|
2022-09-19 09:26:50 +00:00
|
|
|
);
|
|
|
|
if (!subjectRef) {
|
|
|
|
return {
|
2023-03-23 08:54:33 +00:00
|
|
|
label: t("core.comment.subject_refs.unknown"),
|
|
|
|
title: t("core.comment.subject_refs.unknown"),
|
2022-09-19 09:26:50 +00:00
|
|
|
};
|
|
|
|
}
|
feat: make comment subject ref provider extensible (#4039)
#### What type of PR is this?
/area console
/kind feature
#### What this PR does / why we need it:
让评论来源的显示支持通过插件扩展,目前如 [瞬间](https://github.com/halo-sigs/plugin-moments) 这类的插件如果使用了评论模块,那么在评论管理是无法显示具体来源的:
<img width="627" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/0df354dc-ed42-4217-abbd-5bce67329e0d">
此 PR 为 Console 端提供了拓展方法,使用方式如下:
```ts
import { definePlugin } from "@halo-dev/console-shared";
import type { CommentSubjectRefResult } from "@halo-dev/console-shared";
import type { Extension } from "@halo-dev/api-client";
import type { Moment } from "./types";
export default definePlugin({
components: {},
extensionPoints: {
"comment:subject-ref:create": () => {
return [
{
kind: "Moment",
group: "moment.halo.run",
resolve: (subject: Extension): CommentSubjectRefResult => {
const moment = subject as Moment;
return {
label: "瞬间",
title: determineMomentTitle(moment),
externalUrl: `/moments/${moment.metadata.name}`,
route: {
name: "Moments",
},
};
},
},
];
},
},
});
```
#### Which issue(s) this PR fixes:
Fixes #3554
#### Special notes for your reviewer:
#### Does this PR introduce a user-facing change?
```release-note
Console 端的评论来源显示支持通过插件扩展
```
2023-06-26 04:20:18 +00:00
|
|
|
return subjectRef.resolve(subject);
|
2022-09-19 09:26:50 +00:00
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
|
|
|
<ReplyCreationModal
|
2024-05-23 02:56:50 +00:00
|
|
|
v-if="replyModal"
|
2022-09-19 09:26:50 +00:00
|
|
|
:comment="comment"
|
|
|
|
@close="onReplyCreationModalClose"
|
|
|
|
/>
|
|
|
|
<VEntity :is-selected="isSelected" :class="{ 'hover:bg-white': showReplies }">
|
|
|
|
<template v-if="showReplies" #prepend>
|
|
|
|
<div class="absolute inset-y-0 left-0 w-[1px] bg-black/50"></div>
|
|
|
|
<div class="absolute inset-y-0 right-0 w-[1px] bg-black/50"></div>
|
|
|
|
<div class="absolute inset-x-0 top-0 h-[1px] bg-black/50"></div>
|
|
|
|
<div class="absolute inset-x-0 bottom-0 h-[1px] bg-black/50"></div>
|
|
|
|
</template>
|
2022-09-30 09:48:19 +00:00
|
|
|
<template
|
2022-09-30 11:03:38 +00:00
|
|
|
v-if="currentUserHasPermission(['system:comments:manage'])"
|
2022-09-30 09:48:19 +00:00
|
|
|
#checkbox
|
|
|
|
>
|
2022-09-19 09:26:50 +00:00
|
|
|
<slot name="checkbox" />
|
|
|
|
</template>
|
|
|
|
<template #start>
|
|
|
|
<VEntityField>
|
|
|
|
<template #description>
|
2022-10-17 16:45:38 +00:00
|
|
|
<VAvatar
|
|
|
|
circle
|
|
|
|
:src="comment?.owner.avatar"
|
|
|
|
:alt="comment?.owner.displayName"
|
|
|
|
size="md"
|
|
|
|
></VAvatar>
|
2022-09-19 09:26:50 +00:00
|
|
|
</template>
|
|
|
|
</VEntityField>
|
|
|
|
<VEntityField
|
|
|
|
class="w-28 min-w-[7rem]"
|
|
|
|
:title="comment?.owner?.displayName"
|
|
|
|
:description="comment?.owner?.email"
|
|
|
|
></VEntityField>
|
2023-03-23 14:04:34 +00:00
|
|
|
<VEntityField width="100%">
|
2022-09-19 09:26:50 +00:00
|
|
|
<template #description>
|
|
|
|
<div class="flex flex-col gap-2">
|
2023-03-23 14:04:34 +00:00
|
|
|
<div class="mb-1 flex items-center gap-2">
|
|
|
|
<VTag>{{ subjectRefResult.label }}</VTag>
|
|
|
|
<RouterLink
|
|
|
|
:to="subjectRefResult.route || $route"
|
2023-06-25 06:34:17 +00:00
|
|
|
class="line-clamp-2 inline-block text-sm font-medium text-gray-900 hover:text-gray-600"
|
2023-03-23 14:04:34 +00:00
|
|
|
>
|
|
|
|
{{ subjectRefResult.title }}
|
|
|
|
</RouterLink>
|
|
|
|
<a
|
|
|
|
v-if="subjectRefResult.externalUrl"
|
|
|
|
:href="subjectRefResult.externalUrl"
|
|
|
|
target="_blank"
|
|
|
|
class="hidden text-gray-600 hover:text-gray-900 group-hover:block"
|
|
|
|
>
|
|
|
|
<IconExternalLinkLine class="h-3.5 w-3.5" />
|
|
|
|
</a>
|
|
|
|
</div>
|
2023-02-13 08:30:20 +00:00
|
|
|
<div class="break-all text-sm text-gray-900">
|
2022-09-19 09:26:50 +00:00
|
|
|
{{ comment?.comment?.spec.content }}
|
|
|
|
</div>
|
|
|
|
<div class="flex items-center gap-3 text-xs">
|
|
|
|
<span
|
|
|
|
class="select-none text-gray-700 hover:text-gray-900"
|
|
|
|
@click="handleToggleShowReplies"
|
|
|
|
>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{
|
|
|
|
$t("core.comment.list.fields.reply_count", {
|
|
|
|
count: comment?.comment?.status?.replyCount || 0,
|
|
|
|
})
|
|
|
|
}}
|
2022-09-19 09:26:50 +00:00
|
|
|
</span>
|
|
|
|
<VStatusDot
|
2023-07-28 02:35:09 +00:00
|
|
|
v-show="(comment?.comment?.status?.unreadReplyCount || 0) > 0"
|
2023-03-23 08:54:33 +00:00
|
|
|
v-tooltip="$t('core.comment.list.fields.has_new_replies')"
|
2022-09-19 09:26:50 +00:00
|
|
|
state="success"
|
|
|
|
animate
|
|
|
|
/>
|
|
|
|
<span
|
|
|
|
class="select-none text-gray-700 hover:text-gray-900"
|
2024-05-23 02:56:50 +00:00
|
|
|
@click="replyModal = true"
|
2022-09-19 09:26:50 +00:00
|
|
|
>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.comment.operations.reply.button") }}
|
2022-09-19 09:26:50 +00:00
|
|
|
</span>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</VEntityField>
|
|
|
|
</template>
|
|
|
|
<template #end>
|
|
|
|
<VEntityField v-if="!comment?.comment.spec.approved">
|
|
|
|
<template #description>
|
|
|
|
<VStatusDot state="success">
|
|
|
|
<template #text>
|
2023-03-23 08:54:33 +00:00
|
|
|
<span class="text-xs text-gray-500">
|
|
|
|
{{ $t("core.comment.list.fields.pending_review") }}
|
|
|
|
</span>
|
2022-09-19 09:26:50 +00:00
|
|
|
</template>
|
|
|
|
</VStatusDot>
|
|
|
|
</template>
|
|
|
|
</VEntityField>
|
|
|
|
<VEntityField v-if="comment?.comment?.metadata.deletionTimestamp">
|
|
|
|
<template #description>
|
2023-03-23 08:54:33 +00:00
|
|
|
<VStatusDot
|
|
|
|
v-tooltip="$t('core.common.status.deleting')"
|
|
|
|
state="warning"
|
|
|
|
animate
|
|
|
|
/>
|
2022-09-19 09:26:50 +00:00
|
|
|
</template>
|
|
|
|
</VEntityField>
|
2023-02-24 09:50:28 +00:00
|
|
|
<VEntityField>
|
2022-09-29 03:10:31 +00:00
|
|
|
<template #description>
|
|
|
|
<span class="truncate text-xs tabular-nums text-gray-500">
|
2023-02-24 09:50:28 +00:00
|
|
|
{{
|
|
|
|
formatDatetime(
|
|
|
|
comment?.comment.spec.creationTime ||
|
|
|
|
comment?.comment.metadata.creationTimestamp
|
|
|
|
)
|
|
|
|
}}
|
2022-09-29 03:10:31 +00:00
|
|
|
</span>
|
|
|
|
</template>
|
2022-09-19 09:26:50 +00:00
|
|
|
</VEntityField>
|
|
|
|
</template>
|
2022-09-30 09:48:19 +00:00
|
|
|
<template
|
2022-09-30 11:03:38 +00:00
|
|
|
v-if="currentUserHasPermission(['system:comments:manage'])"
|
2022-09-30 09:48:19 +00:00
|
|
|
#dropdownItems
|
|
|
|
>
|
2023-03-27 08:06:13 +00:00
|
|
|
<VDropdownItem
|
2022-09-19 09:26:50 +00:00
|
|
|
v-if="!comment?.comment.spec.approved"
|
|
|
|
@click="handleApprove"
|
|
|
|
>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.comment.operations.approve_comment_in_batch.button") }}
|
2023-03-27 08:06:13 +00:00
|
|
|
</VDropdownItem>
|
|
|
|
<VDropdownItem @click="handleApproveReplyInBatch">
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.comment.operations.approve_applies_in_batch.button") }}
|
2023-03-27 08:06:13 +00:00
|
|
|
</VDropdownItem>
|
|
|
|
<VDropdownItem type="danger" @click="handleDelete">
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.common.buttons.delete") }}
|
2023-03-27 08:06:13 +00:00
|
|
|
</VDropdownItem>
|
2022-09-19 09:26:50 +00:00
|
|
|
</template>
|
|
|
|
|
|
|
|
<template v-if="showReplies" #footer>
|
|
|
|
<!-- Replies -->
|
|
|
|
<div
|
|
|
|
class="ml-8 mt-3 divide-y divide-gray-100 rounded-base border-t border-gray-100 pt-3"
|
|
|
|
>
|
2023-02-28 15:46:18 +00:00
|
|
|
<VLoading v-if="isLoading" />
|
|
|
|
<Transition v-else-if="!replies?.length" appear name="fade">
|
2023-03-23 08:54:33 +00:00
|
|
|
<VEmpty
|
|
|
|
:message="$t('core.comment.reply_empty.message')"
|
|
|
|
:title="$t('core.comment.reply_empty.title')"
|
|
|
|
>
|
2022-11-24 14:51:07 +00:00
|
|
|
<template #actions>
|
|
|
|
<VSpace>
|
2023-03-23 08:54:33 +00:00
|
|
|
<VButton @click="refetch()">
|
|
|
|
{{ $t("core.common.buttons.refresh") }}
|
|
|
|
</VButton>
|
2022-11-24 14:51:07 +00:00
|
|
|
<VButton type="secondary" @click="replyModal = true">
|
|
|
|
<template #icon>
|
|
|
|
<IconAddCircle class="h-full w-full" />
|
|
|
|
</template>
|
2023-03-23 08:54:33 +00:00
|
|
|
{{ $t("core.comment.reply_empty.new") }}
|
2022-11-24 14:51:07 +00:00
|
|
|
</VButton>
|
|
|
|
</VSpace>
|
|
|
|
</template>
|
|
|
|
</VEmpty>
|
|
|
|
</Transition>
|
|
|
|
<Transition v-else appear name="fade">
|
|
|
|
<div>
|
|
|
|
<ReplyListItem
|
|
|
|
v-for="reply in replies"
|
|
|
|
:key="reply.reply.metadata.name"
|
|
|
|
:class="{ 'hover:bg-white': showReplies }"
|
|
|
|
:reply="reply"
|
2024-05-23 02:56:50 +00:00
|
|
|
:comment="comment"
|
2022-11-24 14:51:07 +00:00
|
|
|
:replies="replies"
|
|
|
|
></ReplyListItem>
|
|
|
|
</div>
|
|
|
|
</Transition>
|
2022-09-19 09:26:50 +00:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
</VEntity>
|
|
|
|
</template>
|