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 评论和回复管理列表项的操作按钮支持被插件扩展。
```
pull/6442/head
困困鱼 2024-08-05 14:56:25 +08:00 committed by GitHub
parent 684c3b045b
commit 4a4f8b655d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 88 additions and 28 deletions

View File

@ -29,12 +29,23 @@ import {
import type {
CommentSubjectRefProvider,
CommentSubjectRefResult,
OperationItem,
} from "@halo-dev/console-shared";
import { useMutation, useQuery, useQueryClient } from "@tanstack/vue-query";
import { computed, onMounted, provide, ref, type Ref } from "vue";
import {
computed,
onMounted,
provide,
ref,
type Ref,
toRefs,
markRaw,
} from "vue";
import { useI18n } from "vue-i18n";
import ReplyCreationModal from "./ReplyCreationModal.vue";
import ReplyListItem from "./ReplyListItem.vue";
import { useOperationItemExtensionPoint } from "@console/composables/use-operation-extension-points";
import EntityDropdownItems from "@/components/entity/EntityDropdownItems.vue";
const { currentUserHasPermission } = usePermission();
const { t } = useI18n();
@ -50,6 +61,8 @@ const props = withDefaults(
}
);
const { comment } = toRefs(props);
const hoveredReply = ref<ListedReply>();
const showReplies = ref(false);
const replyModal = ref(false);
@ -293,6 +306,35 @@ const subjectRefResult = computed(() => {
}
return subjectRef.resolve(subject);
});
const { operationItems } = useOperationItemExtensionPoint<ListedComment>(
"comment:list-item:operation:create",
comment,
computed((): OperationItem<ListedComment>[] => [
{
priority: 0,
component: markRaw(VDropdownItem),
label: t("core.comment.operations.approve_comment_in_batch.button"),
action: handleApprove,
hidden: props.comment?.comment.spec.approved,
},
{
priority: 10,
component: markRaw(VDropdownItem),
label: t("core.comment.operations.approve_applies_in_batch.button"),
action: handleApproveReplyInBatch,
},
{
priority: 20,
component: markRaw(VDropdownItem),
props: {
type: "danger",
},
label: t("core.common.buttons.delete"),
action: handleDelete,
},
])
);
</script>
<template>
@ -419,18 +461,7 @@ const subjectRefResult = computed(() => {
v-if="currentUserHasPermission(['system:comments:manage'])"
#dropdownItems
>
<VDropdownItem
v-if="!comment?.comment.spec.approved"
@click="handleApprove"
>
{{ $t("core.comment.operations.approve_comment_in_batch.button") }}
</VDropdownItem>
<VDropdownItem @click="handleApproveReplyInBatch">
{{ $t("core.comment.operations.approve_applies_in_batch.button") }}
</VDropdownItem>
<VDropdownItem type="danger" @click="handleDelete">
{{ $t("core.common.buttons.delete") }}
</VDropdownItem>
<EntityDropdownItems :dropdown-items="operationItems" :item="comment" />
</template>
<template v-if="showReplies" #footer>

View File

@ -13,10 +13,13 @@ import {
VStatusDot,
VTag,
} from "@halo-dev/components";
import type { OperationItem } from "@halo-dev/console-shared";
import { useQueryClient } from "@tanstack/vue-query";
import { computed, inject, ref, type Ref } from "vue";
import { computed, inject, ref, type Ref, toRefs, markRaw } from "vue";
import { useI18n } from "vue-i18n";
import ReplyCreationModal from "./ReplyCreationModal.vue";
import { useOperationItemExtensionPoint } from "@console/composables/use-operation-extension-points";
import EntityDropdownItems from "@/components/entity/EntityDropdownItems.vue";
const { t } = useI18n();
const queryClient = useQueryClient();
@ -33,6 +36,8 @@ const props = withDefaults(
}
);
const { reply } = toRefs(props);
const quoteReply = computed(() => {
const { quoteReply: replyName } = props.reply.reply.spec;
@ -119,6 +124,31 @@ function onReplyCreationModalClose() {
});
replyModal.value = false;
}
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>
@ -214,20 +244,7 @@ function onReplyCreationModalClose() {
</VEntityField>
</template>
<template #dropdownItems>
<VDropdownItem
v-if="!reply?.reply.spec.approved"
v-permission="['system:comments:manage']"
@click="handleApprove"
>
{{ $t("core.comment.operations.approve_reply.button") }}
</VDropdownItem>
<VDropdownItem
v-permission="['system:comments:manage']"
type="danger"
@click="handleDelete"
>
{{ $t("core.common.buttons.delete") }}
</VDropdownItem>
<EntityDropdownItems :dropdown-items="operationItems" :item="reply" />
</template>
</VEntity>
</template>

View File

@ -9,6 +9,8 @@
目前支持扩展的数据列表:
- 文章:`"post:list-item:operation:create"?: (post: Ref<ListedPost>) => | OperationItem<ListedPost>[] | Promise<OperationItem<ListedPost>[]>`
- 评论:`"comment:list-item:operation:create"?: (comment: Ref<ListedComment>) => | OperationItem<ListedComment>[] | Promise<OperationItem<ListedComment>[]>`
- 回复:`"reply:list-item:operation:create"?: (reply: Ref<ListedReply>) => | OperationItem<ListedReply>[] | Promise<OperationItem<ListedReply>[]>`
- 插件:`"plugin:list-item:operation:create"?: (plugin: Ref<Plugin>) => | OperationItem<Plugin>[] | Promise<OperationItem<Plugin>[]>`
- 备份:`"backup:list-item:operation:create"?: (backup: Ref<Backup>) => | OperationItem<Backup>[] | Promise<OperationItem<Backup>[]>`
- 主题:`"theme:list-item:operation:create"?: (theme: Ref<Theme>) => | OperationItem<Theme>[] | Promise<OperationItem<Theme>[]>`

View File

@ -11,6 +11,8 @@ import type {
ListedPost,
Plugin,
Theme,
ListedComment,
ListedReply,
} from "@halo-dev/api-client";
import type { AnyExtension } from "@halo-dev/richtext-editor";
import type { Component, Ref } from "vue";
@ -52,6 +54,14 @@ export interface ExtensionPoint {
post: Ref<ListedPost>
) => OperationItem<ListedPost>[];
"comment:list-item:operation:create"?: (
comment: Ref<ListedComment>
) => OperationItem<ListedComment>[];
"reply:list-item:operation:create"?: (
reply: Ref<ListedReply>
) => OperationItem<ListedReply>[];
"plugin:list-item:operation:create"?: (
plugin: Ref<Plugin>
) => OperationItem<Plugin>[];