Skip to content
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

feat: TreeSelect support maxCount #596

Merged
merged 38 commits into from
Dec 3, 2024

Conversation

aojunhao123
Copy link
Contributor

@aojunhao123 aojunhao123 commented Nov 9, 2024

Add maxCount support for TreeSelect

Related Issue

Screen Shot

maxCount

Description

Added maxCount property support to limit the maximum number of selectable items in TreeSelect component's multiple mode. When the selected count reaches maxCount, other unselected options will be disabled.

Main updates include:

  • Added maxCount property support in TreeSelect component
  • Implemented option disabling logic in OptionList
  • Added related unit test cases

API

interface TreeSelectProps {
   maxCount?: number;
}

Usage Example

<TreeSelect
  multiple
  maxCount={2}
  treeData={[
    { key: '0', value: '0', title: '0 label' },
    { key: '1', value: '1', title: '1 label' },
    { key: '2', value: '2', title: '2 label' },
  ]}
/>

Features

  • Support limiting maximum selectable items in multiple mode
  • Automatically disable unselected options when reaching maximum count
  • Allow deselecting selected options even when maximum count is reached
  • Keyboard operations also follow the maximum count limit

Test Coverage

  • Added tests/Select.maxCount.spec.tsx test file
  • Test cases cover the following scenarios:
    • Basic maximum count limit functionality
    • Option disable/enable state switching
    • Deselection behavior
    • Keyboard operation restrictions
    • Behavior when maxCount is 0
    • Behavior when maxCount is greater than total options

Breaking Changes

None

Notes

  • maxCount property only works in multiple mode
  • Setting maxCount to 0 will disable all options
  • No restrictions will be applied when maxCount is greater than total number of options

Summary by CodeRabbit

更新后的版本

  • 新功能

    • TreeSelect 组件中添加了 maxCount 属性,以限制可选择的最大项数。
    • 新增文档文件 mutiple-with-maxCount.md,提供关于 maxCount 功能的示例和说明。
  • 文档

    • 更新了 README.md,增强了 API 文档的可读性,添加了 maxCount 属性的说明,并明确了其他属性的描述。
    • 优化了优化提示部分的格式,提高了可读性。
  • 测试

    • 新增测试文件 Select.maxCount.spec.tsx,覆盖 TreeSelect 组件的 maxCount 功能,确保选择限制的正确性。
    • 扩展了现有测试,确保组件在多选和搜索输入情况下的行为符合预期。

Copy link

vercel bot commented Nov 9, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
tree-select ✅ Ready (Inspect) Visit Preview 💬 Add feedback Dec 3, 2024 6:24am

Copy link

coderabbitai bot commented Nov 9, 2024

Walkthrough

此拉取请求主要对 rc-tree-select 组件的文档进行了更新,特别是 README.md 文件,增强了 TreeSelect 和 TreeNode 属性的 API 文档。新增了 maxCount 属性以限制多选模式下的最大选择项数,并对相关属性的描述进行了澄清和重新格式化。此外,新增了一个示例文件 mutiple-with-maxCount.md,展示了该功能的使用。还对 OptionListTreeSelect 组件进行了逻辑修改,以支持 maxCount 功能,并新增了相应的单元测试。

Changes

文件路径 变更摘要
README.md 增加 maxCount 属性,更新 treeExpandAction 描述,重新格式化属性表格,澄清 dropdownMatchSelectWidth 描述。
docs/demo/mutiple-with-maxCount.md 新增文件,包含演示 maxCount 功能的代码块。
examples/mutiple-with-maxCount.tsx 新增 React 组件,展示 TreeSelect 的多选功能和最大选择限制。
src/OptionList.tsx 修改选择逻辑以支持 maxCount,更新 onActiveChange 方法。
src/TreeSelect.tsx TreeSelectProps 接口中新增 maxCount 属性,更新选择逻辑以包含 maxCount 检查。
src/TreeSelectContext.ts TreeSelectContextProps 接口中新增 displayValuesisOverMaxCount 属性。
tests/Select.maxCount.spec.tsx 新增单元测试,验证 TreeSelect 组件的 maxCount 功能。
tests/Select.multiple.spec.js 更新测试用例,改进可读性,扩展对多选功能的测试。
tests/util.tsx 新增 keyDownkeyUp 函数以模拟键盘事件。
tests/Select.SearchInput.spec.js 增强 TreeSelect.SearchInput 组件的测试,覆盖更多边缘情况。

Assessment against linked issues

Objective Addressed Explanation
增加 maxCount 属性控制最大选择数量 (#51490)

Possibly related PRs

Suggested reviewers

  • zombieJ

🐇 在树间跳跃,选择如风,
最大数量,轻松掌控。
文档更新,清晰可见,
代码示例,助你前行。
兔子祝你,快乐无穷! 🌟


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 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

codecov bot commented Nov 11, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 100.00%. Comparing base (c3bf3cb) to head (4c23314).
Report is 1 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff            @@
##            master      #596   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           16        16           
  Lines          546       561   +15     
  Branches       162       169    +7     
=========================================
+ Hits           546       561   +15     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@aojunhao123 aojunhao123 marked this pull request as ready for review November 11, 2024 11:39
@aojunhao123 aojunhao123 changed the title [WIP] feat: TreeSelect support maxCount feat: TreeSelect support maxCount Nov 11, 2024
Copy link

@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: 5

🧹 Outside diff range and nitpick comments (18)
tests/util.tsx (1)

13-16: 建议重构键盘事件处理函数

当前的 keyUp 函数实现与 keyDown 非常相似,建议提取共同逻辑以减少代码重复。

建议重构为:

+type KeyEventType = 'keyDown' | 'keyUp';
+
+function createKeyboardEvent(
+  element: HTMLElement,
+  key: string,
+  eventType: KeyEventType
+) {
+  const event = createEvent[eventType](element, { key });
+  fireEvent(element, event);
+}
+
-export function keyDown(element: HTMLElement, keyCode: number) {
-  const event = createEvent.keyDown(element, { keyCode });
-  fireEvent(element, event);
+export function keyDown(element: HTMLElement, key: string) {
+  createKeyboardEvent(element, key, 'keyDown');
 }
 
-export function keyUp(element: HTMLElement, keyCode: number) {
-  const event = createEvent.keyUp(element, { keyCode });
-  fireEvent(element, event);
+export function keyUp(element: HTMLElement, key: string) {
+  createKeyboardEvent(element, key, 'keyUp');
 }
src/TreeSelectContext.ts (1)

17-17: 建议添加 JSDoc 注释说明属性用途

为了提高代码可维护性和开发体验,建议为 maxCount 属性添加 JSDoc 注释,说明其用途和使用场景。

建议添加如下注释:

+  /** 多选模式下用户最多可以选择的节点数量 */
   maxCount?: number;
src/utils/valueUtil.ts (1)

39-40: 函数实现正确但缺少文档说明

函数实现简洁且符合逻辑,但建议添加 JSDoc 文档说明函数的用途、参数和返回值。

建议添加如下文档:

+/**
+ * 检查给定的数值是否有效(已定义且不是 NaN)
+ * @param value - 要检查的数值
+ * @returns 如果数值有效则返回 true,否则返回 false
+ */
 export const isValidCount = (value?: number) =>
   typeof value !== 'undefined' && !Number.isNaN(value);
examples/mutiple-with-maxCount.tsx (5)

1-5: 文件名称中存在拼写错误

文件名 mutiple-with-maxCount.tsx 中的 "mutiple" 应该改为 "multiple"。这个拼写错误可能会影响示例文档的可发现性。


7-35: 建议优化示例数据的可读性

当前的示例数据中,标题使用了简单的数字(如 "1","2","3"),建议使用更具描述性的标题来提高示例的可读性和教学价值。

建议修改如下:

 const treeData = [
   {
     key: '1',
     value: '1',
-    title: '1',
+    title: '父节点 1',
     children: [
       {
         key: '1-1',
         value: '1-1',
-        title: '1-1',
+        title: '子节点 1-1',
       },
     ],
   },
   {
     key: '2',
     value: '2',
-    title: '2',
+    title: '节点 2',
   },
   // ... 其他节点类似修改
 ];

37-39: 建议添加值的验证逻辑

当前的 onChange 处理函数直接设置状态,建议添加值的验证逻辑以确保数据的正确性。

建议修改如下:

 const onChange = (val: string[]) => {
+  if (!Array.isArray(val)) {
+    console.warn('预期接收数组类型的值');
+    return;
+  }
   setValue(val);
 };

44-51: 移除或说明注释掉的代码

第一个 TreeSelect 示例中包含注释掉的 onChangevalue 属性。如果这是有意为之,建议添加注释说明原因;如果不是,建议删除这些注释掉的代码。


41-74: 优化示例代码的结构和可读性

建议进行以下改进:

  1. 为每个 TreeSelect 示例添加注释,说明其配置的特点和用途
  2. 统一示例之间的间距
  3. 将重复的样式提取为常量

建议修改如下:

+const treeSelectStyle = { width: 300 };
+
 return (
   <>
     <h2>multiple with maxCount</h2>
+    {/* 基础多选示例:最多选择3项 */}
     <TreeSelect
-      style={{ width: 300 }}
+      style={treeSelectStyle}
       multiple
       maxCount={3}
       treeData={treeData}
     />
 
     <h2>checkable with maxCount</h2>
+    {/* 可勾选多选示例:最多选择3项,严格勾选模式 */}
     <TreeSelect
-      style={{ width: 300 }}
+      style={treeSelectStyle}
       multiple
       treeCheckable
       treeCheckStrictly
       maxCount={3}
       treeData={treeData}
       onChange={onChange}
       value={value}
     />
 
+    {/* 简单数据示例:最多选择2项 */}
     <TreeSelect
-      style={{ width: 300 }}
+      style={treeSelectStyle}
       treeData={[
         { key: '0', value: '0', title: '0 label' },
         { key: '1', value: '1', title: '1 label' },
         { key: '2', value: '2', title: '2 label' },
       ]}
       multiple
       maxCount={2}
     />
   </>
 );
tests/Select.maxCount.spec.tsx (3)

15-17: 建议改进 renderTreeSelect 函数的类型定义

为了提高代码的可维护性和类型安全性,建议添加适当的类型定义。

-  const renderTreeSelect = (props?: any) => {
+  const renderTreeSelect = (props?: Partial<TreeSelectProps>) => {

26-106: 建议添加初始渲染时的预选值测试用例

当前的测试用例已经很全面,但建议添加一个测试用例来验证组件初始化时带有预选值的情况。这对于确保组件在所有场景下都能正确处理 maxCount 限制很重要。

it('should handle pre-selected values correctly', () => {
  const { container } = renderTreeSelect({
    value: ['0', '1'],
    maxCount: 2
  });
  
  const dropdownList = container.querySelector('.rc-tree-select-dropdown');
  const option3 = within(dropdownList).getByText('2 label');
  
  expect(option3.closest('div')).toHaveClass('rc-tree-select-tree-treenode-disabled');
});

107-157: 建议补充键盘取消选择的测试用例

键盘操作的测试覆盖了选择操作,但缺少使用键盘取消选择的测试用例。建议添加相关测试以确保完整的键盘操作支持。

it('should allow keyboard deselection when maxCount is reached', () => {
  const { container } = render(
    <TreeSelect
      treeData={treeData}
      multiple
      open
      maxCount={2}
      value={['0', '1']}
    />
  );

  const input = container.querySelector('input');
  
  // 模拟键盘取消选择第一个选项
  keyDown(input, KeyCode.BACKSPACE);
  
  // 验证第三个选项是否变为可选状态
  expect(container.querySelector('.rc-tree-select-tree-treenode-disabled')).toBeFalsy();
});
tests/Select.multiple.spec.js (2)

2-2: 新增测试工具导入需要更新相关测试用例

新增了 fireEventwithin 测试工具的导入,但现有测试用例仍在使用 simulate。建议统一使用 @testing-library 提供的事件触发方式。

-wrapper.simulate('keyDown', { which: KeyCode.BACKSPACE });
+fireEvent.keyDown(wrapper.getByRole('textbox'), { key: 'Backspace', keyCode: KeyCode.BACKSPACE });

35-38: 代码格式调整建议

链式调用的格式调整提高了可读性,但建议在整个测试文件中保持一致的格式。目前只有部分代码块进行了调整。

建议统一所有类似的链式调用格式:

-wrapper.find('input').first().simulate('keyDown', ...);
+wrapper
+  .find('input')
+  .first()
+  .simulate('keyDown', ...);

Also applies to: 65-73

src/TreeSelect.tsx (1)

75-75: 需要为新属性添加JSDoc文档注释

请为maxCount属性添加JSDoc文档注释,说明其用途、类型和示例用法。这将帮助其他开发者更好地理解和使用这个新功能。

+ /** 
+  * 限制多选模式下最多可选中的节点数量
+  * @default undefined
+  */
  maxCount?: number;
README.md (3)

64-64: 文档描述中的语法问题需要修正

以下几处描述需要改进:

  1. dropdownMatchSelectWidth 属性描述中的 "with" 应为 "width"
  2. treeData 描述中的语法不通顺
  3. key 属性描述中的 "it's" 应为 "its"

建议修改如下:

- whether dropdown's with is same with select
+ whether dropdown's width is same as select

- treeNodes data Array, if set it then you need not to construct children TreeNode
+ treeNodes data array. If set, you don't need to construct children TreeNode

- it's value must be unique
+ its value must be unique

Also applies to: 97-97, 116-116


111-119: 建议优化 TreeNode props 部分的提示样式

为了提高可读性,建议将使用 treeData 的提示更加醒目。

-> note: you'd better to use `treeData` instead of using TreeNode.
+> **注意:** 推荐使用 `treeData` 属性而不是 TreeNode 方式。
🧰 Tools
🪛 LanguageTool

[grammar] ~116-~116: Did you mean to use the possessive pronoun “its”?
Context: ...bool | false | | key | it's value must be unique across the tree's ...

(IT_S_ITS)


122-126: 建议改进性能优化建议部分的格式

性能优化建议部分的格式可以更加规范,同时建议补充与新增 maxCount 功能相关的性能考虑。

建议调整格式如下:

- 1. Optimization tips(when there are large amounts of data, like more than 5000 nodes)
-    - Do not Expand all nodes.
-    - Recommend not exist many `TreeSelect` components in a page at the same time.
-    - Recommend not use `treeCheckable` mode, or use `treeCheckStrictly`.

+ ## 性能优化建议
+ 
+ 当数据量较大时(如超过 5000 个节点),请注意以下几点:
+ 
+ 1. 避免展开所有节点
+ 2. 避免在同一页面中同时使用多个 TreeSelect 组件
+ 3. 避免使用 `treeCheckable` 模式,或使用 `treeCheckStrictly` 模式
+ 4. 使用 `maxCount` 时建议设置合理的限制值,过大的显示数量可能影响性能
🧰 Tools
🪛 LanguageTool

[uncategorized] ~125-~125: The preposition “on” seems more likely in this position than the preposition “in”.
Context: ... not exist many TreeSelect components in a page at the same time. - Recommend...

(AI_EN_LECTOR_REPLACEMENT_PREPOSITION_IN_ON)

src/OptionList.tsx (1)

85-91: 考虑优化 traverse 函数的性能

递归遍历整个树以设置节点的 disabled 状态,可能在大型数据集上导致性能问题。建议对树数据进行缓存或优化,提升性能。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between a16f0f0 and cc3b839.

📒 Files selected for processing (10)
  • README.md (2 hunks)
  • docs/demo/mutiple-with-maxCount.md (1 hunks)
  • examples/mutiple-with-maxCount.tsx (1 hunks)
  • src/OptionList.tsx (7 hunks)
  • src/TreeSelect.tsx (5 hunks)
  • src/TreeSelectContext.ts (1 hunks)
  • src/utils/valueUtil.ts (1 hunks)
  • tests/Select.maxCount.spec.tsx (1 hunks)
  • tests/Select.multiple.spec.js (4 hunks)
  • tests/util.tsx (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • docs/demo/mutiple-with-maxCount.md
🧰 Additional context used
🪛 LanguageTool
README.md

[uncategorized] ~85-~85: This verb does not appear to agree with the subject. Consider using a different form.
Context: ...ust show parent treeNode). Default just show child. | enum{TreeSelect.SHOW_ALL, Tree...

(AI_EN_LECTOR_REPLACEMENT_VERB_AGREEMENT)


[typographical] ~97-~97: Consider adding a comma.
Context: ... | treeNodes data Array, if set it then you need not to construct children Tree...

(IF_THEN_COMMA)


[grammar] ~97-~97: Did you mean “construct”?
Context: ...data Array, if set it then you need not to construct children TreeNode. (value should be uni...

(NEEDNT_TO_DO_AND_DONT_NEED_DO)


[uncategorized] ~102-~102: It appears that a hyphen is missing (if ‘auto’ is not used in the context of ‘cars’).
Context: ...t.body;} | | autoClearSearchValue | auto clear search input value when multiple select...

(AUTO_HYPHEN)


[grammar] ~116-~116: Did you mean to use the possessive pronoun “its”?
Context: ...bool | false | | key | it's value must be unique across the tree's ...

(IT_S_ITS)


[uncategorized] ~125-~125: The preposition “on” seems more likely in this position than the preposition “in”.
Context: ... not exist many TreeSelect components in a page at the same time. - Recommend...

(AI_EN_LECTOR_REPLACEMENT_PREPOSITION_IN_ON)

🪛 Markdownlint
README.md

99-99: Expected: 4; Actual: 3; Too few cells, row will be missing data
Table column count

(MD056, table-column-count)

🔇 Additional comments (14)
tests/util.tsx (2)

1-1: 导入语句看起来不错!

导入了必要的 createEvent 函数用于创建键盘事件,同时保持了原有的 fireEvent 导入。


8-16: 请确保新增函数的测试覆盖率

建议验证这些新增的键盘事件模拟函数是否有充分的测试覆盖。

✅ Verification successful

键盘事件函数已得到充分测试覆盖

keyDownkeyUp 函数在多个测试文件中都有使用,包括:

  • Select.maxCount.spec.tsx 中用于测试按键选择和最大选择数量限制
  • Select.spec.tsx 中用于测试键盘导航和选择功能
  • Select.SearchInput.spec.js 中用于测试搜索输入的键盘交互
  • Select.multiple.spec.js 中用于测试多选模式的键盘操作

这些测试涵盖了各种键盘事件场景,包括 Enter、ESC、上下键导航、退格键等,测试覆盖率充分。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:检查键盘事件相关的测试用例

# 搜索使用这些函数的测试文件
echo "检查 keyDown 和 keyUp 函数的使用情况:"
rg -l "keyDown|keyUp" "tests/**/*.(test|spec).(ts|tsx|js|jsx)"

Length of output: 208


Script:

#!/bin/bash
# 检查测试文件的位置
echo "查找所有测试文件:"
fd -e test.tsx -e test.ts -e test.jsx -e test.js -e spec.tsx -e spec.ts -e spec.jsx -e spec.js

echo -e "\n检查 keyDown 和 keyUp 函数的使用情况:"
rg "keyDown|keyUp" -l

Length of output: 746


Script:

#!/bin/bash
# 检查 keyDown 和 keyUp 函数的具体使用情况
echo "在测试文件中查找 keyDown 和 keyUp 函数的使用:"
rg "keyDown|keyUp" tests/Select.maxCount.spec.tsx tests/Select.multiple.spec.js tests/Select.spec.tsx tests/Select.SearchInput.spec.js -B 2 -A 2

Length of output: 7868

src/TreeSelectContext.ts (1)

17-17: 代码变更看起来不错!

maxCount 属性的添加符合需求,类型定义正确,且保持了可选特性。这与 Select 组件中的实现保持一致。

src/utils/valueUtil.ts (1)

39-40: 建议验证函数的测试覆盖情况

作为 maxCount 功能的关键验证函数,建议确保测试用例完整覆盖各种边界情况。

运行以下脚本检查测试覆盖:

✅ Verification successful

Let me gather more information about the test coverage and usage patterns.


Let me check one more aspect to see if there are any integration tests or related test files in the test directory.


Let me check the test directory content for any relevant tests.


测试覆盖情况已得到验证,无需担心

isValidCount 函数虽然没有直接的单元测试,但在 tests/Select.maxCount.spec.tsx 中有完整的集成测试覆盖:

  • 测试了当选择达到 maxCount 限制时的行为
  • 验证了 maxCount 为 0 时的情况
  • 验证了 maxCount 大于选项数量时的情况
  • 包含了键盘操作相关的测试场景

这些测试用例充分验证了 isValidCount 函数在各种边界情况下的正确性。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:检查 isValidCount 函数的测试覆盖情况

# 搜索测试文件中对 isValidCount 的测试
rg -l "isValidCount" --glob "**/*.test.{ts,tsx}"

# 检查实际使用情况
rg "isValidCount" --type ts

Length of output: 493


Script:

#!/bin/bash
# 检查 OptionList.tsx 中的具体使用场景
rg -B 5 -A 5 "isValidCount" src/OptionList.tsx

# 检查是否存在其他相关的测试文件
fd "option.*test\.(ts|tsx)$"

# 检查 valueUtil.ts 的测试文件
fd "valueUtil.*test\.(ts|tsx)$"

# 查看 OptionList 组件的测试文件
fd "OptionList.*test\.(ts|tsx)$"

Length of output: 886


Script:

#!/bin/bash
# 搜索所有测试文件中可能包含 maxCount 相关测试的内容
rg -B 3 -A 3 "maxCount" "**/*.test.{ts,tsx}"

# 检查是否存在专门的测试目录
fd -t d "tests?"

# 检查 __tests__ 目录下的文件
fd . -t f "__tests__"

Length of output: 248


Script:

#!/bin/bash
# 检查 tests 目录下的所有测试文件
fd . tests/

# 在 tests 目录中搜索与 maxCount 或 isValidCount 相关的测试
rg -B 3 -A 3 "maxCount|isValidCount" tests/

# 检查 Select.test 相关文件
fd "Select.*test" tests/

Length of output: 6630

tests/Select.maxCount.spec.tsx (2)

1-6: 测试工具选择恰当!

使用 @testing-library/react 作为测试工具是个很好的选择,它提供了模拟用户行为的优秀 API。导入的依赖项都是必要的,没有多余导入。


1-157: 测试文件整体评估:代码质量优秀!

整体测试覆盖率很好,包含了:

  • 基础功能测试
  • 边界条件测试
  • 键盘操作测试
  • 事件处理测试

代码结构清晰,测试用例设计合理,符合测试最佳实践。

src/TreeSelect.tsx (1)

563-563: ⚠️ Potential issue

验证maxCount在选择逻辑中的实现

maxCount已被添加到依赖数组中,但在onOptionSelect函数中似乎缺少相关的选择限制逻辑。需要确保在达到最大选择数量时,正确处理用户的选择操作。

Also applies to: 615-615, 629-629

src/OptionList.tsx (7)

12-12: 正确导入新工具函数 isValidCount

导入了 isValidCount 函数,确保了对 maxCount 值的有效性验证。


48-48: maxCount 添加到上下文

TreeSelectContext 中解构出 maxCount,以便在组件中使用该属性。


80-83: 正确计算 isOverMaxCount 的值

使用 useMemo 计算 isOverMaxCount,逻辑清晰,依赖项合理。


93-97: 正确地生成 processedTreeData

使用 useMemo 对处理后的树数据进行缓存,确保数据在依赖项变化时更新。


207-213: 验证 onActiveChange 中的条件

当超过最大选择数量且当前节点未被选中时,onActiveChange 将不更新 activeKey。请确认此行为符合预期,并考虑在界面上给予用户反馈。


310-310: 更新 Tree 组件的 treeData

treeData 属性更新为 processedTreeData,以应用节点的禁用状态。


332-332: 添加自定义的 onActiveChange 处理函数

onActiveChange 函数传递给 Tree 组件,控制激活节点的更新逻辑。

Comment on lines +8 to +11
export function keyDown(element: HTMLElement, keyCode: number) {
const event = createEvent.keyDown(element, { keyCode });
fireEvent(element, event);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

建议改进键盘事件的实现

当前实现使用了已废弃的 keyCode 属性,建议使用现代的 keycode 属性来提高代码的可维护性。

建议按照以下方式修改:

-export function keyDown(element: HTMLElement, keyCode: number) {
-  const event = createEvent.keyDown(element, { keyCode });
+export function keyDown(element: HTMLElement, key: string) {
+  const event = createEvent.keyDown(element, { key });
   fireEvent(element, event);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function keyDown(element: HTMLElement, keyCode: number) {
const event = createEvent.keyDown(element, { keyCode });
fireEvent(element, event);
}
export function keyDown(element: HTMLElement, key: string) {
const event = createEvent.keyDown(element, { key });
fireEvent(element, event);
}

tests/Select.multiple.spec.js Show resolved Hide resolved
src/TreeSelect.tsx Show resolved Hide resolved
README.md Outdated Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
Copy link

@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

🧹 Outside diff range and nitpick comments (1)
tests/Select.SearchInput.spec.js (1)

224-224: 键盘事件处理需要同时测试 keyUp

为了更完整地模拟键盘交互,在测试 Enter 键选择时添加了 keyUp 事件。这样的改进使测试更接近真实用户的交互场景。

建议在其他键盘事件测试用例中也添加相应的 keyUp 事件测试,以保持一致性。

Also applies to: 231-231

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 5039213 and 15472c5.

📒 Files selected for processing (2)
  • tests/Select.SearchInput.spec.js (1 hunks)
  • tests/Select.maxCount.spec.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/Select.maxCount.spec.tsx
🔇 Additional comments (1)
tests/Select.SearchInput.spec.js (1)

234-239: 完善了选择第三个选项的测试用例

通过添加对第三个选项的测试,提高了测试覆盖率。这个测试用例验证了在有多个选项时,Enter 键仍然能够正确选择匹配的非禁用节点。

运行以下脚本检查是否还有其他未覆盖的选择场景:

✅ Verification successful

Let me analyze the test coverage based on the results. I can see comprehensive test coverage for selection scenarios including:

  1. Search and select functionality
  2. Multiple selection scenarios
  3. Keyboard navigation (UP/DOWN/ENTER)
  4. Max count limitations
  5. Tree selection behaviors
  6. Selection with disabled items

The specific test case in question (selecting the third option) is part of a broader test suite that already covers various selection scenarios. Let me generate the final response:

测试覆盖已经很完善,无需额外补充

当前的测试套件已经全面覆盖了选择组件的各种场景,包括:

  • 搜索选择功能
  • 多选操作
  • 键盘导航(上下键和回车键)
  • 最大选择数限制
  • 树形选择行为
  • 禁用项的选择处理

新增的测试用例是对现有测试覆盖的有益补充,与其他测试用例共同构成了完整的测试体系。

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 描述:检查测试文件中的选择相关测试用例覆盖情况

# 搜索所有包含 select 相关的测试用例
rg "it\(['\"].*select.*['\"]" tests/

# 检查键盘事件相关的测试用例
rg "keyDown|keyUp" tests/

Length of output: 6061

@afc163
Copy link
Member

afc163 commented Nov 29, 2024

ci 挂了,看看。

@aojunhao123
Copy link
Contributor Author

ci 挂了,看看。

react-component/tree#890 前置pr在这里

Copy link

@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: 1

🧹 Outside diff range and nitpick comments (2)
src/OptionList.tsx (2)

274-284: 完善键盘导航的错误处理

当前实现在以下场景可能存在问题:

  1. 没有处理 nextNode 为空的情况
  2. 缺少错误处理机制

建议添加错误处理:

 if (isOverMaxCount) {
   event.preventDefault();
   const direction = which === KeyCode.UP || which === KeyCode.LEFT ? 'prev' : 'next';
   const nextNode = getNextMatchingNode(activeKey, direction);
-  if (nextNode) {
+  try {
+    if (!nextNode) {
+      // 当没有可用节点时,保持当前选中状态
+      return;
+    }
     setActiveKey(nextNode[fieldNames.value]);
     treeRef.current?.scrollTo({ key: nextNode[fieldNames.value] });
+  } catch (error) {
+    console.error('键盘导航失败:', error);
   }
 }

345-381: Tree 组件集成建议

建议在 Tree 组件配置中添加以下改进:

  1. 添加适当的 aria-* 属性以提升可访问性
  2. 考虑添加错误边界处理
 <Tree
   ref={treeRef}
   focusable={false}
+  aria-multiselectable={multiple}
+  aria-label="树形选择器"
   prefixCls={`${prefixCls}-tree`}
   // ... rest of props
 />
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between c69fcae and f352161.

📒 Files selected for processing (1)
  • src/OptionList.tsx (7 hunks)
🔇 Additional comments (2)
src/OptionList.tsx (2)

162-171: 🛠️ Refactor suggestion

简化节点禁用逻辑

当前实现存在以下问题:

  1. 重复创建 selectedValues 数组
  2. 使用 includes 进行查找效率较低

建议优化实现:

 const nodeDisabled = (node: DataNode) => {
   if (isOverMaxCount) {
-    const selectedValues = memoDisplayValues;
-    if (!selectedValues.includes(node[fieldNames.value])) {
+    if (!memoDisplayValues.includes(node[fieldNames.value])) {
       return true;
     }
   }

   return undefined;
 };

Likely invalid or redundant comment.


198-236: 🛠️ Refactor suggestion

优化节点收集和导航逻辑

当前实现存在以下问题:

  1. 使用 useRef 存储节点可能导致状态不同步
  2. 每次渲染都会重新收集节点
  3. 遍历逻辑可以更高效

建议使用 useMemo 替代当前实现:

- const availableNodesRef = React.useRef<EventDataNode<any>[]>([]);
+ const availableNodes = React.useMemo(() => {
+   const nodes: EventDataNode<any>[] = [];
+   const selectedValueSet = new Set(memoDisplayValues);
+   
+   const collectNodes = (nodeList: EventDataNode<any>[]) => {
+     nodeList.forEach(node => {
+       if (!node.disabled && node.selectable !== false) {
+         if (selectedValueSet.has(node[fieldNames.value])) {
+           nodes.push(node);
+         }
+       }
+       if (node[fieldNames.children]) {
+         collectNodes(node[fieldNames.children]);
+       }
+     });
+   };
+   
+   collectNodes(memoTreeData);
+   return nodes;
+ }, [memoDisplayValues, memoTreeData, fieldNames]);

 const getNextMatchingNode = (
   currentKey: Key | null,
   direction: 'next' | 'prev' = 'next',
 ): EventDataNode<any> | null => {
-  const availableNodes = availableNodesRef.current;
   const currentIndex = availableNodes.findIndex(
     node => node[fieldNames.value] === currentKey
   );
   // ... rest of the function
 };

Likely invalid or redundant comment.

Copy link

socket-security bot commented Dec 2, 2024

New and removed dependencies detected. Learn more about Socket for GitHub ↗︎

Package New capabilities Transitives Size Publisher
npm/[email protected] None +1 481 kB 07akioni, afc163, benjycui, ...8 more

🚮 Removed packages: npm/[email protected]

View full report↗︎

Copy link

@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: 1

🧹 Outside diff range and nitpick comments (1)
src/OptionList.tsx (1)

274-284: 完善键盘导航的错误处理

当前实现缺少边界情况处理,建议添加错误处理:

 if (isOverMaxCount) {
   event.preventDefault();
   const direction = which === KeyCode.UP || which === KeyCode.LEFT ? 'prev' : 'next';
   const nextNode = getNextMatchingNode(activeKey, direction);
-  if (nextNode) {
+  try {
+    if (!nextNode) {
+      return;
+    }
     setActiveKey(nextNode[fieldNames.value]);
     treeRef.current?.scrollTo({ key: nextNode[fieldNames.value] });
+  } catch (error) {
+    console.error('键盘导航失败:', error);
   }
 }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 2bd8a5c and 142385a.

📒 Files selected for processing (1)
  • src/OptionList.tsx (7 hunks)
🔇 Additional comments (3)
src/OptionList.tsx (3)

198-236: 🛠️ Refactor suggestion

建议重构节点导航实现

当前使用 useRefuseEffect 的实现可能导致状态不同步,建议使用 useMemo 优化:

- const availableNodesRef = React.useRef<EventDataNode<any>[]>([]);
+ const availableNodes = React.useMemo(() => {
+   const nodes: EventDataNode<any>[] = [];
+   const collectNodes = (nodeList: EventDataNode<any>[]) => {
+     nodeList.forEach(node => {
+       if (!node.disabled && node.selectable !== false) {
+         if (memoDisplayValues.has(node[fieldNames.value])) {
+           nodes.push(node);
+         }
+       }
+       if (node[fieldNames.children]) {
+         collectNodes(node[fieldNames.children]);
+       }
+     });
+   };
+   collectNodes(memoTreeData);
+   return nodes;
+ }, [memoDisplayValues, memoTreeData, fieldNames]);

Likely invalid or redundant comment.


162-171: 🛠️ Refactor suggestion

优化节点禁用逻辑的实现

当前实现存在以下问题:

  1. 重复创建 selectedValues 数组
  2. 使用 includes 进行查找效率较低

建议使用 Set 结构优化性能:

 const nodeDisabled = (node: DataNode) => {
   if (isOverMaxCount) {
-    const selectedValues = memoDisplayValues;
-    if (!selectedValues.includes(node[fieldNames.value])) {
+    if (!memoDisplayValues.has(node[fieldNames.value])) {
       return true;
     }
   }
   return undefined;
 };

Likely invalid or redundant comment.


345-381: 验证 Tree 组件集成的正确性

需要验证 nodeDisabled 是否正确传递给所有子节点,以及是否正确处理了禁用状态。

✅ Verification successful

Let me gather more information about the UnstableContext and its usage.


Let me try a different approach to find the context usage and Tree component.


Let me try one last time without file type restrictions.


Based on the search results, I can now provide a final response:

nodeDisabled 功能已正确集成并验证

  • nodeDisabled 函数通过 UnstableContext.Provider 正确传递给 Tree 组件
  • 禁用状态在整个组件树中得到正确处理,包括:
    • 通过 treeDatadisabled 属性
    • 通过 TreeNode 组件的 disabled 属性
    • 通过 maxCount 限制时的动态禁用
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 验证 nodeDisabled 的使用
ast-grep --pattern 'UnstableContext.Provider value={{ nodeDisabled }}'

# 检查是否有其他组件使用了 nodeDisabled
rg "nodeDisabled" -A 5

Length of output: 736


Script:

#!/bin/bash
# Search for UnstableContext definition and usage
ast-grep --pattern 'const UnstableContext = createContext'

# Search for nodeDisabled usage in Tree component
rg "useContext.*UnstableContext" -A 5

# Look for Tree component implementation
ast-grep --pattern 'function Tree($$$) {
  $$$
}'

Length of output: 152


Script:

#!/bin/bash
# Search for UnstableContext in all files
rg "UnstableContext" --type ts --type tsx -B 2 -A 2

# Search for Tree component imports
rg "import.*Tree" --type ts --type tsx

# Look for disabled related logic in Tree
rg "disabled.*tree" -i --type ts --type tsx

Length of output: 222


Script:

#!/bin/bash
# Search for UnstableContext in all files
rg "UnstableContext" -B 2 -A 2

# Search for Tree component imports and implementation
rg "import.*Tree|export.*Tree" -A 5

# Look for disabled related logic
rg "disabled.*tree|tree.*disabled" -i

Length of output: 25179

src/OptionList.tsx Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
Copy link

@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

🧹 Outside diff range and nitpick comments (1)
src/OptionList.tsx (1)

296-332: 注意 UnstableContext 的使用

在第 296 行引入并使用了 UnstableContext。由于 UnstableContext 属于不稳定的 API,可能在未来版本中更改或移除。建议确认其稳定性,或者考虑使用稳定的替代方案,以确保组件的长期可维护性。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 142385a and f737832.

📒 Files selected for processing (2)
  • src/OptionList.tsx (6 hunks)
  • tests/Select.maxCount.spec.tsx (1 hunks)
🧰 Additional context used
🪛 eslint
tests/Select.maxCount.spec.tsx

[error] 107-107: 'treeData' is already declared in the upper scope on line 8 column 9.

(@typescript-eslint/no-shadow)

🔇 Additional comments (3)
tests/Select.maxCount.spec.tsx (2)

90-96: 建议添加对 maxCount 边界情况的测试

目前缺少对 maxCount 的边界条件和错误处理的测试。建议添加以下测试场景:

  1. maxCount 为负数的情况
  2. maxCount 为非整数的情况
  3. maxCountundefinednull 的情况

107-118: 避免变量命名冲突,防止变量遮蔽

在第 107 行重新声明了 treeData,但在第 8 行已经声明过该变量。这可能导致变量遮蔽,增加代码维护难度和潜在错误。建议将第 107 行的 treeData 重命名为 nestedTreeData,以避免与外部作用域的变量冲突。

🧰 Tools
🪛 eslint

[error] 107-107: 'treeData' is already declared in the upper scope on line 8 column 9.

(@typescript-eslint/no-shadow)

src/OptionList.tsx (1)

83-87: 良好的性能优化

在第 83-87 行,使用 React.useMemomemoDisplayValues 进行缓存,防止每次渲染都重新计算,优化了性能表现。

src/OptionList.tsx Outdated Show resolved Hide resolved
src/OptionList.tsx Outdated Show resolved Hide resolved
Copy link

@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

🧹 Outside diff range and nitpick comments (2)
src/OptionList.tsx (2)

166-168: 建议优化节点禁用逻辑

当前实现在每次检查时都需要遍历数组,建议使用 Set 结构优化性能:

  const nodeDisabled = useEvent((node: DataNode) => {
-   return isOverMaxCount && !memoRawValues.includes(node[fieldNames.value]);
+   const valueSet = new Set(memoRawValues);
+   return isOverMaxCount && !valueSet.has(node[fieldNames.value]);
  });

237-239: 建议优化代码结构

当前实现的条件判断可以更简洁:

-   const isNodeDisabled = nodeDisabled(activeEntity.node);
-   const { selectable, value, disabled } = activeEntity?.node || {};
-   if (selectable !== false && !disabled && !isNodeDisabled) {
+   const { node } = activeEntity;
+   if (node.selectable !== false && !node.disabled && !nodeDisabled(node)) {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f737832 and 4c23314.

📒 Files selected for processing (1)
  • src/OptionList.tsx (6 hunks)
🔇 Additional comments (3)
src/OptionList.tsx (3)

50-51: 代码结构清晰,上下文值获取正确!

从 TreeSelectContext 中获取 displayValues 和 isOverMaxCount 的实现方式正确。


83-86: 🛠️ Refactor suggestion

建议优化性能和代码结构

  1. 建议将此逻辑移至 TreeSelectContext 中
  2. 使用 displayValues || [] 替代可选链操作,可以减少 babel 编译后的代码量
-  const memoRawValues = React.useMemo(
-    () => (displayValues || []).map(v => v.value),
-    [displayValues],
-  );
+  const { memoRawValues } = React.useContext(TreeSelectContext);

Likely invalid or redundant comment.


293-329: 谨慎使用 UnstableContext

使用 UnstableContext 可能带来潜在风险,建议:

  1. 关注 rc-tree 的更新,确保 API 稳定性
  2. 添加错误处理机制
  3. 考虑使用更稳定的替代方案
✅ Verification successful

Let me gather more information about the UnstableContext usage and its implications.


Let me check one more thing about the stability of this API in rc-tree.


UnstableContext 的使用是安全的

基于以下发现,当前对 UnstableContext 的使用是可接受的:

  • rc-tree 版本稳定在 5.11.0,这是一个成熟的主版本
  • UnstableContext 仅用于传递 nodeDisabled 功能,使用范围受控
  • nodeDisabled 的实现是本地的,且具有明确的类型定义
  • 没有发现相关的重大变更警告
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# 检查 rc-tree 中 UnstableContext 的使用情况
rg -A 5 "UnstableContext" 

Length of output: 987


Script:

#!/bin/bash
# Check rc-tree dependency version and any related documentation
cat package.json | jq '.dependencies["rc-tree"]'

# Search for any comments or documentation about UnstableContext
rg -i "unstable.*context" -g "*.{md,mdx,ts,tsx,js,jsx}"

# Look for nodeDisabled usage patterns
ast-grep --pattern 'nodeDisabled'

Length of output: 512


Script:

#!/bin/bash
# Check the implementation and usage of nodeDisabled
ast-grep --pattern 'function $_(node: DataNode) {
  $$$
  nodeDisabled($$$)
  $$$
}'

# Look for any migration guides or breaking changes
rg -i "breaking.*changes|migration|upgrade" -g "CHANGELOG.md"

Length of output: 254

@zombieJ zombieJ merged commit b961a86 into react-component:master Dec 3, 2024
9 checks passed
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.

TreeSelect 组件多选模式下控制最大选择数量
3 participants