From 3ebb45c266bda7d560713163e8bb9bff76d6bd58 Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Fri, 19 Jan 2024 13:34:10 +0800 Subject: [PATCH] Refactor menu generation strategy to support sub-menu items. (#5177) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /area console /kind feature /milestone 2.12.x #### What this PR does / why we need it: 重构 Console 和 UC 的菜单生成逻辑,支持配置二级菜单项。 图片 配置方式: ```ts export default definePlugin({ components: {}, routes: [ { parentName: "AttachmentsRoot", route: { name: "S3Link", path: "s3-link", component: markRaw(HomeView), meta: { title: "S3 关联", searchable: true, menu: { name: "S3 关联", icon: markRaw(IconAddCircle), priority: 0, mobile: true, }, }, }, }, ], }); ``` 只需要指定 parentName 并在其下 route 需要配置 meta.menu 即可。 最终文档会补充在:https://github.com/halo-dev/docs/pull/291 #### Which issue(s) this PR fixes: Fixes https://github.com/halo-dev/halo/issues/4807 #### Special notes for your reviewer: 1. 可以按照上述配置方式测试。 2. 可以安装 [plugin-s3-1.5.0-SNAPSHOT.jar.zip](https://github.com/halo-dev/halo/files/13959977/plugin-s3-1.5.0-SNAPSHOT.jar.zip) 进行测试。 #### Does this PR introduce a user-facing change? ```release-note 重构 Console 和 UC 的菜单生成逻辑,支持配置二级菜单项。 ``` --- .../modules/contents/attachments/module.ts | 23 ++--- .../modules/contents/comments/module.ts | 25 ++--- .../modules/contents/pages/module.ts | 23 ++--- .../modules/contents/posts/module.ts | 25 ++--- .../modules/interface/menus/module.ts | 23 ++--- .../modules/interface/themes/module.ts | 23 ++--- .../modules/system/actuator/module.ts | 24 ++--- .../modules/system/backup/module.ts | 23 ++--- .../modules/system/plugins/module.ts | 54 ++++------- .../modules/system/settings/module.ts | 21 ++-- .../modules/system/users/module.ts | 25 ++--- console/console-src/setup/setupModules.ts | 9 +- console/env.d.ts | 3 + .../src/components/menu/Menu.stories.ts | 7 ++ .../src/components/menu/MenuItem.vue | 20 ++-- .../components/menu/__tests__/Menu.spec.tsx | 2 +- console/src/components/menu/RoutesMenu.tsx | 4 +- .../composables/use-route-menu-generator.ts | 95 +++++++++++++------ .../uc-src/modules/contents/posts/module.ts | 25 ++--- .../uc-src/modules/notifications/module.ts | 23 ++--- console/uc-src/setup/setupModules.ts | 9 +- 21 files changed, 278 insertions(+), 208 deletions(-) diff --git a/console/console-src/modules/contents/attachments/module.ts b/console/console-src/modules/contents/attachments/module.ts index 3b7df17a3..8ebe2a708 100644 --- a/console/console-src/modules/contents/attachments/module.ts +++ b/console/console-src/modules/contents/attachments/module.ts @@ -12,23 +12,24 @@ export default definePlugin({ routes: [ { path: "/attachments", + name: "AttachmentsRoot", component: BasicLayout, + meta: { + title: "core.attachment.title", + permissions: ["system:attachments:view"], + menu: { + name: "core.sidebar.menu.items.attachments", + group: "content", + icon: markRaw(IconFolder), + priority: 3, + mobile: true, + }, + }, children: [ { path: "", name: "Attachments", component: AttachmentList, - meta: { - title: "core.attachment.title", - permissions: ["system:attachments:view"], - menu: { - name: "core.sidebar.menu.items.attachments", - group: "content", - icon: markRaw(IconFolder), - priority: 3, - mobile: true, - }, - }, }, ], }, diff --git a/console/console-src/modules/contents/comments/module.ts b/console/console-src/modules/contents/comments/module.ts index 2172fde2d..c2c2f4b0c 100644 --- a/console/console-src/modules/contents/comments/module.ts +++ b/console/console-src/modules/contents/comments/module.ts @@ -12,24 +12,25 @@ export default definePlugin({ routes: [ { path: "/comments", + name: "CommentsRoot", component: BasicLayout, + meta: { + title: "core.comment.title", + searchable: true, + permissions: ["system:comments:view"], + menu: { + name: "core.sidebar.menu.items.comments", + group: "content", + icon: markRaw(IconMessage), + priority: 2, + mobile: true, + }, + }, children: [ { path: "", name: "Comments", component: CommentList, - meta: { - title: "core.comment.title", - searchable: true, - permissions: ["system:comments:view"], - menu: { - name: "core.sidebar.menu.items.comments", - group: "content", - icon: markRaw(IconMessage), - priority: 2, - mobile: true, - }, - }, }, ], }, diff --git a/console/console-src/modules/contents/pages/module.ts b/console/console-src/modules/contents/pages/module.ts index 9331b0ab0..df2e4bc69 100644 --- a/console/console-src/modules/contents/pages/module.ts +++ b/console/console-src/modules/contents/pages/module.ts @@ -14,23 +14,24 @@ export default definePlugin({ routes: [ { path: "/single-pages", + name: "SinglePagesRoot", component: BasicLayout, + meta: { + title: "core.page.title", + searchable: true, + permissions: ["system:singlepages:view"], + menu: { + name: "core.sidebar.menu.items.single_pages", + group: "content", + icon: markRaw(IconPages), + priority: 1, + }, + }, children: [ { path: "", name: "SinglePages", component: SinglePageList, - meta: { - title: "core.page.title", - searchable: true, - permissions: ["system:singlepages:view"], - menu: { - name: "core.sidebar.menu.items.single_pages", - group: "content", - icon: markRaw(IconPages), - priority: 1, - }, - }, }, { path: "deleted", diff --git a/console/console-src/modules/contents/posts/module.ts b/console/console-src/modules/contents/posts/module.ts index 06a74a3fc..c19966949 100644 --- a/console/console-src/modules/contents/posts/module.ts +++ b/console/console-src/modules/contents/posts/module.ts @@ -19,24 +19,25 @@ export default definePlugin({ routes: [ { path: "/posts", + name: "PostsRoot", component: BasicLayout, + meta: { + title: "core.post.title", + searchable: true, + permissions: ["system:posts:view"], + menu: { + name: "core.sidebar.menu.items.posts", + group: "content", + icon: markRaw(IconBookRead), + priority: 0, + mobile: true, + }, + }, children: [ { path: "", name: "Posts", component: PostList, - meta: { - title: "core.post.title", - searchable: true, - permissions: ["system:posts:view"], - menu: { - name: "core.sidebar.menu.items.posts", - group: "content", - icon: markRaw(IconBookRead), - priority: 0, - mobile: true, - }, - }, }, { path: "deleted", diff --git a/console/console-src/modules/interface/menus/module.ts b/console/console-src/modules/interface/menus/module.ts index 1ff12f274..f1e860624 100644 --- a/console/console-src/modules/interface/menus/module.ts +++ b/console/console-src/modules/interface/menus/module.ts @@ -9,23 +9,24 @@ export default definePlugin({ routes: [ { path: "/menus", + name: "MenusRoot", component: BasicLayout, + meta: { + title: "core.menu.title", + searchable: true, + permissions: ["system:menus:view"], + menu: { + name: "core.sidebar.menu.items.menus", + group: "interface", + icon: markRaw(IconListSettings), + priority: 1, + }, + }, children: [ { path: "", name: "Menus", component: Menus, - meta: { - title: "core.menu.title", - searchable: true, - permissions: ["system:menus:view"], - menu: { - name: "core.sidebar.menu.items.menus", - group: "interface", - icon: markRaw(IconListSettings), - priority: 1, - }, - }, }, ], }, diff --git a/console/console-src/modules/interface/themes/module.ts b/console/console-src/modules/interface/themes/module.ts index 7eb7faf1d..46c00d4b7 100644 --- a/console/console-src/modules/interface/themes/module.ts +++ b/console/console-src/modules/interface/themes/module.ts @@ -10,23 +10,24 @@ export default definePlugin({ routes: [ { path: "/theme", + name: "ThemeRoot", component: ThemeLayout, + meta: { + title: "core.theme.title", + searchable: true, + permissions: ["system:themes:view"], + menu: { + name: "core.sidebar.menu.items.themes", + group: "interface", + icon: markRaw(IconPalette), + priority: 0, + }, + }, children: [ { path: "", name: "ThemeDetail", component: ThemeDetail, - meta: { - title: "core.theme.title", - searchable: true, - permissions: ["system:themes:view"], - menu: { - name: "core.sidebar.menu.items.themes", - group: "interface", - icon: markRaw(IconPalette), - priority: 0, - }, - }, }, { path: "settings/:group", diff --git a/console/console-src/modules/system/actuator/module.ts b/console/console-src/modules/system/actuator/module.ts index c31e1b749..ffa9e3807 100644 --- a/console/console-src/modules/system/actuator/module.ts +++ b/console/console-src/modules/system/actuator/module.ts @@ -9,22 +9,24 @@ export default definePlugin({ routes: [ { path: "/actuator", + name: "OverviewRoot", // fixme: actuator will be renamed to overview in the future component: BasicLayout, + meta: { + title: "core.actuator.title", + searchable: true, + permissions: ["system:actuator:manage"], + menu: { + name: "core.sidebar.menu.items.actuator", + group: "system", + icon: markRaw(IconTerminalBoxLine), + priority: 3, + }, + }, children: [ { path: "", + name: "Actuator", component: Actuator, - meta: { - title: "core.actuator.title", - searchable: true, - permissions: ["system:actuator:manage"], - menu: { - name: "core.sidebar.menu.items.actuator", - group: "system", - icon: markRaw(IconTerminalBoxLine), - priority: 3, - }, - }, }, ], }, diff --git a/console/console-src/modules/system/backup/module.ts b/console/console-src/modules/system/backup/module.ts index 181fafe5c..b56e1c533 100644 --- a/console/console-src/modules/system/backup/module.ts +++ b/console/console-src/modules/system/backup/module.ts @@ -9,23 +9,24 @@ export default definePlugin({ routes: [ { path: "/backup", + name: "BackupRoot", component: BasicLayout, + meta: { + title: "core.backup.title", + searchable: true, + permissions: ["system:migrations:manage"], + menu: { + name: "core.sidebar.menu.items.backup", + group: "system", + icon: markRaw(IconServerLine), + priority: 4, + }, + }, children: [ { path: "", name: "Backup", component: Backups, - meta: { - title: "core.backup.title", - searchable: true, - permissions: ["system:migrations:manage"], - menu: { - name: "core.sidebar.menu.items.backup", - group: "system", - icon: markRaw(IconServerLine), - priority: 4, - }, - }, }, ], }, diff --git a/console/console-src/modules/system/plugins/module.ts b/console/console-src/modules/system/plugins/module.ts index 69edb7272..2add63468 100644 --- a/console/console-src/modules/system/plugins/module.ts +++ b/console/console-src/modules/system/plugins/module.ts @@ -1,6 +1,5 @@ import { definePlugin } from "@halo-dev/console-shared"; import BasicLayout from "@console/layouts/BasicLayout.vue"; -import BlankLayout from "@console/layouts/BlankLayout.vue"; import PluginList from "./PluginList.vue"; import PluginDetail from "./PluginDetail.vue"; import { IconPlug } from "@halo-dev/components"; @@ -11,44 +10,33 @@ export default definePlugin({ routes: [ { path: "/plugins", - component: BlankLayout, + name: "PluginsRoot", + component: BasicLayout, + meta: { + title: "core.plugin.title", + searchable: true, + permissions: ["system:plugins:view"], + menu: { + name: "core.sidebar.menu.items.plugins", + group: "system", + icon: markRaw(IconPlug), + priority: 0, + }, + }, children: [ { path: "", - component: BasicLayout, - children: [ - { - path: "", - name: "Plugins", - component: PluginList, - meta: { - title: "core.plugin.title", - searchable: true, - permissions: ["system:plugins:view"], - menu: { - name: "core.sidebar.menu.items.plugins", - group: "system", - icon: markRaw(IconPlug), - priority: 0, - }, - }, - }, - ], + name: "Plugins", + component: PluginList, }, { path: ":name", - component: BasicLayout, - children: [ - { - path: "", - name: "PluginDetail", - component: PluginDetail, - meta: { - title: "core.plugin.detail.title", - permissions: ["system:plugins:view"], - }, - }, - ], + name: "PluginDetail", + component: PluginDetail, + meta: { + title: "core.plugin.detail.title", + permissions: ["system:plugins:view"], + }, }, ], }, diff --git a/console/console-src/modules/system/settings/module.ts b/console/console-src/modules/system/settings/module.ts index d9f0c5106..faaee6902 100644 --- a/console/console-src/modules/system/settings/module.ts +++ b/console/console-src/modules/system/settings/module.ts @@ -9,22 +9,23 @@ export default definePlugin({ routes: [ { path: "/settings", + name: "SettingsRoot", component: BasicLayout, + meta: { + title: "core.setting.title", + permissions: ["system:settings:view"], + menu: { + name: "core.sidebar.menu.items.settings", + group: "system", + icon: markRaw(IconSettings), + priority: 2, + }, + }, children: [ { path: "", name: "SystemSetting", component: SystemSettings, - meta: { - title: "core.setting.title", - permissions: ["system:settings:view"], - menu: { - name: "core.sidebar.menu.items.settings", - group: "system", - icon: markRaw(IconSettings), - priority: 2, - }, - }, }, ], }, diff --git a/console/console-src/modules/system/users/module.ts b/console/console-src/modules/system/users/module.ts index 9f260715c..91a5e009a 100644 --- a/console/console-src/modules/system/users/module.ts +++ b/console/console-src/modules/system/users/module.ts @@ -33,24 +33,25 @@ export default definePlugin({ }, { path: "/users", + name: "UsersRoot", component: BasicLayout, + meta: { + title: "core.user.title", + searchable: true, + permissions: ["system:users:view"], + menu: { + name: "core.sidebar.menu.items.users", + group: "system", + icon: markRaw(IconUserSettings), + priority: 1, + mobile: true, + }, + }, children: [ { path: "", name: "Users", component: UserList, - meta: { - title: "core.user.title", - searchable: true, - permissions: ["system:users:view"], - menu: { - name: "core.sidebar.menu.items.users", - group: "system", - icon: markRaw(IconUserSettings), - priority: 1, - mobile: true, - }, - }, }, { path: ":name", diff --git a/console/console-src/setup/setupModules.ts b/console/console-src/setup/setupModules.ts index f85006261..f96c0f883 100644 --- a/console/console-src/setup/setupModules.ts +++ b/console/console-src/setup/setupModules.ts @@ -73,7 +73,14 @@ function registerModule(app: App, pluginModule: PluginModule, core: boolean) { for (const route of pluginModule.routes) { if ("parentName" in route) { - router.addRoute(route.parentName, route.route); + const parentRoute = router + .getRoutes() + .find((item) => item.name === route.parentName); + if (parentRoute) { + router.removeRoute(route.parentName); + parentRoute.children = [...parentRoute.children, route.route]; + router.addRoute(parentRoute); + } } else { router.addRoute(route); } diff --git a/console/env.d.ts b/console/env.d.ts index a2f91d29e..9e640bf66 100644 --- a/console/env.d.ts +++ b/console/env.d.ts @@ -18,8 +18,11 @@ declare module "*.vue" { } declare module "vue-router" { + import type { Component } from "vue"; + interface RouteMeta { title?: string; + description?: string; searchable?: boolean; permissions?: string[]; core?: boolean; diff --git a/console/packages/components/src/components/menu/Menu.stories.ts b/console/packages/components/src/components/menu/Menu.stories.ts index 7cb5a38fb..b5f1ada85 100644 --- a/console/packages/components/src/components/menu/Menu.stories.ts +++ b/console/packages/components/src/components/menu/Menu.stories.ts @@ -6,6 +6,7 @@ import { IconFolder, IconMessage, IconPages, + IconAddCircle, } from "@/icons/icons"; const meta: Meta = { @@ -22,6 +23,7 @@ const meta: Meta = { IconMessage, IconFolder, IconPages, + IconAddCircle, }, setup() { return { @@ -41,6 +43,11 @@ const meta: Meta = { + + +