Skip to content

Conversation

@mynetfan
Copy link
Collaborator

@mynetfan mynetfan commented Feb 26, 2025

Description

添加菜单管理页面演示

Type of change

Please delete options that are not relevant.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update
  • Please, don't make changes to pnpm-lock.yaml unless you introduce a new test example.

Checklist

ℹ️ Check all checkboxes - this will indicate that you have done everything in accordance with the rules in CONTRIBUTING.

  • If you introduce new functionality, document it. You can run documentation with pnpm run docs:dev command.
  • Run the tests with pnpm test.
  • Changes in changelog are generated from PR name. Please, make sure that it explains your changes in an understandable manner. Please, prefix changeset messages with feat:, fix:, perf:, docs:, or chore:.
  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Summary by CodeRabbit

  • New Features

    • Launched an enhanced system menu management interface with interactive grids and forms for creating, updating, and deleting menu items.
    • Added new API endpoints to verify menu names and paths.
    • Expanded localization support with additional key-value pairs for menu management in both English and Chinese.
    • Introduced a new navigational route for easy access to menu management.
    • Added a new constant for menu type options and improved column definitions for table grids.
  • Refactor

    • Improved data handling and error management in table and form components to enhance overall user experience.

@mynetfan mynetfan requested review from a team, anncwb and vince292007 as code owners February 26, 2025 16:28
@changeset-bot
Copy link

changeset-bot bot commented Feb 26, 2025

⚠️ No Changeset found

Latest commit: c074b83

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 26, 2025

Walkthrough

This pull request introduces new API endpoints for menu management, including listing, name existence, and path existence checks with token verification. It also adds a detailed mock menu data structure and updates localization files for both English and Chinese. Additionally, the PR enhances type safety in the form API, refines table adapter data access, adds new routes, and creates comprehensive Vue components for managing system menus through grid views and forms.

Changes

File(s) Change Summary
apps/backend-mock/api/system/menu/list.ts
apps/backend-mock/api/system/menu/name-exists.ts
apps/backend-mock/api/system/menu/path-exists.ts
New API endpoints for menu listing and existence checks that verify access tokens and return appropriate responses.
apps/backend-mock/utils/mock-data.ts New constant MOCK_MENU_LIST added with detailed menu configuration information.
packages/@core/ui-kit/form-ui/src/form-api.ts Updated getValues method to include a generic type parameter and explicit return type casting for enhanced type safety.
packages/locales/src/langs/en-US/common.json
packages/locales/src/langs/en-US/ui.json
packages/locales/src/langs/zh-CN/common.json
packages/locales/src/langs/zh-CN/ui.json
Extended localization files with new keys for affirmative responses and additional form validation messages.
playground/src/adapter/vxe-table.ts Enhanced safe data retrieval in the CellTag renderer by using the get function and nullish coalescing operator.
playground/src/api/system/menu.ts Introduced new SystemMenuApi namespace with types, constants, and asynchronous functions for menu management operations.
playground/src/locales/langs/en-US/system.json
playground/src/locales/langs/zh-CN/system.json
Added a new "menu" section to define properties for comprehensive menu management localization.
playground/src/router/routes/index.ts
playground/src/router/routes/modules/system.ts
Added new routing constant componentKeys and introduced a new SystemMenu route for menu management UI access.
playground/src/views/system/menu/data.ts New functions added to provide menu type options and generate column definitions for the grid view.
playground/src/views/system/menu/list.vue New Vue component that integrates a grid and form drawer for managing system menus with support for various actions.
playground/src/views/system/menu/modules/form.vue New Vue component implementing a form for creating/updating system menus, complete with validation and dynamic behavior.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API
    participant TokenVerifier
    Client->>API: Send request (list, name/path check)
    API->>TokenVerifier: verifyAccessToken(token)
    TokenVerifier-->>API: Return user info / null
    alt Valid Token
      API->>Client: Success response with relevant data
    else Invalid Token
      API->>Client: Unauthorized response
    end
Loading
sequenceDiagram
    participant User
    participant Grid
    participant API
    participant FormDrawer
    User->>Grid: Trigger refresh (onRefresh)
    Grid->>API: getMenuList()
    API-->>Grid: Return menu data
    User->>Grid: Click action (edit/create/append/delete)
    Grid->>FormDrawer: Open form drawer with selected data
    FormDrawer->>API: Submit form data (create/update menu)
    API-->>FormDrawer: Return success
    FormDrawer->>Grid: Trigger grid refresh
Loading

Possibly related PRs

  • chore: demo page for system/department #5611: The changes in the main PR, which introduce a new event handler for a menu list, are related to the retrieved PR as both involve the creation of new event handler functions that utilize the same verifyAccessToken utility and handle unauthorized responses in a similar manner.

Suggested labels

feature

Suggested reviewers

  • vince292007
  • anncwb

Poem

In a world of code, I hop with cheer,
New menus and endpoints have now appeared.
Token checks and mock data, all set in place,
Vue grids and forms light up the interface.
I, a rabbit, skip along with delight,
Celebrating changes in code day and night!
🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4d6ed4 and c074b83.

📒 Files selected for processing (1)
  • apps/backend-mock/api/system/menu/list.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/backend-mock/api/system/menu/list.ts
⏰ Context from checks skipped due to timeout of 90000ms (5)
  • GitHub Check: post-update (windows-latest)
  • GitHub Check: post-update (ubuntu-latest)
  • GitHub Check: Test (windows-latest)
  • GitHub Check: Lint (windows-latest)
  • GitHub Check: Check (windows-latest)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (8)
apps/backend-mock/api/system/menu/path-exists.ts (2)

5-15: Consider improving the path mapping implementation.

The pathMap initialization and population look good, but consider adding a comment explaining the purpose of initializing with '/': 0.


17-28: Improve readability of the path existence logic.

The condition for determining if a path exists is complex and could be more readable.

Consider refactoring like this:

  const { id, path } = getQuery(event);
  
-  return (path as string) in pathMap &&
-    (!id || pathMap[path as string] !== String(id))
-    ? useResponseSuccess(true)
-    : useResponseSuccess(false);
+  // Check if path exists and has a different ID (conflict)
+  const pathExists = (path as string) in pathMap;
+  const isDifferentId = !id || pathMap[path as string] !== String(id);
+  const hasConflict = pathExists && isDifferentId;
+  
+  return useResponseSuccess(hasConflict);
apps/backend-mock/api/system/menu/name-exists.ts (1)

17-28: Secure API endpoint implementation

The endpoint properly verifies access tokens before processing requests and returns appropriate responses. The logic for checking name existence while accounting for ID exclusion is concise and effective.

One thing to note: This API returns true when a name exists (is a duplicate) and should not be used, which might be counterintuitive at first glance. Consider documenting this behavior in comments to make the intention clearer.

+ // Returns true if the name already exists (is a duplicate) and cannot be used
+ // except when it belongs to the same menu item (matching id)
  return (name as string) in namesMap &&
    (!id || namesMap[name as string] !== String(id))
    ? useResponseSuccess(true)
    : useResponseSuccess(false);
playground/src/views/system/menu/data.ts (1)

93-95: Localize the “新增下级” text for consistency.
The text “新增下级” is hardcoded, which might not align with your i18n approach. Converting it into a localized string helps maintain consistency across all locales.

Example fix:

-            text: '新增下级',
+            text: $t('system.menu.appendSubmenu'),

(Assuming you add a corresponding locale entry in your translation files.)

playground/src/views/system/menu/modules/form.vue (1)

50-67: Consider adding fallback/error handling for asynchronous validations.
Your Zod refinements call isMenuNameExists and isMenuPathExists over a network. If these requests fail, the refinement might break unexpectedly. Adding a catch or fallback mechanism can gracefully handle such failures.

playground/src/views/system/menu/list.vue (2)

94-111: Consider adding success loading state handling in the delete operation

While the error case calls hideLoading(), there's no equivalent call in the success path. Even though message.success might implicitly handle this, it would be more explicit to ensure the loading state is properly cleared in all scenarios.

  deleteMenu(row.id)
    .then(() => {
+     hideLoading();
      message.success({
        content: $t('ui.actionMessage.deleteSuccess', [row.name]),
        key: 'action_process_msg',
      });
      onRefresh();
    })

138-138: Remove or utilize the empty div element

This div has styling classes but contains no content. If it's meant to be a placeholder for future content, consider adding a comment. Otherwise, it can be removed to keep the template clean.

-          <div class="items-center justify-end"></div>
playground/src/api/system/menu.ts (1)

26-26: Consider removing the index signature with any type

The index signature [key: string]: any; reduces type safety by allowing any property to be added with any type. This can lead to unexpected runtime errors if incorrect properties are accessed. Consider removing this line and explicitly defining all expected properties.

  export interface SystemMenu {
-    [key: string]: any;
    /** 后端权限标识 */
    authCode: string;
    /** 子级 */
    children?: SystemMenu[];
    // ... other properties
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d8676f and 4cbec9c.

📒 Files selected for processing (18)
  • apps/backend-mock/api/system/menu/list.ts (1 hunks)
  • apps/backend-mock/api/system/menu/name-exists.ts (1 hunks)
  • apps/backend-mock/api/system/menu/path-exists.ts (1 hunks)
  • apps/backend-mock/utils/mock-data.ts (1 hunks)
  • packages/@core/ui-kit/form-ui/src/form-api.ts (1 hunks)
  • packages/locales/src/langs/en-US/common.json (1 hunks)
  • packages/locales/src/langs/en-US/ui.json (1 hunks)
  • packages/locales/src/langs/zh-CN/common.json (1 hunks)
  • packages/locales/src/langs/zh-CN/ui.json (1 hunks)
  • playground/src/adapter/vxe-table.ts (3 hunks)
  • playground/src/api/system/menu.ts (1 hunks)
  • playground/src/locales/langs/en-US/system.json (1 hunks)
  • playground/src/locales/langs/zh-CN/system.json (1 hunks)
  • playground/src/router/routes/index.ts (1 hunks)
  • playground/src/router/routes/modules/system.ts (1 hunks)
  • playground/src/views/system/menu/data.ts (1 hunks)
  • playground/src/views/system/menu/list.vue (1 hunks)
  • playground/src/views/system/menu/modules/form.vue (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Lint (windows-latest)
  • GitHub Check: post-update (windows-latest)
  • GitHub Check: post-update (ubuntu-latest)
🔇 Additional comments (17)
packages/locales/src/langs/zh-CN/common.json (1)

19-21: Localization entries added correctly

The new "yes" and "no" localization keys are properly added with correct Chinese translations, maintaining consistency with the existing entries in the file.

packages/locales/src/langs/en-US/common.json (1)

19-21: Localization entries added correctly

The new "yes" and "no" localization keys are properly added with correct English translations, ensuring language consistency with the Chinese translations added in the zh-CN file.

playground/src/router/routes/modules/system.ts (1)

15-23: Menu management route added properly

The new route for system menu management is correctly implemented with appropriate path, name, icon, and component import. The use of the translation function for the title supports internationalization.

packages/locales/src/langs/zh-CN/ui.json (1)

7-10: LGTM! Form validation messages added correctly.

The new validation messages are properly localized in Chinese and follow the existing pattern with placeholders for dynamic content. These will be useful for the new menu management functionality.

packages/@core/ui-kit/form-ui/src/form-api.ts (1)

96-98: Enhanced type safety for getValues method.

The addition of a generic type parameter to the getValues method is a good improvement that allows consumers to specify the expected return type, providing better type checking and IDE support.

packages/locales/src/langs/en-US/ui.json (1)

7-10: LGTM! Form validation messages added correctly.

The new validation messages are properly formatted in English and match the Chinese translations. They follow the existing pattern with appropriate placeholders for dynamic content.

playground/src/router/routes/index.ts (2)

38-45: Implementation of dynamic component keys for routing

The addition of componentKeys is a good approach for dynamically accessing Vue components in the routing system. It provides a centralized way to reference all available view components without hardcoding paths.


47-47: Updated export statement to include componentKeys

Good addition of the new componentKeys constant to the exports. This makes the component paths accessible to other parts of the application that need to reference these paths.

apps/backend-mock/utils/mock-data.ts (1)

189-379: Well-structured mock menu data

The MOCK_MENU_LIST provides a comprehensive structure for menu items with appropriate nesting and metadata. It includes different types of menu items (menu, catalog, button) and demonstrates various use cases like embedded views and external links.

A few observations:

  • Good use of hierarchical structure with parent-child relationships
  • Proper inclusion of metadata like icons, titles, and ordering
  • Comprehensive representation of different menu states (enabled/disabled)
  • Inclusion of permission codes (authCode) for access control

This mock data will be very useful for the menu management demo page.

playground/src/adapter/vxe-table.ts (3)

8-8: Updated import to include the get utility

Good addition of the get utility function import which will be used for safer property access in the CellTag renderer.


80-81: Enhanced property access safety in CellTag renderer

The changes improve the code in two important ways:

  1. Using get(row, column.field) instead of direct property access ensures safe handling of nested properties
  2. Using the nullish coalescing operator (??) instead of logical OR is more precise, as it only falls back to the default when the value is null or undefined

These changes make the code more robust against potential runtime errors.


90-90: Improved object spread safety for undefined values

Using the nullish coalescing operator with an empty object (tagItem ?? {}) ensures that even if tagItem is undefined, the spread operation will still work correctly without causing runtime errors.

apps/backend-mock/api/system/menu/name-exists.ts (1)

1-16: Well-implemented utility for checking menu name existence

The implementation correctly uses a map data structure to efficiently look up menu names. The recursive getNames function properly traverses the nested menu structure to populate the map.

playground/src/locales/langs/en-US/system.json (1)

13-51: Well-structured internationalization additions for menu management

The new menu section in the localization file is comprehensive and includes all necessary text entries for the menu management functionality. The keys follow a consistent naming pattern and provide thorough coverage of all UI elements mentioned in the PR objectives.

playground/src/views/system/menu/list.vue (1)

26-56: Grid configuration is well-structured for hierarchical menu display

The grid configuration appropriately uses tree configuration with parent-child relationships, which is essential for menu hierarchy visualization. The proxy configuration correctly fetches data using the API and the toolbar is properly configured with custom buttons.

playground/src/api/system/menu.ts (2)

25-90: Well-structured menu interface with comprehensive metadata properties

The SystemMenu interface is thoroughly designed with all the necessary properties for a flexible menu system. The use of type constraints from the constant collections ensures type safety for enum-like values.


124-128: Good use of TypeScript's Omit utility for CRUD operations

The Omit<SystemMenuApi.SystemMenu, 'children' | 'id'> type ensures that the client doesn't send unnecessary or potentially problematic fields like children or id during creation. This is excellent type safety practice.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (6)
playground/src/views/system/menu/modules/form.vue (6)

76-77: Simplify the empty input check.

The condition could be simplified since an empty string will also have length 0.

-        if (!input || input.length === 0) {
+        if (!input) {
           return true;
         }

465-466: Improve optional chaining in titleSuffix assignment.

The code checks for meta?.title but then assumes meta is defined when calling $t(formData.value.meta.title).

-        titleSuffix.value = formData.value.meta?.title
-          ? $t(formData.value.meta.title)
-          : '';
+        titleSuffix.value = formData.value.meta?.title
+          ? $t(formData.value.meta?.title)
+          : '';

493-493: Consider using immutable operations instead of delete.

Mutating the data object by deleting a property can be problematic in reactive environments. Consider using destructuring or spread operators.

-    delete data.linkSrc;
+    const { linkSrc, ...dataWithoutLinkSrc } = data;
+    data = dataWithoutLinkSrc;

174-175: Simplify async/await usage in validation.

The async and await keywords are redundant if isMenuPathExists already returns a Promise.

-      .refine(async (value: string) => {
-        return await isMenuPathExists(value, formData.value?.id);
+      .refine((value: string) => {
+        return isMenuPathExists(value, formData.value?.id);
       }, $t('system.menu.activePathMustExist'))

142-143: Apply the same async/await simplification here.

This is similar to the previous comment about redundant async/await usage.

-      .refine(
-        async (value: string) => {
-          return !(await isMenuPathExists(value, formData.value?.id));
-        },
+      .refine(
+        (value: string) => {
+          return isMenuPathExists(value, formData.value?.id).then(exists => !exists);
+        },

59-60: Apply the same async/await simplification pattern here as well.

This is another instance of redundant async/await usage.

-      .refine(
-        async (value: string) => {
-          return !(await isMenuNameExists(value, formData.value?.id));
-        },
+      .refine(
+        (value: string) => {
+          return isMenuNameExists(value, formData.value?.id).then(exists => !exists);
+        },
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4cbec9c and d4d6ed4.

📒 Files selected for processing (2)
  • playground/src/views/system/menu/data.ts (1 hunks)
  • playground/src/views/system/menu/modules/form.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • playground/src/views/system/menu/data.ts
⏰ Context from checks skipped due to timeout of 90000ms (6)
  • GitHub Check: Test (windows-latest)
  • GitHub Check: Lint (windows-latest)
  • GitHub Check: post-update (windows-latest)
  • GitHub Check: Check (windows-latest)
  • GitHub Check: post-update (ubuntu-latest)
  • GitHub Check: Check (ubuntu-latest)
🔇 Additional comments (6)
playground/src/views/system/menu/modules/form.vue (6)

125-126: Fix the mismatch with 'embedded' vs 'embed'.

This block references data.type === 'embedded' to set data.meta.iframeSrc, but in other parts of your code, you use 'embed'. Align both references to avoid inconsistent or failing logic.

Example fix:

-    } else if (data.type === 'embedded') {
+    } else if (data.type === 'embed') {
       data.meta = { ...data.meta, iframeSrc: data.linkSrc };
     }

Also applies to: 157-159, 187-187, 200-201, 233-234, 248-249, 361-362, 457-458, 488-492


174-176: Verify the condition in activePath validation.

The current implementation checks if the path already exists, but this seems counterintuitive for an input validation. Usually, you would check that a path doesn't exist for a new item.

Make sure this is the intended behavior:

.refine(async (value: string) => {
  return await isMenuPathExists(value, formData.value?.id);
}, $t('system.menu.activePathMustExist'))

1-36: Great organization of imports and component setup.

The imports are well-organized, and the component setup with TypeScript is clean and follows best practices.


37-432: Form schema is comprehensive and well-structured.

The form schema includes all necessary fields for menu management with appropriate validation rules, conditional rendering, and internationalization support.


474-510: Form submission logic properly handles validation, API calls, and error cases.

The form submission function includes proper validation, state management, and error handling with try/finally blocks to ensure loading states are reset even if errors occur.


517-521: Clean and responsive template structure.

The template is clean and uses responsive layout based on screen size via the isHorizontal computed property.

@mynetfan mynetfan merged commit 5e421ce into vbenjs:main Feb 26, 2025
14 checks passed
@mynetfan mynetfan deleted the chore/menu-management branch February 26, 2025 17:22
@github-actions github-actions bot locked and limited conversation to collaborators Mar 29, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant