halo/ui/console-src/modules/contents/comments/components/ReplyListItem.vue

251 lines
7.2 KiB
Vue
Raw Normal View History

<script lang="ts" setup>
import { formatDatetime } from "@/utils/date";
import type { ListedComment, ListedReply } from "@halo-dev/api-client";
import { coreApiClient } from "@halo-dev/api-client";
import {
Dialog,
IconReplyLine,
Toast,
VAvatar,
VDropdownItem,
VEntity,
VEntityField,
VStatusDot,
VTag,
} from "@halo-dev/components";
feat: make comment and reply list item operations extendable (#6438) #### What type of PR is this? /area console /kind feature /milestone 2.18.x #### What this PR does / why we need it: 评论和回复管理列表项的操作按钮支持被插件扩展。 ![image](https://github.com/user-attachments/assets/20174eda-ec46-4ab2-b1d9-c27e4aaa6cba) ![image](https://github.com/user-attachments/assets/ac44c221-71f5-4077-8116-a92245c22697) #### Which issue(s) this PR fixes: Fixes #6392 #### Special notes for your reviewer: 需要评论和回复的关于列表的已有功能是否正常。 如果需要测试扩展点是否有效,可以使用此插件测试:[plugin-starter-1.0.0-SNAPSHOT.jar.zip](https://github.com/user-attachments/files/16482348/plugin-starter-1.0.0-SNAPSHOT.jar.zip) ``` export default definePlugin({ components: {}, routes: [], extensionPoints: { "comment:list-item:operation:create": (comment: Ref<ListedComment>) => { return [ { priority: 21, component: markRaw(VDropdownItem), label: "测试评论菜单", visible: true, permissions: [], action: () => { console.log(comment) }, }, ]; }, "reply:list-item:operation:create": (reply: Ref<ListedReply>) => { return [ { priority: 11, component: markRaw(VDropdownItem), label: "测试回复菜单", visible: true, permissions: [], action: () => { console.log(reply) }, }, ]; }, }, }); ``` #### Does this PR introduce a user-facing change? ```release-note Console 评论和回复管理列表项的操作按钮支持被插件扩展。 ```
2024-08-05 06:56:25 +00:00
import type { OperationItem } from "@halo-dev/console-shared";
import { useQueryClient } from "@tanstack/vue-query";
feat: make comment and reply list item operations extendable (#6438) #### What type of PR is this? /area console /kind feature /milestone 2.18.x #### What this PR does / why we need it: 评论和回复管理列表项的操作按钮支持被插件扩展。 ![image](https://github.com/user-attachments/assets/20174eda-ec46-4ab2-b1d9-c27e4aaa6cba) ![image](https://github.com/user-attachments/assets/ac44c221-71f5-4077-8116-a92245c22697) #### Which issue(s) this PR fixes: Fixes #6392 #### Special notes for your reviewer: 需要评论和回复的关于列表的已有功能是否正常。 如果需要测试扩展点是否有效,可以使用此插件测试:[plugin-starter-1.0.0-SNAPSHOT.jar.zip](https://github.com/user-attachments/files/16482348/plugin-starter-1.0.0-SNAPSHOT.jar.zip) ``` export default definePlugin({ components: {}, routes: [], extensionPoints: { "comment:list-item:operation:create": (comment: Ref<ListedComment>) => { return [ { priority: 21, component: markRaw(VDropdownItem), label: "测试评论菜单", visible: true, permissions: [], action: () => { console.log(comment) }, }, ]; }, "reply:list-item:operation:create": (reply: Ref<ListedReply>) => { return [ { priority: 11, component: markRaw(VDropdownItem), label: "测试回复菜单", visible: true, permissions: [], action: () => { console.log(reply) }, }, ]; }, }, }); ``` #### Does this PR introduce a user-facing change? ```release-note Console 评论和回复管理列表项的操作按钮支持被插件扩展。 ```
2024-08-05 06:56:25 +00:00
import { computed, inject, ref, type Ref, toRefs, markRaw } from "vue";
import { useI18n } from "vue-i18n";
import ReplyCreationModal from "./ReplyCreationModal.vue";
feat: make comment and reply list item operations extendable (#6438) #### What type of PR is this? /area console /kind feature /milestone 2.18.x #### What this PR does / why we need it: 评论和回复管理列表项的操作按钮支持被插件扩展。 ![image](https://github.com/user-attachments/assets/20174eda-ec46-4ab2-b1d9-c27e4aaa6cba) ![image](https://github.com/user-attachments/assets/ac44c221-71f5-4077-8116-a92245c22697) #### Which issue(s) this PR fixes: Fixes #6392 #### Special notes for your reviewer: 需要评论和回复的关于列表的已有功能是否正常。 如果需要测试扩展点是否有效,可以使用此插件测试:[plugin-starter-1.0.0-SNAPSHOT.jar.zip](https://github.com/user-attachments/files/16482348/plugin-starter-1.0.0-SNAPSHOT.jar.zip) ``` export default definePlugin({ components: {}, routes: [], extensionPoints: { "comment:list-item:operation:create": (comment: Ref<ListedComment>) => { return [ { priority: 21, component: markRaw(VDropdownItem), label: "测试评论菜单", visible: true, permissions: [], action: () => { console.log(comment) }, }, ]; }, "reply:list-item:operation:create": (reply: Ref<ListedReply>) => { return [ { priority: 11, component: markRaw(VDropdownItem), label: "测试回复菜单", visible: true, permissions: [], action: () => { console.log(reply) }, }, ]; }, }, }); ``` #### Does this PR introduce a user-facing change? ```release-note Console 评论和回复管理列表项的操作按钮支持被插件扩展。 ```
2024-08-05 06:56:25 +00:00
import { useOperationItemExtensionPoint } from "@console/composables/use-operation-extension-points";
import EntityDropdownItems from "@/components/entity/EntityDropdownItems.vue";
const { t } = useI18n();
const queryClient = useQueryClient();
const props = withDefaults(
defineProps<{
comment: ListedComment;
reply: ListedReply;
replies?: ListedReply[];
}>(),
{
reply: undefined,
replies: undefined,
}
);
feat: make comment and reply list item operations extendable (#6438) #### What type of PR is this? /area console /kind feature /milestone 2.18.x #### What this PR does / why we need it: 评论和回复管理列表项的操作按钮支持被插件扩展。 ![image](https://github.com/user-attachments/assets/20174eda-ec46-4ab2-b1d9-c27e4aaa6cba) ![image](https://github.com/user-attachments/assets/ac44c221-71f5-4077-8116-a92245c22697) #### Which issue(s) this PR fixes: Fixes #6392 #### Special notes for your reviewer: 需要评论和回复的关于列表的已有功能是否正常。 如果需要测试扩展点是否有效,可以使用此插件测试:[plugin-starter-1.0.0-SNAPSHOT.jar.zip](https://github.com/user-attachments/files/16482348/plugin-starter-1.0.0-SNAPSHOT.jar.zip) ``` export default definePlugin({ components: {}, routes: [], extensionPoints: { "comment:list-item:operation:create": (comment: Ref<ListedComment>) => { return [ { priority: 21, component: markRaw(VDropdownItem), label: "测试评论菜单", visible: true, permissions: [], action: () => { console.log(comment) }, }, ]; }, "reply:list-item:operation:create": (reply: Ref<ListedReply>) => { return [ { priority: 11, component: markRaw(VDropdownItem), label: "测试回复菜单", visible: true, permissions: [], action: () => { console.log(reply) }, }, ]; }, }, }); ``` #### Does this PR introduce a user-facing change? ```release-note Console 评论和回复管理列表项的操作按钮支持被插件扩展。 ```
2024-08-05 06:56:25 +00:00
const { reply } = toRefs(props);
const quoteReply = computed(() => {
const { quoteReply: replyName } = props.reply.reply.spec;
if (!replyName) {
return undefined;
}
return props.replies?.find(
(reply) => reply.reply.metadata.name === replyName
);
});
const handleDelete = async () => {
Dialog.warning({
title: t("core.comment.operations.delete_reply.title"),
description: t("core.common.dialog.descriptions.cannot_be_recovered"),
confirmType: "danger",
confirmText: t("core.common.buttons.confirm"),
cancelText: t("core.common.buttons.cancel"),
onConfirm: async () => {
try {
await coreApiClient.content.reply.deleteReply({
name: props.reply?.reply.metadata.name as string,
});
Toast.success(t("core.common.toast.delete_success"));
} catch (error) {
console.error("Failed to delete comment reply", error);
} finally {
queryClient.invalidateQueries({ queryKey: ["comment-replies"] });
}
},
});
};
const handleApprove = async () => {
try {
await coreApiClient.content.reply.patchReply({
name: props.reply.reply.metadata.name,
jsonPatchInner: [
{
op: "add",
path: "/spec/approved",
value: true,
},
{
op: "add",
path: "/spec/approvedTime",
// TODO: 暂时由前端设置发布时间。see https://github.com/halo-dev/halo/pull/2746
value: new Date().toISOString(),
},
],
});
Toast.success(t("core.common.toast.operation_success"));
} catch (error) {
console.error("Failed to approve comment reply", error);
} finally {
queryClient.invalidateQueries({ queryKey: ["comment-replies"] });
}
};
// Show hovered reply
const hoveredReply = inject<Ref<ListedReply | undefined>>("hoveredReply");
const handleShowQuoteReply = (show: boolean) => {
if (hoveredReply) {
hoveredReply.value = show ? quoteReply.value : undefined;
}
};
const isHoveredReply = computed(() => {
return (
hoveredReply?.value?.reply.metadata.name === props.reply.reply.metadata.name
);
});
// Create reply
const replyModal = ref(false);
function onReplyCreationModalClose() {
queryClient.invalidateQueries({
queryKey: ["comment-replies", props.comment.comment.metadata.name],
});
replyModal.value = false;
}
feat: make comment and reply list item operations extendable (#6438) #### What type of PR is this? /area console /kind feature /milestone 2.18.x #### What this PR does / why we need it: 评论和回复管理列表项的操作按钮支持被插件扩展。 ![image](https://github.com/user-attachments/assets/20174eda-ec46-4ab2-b1d9-c27e4aaa6cba) ![image](https://github.com/user-attachments/assets/ac44c221-71f5-4077-8116-a92245c22697) #### Which issue(s) this PR fixes: Fixes #6392 #### Special notes for your reviewer: 需要评论和回复的关于列表的已有功能是否正常。 如果需要测试扩展点是否有效,可以使用此插件测试:[plugin-starter-1.0.0-SNAPSHOT.jar.zip](https://github.com/user-attachments/files/16482348/plugin-starter-1.0.0-SNAPSHOT.jar.zip) ``` export default definePlugin({ components: {}, routes: [], extensionPoints: { "comment:list-item:operation:create": (comment: Ref<ListedComment>) => { return [ { priority: 21, component: markRaw(VDropdownItem), label: "测试评论菜单", visible: true, permissions: [], action: () => { console.log(comment) }, }, ]; }, "reply:list-item:operation:create": (reply: Ref<ListedReply>) => { return [ { priority: 11, component: markRaw(VDropdownItem), label: "测试回复菜单", visible: true, permissions: [], action: () => { console.log(reply) }, }, ]; }, }, }); ``` #### Does this PR introduce a user-facing change? ```release-note Console 评论和回复管理列表项的操作按钮支持被插件扩展。 ```
2024-08-05 06:56:25 +00:00
const { operationItems } = useOperationItemExtensionPoint<ListedReply>(
"reply:list-item:operation:create",
reply,
computed((): OperationItem<ListedReply>[] => [
{
priority: 0,
component: markRaw(VDropdownItem),
label: t("core.comment.operations.approve_reply.button"),
permissions: ["system:comments:manage"],
action: handleApprove,
hidden: props.reply?.reply.spec.approved,
},
{
priority: 10,
component: markRaw(VDropdownItem),
props: {
type: "danger",
},
label: t("core.common.buttons.delete"),
permissions: ["system:comments:manage"],
action: handleDelete,
},
])
);
</script>
<template>
<ReplyCreationModal
v-if="replyModal"
:comment="comment"
:reply="reply"
@close="onReplyCreationModalClose"
/>
<VEntity class="!px-0 !py-2" :class="{ 'animate-breath': isHoveredReply }">
<template #start>
<VEntityField>
<template #description>
<VAvatar
circle
:src="reply?.owner.avatar"
:alt="reply?.owner.displayName"
size="md"
></VAvatar>
</template>
</VEntityField>
<VEntityField
class="w-28 min-w-[7rem]"
:title="reply?.owner.displayName"
:description="reply?.owner.email"
></VEntityField>
<VEntityField width="60%">
<template #description>
<div class="flex flex-col gap-2">
<div class="text-sm text-gray-800">
<p class="break-all">
<a
v-if="quoteReply"
class="mr-1 inline-flex flex-row items-center gap-1 rounded bg-gray-200 px-1 py-0.5 text-xs font-medium text-gray-600 hover:text-blue-500 hover:underline"
href="javascript:void(0)"
@mouseenter="handleShowQuoteReply(true)"
@mouseleave="handleShowQuoteReply(false)"
>
<IconReplyLine />
<span>{{ quoteReply.owner.displayName }}</span>
</a>
<br v-if="quoteReply" />
{{ reply?.reply.spec.content }}
</p>
</div>
<div class="flex items-center gap-3 text-xs">
<span
class="select-none text-gray-700 hover:text-gray-900"
@click="replyModal = true"
>
{{ $t("core.comment.operations.reply.button") }}
</span>
<div v-if="false" class="flex items-center">
<VTag>New</VTag>
</div>
</div>
</div>
</template>
</VEntityField>
</template>
<template #end>
<VEntityField v-if="!reply?.reply.spec.approved">
<template #description>
<VStatusDot state="success">
<template #text>
<span class="text-xs text-gray-500">
{{ $t("core.comment.list.fields.pending_review") }}
</span>
</template>
</VStatusDot>
</template>
</VEntityField>
<VEntityField v-if="reply?.reply.metadata.deletionTimestamp">
<template #description>
<VStatusDot
v-tooltip="$t('core.common.status.deleting')"
state="warning"
animate
/>
</template>
</VEntityField>
<VEntityField>
<template #description>
<span class="truncate text-xs tabular-nums text-gray-500">
{{
formatDatetime(
reply?.reply?.spec.creationTime ||
reply?.reply.metadata.creationTimestamp
)
}}
</span>
</template>
</VEntityField>
</template>
<template #dropdownItems>
feat: make comment and reply list item operations extendable (#6438) #### What type of PR is this? /area console /kind feature /milestone 2.18.x #### What this PR does / why we need it: 评论和回复管理列表项的操作按钮支持被插件扩展。 ![image](https://github.com/user-attachments/assets/20174eda-ec46-4ab2-b1d9-c27e4aaa6cba) ![image](https://github.com/user-attachments/assets/ac44c221-71f5-4077-8116-a92245c22697) #### Which issue(s) this PR fixes: Fixes #6392 #### Special notes for your reviewer: 需要评论和回复的关于列表的已有功能是否正常。 如果需要测试扩展点是否有效,可以使用此插件测试:[plugin-starter-1.0.0-SNAPSHOT.jar.zip](https://github.com/user-attachments/files/16482348/plugin-starter-1.0.0-SNAPSHOT.jar.zip) ``` export default definePlugin({ components: {}, routes: [], extensionPoints: { "comment:list-item:operation:create": (comment: Ref<ListedComment>) => { return [ { priority: 21, component: markRaw(VDropdownItem), label: "测试评论菜单", visible: true, permissions: [], action: () => { console.log(comment) }, }, ]; }, "reply:list-item:operation:create": (reply: Ref<ListedReply>) => { return [ { priority: 11, component: markRaw(VDropdownItem), label: "测试回复菜单", visible: true, permissions: [], action: () => { console.log(reply) }, }, ]; }, }, }); ``` #### Does this PR introduce a user-facing change? ```release-note Console 评论和回复管理列表项的操作按钮支持被插件扩展。 ```
2024-08-05 06:56:25 +00:00
<EntityDropdownItems :dropdown-items="operationItems" :item="reply" />
</template>
</VEntity>
</template>