feat: add tools page for console (#5252)

#### What type of PR is this?

/area console
/kind feature
/milestone 2.12.x

#### What this PR does / why we need it:

为 Console 提供工具页面和菜单项,方便插件集成。

<img width="1920" alt="image" src="https://github.com/halo-dev/halo/assets/21301288/9b63284f-7bdb-4eed-bc6e-cbe2c78359db">

#### Which issue(s) this PR fixes:

Fixes https://github.com/halo-dev/halo/issues/5249

#### Special notes for your reviewer:

可以使用以下插件进行测试:

1. [plugin-umami-1.0.0-SNAPSHOT.jar.zip](https://github.com/halo-dev/halo/files/14049119/plugin-umami-1.0.0-SNAPSHOT.jar.zip)
2. [plugin-metrics-graph-1.0.0-beta.1.jar.zip](https://github.com/halo-dev/halo/files/14049127/plugin-metrics-graph-1.0.0-beta.1.jar.zip)
3. [NotifyMe-1.1.0.jar.zip](https://github.com/halo-dev/halo/files/14049131/NotifyMe-1.1.0.jar.zip)

#### Does this PR introduce a user-facing change?

```release-note
为 Console 提供工具页面和菜单项,方便插件集成。
```
pull/5256/head
Ryan Wang 2024-01-26 10:40:08 +08:00 committed by GitHub
parent 3f27f6f262
commit 22104fe636
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 155 additions and 0 deletions

View File

@ -0,0 +1,98 @@
<script lang="ts" setup>
import { useRoleStore } from "@/stores/role";
import { hasPermission } from "@/utils/permission";
import {
VPageHeader,
IconToolsFill,
VCard,
VEntity,
VEntityField,
VButton,
VEmpty,
} from "@halo-dev/components";
import { computed } from "vue";
import type { RouteRecordRaw } from "vue-router";
import { useRouter } from "vue-router";
const router = useRouter();
const roleStore = useRoleStore();
const { uiPermissions } = roleStore.permissions;
function isRouteValid(route?: RouteRecordRaw) {
if (!route) return false;
const { meta } = route;
if (!meta?.menu) return false;
return (
!meta.permissions || hasPermission(uiPermissions, meta.permissions, true)
);
}
const routes = computed(() => {
const matchedRoute = router.currentRoute.value.matched[0];
return router
.getRoutes()
.find((route) => route.name === matchedRoute.name)
?.children.filter((route) => route.path !== "")
.filter((route) => isRouteValid(route));
});
</script>
<template>
<VPageHeader :title="$t('core.tool.title')">
<template #icon>
<IconToolsFill class="mr-2 self-center" />
</template>
</VPageHeader>
<div class="m-0 md:m-4">
<VCard :body-class="['!p-0']">
<VEmpty
v-if="!routes?.length"
:title="$t('core.tool.empty.title')"
:message="$t('core.tool.empty.message')"
></VEmpty>
<ul
v-else
class="box-border h-full w-full divide-y divide-gray-100"
role="list"
>
<li v-for="route in routes" :key="route.name">
<VEntity>
<template #start>
<VEntityField>
<template #description>
<component
:is="route.meta?.menu?.icon"
v-if="route.meta?.menu?.icon"
class="text-lg"
/>
<IconToolsFill v-else class="text-lg" />
</template>
</VEntityField>
<VEntityField
:route="{ name: route.name }"
:title="route.meta?.menu?.name"
:description="route.meta?.description"
></VEntityField>
</template>
<template #end>
<VEntityField>
<template #description>
<VButton
size="sm"
@click="$router.push({ name: route.name })"
>
{{ $t("core.common.buttons.access") }}
</VButton>
</template>
</VEntityField>
</template>
</VEntity>
</li>
</ul>
</VCard>
</div>
</template>

View File

@ -0,0 +1,32 @@
import { definePlugin } from "@halo-dev/console-shared";
import Tools from "./Tools.vue";
import { markRaw } from "vue";
import BasicLayout from "@console/layouts/BasicLayout.vue";
import { IconToolsFill } from "@halo-dev/components";
export default definePlugin({
components: {},
routes: [
{
path: "/tools",
name: "ToolsRoot",
component: BasicLayout,
meta: {
title: "core.tool.title",
menu: {
name: "core.sidebar.menu.items.tools",
group: "system",
icon: markRaw(IconToolsFill),
priority: 5,
},
},
children: [
{
path: "",
name: "Tools",
component: Tools,
},
],
},
],
});

View File

@ -71,6 +71,7 @@ import IconLogoutCircleRLine from "~icons/ri/logout-circle-r-line";
import IconAccountCircleLine from "~icons/ri/account-circle-line"; import IconAccountCircleLine from "~icons/ri/account-circle-line";
import IconSettings3Line from "~icons/ri/settings-3-line"; import IconSettings3Line from "~icons/ri/settings-3-line";
import IconImageAddLine from "~icons/ri/image-add-line"; import IconImageAddLine from "~icons/ri/image-add-line";
import IconToolsFill from "~icons/ri/tools-fill";
export { export {
IconDashboard, IconDashboard,
@ -146,4 +147,5 @@ export {
IconAccountCircleLine, IconAccountCircleLine,
IconSettings3Line, IconSettings3Line,
IconImageAddLine, IconImageAddLine,
IconToolsFill,
}; };

View File

@ -77,6 +77,7 @@ core:
settings: Settings settings: Settings
actuator: Actuator actuator: Actuator
backup: Backup backup: Backup
tools: Tools
operations: operations:
logout: logout:
tooltip: Logout tooltip: Logout
@ -1495,6 +1496,7 @@ core:
view_all: View all view_all: View all
verify: Verify verify: Verify
modify: Modify modify: Modify
access: Access
radio: radio:
"yes": "Yes" "yes": "Yes"
"no": "No" "no": "No"
@ -1601,3 +1603,10 @@ core:
toast_success: >- toast_success: >-
If your username and email address match, we will send an email to If your username and email address match, we will send an email to
your email address. your email address.
tool:
title: Tools
empty:
title: There are no tools available
message: >-
There are currently no tools available, and system tools may be provided
by plugins

View File

@ -75,6 +75,7 @@ core:
settings: 设置 settings: 设置
actuator: 概览 actuator: 概览
backup: 备份 backup: 备份
tools: 工具
operations: operations:
logout: logout:
tooltip: 退出登录 tooltip: 退出登录
@ -1441,6 +1442,7 @@ core:
view_all: 查看全部 view_all: 查看全部
verify: 验证 verify: 验证
modify: 修改 modify: 修改
access: 访问
radio: radio:
"yes": "yes":
"no": "no":
@ -1509,3 +1511,8 @@ core:
recovering: 恢复中 recovering: 恢复中
fields: fields:
post_count: "{count} 篇文章" post_count: "{count} 篇文章"
tool:
title: 工具
empty:
title: 没有可用工具
message: 当前没有可用的工具,系统工具可能由插件提供

View File

@ -75,6 +75,7 @@ core:
settings: 設置 settings: 設置
actuator: 概覽 actuator: 概覽
backup: 備份 backup: 備份
tools: 工具
operations: operations:
logout: logout:
tooltip: 登出 tooltip: 登出
@ -1407,6 +1408,7 @@ core:
view_all: 查看全部 view_all: 查看全部
modify: 修改 modify: 修改
verify: 驗證 verify: 驗證
access: 访问
radio: radio:
"yes": "yes":
"no": "no":
@ -1509,3 +1511,8 @@ core:
send: send:
label: 發送驗證郵件 label: 發送驗證郵件
toast_success: 如果你的用戶名和郵箱地址匹配,我們將會發送一封郵件到你的郵箱。 toast_success: 如果你的用戶名和郵箱地址匹配,我們將會發送一封郵件到你的郵箱。
tool:
title: 工具
empty:
title: 沒有可用工具
message: 目前沒有可用的工具,系統工具可能由外掛提供