Skip to content

perf: perf the control logic of Tab #6220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 18, 2025
Merged

perf: perf the control logic of Tab #6220

merged 4 commits into from
May 18, 2025

Conversation

ming4762
Copy link
Contributor

@ming4762 ming4762 commented May 17, 2025

  • 每个标签页Tab使用唯一的key来控制关闭打开等逻辑
  • 统一函数获取tab的key
  • 通过3种方式设置tab key:1、使用router query参数pageKey 2、使用路由meta参数fullPathKey设置使用fullPath或path作为key
  • 单个路由可以打开多个标签页
  • 如果设置fullPathKey为false,则query变更不会打开新的标签(这很实用)

Summary by CodeRabbit

  • New Features

    • Added support for custom tab key assignment, enabling tabs to be uniquely identified by a flexible key derived from route properties or query parameters.
    • Introduced the fullPathKey option in route meta to control tab key behavior.
  • Documentation

    • Enhanced documentation to clarify tab key assignment logic, usage scenarios, and configuration options for tabs and routes.
  • Refactor

    • Standardized tab identification and operations to use keys instead of paths, improving consistency and reliability.
    • Updated tab components and layout logic to utilize the new key-based system.
  • Tests

    • Revised tests to reflect the key-based tab identification and management approach.

ming4762 added 3 commits May 17, 2025 21:57
* 每个标签页Tab使用唯一的key来控制关闭打开等逻辑
* 统一函数获取tab的key
* 通过3种方式设置tab key:1、使用router query参数pageKey 2、使用路由meta参数fullPathKey设置使用fullPath或path作为key
* 单个路由可以打开多个标签页
* 如果设置fullPathKey为false,则query变更不会打开新的标签(这很实用)
@ming4762 ming4762 requested review from anncwb, vince292007, mynetfan, jinmao88 and a team as code owners May 17, 2025 14:04
Copy link

changeset-bot bot commented May 17, 2025

⚠️ No Changeset found

Latest commit: 88843ab

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

Copy link
Contributor

coderabbitai bot commented May 17, 2025

Walkthrough

This update standardizes tab identification and management by introducing a key-based system for tabs, replacing previous path-based logic. It adds a key property to tab definitions, updates type declarations, modifies tab-related store and UI logic to use keys, and enhances documentation to explain the new approach and configuration options.

Changes

File(s) Change Summary
docs/src/guide/essentials/route.md, packages/@core/base/typings/src/vue-router.d.ts Added documentation and type declaration for new fullPathKey?: boolean property in RouteMeta, explaining its effect on tab key derivation and tab management. Added a new section detailing tab key priority and usage scenarios.
packages/@core/base/typings/src/tabs.ts Changed TabDefinition from a type alias to an interface extending RouteLocationNormalized, adding an optional key?: string property.
packages/@core/ui-kit/tabs-ui/src/components/tabs.vue, .../tabs-chrome/tabs.vue Modified computed property tabsView to use the explicit key property from each tab object for tab identification, instead of deriving it from path properties.
packages/effects/layouts/src/basic/content/content.vue Updated all :key bindings to use getTabKey(route) instead of route.fullPath, ensuring consistent key-based identification in component rendering.
packages/effects/layouts/src/basic/tabbar/tabbar.vue Changed tab retrieval in a computed property from getTabByPath to getTabByKey, aligning with the new key-based system.
packages/effects/layouts/src/basic/tabbar/use-tabbar.ts Updated imports and logic to use getTabKey(route) for active tab key, and modified tab navigation and watcher logic to use keys and full paths.
packages/stores/src/modules/tabbar.ts Refactored tab management to use key-based identification throughout: added getTabKey, getTabKeyFromTab, and equalTab functions; updated all tab operations to use keys; renamed and updated relevant methods; ensured TabDefinition includes key.
packages/stores/src/modules/tabbar.test.ts Updated tests to use the new key-based tab identification, including adding key properties, using returned tab instances, and updating method calls to reflect the new API.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Router
    participant TabbarStore
    participant TabsUI

    User->>Router: Navigates to a route (with or without pageKey)
    Router->>TabbarStore: Calls addTab(route)
    TabbarStore->>TabbarStore: getTabKey(route) // Uses pageKey, fullPath, or path
    TabbarStore->>TabbarStore: Assigns key to tab
    TabbarStore-->>TabsUI: Provides tabs with key property
    TabsUI->>TabsUI: Renders tabs using tab.key for identification
    User->>TabsUI: Interacts with tabs (activate, close, etc.)
    TabsUI->>TabbarStore: Performs tab operations using tab.key
Loading

Poem

In fields of keys, the tabs now play,
No longer lost in paths astray.
With fullPathKey or custom flair,
Each tab finds its place with care.
Rabbits hop from tab to tab—
Organized, unique, and oh-so-fab!
🐇✨

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.

✨ Finishing Touches
  • 📝 Generate Docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in 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: 3

🧹 Nitpick comments (4)
packages/stores/src/modules/tabbar.ts (1)

630-641: Guard against missing key when comparing tabs

getTabKeyFromTab silently falls back to getTabKey(tab) when tab.key is falsy.
If a caller passes { key: '' }, the empty string is accepted and will never equal any legitimate tab key, breaking equality checks.

-function getTabKeyFromTab(tab: TabDefinition): string {
-  return tab.key ?? getTabKey(tab);
+function getTabKeyFromTab(tab: TabDefinition): string {
+  return tab.key && tab.key.length > 0 ? tab.key : getTabKey(tab);
 }

A tiny guard prevents subtle logic errors while preserving the optimisation of using the cached key when present.

packages/stores/src/modules/tabbar.test.ts (3)

8-13: Misleading test suite name

The suite is called 'useAccessStore', yet the subject under test is useTabbarStore.
This causes confusion when scanning test reports.

-describe('useAccessStore', () => {
+describe('useTabbarStore', () => {

145-170: Update test description to reflect key-based logic

The case still reads “closes multiple tabs by paths” but now targets _bulkCloseByKeys.
Aligning the description avoids drift between intent and implementation.

-it('closes multiple tabs by paths', async () => {
+it('closes multiple tabs by keys', async () => {

20-32: Redundant manual key in first test

addTab will auto-assign a key when none is provided, so explicitly setting key: '/home' in the fixture is unnecessary and couples the test to implementation details.

While harmless, removing it keeps the test lean:

-      meta: {},
-      key: '/home',
+      meta: {},
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 024c01d and 9388983.

📒 Files selected for processing (10)
  • docs/src/guide/essentials/route.md (3 hunks)
  • packages/@core/base/typings/src/tabs.ts (1 hunks)
  • packages/@core/base/typings/src/vue-router.d.ts (1 hunks)
  • packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue (1 hunks)
  • packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue (1 hunks)
  • packages/effects/layouts/src/basic/content/content.vue (3 hunks)
  • packages/effects/layouts/src/basic/tabbar/tabbar.vue (1 hunks)
  • packages/effects/layouts/src/basic/tabbar/use-tabbar.ts (4 hunks)
  • packages/stores/src/modules/tabbar.test.ts (8 hunks)
  • packages/stores/src/modules/tabbar.ts (14 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (3)
packages/effects/layouts/src/basic/tabbar/use-tabbar.ts (1)
packages/stores/src/modules/tabbar.ts (1)
  • getTabKey (652-652)
packages/stores/src/modules/tabbar.test.ts (1)
packages/stores/src/modules/tabbar.ts (1)
  • useTabbarStore (55-553)
packages/stores/src/modules/tabbar.ts (1)
packages/@core/base/typings/src/tabs.ts (1)
  • TabDefinition (3-8)
⏰ Context from checks skipped due to timeout of 90000ms (7)
  • GitHub Check: Check (windows-latest)
  • GitHub Check: Test (windows-latest)
  • GitHub Check: Lint (ubuntu-latest)
  • GitHub Check: Lint (windows-latest)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: post-update (ubuntu-latest)
  • GitHub Check: post-update (windows-latest)
🔇 Additional comments (15)
packages/@core/base/typings/src/vue-router.d.ts (1)

46-49: Well-structured addition of the fullPathKey property

The addition of the fullPathKey boolean property to the RouteMeta interface is well-documented with clear comments. This property enables controlling whether a route's full path should be used as the key for tab identification, which is essential for the new key-based tab management system.

packages/effects/layouts/src/basic/tabbar/tabbar.vue (1)

33-33: Updated to use key-based tab retrieval method

The change from path-based to key-based tab retrieval (getTabByKey instead of what was likely getTabByPath) aligns with the PR's objective of using unique keys for tab operations. This makes tab management more consistent and flexible.

packages/@core/ui-kit/tabs-ui/src/components/tabs/tabs.vue (2)

50-51: Properly destructures the key property from tab object

The updated code now correctly destructures the key property along with other properties from the tab object, supporting the new key-based tab identification system.


57-57: Correctly uses the tab key for identification

The tab's key property is now directly assigned to the returned object instead of deriving it from paths, ensuring consistent tab identification throughout the application.

packages/@core/base/typings/src/tabs.ts (1)

3-8: Clear definition of the TabDefinition interface with key property

The change from a type alias to an interface that extends RouteLocationNormalized is appropriate. The addition of the key property is well-documented and provides the foundation for the key-based tab management system described in the PR objectives.

This change enables:

  1. Unique identification of tabs using keys instead of paths
  2. More flexible tab management with multiple tabs for a single route
  3. Consistent tab operations (opening/closing) based on keys
packages/@core/ui-kit/tabs-ui/src/components/tabs-chrome/tabs.vue (1)

43-43: Updated tab property extraction to support key-based identification

The code now explicitly destructures and uses the key property from each tab, which aligns with the PR objective of using unique keys for tab management.

Also applies to: 50-50

packages/effects/layouts/src/basic/content/content.vue (2)

12-12: Added import for getTabKey function

The import now includes the getTabKey function from the tabbar store, which will be used for consistent tab key generation.


118-118: Standardized component keys using getTabKey function

The component keys are now consistently derived using the getTabKey(route) function instead of directly using route.fullPath. This ensures that the component caching in <KeepAlive> works correctly with the new tab key system.

Also applies to: 124-124, 137-137, 143-143

packages/effects/layouts/src/basic/tabbar/use-tabbar.ts (4)

25-25: Added import for getTabKey function

The import statement now includes the getTabKey function from the tabbar store, supporting the unified approach to tab key management.


47-52: Updated tab key computation to use getTabKey

The computed property currentActive now correctly uses the getTabKey(route) function to determine the current active tab's key.


79-81: Enhanced tab click handler to support key-based navigation

The handleClick function now retrieves the tab object by key first, then navigates to the appropriate path. This is crucial for the key-based tab system to work correctly, especially when a single route can open multiple tabs.


107-107: Updated route watcher to track fullPath instead of path

The watcher now tracks route.fullPath which provides more accurate tab management, especially when dealing with query parameters.

docs/src/guide/essentials/route.md (3)

343-345: Added documentation for the new fullPathKey property

The RouteMeta interface documentation now includes the fullPathKey property, which controls whether the route's full path is used as the tab key.


509-515: Added detailed documentation for the fullPathKey property

This section provides clear documentation for the fullPathKey property, explaining its type, default value, and purpose. This information is essential for developers to understand how tab keys are generated and controlled.


617-644: Added comprehensive documentation for Tab and Route Control

This new section excellently documents the three ways to set tab keys (query parameter pageKey, fullPath, or path) and their priority order. It includes a practical example of using the pageKey query parameter to create unique tabs, which directly addresses the PR objective of allowing a single route to open multiple tabs.

* 解决AI提示的警告
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 (1)
packages/stores/src/modules/tabbar.ts (1)

320-329: Consider consolidating tab update logic

Both pinTab and unpinTab have repetitive code where they:

  1. Find a tab by key
  2. Check if it exists
  3. Update its properties
  4. Splice it back into the array

This pattern appears in multiple places. Consider creating a helper function to reduce duplication.

+ /**
+  * Helper to update a tab in place
+  * @param tab The tab to update
+  * @param updates Function that applies updates to the tab
+  * @returns Whether the tab was found and updated
+  */
+ function updateTab(tab: TabDefinition, updates: (oldTab: TabDefinition) => void): boolean {
+   const index = this.tabs.findIndex((item) => equalTab(item, tab));
+   if (index === -1) {
+     return false;
+   }
+   const oldTab = this.tabs[index];
+   updates(tab);
+   tab.meta.title = oldTab?.meta?.title as string;
+   this.tabs.splice(index, 1, tab);
+   return true;
+ }

Also applies to: 463-472

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between 9388983 and 88843ab.

📒 Files selected for processing (1)
  • packages/stores/src/modules/tabbar.ts (13 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
packages/stores/src/modules/tabbar.ts (1)
packages/@core/base/typings/src/tabs.ts (1)
  • TabDefinition (3-8)
⏰ Context from checks skipped due to timeout of 90000ms (8)
  • GitHub Check: Check (windows-latest)
  • GitHub Check: Test (windows-latest)
  • GitHub Check: Lint (ubuntu-latest)
  • GitHub Check: Check (ubuntu-latest)
  • GitHub Check: Lint (windows-latest)
  • GitHub Check: Analyze (javascript-typescript)
  • GitHub Check: post-update (ubuntu-latest)
  • GitHub Check: post-update (windows-latest)
🔇 Additional comments (9)
packages/stores/src/modules/tabbar.ts (9)

60-66: Good fix for the async function

You've properly added await before updateCacheTabs(), resolving the issue where the async function wasn't awaiting the promise. This prevents potential race conditions.


109-113: Key assignment handled properly

Good implementation of key assignment for tabs. The function now ensures that every tab has a key property by falling back to getTabKey when needed.


165-169: Fixed the stale reference issue

You've correctly addressed the previous issue where addTab was returning a stale clone. Now the method properly returns the actual tab instance that's stored in the tabs array.


206-224: Consistent key-based approach for closeOtherTabs

The logic for closing other tabs has been properly rewritten to use keys instead of paths, making it consistent with the overall approach.


607-629: Robust key extraction implementation

The getTabKey function addresses the earlier issues by:

  1. Handling array-type query parameters
  2. Using a fallback path when fullPath is missing
  3. Safely decoding URIs with proper error handling

This is a well-implemented fix for the potential issues raised in previous reviews.


636-638: Clean abstraction of key extraction

This helper function provides a good abstraction for getting a key from a tab, with proper fallback to getTabKey if no explicit key exists.


645-647: Simple and effective tab comparison

The equalTab function provides a clean way to compare tabs by their keys, which is more robust than comparing by paths or other properties.


654-654: Ensure consistent key generation

The routeToTab function now properly assigns a key to the returned tab object, ensuring consistency with the new key-based approach.


658-658: Good export of the utility function

Exporting getTabKey makes this utility available to other components that need to generate consistent keys, supporting the new key-based tab management system.

@jinmao88 jinmao88 merged commit 3d9dba9 into vbenjs:main May 18, 2025
14 checks passed
@ming4762 ming4762 deleted the 20250517 branch May 18, 2025 08:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants